Vorbereitung
Cursor, Windsurf, Claude 3.5 Sonnet, Bolt.new, Cline, Lovable, Replit Agent, GitHub Copilot Edits.
Die Frage nach dem Setup – am Ende eine pragmatische:
- Ich habe ein laufendes OpenAI‑ChatGPT‑Abo mit Zugriff auf Codex, das wars.
- Kein vorheriges Benchmark, kein Testlauf, alles was jetzt kommt ist ein First Shot.
- Zwar mit versilberten Kugeln, Silber und Erfahrung und einem Zielfernrohr und stillstehendem Wetterfähnchen (kein Wind), aber das ist der erste Durchlauf.
Was auch bedeuten könnte, dass diese Post‑Serie sehr kurz wird.
Also zu den Vorbereitungen:
eine Idee, ein Ziel, ein übersichtlicher Tech‑Stack, garniert mit ein paar Vorlieben: KISS, YAGNI, VANILLA – meine drei Kugeln Eis, ohne Sahne, mit Streusel, mit einem Streusel.
Also kein Hexenwerk, Wald‑ und Wiesen‑Anforderungen.
Das alles nicht in der Waffel und auch nicht im Becher, sondern zusammengefasst in einer SPEC.md
# 📘 SPEC.md — *Employee Management System (EMS)*
**Version:** 1.0
**Status:** Final
**Zweck:** Vollständige technische Spezifikation für ein API‑first, DSGVO‑konformes Mitarbeiter‑Management-System.
**Ziel:** Codex‑kompatible, deterministische Vorgaben für Implementierung & Review.
---
# 0) Leitprinzipien
- **API-first**: UI ist ein Client der API. Keine direkte DB‑Kopplung.
- **Schema.org JSON‑LD**: Jede Entität hat eine JSON‑LD‑Repräsentation.
- **DSGVO by design**: Zweckbindung, Datenminimierung, Einwilligungen, Audit, Export, Löschung.
- **Observability**: Health, strukturierte Logs, Audit Trails, Metriken.
- **KISS/YAGNI**: Nur Employee, SkillGraph, Evidence, Consent, Audit.
- **Austauschbarkeit**: UI, API, Infra klar getrennt.
---
# 1) Runtime / Docker Setup
## Services
- **nginx** (static + reverse proxy)
- **php-fpm** (eigener Dockerfile, siehe unten)
- **mariadb**
- **redis**
- **node-build** (nur on-demand, Profil `build`)
- **playwright** (Test Runner)
## Ports
- `/` → UI
- `/api` → API
- `/docs` → OpenAPI UI
- `/health` → Health
- `/metrics` → Metriken
## Compose-Regeln
- `node-build` läuft **nicht automatisch**, nur via:
```
docker compose run --rm --profile build node-build
```
---
# 2) PHP Runtime (Dockerfile)
**Pflicht: eigener Dockerfile unter `ops/php/Dockerfile`.**
### Muss enthalten:
- Extensions:
`pdo_mysql`, `intl`, `mbstring`, `ctype`, `json`, `opcache`
- Composer (offizieller Installer)
- Opcache aktiviert (prod‑ready)
- Optional: `redis` Extension oder `predis/predis`
### Beispiel-Skeleton:
```Dockerfile
FROM php:8.3-fpm-alpine
RUN apk add --no-cache icu-dev oniguruma-dev $PHPIZE_DEPS \
&& docker-php-ext-install pdo_mysql intl mbstring \
&& docker-php-ext-enable opcache
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
WORKDIR /var/www
```
---
# 3) Request/Response Kernel (PSR‑7)
## Verbindliche Entscheidung:
> **ServerRequest wird ausschließlich mit `nyholm/psr7-server` erzeugt.**
### Code:
```php
$psr17 = new Nyholm\Psr7\Factory\Psr17Factory();
$creator = new Nyholm\Psr7Server\ServerRequestCreator(
$psr17, $psr17, $psr17, $psr17
);
$request = $creator->fromGlobals();
```
### Emitter:
> **Response wird ausschließlich mit `Laminas\HttpHandlerRunner\Emitter\SapiEmitter` ausgegeben.**
---
# 4) Routing
## Zwei Frontcontroller:
- `public/index.php` → UI
- `public/api.php` → API
## UI Routing:
> **UI verwendet ebenfalls FastRoute. Keine separaten PHP‑Dateien pro Seite.**
---
# 5) Ordnerstruktur
```
app/
Domain/
Employee/
Skill/
Evidence/
Consent/
Audit/
Application/
UseCase/
Infrastructure/
Persistence/
Auth/
Logging/
JsonLd/
Http/
Controller/
Middleware/
Request/
Response/
public/
index.php
api.php
ops.php
assets/
docs/
assets/
less/
js/
openapi/
openapi.yaml
db/
migrations/
seeds/
phinx.php
tests/
playwright/
ops/
php/
Dockerfile
nginx/
default.conf
scripts/
migrate.sh
seed.sh
```
---
# 6) Datenmodell (SQL)
## Tabellen (MVP)
### employee
- id (UUID, PK)
- internal_number
- first_name
- last_name
- email (nullable, UNIQUE)
- status (active/inactive)
- created_at, updated_at, deleted_at
### skill
- id (UUID)
- code
- label
- description
- defined_term_set
### employee_skill
- id (UUID)
- employee_id
- skill_id (nullable)
- custom_label (nullable)
- level
- valid_from, valid_to
**Constraint:** entweder `skill_id` ODER `custom_label`
### evidence
- id (UUID)
- employee_id
- type
- title
- source_url
- issued_at
- valid_until
- verification_status
### organization_role
- id (UUID)
- employee_id
- role_title
- organization_name
- from, to
### consent
- id (UUID)
- employee_id
- purpose
- legal_basis
- granted_at
- revoked_at
- scope (JSON)
### audit_log
- id (UUID)
- actor_id
- actor_type
- entity_type
- entity_id
- action
- purpose
- created_at
- metadata (JSON)
---
# 7) Migrations
> **Verbindlich: Phinx als einziges Migrationstool.**
Ausführung:
```
docker compose exec php vendor/bin/phinx migrate
docker compose exec php vendor/bin/phinx seed:run
```
---
# 8) Auth Contract
## Humans
- Session‑Cookie (`HttpOnly`, `SameSite=Lax`)
## Machines
- Bearer Token
- Tokens haben **Scopes**:
`employees.read`, `employees.write`, `audit.read`, …
## Middleware Pipeline
1. `AuthMiddleware`
2. `ScopeMiddleware`
---
# 9) Audit Contract
- **Write‑Operationen** → immer loggen
- **Read‑Operationen** → loggen, wenn entity ∈ {employee, evidence, consent}
- **Export** → immer loggen
- Audit‑Log in DB + eigenem Log‑Channel `audit`
---
# 10) PII-Masking Contract
Felder, die **niemals** in App‑Logs erscheinen:
- email
- phone
- address
- consent.scope
Masking:
- Email → `a***@domain.tld`
- Sonst → `***MASKED***`
---
# 11) JSON-LD Contract
Jede Entität hat eine JSON‑LD‑Repräsentation mit:
- `@context: https://schema.org`
- `@type`
- `@id` (URN: `urn:employee:<uuid>` etc.)
---
# 12) API Design
## Versionierung
`/api/v1/...`
## Content Negotiation
- `application/json` (default)
- `application/ld+json` (JSON‑LD Serializer)
## Fehlerformat
RFC7807 Problem Details
## Endpunkte (MVP)
- Auth: login/logout/me
- Employee CRUD
- Skills + Evidence
- Graph Endpoint
- Export + Erase
- Audit Query
- Health + Metrics
---
# 13) Observability
## Health
- `/health` → liveness + readiness
- readiness prüft DB + Migrations + Redis
## Metrics
- `/metrics` → einfache Counter/Gauges
## Logging
- JSON Logs
- Felder: request_id, actor_id, action, entity, latency_ms, status, purpose
- Channels: `app`, `audit`
---
# 14) Frontend
- SSR HTML
- JS als progressive enhancement
- ESM Modules
- LESS → CSS (build via node-build)
- A11y: Skip Links, aria‑describedBy, Fokus‑Management
- JSON‑LD im HTML
---
# 15) Tests
## Playwright
- Smoke: Startseite, Login, Liste, Detail
- A11y: axe
- API Contract Tests
- Visual minimal
---
# 16) MVP Scope (2 Wochen)
1. Login + Token
2. Employee CRUD
3. Skill + Evidence
4. Graph Endpoint
5. JSON‑LD + OpenAPI
6. Audit + Export
---
# 17) Implementierungsplan
**Schritt 1–2**
- Repo + Docker-Setup
- Nginx-Config, public/index.php, Hello World
**Schritt 3–4**
- DB-Migrations
- Domain-Layer
**Schritt 5–6**
- Routing + Auth
- Employee CRUD
**Schritt 7–8**
- Skills + Evidence
- Graph Endpoint
**Schritt 9**
- JSON-LD + Content Negotiation
- OpenAPI + /docs
**Schritt 10**
- Audit Hooks
- Export Endpoint
**Schritt 11–12**
- Playwright + Smoke + A11y
**Schritt 13–14**
- Lighthouse + A11y/SEO
- Seeds + READMEund einem Coding Flow, von dem ich denke:
# 📘 CODING_FLOW.md
**Iterativer Implementierungsablauf für das Employee Management System (EMS)**
**Version:** 1.0
**Status:** Final
Dieses Dokument definiert die **exakte Reihenfolge**, in der Codex das Projekt gemäß **SPEC.md** implementiert.
Jeder Schritt besteht aus:
- einem **Ausführungs‑Prompt**
- einem **Review‑Prompt**
Codex arbeitet diese Prompts **sequenziell** ab.
Codex darf **keine Schritte überspringen**, **keine eigenen Entscheidungen treffen** und **keine Patterns erfinden**, die nicht in SPEC.md stehen.
---
# 🔰 Startprompt (immer zuerst ausführen)
```
Lies die Datei SPEC.md vollständig.
Du implementierst das Projekt strikt nach dieser Spezifikation.
Du darfst keine eigenen Patterns, Libraries oder Strukturen erfinden.
Alle Entscheidungen sind in SPEC.md normativ festgelegt.
Bestätige, dass du SPEC.md vollständig verstanden hast.
```
---
# 🧱 Prompt 1 — Grundstruktur (Schritt 1–2)
```
Erstelle die Grundstruktur des Repositories gemäß SPEC.md:
- Ordnerstruktur anlegen
- Docker Compose erstellen
- PHP Dockerfile erstellen
- nginx default.conf erstellen
- public/index.php mit "Hello Employee Management"
- ops/scripts/migrate.sh + seed.sh (noch leer)
- node-build Service (Profil build)
Erzeuge ausschließlich Dateien und Code, die SPEC.md exakt entsprechen.
Keine Business-Logik, keine DB-Migrationen.
```
---
# 🔍 Prompt 2 — Review + Spec-Abgleich
```
Prüfe die erzeugten Dateien gegen SPEC.md:
- Entsprechen alle Pfade der vorgegebenen Struktur?
- Sind alle Services korrekt konfiguriert?
- Ist node-build im Profil "build"?
- Wird der PHP Dockerfile korrekt verwendet?
- Ist nginx Routing korrekt?
- Ist index.php minimal und korrekt?
Liste Abweichungen auf und korrigiere sie.
Wenn etwas unklar ist, stelle eine Rückfrage.
```
---
# 🧱 Prompt 3 — Schritt 3–4 (Migrations + Domain-Layer)
```
Implementiere:
1. Phinx-Migrations für:
- employee
- skill
- employee_skill
- evidence
- consent
- audit_log
2. Minimaler Domain-Layer:
- Entities (Value Objects, Aggregate Roots)
- Repository Interfaces
- RepositoryDb Implementierungen (leer oder minimal)
Keine Business-Logik, nur Struktur + Konstruktoren + Getter.
```
---
# 🔍 Prompt 4 — Review + Spec-Abgleich
```
Prüfe:
- Stimmen alle Tabellen exakt mit SPEC.md überein?
- Sind Constraints korrekt (z. B. skill_id XOR custom_label)?
- Sind Entities vollständig?
- Sind Repositories korrekt benannt und platziert?
Liste Abweichungen auf und korrigiere sie.
```
---
# 🧱 Prompt 5 — Schritt 5–6 (Routing + Auth + Employee CRUD)
```
Implementiere:
1. FastRoute Routing (UI + API)
2. AuthMiddleware + ScopeMiddleware
3. Session-Login (POST /auth/login)
4. GET /me
5. Employee CRUD (API)
6. Einfache HTML-Views für Employee-Liste + Detail
Beachte:
- PSR-7 Request/Response
- nyholm/psr7-server
- SapiEmitter
- PII-Masking in Logs
```
---
# 🔍 Prompt 6 — Review + Spec-Abgleich
```
Prüfe:
- Funktioniert das Routing korrekt?
- Ist Auth gemäß SPEC.md implementiert?
- Werden Sessions korrekt gesetzt?
- Sind Employee CRUD Endpunkte vollständig?
- Sind HTML-Views minimal, aber korrekt?
Liste Abweichungen auf und korrigiere sie.
```
---
# 🧱 Prompt 7 — Schritt 7–8 (Skills, Evidence, Graph Endpoint)
```
Implementiere gemäß SPEC.md:
1. Endpunkte für Skills:
- POST /employees/{id}/skills
- PATCH /employees/{id}/skills/{skillId}
2. Endpunkte für Evidence:
- POST /employees/{id}/evidence
3. Graph Endpoint:
- GET /employees/{id}/graph
- Aggregierter DTO: Employee + Skills + Evidence
- JSON-Ausgabe gemäß SPEC.md (noch ohne JSON-LD)
4. Validierung:
- PSR-7 Request
- Request-Validator (Symfony Validator)
- Fehlerformat: RFC7807 Problem Details
5. Logging:
- App-Log für alle Requests
- Audit-Log für alle Write-Operationen
Erzeuge ausschließlich Code, der SPEC.md exakt entspricht.
Keine JSON-LD-Serialisierung in diesem Schritt.
```
---
# 🔍 Prompt 8 — Review + Spec-Abgleich
```
Prüfe:
- Stimmen alle Routen exakt mit SPEC.md überein?
- Werden Write-Operationen korrekt auditiert?
- Ist das Fehlerformat RFC7807-konform?
- Sind alle DTOs konsistent aufgebaut?
- Ist die Aggregation im Graph-Endpoint korrekt?
- Werden keine JSON-LD-Elemente verwendet?
Liste Abweichungen auf und korrigiere sie.
```
---
# 🧱 Prompt 9 — Schritt 9 (JSON-LD + Content Negotiation + OpenAPI)
```
Implementiere gemäß SPEC.md:
1. JSON-LD Serializer:
- EmployeeJsonLdSerializer
- SkillJsonLdSerializer
- EvidenceJsonLdSerializer
- URN-IDs gemäß SPEC.md
- @context: https://schema.org
2. Content Negotiation:
- Accept: application/json → normale DTOs
- Accept: application/ld+json → JSON-LD Serializer
- Middleware: ContentNegotiationMiddleware
3. OpenAPI 3.1:
- Erstelle openapi/openapi.yaml
- Dokumentiere alle Endpunkte aus SPEC.md
- Nutze schema.org-Begriffe als Referenz, aber keine externen Schemas einbinden
4. /docs:
- Statische OpenAPI UI unter public/docs
- Nginx-Route sicherstellen
Erzeuge ausschließlich Code, der SPEC.md exakt entspricht.
```
---
# 🔍 Prompt 10 — Review + Spec-Abgleich
```
Prüfe:
- JSON-LD-Ausgabe korrekt?
- URN-IDs korrekt aufgebaut?
- Content Negotiation Middleware korrekt implementiert?
- OpenAPI.yaml vollständig und valide?
- /docs korrekt erreichbar?
Liste Abweichungen auf und korrigiere sie.
```
---
# 🧱 Prompt 11 — Schritt 10 (Audit Hooks + Export Endpoint)
```
Implementiere gemäß SPEC.md:
1. Audit Hooks:
- Middleware, die Write-Operationen IMMER loggt
- Read-Operationen loggen, wenn entity_type ∈ {employee, evidence, consent}
- Export IMMER loggen
- AuditRepositoryDb implementieren
2. Export Endpoint:
- GET /employees/{id}/export
- Ausgabe: vollständiger Datensatz (Employee + Skills + Evidence + Consent)
- Format: application/json (kein JSON-LD)
- PII-Masking NICHT anwenden (Export ist legitim)
3. Logging:
- Audit-Channel
- App-Channel
Erzeuge ausschließlich Code, der SPEC.md exakt entspricht.
```
---
# 🔍 Prompt 12 — Review + Spec-Abgleich
```
Prüfe:
- Werden alle Audit-Regeln exakt eingehalten?
- Werden Read-Operationen korrekt gefiltert?
- Ist der Export vollständig und SPEC-konform?
- Werden keine PII-Felder im App-Log ausgegeben?
- Ist das Audit-Log vollständig (actor_id, entity_id, purpose, metadata)?
Liste Abweichungen auf und korrigiere sie.
```
---
# 🧱 Prompt 13 — Schritt 11–12 (Playwright + Smoke + A11y)
```
Implementiere gemäß SPEC.md:
1. Playwright Container:
- tests/playwright/
- playwright.config.ts
- Smoke Tests:
- Startseite lädt
- Login funktioniert
- Employee-Liste lädt
- Employee-Detail lädt
2. A11y Tests:
- axe-core Integration
- Prüfe: headings, labels, aria-describedby, skip links
3. CI-Ready:
- Tests müssen gegen compose stack laufen
- Reports als Artefakte erzeugen
Erzeuge ausschließlich Code, der SPEC.md exakt entspricht.
```
---
# 🔍 Prompt 14 — Review + Spec-Abgleich
```
Prüfe:
- Läuft Playwright gegen den laufenden Compose-Stack?
- Sind Smoke-Tests stabil?
- Sind A11y-Checks korrekt integriert?
- Werden Reports erzeugt?
Liste Abweichungen auf und korrigiere sie.
```
---
# 🧱 Prompt 15 — Schritt 13–14 (Lighthouse + Seeds + README)
```
Implementiere gemäß SPEC.md:
1. Lighthouse:
- Führe Lighthouse gegen die UI aus
- Optimiere:
- A11y
- SEO
- Performance (Critical CSS, Caching)
- Keine Frameworks hinzufügen
2. Seeds:
- db/seeds/ Demo-Dataset:
- 10 Employees
- 50 Skills
- 30 Evidence
3. README.md:
- "compose up -d"
- "docker compose run --rm --profile build node-build"
- "docker compose exec php vendor/bin/phinx migrate"
- "docker compose exec php vendor/bin/phinx seed:run"
- "npx playwright test"
Erzeuge ausschließlich Code, der SPEC.md exakt entspricht.
```„Das könnte funktionieren. Kann man so machen. Und wird hoffentlich nicht scheiße.“
GitHub‑Repo angelegt
Repo angelegt – klappt mit Codex.
Prompts geschrieben.
Und so langsam juckt es mich in den Fingern, den ersten Prompt ins Chatfenster zu posten.