rename cts-work to pp-planer, move Dockerfile to build/, optimize dev scripts
- Rename all cts-work references to pp-planer (valet, sanctum, playwright, e2e, docs) - Fix docker-compose build context to use project root with build/Dockerfile - Add .dockerignore to exclude unnecessary files from Docker build - start_dev.sh: stale PID cleanup, dependency checks, APP_KEY check, process health verification - stop_dev.sh: fix set -e crash on arithmetic, report already-dead processes, idempotent exit
This commit is contained in:
parent
af9b8d1882
commit
1eb4f1642f
10
.dockerignore
Normal file
10
.dockerignore
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
node_modules
|
||||||
|
vendor
|
||||||
|
.git
|
||||||
|
.env
|
||||||
|
storage/logs/*
|
||||||
|
storage/framework/cache/*
|
||||||
|
storage/framework/views/*
|
||||||
|
test-results
|
||||||
|
tests/e2e/.auth
|
||||||
|
.dev.pid
|
||||||
10
AGENTS.md
10
AGENTS.md
|
|
@ -104,14 +104,14 @@ ## Repository Structure
|
||||||
|
|
||||||
| Repo | Path | Branch | Purpose |
|
| Repo | Path | Branch | Purpose |
|
||||||
|------|------|--------|---------|
|
|------|------|--------|---------|
|
||||||
| **cts-work** | `/Users/thorsten/AI/cts-work` | `cts-presenter-app` | Laravel app (main codebase) |
|
| **pp-planer** | `/Users/thorsten/AI/pp-planer` | `cts-presenter-app` | Laravel app (main codebase) |
|
||||||
| **propresenter-work** | `/Users/thorsten/AI/propresenter-work/php` | `propresenter-parser` | ProPresenter .pro/.proplaylist parser (composer path dependency) |
|
| **propresenter-work** | `/Users/thorsten/AI/propresenter-work/php` | `propresenter-parser` | ProPresenter .pro/.proplaylist parser (composer path dependency) |
|
||||||
|
|
||||||
The parser is linked via `composer.json` path repository: `"url": "../propresenter-work/php"`.
|
The parser is linked via `composer.json` path repository: `"url": "../propresenter-work/php"`.
|
||||||
|
|
||||||
## Build, Test, Lint Commands
|
## Build, Test, Lint Commands
|
||||||
|
|
||||||
### cts-work (Laravel App)
|
### pp-planer (Laravel App)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# First-time setup
|
# First-time setup
|
||||||
|
|
@ -141,7 +141,7 @@ # PHP formatting (Laravel Pint, default preset — no pint.json)
|
||||||
./vendor/bin/pint
|
./vendor/bin/pint
|
||||||
./vendor/bin/pint --test # check only
|
./vendor/bin/pint --test # check only
|
||||||
|
|
||||||
# E2E tests (requires dev server at http://cts-work.test)
|
# E2E tests (requires dev server at http://pp-planer.test)
|
||||||
npx playwright test
|
npx playwright test
|
||||||
npx playwright test tests/e2e/service-list.spec.ts
|
npx playwright test tests/e2e/service-list.spec.ts
|
||||||
|
|
||||||
|
|
@ -164,7 +164,7 @@ # Single test file
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
```
|
```
|
||||||
cts-work/
|
pp-planer/
|
||||||
app/Http/Controllers/ # Inertia controllers (Inertia::render or JSON)
|
app/Http/Controllers/ # Inertia controllers (Inertia::render or JSON)
|
||||||
app/Models/ # Eloquent models (factories in database/factories/)
|
app/Models/ # Eloquent models (factories in database/factories/)
|
||||||
app/Services/ # Business logic (ChurchToolsService, ProExportService, etc.)
|
app/Services/ # Business logic (ChurchToolsService, ProExportService, etc.)
|
||||||
|
|
@ -241,7 +241,7 @@ ### ProPresenter Parser Tests (PHPUnit 11)
|
||||||
|
|
||||||
### E2E Tests (Playwright)
|
### E2E Tests (Playwright)
|
||||||
|
|
||||||
- TypeScript in `tests/e2e/`, baseURL `http://cts-work.test`
|
- TypeScript in `tests/e2e/`, baseURL `http://pp-planer.test`
|
||||||
- Auth via `auth.setup.ts` (XSRF token + `/dev-login` endpoint, saves state to `.auth/user.json`)
|
- Auth via `auth.setup.ts` (XSRF token + `/dev-login` endpoint, saves state to `.auth/user.json`)
|
||||||
- Selectors: `page.getByTestId('...')`, `page.getByText('...')`, `page.getByRole('...')`
|
- Selectors: `page.getByTestId('...')`, `page.getByText('...')`, `page.getByRole('...')`
|
||||||
- German text assertions: `await expect(page.getByText('Mit ChurchTools anmelden')).toBeVisible()`
|
- German text assertions: `await expect(page.getByText('Mit ChurchTools anmelden')).toBeVisible()`
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', 'localhost,localhost:8000,127.0.0.1,127.0.0.1:8000,::1,cts-work.test')),
|
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', 'localhost,localhost:8000,127.0.0.1,127.0.0.1:8000,::1,pp-planer.test')),
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
version: '3.8'
|
version: "3.8"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: build/Dockerfile
|
||||||
container_name: cts-presenter-app
|
container_name: pp-planer-app
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
working_dir: /app
|
working_dir: /app
|
||||||
environment:
|
environment:
|
||||||
|
|
@ -27,13 +27,13 @@ services:
|
||||||
ports:
|
ports:
|
||||||
- "8000:8000"
|
- "8000:8000"
|
||||||
networks:
|
networks:
|
||||||
- cts-network
|
- pp-planer-network
|
||||||
depends_on:
|
depends_on:
|
||||||
- node
|
- node
|
||||||
|
|
||||||
node:
|
node:
|
||||||
image: node:20-alpine
|
image: node:20-alpine
|
||||||
container_name: cts-presenter-node
|
container_name: pp-planer-node
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
working_dir: /app
|
working_dir: /app
|
||||||
environment:
|
environment:
|
||||||
|
|
@ -44,14 +44,14 @@ services:
|
||||||
ports:
|
ports:
|
||||||
- "5173:5173"
|
- "5173:5173"
|
||||||
networks:
|
networks:
|
||||||
- cts-network
|
- pp-planer-network
|
||||||
command: npm run dev
|
command: npm run dev
|
||||||
|
|
||||||
# Optional: SQLite database service (for reference, SQLite runs in-process)
|
# Optional: SQLite database service (for reference, SQLite runs in-process)
|
||||||
# For MySQL, uncomment and configure:
|
# For MySQL, uncomment and configure:
|
||||||
# mysql:
|
# mysql:
|
||||||
# image: mysql:8.0
|
# image: mysql:8.0
|
||||||
# container_name: cts-presenter-mysql
|
# container_name: pp-planer-mysql
|
||||||
# restart: unless-stopped
|
# restart: unless-stopped
|
||||||
# environment:
|
# environment:
|
||||||
# MYSQL_DATABASE: ${DB_DATABASE}
|
# MYSQL_DATABASE: ${DB_DATABASE}
|
||||||
|
|
@ -63,12 +63,11 @@ services:
|
||||||
# ports:
|
# ports:
|
||||||
# - "3306:3306"
|
# - "3306:3306"
|
||||||
# networks:
|
# networks:
|
||||||
# - cts-network
|
# - pp-planer-network
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
cts-network:
|
pp-planer-network:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
|
|
||||||
# volumes:
|
# volumes:
|
||||||
# mysql_data:
|
# mysql_data:
|
||||||
# driver: local
|
# driver: local
|
||||||
|
|
|
||||||
2
package-lock.json
generated
2
package-lock.json
generated
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"name": "cts-work",
|
"name": "pp-planer",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ export default defineConfig({
|
||||||
timeout: 5000,
|
timeout: 5000,
|
||||||
},
|
},
|
||||||
use: {
|
use: {
|
||||||
baseURL: 'http://cts-work.test',
|
baseURL: 'http://pp-planer.test',
|
||||||
trace: 'on-first-retry',
|
trace: 'on-first-retry',
|
||||||
},
|
},
|
||||||
projects: [
|
projects: [
|
||||||
|
|
|
||||||
68
start_dev.sh
68
start_dev.sh
|
|
@ -3,6 +3,7 @@ set -euo pipefail
|
||||||
|
|
||||||
PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
PID_FILE="$PROJECT_DIR/.dev.pid"
|
PID_FILE="$PROJECT_DIR/.dev.pid"
|
||||||
|
SITE_NAME="pp-planer"
|
||||||
cd "$PROJECT_DIR"
|
cd "$PROJECT_DIR"
|
||||||
|
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
|
|
@ -11,21 +12,55 @@ RED='\033[0;31m'
|
||||||
CYAN='\033[0;36m'
|
CYAN='\033[0;36m'
|
||||||
NC='\033[0m'
|
NC='\033[0m'
|
||||||
|
|
||||||
|
# ── Stale PID cleanup ──────────────────────────────────────
|
||||||
if [ -f "$PID_FILE" ]; then
|
if [ -f "$PID_FILE" ]; then
|
||||||
echo -e "${RED}Dev-Umgebung läuft bereits.${NC}"
|
ALL_DEAD=true
|
||||||
echo -e "Stoppe zuerst mit: ${CYAN}./stop_dev.sh${NC}"
|
while read -r PID; do
|
||||||
exit 1
|
if kill -0 "$PID" 2>/dev/null; then
|
||||||
|
ALL_DEAD=false
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done < <(tr ' ' '\n' < "$PID_FILE")
|
||||||
|
|
||||||
|
if [ "$ALL_DEAD" = true ]; then
|
||||||
|
echo -e "${YELLOW}▸ Verwaiste PID-Datei entfernt${NC}"
|
||||||
|
rm -f "$PID_FILE"
|
||||||
|
else
|
||||||
|
echo -e "${RED}Dev-Umgebung läuft bereits.${NC}"
|
||||||
|
echo -e "Stoppe zuerst mit: ${CYAN}./stop_dev.sh${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Valet link ──────────────────────────────────────────────
|
# ── Valet link ──────────────────────────────────────────────
|
||||||
echo -e "${YELLOW}▸ Valet-Link prüfen …${NC}"
|
echo -e "${YELLOW}▸ Valet-Link prüfen …${NC}"
|
||||||
if [ ! -L "$HOME/.config/valet/Sites/cts-work" ]; then
|
if [ ! -L "$HOME/.config/valet/Sites/$SITE_NAME" ]; then
|
||||||
valet link cts-work 2>/dev/null
|
valet link "$SITE_NAME" 2>/dev/null
|
||||||
echo -e " ${GREEN}✓${NC} Valet-Link erstellt: cts-work.test"
|
echo -e " ${GREEN}✓${NC} Valet-Link erstellt: ${SITE_NAME}.test"
|
||||||
else
|
else
|
||||||
echo -e " ${GREEN}✓${NC} Valet-Link vorhanden"
|
echo -e " ${GREEN}✓${NC} Valet-Link vorhanden"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ── Dependencies check ──────────────────────────────────────
|
||||||
|
if [ ! -d "node_modules" ]; then
|
||||||
|
echo -e "${YELLOW}▸ npm install …${NC}"
|
||||||
|
npm install --silent
|
||||||
|
echo -e " ${GREEN}✓${NC} Node-Module installiert"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d "vendor" ]; then
|
||||||
|
echo -e "${YELLOW}▸ composer install …${NC}"
|
||||||
|
composer install --quiet
|
||||||
|
echo -e " ${GREEN}✓${NC} Composer-Pakete installiert"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── APP_KEY check ───────────────────────────────────────────
|
||||||
|
if ! grep -q '^APP_KEY=base64:' .env 2>/dev/null; then
|
||||||
|
echo -e "${YELLOW}▸ APP_KEY generieren …${NC}"
|
||||||
|
php artisan key:generate --quiet
|
||||||
|
echo -e " ${GREEN}✓${NC} APP_KEY generiert"
|
||||||
|
fi
|
||||||
|
|
||||||
# ── Migrate ─────────────────────────────────────────────────
|
# ── Migrate ─────────────────────────────────────────────────
|
||||||
echo -e "${YELLOW}▸ Migrations ausführen …${NC}"
|
echo -e "${YELLOW}▸ Migrations ausführen …${NC}"
|
||||||
php artisan migrate --force --quiet
|
php artisan migrate --force --quiet
|
||||||
|
|
@ -35,13 +70,26 @@ echo -e " ${GREEN}✓${NC} Datenbank aktuell"
|
||||||
echo -e "${YELLOW}▸ Queue-Worker starten …${NC}"
|
echo -e "${YELLOW}▸ Queue-Worker starten …${NC}"
|
||||||
php artisan queue:listen --tries=1 --timeout=0 > /dev/null 2>&1 &
|
php artisan queue:listen --tries=1 --timeout=0 > /dev/null 2>&1 &
|
||||||
QUEUE_PID=$!
|
QUEUE_PID=$!
|
||||||
echo -e " ${GREEN}✓${NC} Queue-Worker (PID $QUEUE_PID)"
|
sleep 0.3
|
||||||
|
if kill -0 "$QUEUE_PID" 2>/dev/null; then
|
||||||
|
echo -e " ${GREEN}✓${NC} Queue-Worker (PID $QUEUE_PID)"
|
||||||
|
else
|
||||||
|
echo -e " ${RED}✗${NC} Queue-Worker konnte nicht gestartet werden"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# ── Vite dev server ─────────────────────────────────────────
|
# ── Vite dev server ─────────────────────────────────────────
|
||||||
echo -e "${YELLOW}▸ Vite starten …${NC}"
|
echo -e "${YELLOW}▸ Vite starten …${NC}"
|
||||||
npm run dev > /dev/null 2>&1 &
|
npx --yes vite --port 5173 > /dev/null 2>&1 &
|
||||||
VITE_PID=$!
|
VITE_PID=$!
|
||||||
echo -e " ${GREEN}✓${NC} Vite (PID $VITE_PID)"
|
sleep 0.5
|
||||||
|
if kill -0 "$VITE_PID" 2>/dev/null; then
|
||||||
|
echo -e " ${GREEN}✓${NC} Vite (PID $VITE_PID)"
|
||||||
|
else
|
||||||
|
echo -e " ${RED}✗${NC} Vite konnte nicht gestartet werden"
|
||||||
|
kill "$QUEUE_PID" 2>/dev/null || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# ── Save PIDs ───────────────────────────────────────────────
|
# ── Save PIDs ───────────────────────────────────────────────
|
||||||
echo "$QUEUE_PID $VITE_PID" > "$PID_FILE"
|
echo "$QUEUE_PID $VITE_PID" > "$PID_FILE"
|
||||||
|
|
@ -51,7 +99,7 @@ echo -e "${GREEN}═════════════════════
|
||||||
echo -e "${GREEN} Dev-Umgebung läuft!${NC}"
|
echo -e "${GREEN} Dev-Umgebung läuft!${NC}"
|
||||||
echo -e "${GREEN}═══════════════════════════════════════════════${NC}"
|
echo -e "${GREEN}═══════════════════════════════════════════════${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " App: ${CYAN}http://cts-work.test${NC}"
|
echo -e " App: ${CYAN}http://${SITE_NAME}.test${NC}"
|
||||||
echo -e " Vite: ${CYAN}http://localhost:5173${NC}"
|
echo -e " Vite: ${CYAN}http://localhost:5173${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " Stop: ${YELLOW}./stop_dev.sh${NC}"
|
echo -e " Stop: ${YELLOW}./stop_dev.sh${NC}"
|
||||||
|
|
|
||||||
16
stop_dev.sh
16
stop_dev.sh
|
|
@ -3,7 +3,6 @@ set -euo pipefail
|
||||||
|
|
||||||
PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
PID_FILE="$PROJECT_DIR/.dev.pid"
|
PID_FILE="$PROJECT_DIR/.dev.pid"
|
||||||
cd "$PROJECT_DIR"
|
|
||||||
|
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
|
|
@ -11,18 +10,27 @@ YELLOW='\033[1;33m'
|
||||||
NC='\033[0m'
|
NC='\033[0m'
|
||||||
|
|
||||||
if [ ! -f "$PID_FILE" ]; then
|
if [ ! -f "$PID_FILE" ]; then
|
||||||
echo -e "${RED}Dev-Umgebung läuft nicht.${NC}"
|
echo -e "${RED}Dev-Umgebung läuft nicht (keine PID-Datei).${NC}"
|
||||||
exit 1
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
STOPPED=0
|
||||||
|
ALREADY_DEAD=0
|
||||||
|
|
||||||
while read -r PID; do
|
while read -r PID; do
|
||||||
if kill "$PID" 2>/dev/null; then
|
if kill "$PID" 2>/dev/null; then
|
||||||
|
STOPPED=$((STOPPED + 1))
|
||||||
echo -e " ${YELLOW}▸${NC} Prozess $PID gestoppt"
|
echo -e " ${YELLOW}▸${NC} Prozess $PID gestoppt"
|
||||||
|
else
|
||||||
|
ALREADY_DEAD=$((ALREADY_DEAD + 1))
|
||||||
fi
|
fi
|
||||||
done < <(tr ' ' '\n' < "$PID_FILE")
|
done < <(tr ' ' '\n' < "$PID_FILE")
|
||||||
|
|
||||||
rm -f "$PID_FILE"
|
rm -f "$PID_FILE"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${GREEN}Dev-Umgebung gestoppt.${NC}"
|
if [ "$ALREADY_DEAD" -gt 0 ]; then
|
||||||
|
echo -e "${YELLOW} $ALREADY_DEAD Prozess(e) waren bereits beendet.${NC}"
|
||||||
|
fi
|
||||||
|
echo -e "${GREEN}Dev-Umgebung gestoppt. ($STOPPED Prozess(e) beendet)${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
|
||||||
|
|
@ -4,22 +4,22 @@ const authFile = 'tests/e2e/.auth/user.json';
|
||||||
|
|
||||||
setup('authenticate', async ({ page }) => {
|
setup('authenticate', async ({ page }) => {
|
||||||
// Navigate to login page to establish session cookies (incl. XSRF-TOKEN)
|
// Navigate to login page to establish session cookies (incl. XSRF-TOKEN)
|
||||||
await page.goto('http://cts-work.test/login');
|
await page.goto('http://pp-planer.test/login');
|
||||||
|
|
||||||
// Get XSRF token from cookies for CSRF protection
|
// Get XSRF token from cookies for CSRF protection
|
||||||
const cookies = await page.context().cookies('http://cts-work.test');
|
const cookies = await page.context().cookies('http://pp-planer.test');
|
||||||
const xsrfCookie = cookies.find((c) => c.name === 'XSRF-TOKEN');
|
const xsrfCookie = cookies.find((c) => c.name === 'XSRF-TOKEN');
|
||||||
const xsrfToken = decodeURIComponent(xsrfCookie?.value || '');
|
const xsrfToken = decodeURIComponent(xsrfCookie?.value || '');
|
||||||
|
|
||||||
// POST to dev-login route directly (bypasses Vue rendering dependency)
|
// POST to dev-login route directly (bypasses Vue rendering dependency)
|
||||||
await page.request.post('http://cts-work.test/dev-login', {
|
await page.request.post('http://pp-planer.test/dev-login', {
|
||||||
headers: {
|
headers: {
|
||||||
'X-XSRF-TOKEN': xsrfToken,
|
'X-XSRF-TOKEN': xsrfToken,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Navigate to dashboard to confirm login and load session
|
// Navigate to dashboard to confirm login and load session
|
||||||
await page.goto('http://cts-work.test/dashboard');
|
await page.goto('http://pp-planer.test/dashboard');
|
||||||
await page.waitForURL('**/dashboard');
|
await page.waitForURL('**/dashboard');
|
||||||
|
|
||||||
// Save signed-in state
|
// Save signed-in state
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue