V0.1 Deliverables
Complete list of deliverables expected for the V0.1 (MVP) release, organized by application.Front-Office (13 deliverables)
| # | Deliverable |
|---|---|
| 1 | Repository bootstrapped (Nuxt 3) with dev, build, generate commands |
| 2 | CSS design tokens (light/dark, RTL-ready), Flowbite with no hardcoded hex |
| 3 | Layouts: Home, Article, Page |
| 4 | i18n: fr, en, nl, ar with language switcher and correct <html lang> |
| 5 | SEO: title/description meta, canonical URL, hreflang, sitemap stub, robots.txt |
| 6 | Islands: 1 dynamic block (hero) |
| 7 | Accessibility: skip link, focus management, AA contrast |
| 8 | Placeholder images with blurhash |
| 9 | CSP hash-only in report-only mode + CI grep (unhashed inline = build fail) |
| 10 | Performance budgets CI hard-fail: JS ≤ 180 KB (+20%), CSS ≤ 60 KB (+20%), LCP image ≤ 120 KB, LCP ≤ 2.0s / 2.5s |
| 11 | Consumes /v1/public/* only (never sends Authorization header) |
| 12 | Pagination, sort, and filter UI support |
| 13 | Playwright DNT test: DNT=1 produces zero Matomo hits |
Back-Office (12 deliverables)
| # | Deliverable |
|---|---|
| 1 | Repository SPA (Nuxt) with dashboard and stub pages (Articles, Pages, Media) |
| 2 | i18n: fr, en, nl |
| 3 | UI design tokens with Flowbite overrides |
| 4 | Real Keycloak auth (OIDC PKCE, short AT 5-10 min, no RT), mock available within 48h. Playwright tests for AT expiration + ITP-like behavior |
| 5 | Accessible forms |
| 6 | Unlayer editor with palette locked, client-side sanitization (matched by API) |
| 7 | CSP hash-only in report-only + Trusted Types in report-only |
| 8 | OpenAPI hash conformant (/contract-hash) — build fails on mismatch |
| 9 | ETag/If-Match on PUT/PATCH + UX handling for 412/428 when CONCURRENCY_STRICT=1 |
| 10 | Playwright XSS test: injection attempt produces 0 API calls |
| 11 | Protected navigation with role-based menus |
| 12 | BFF V0.2 ticket referenced with deadline (2025-11-15) and assigned owner |
API (16 deliverables)
| # | Deliverable |
|---|---|
| 1 | Symfony 7 + API Platform repository (Domain/Application/Infrastructure/Security/Voter/State/EventSubscriber/Http/Listener) |
| 2 | JWT Authenticator RS256 via JWKS + JwtUser (tenantId, roles, userId=sub). Strict validation: iss/aud/azp/sub/typ/skew. id_token forbidden. Circuit breaker + double-KID rollover. |
| 3 | Entities: Article, Page, Redirect, Media with localized fields. Unicode slugs + slug_ascii. Unique constraint on (tenant_id, locale, slug_ascii). |
| 4 | Security: Doctrine Filter global (read) + Security expressions. Item-level Voters only (no collection-level). |
| 5 | State Processor: POST/PUT/PATCH forces tenantId from JWT. Malicious body values ignored. |
| 6 | QueryFilterEnforcer: HTTP fail-fast (500 if filter OFF). CLI exemptions whitelisted and tested. |
| 7 | Concurrency: strong ETag + If-Match (PUT/PATCH). CanonicalJsonNormalizer (read groups only). CONCURRENCY_STRICT flag. |
| 8 | Public /v1/public/*: distinct DTO whitelists, anonymous, cacheable, complete Vary. Authorization present returns 403 + no-store. |
| 9 | Preview /v1/preview/*: X-Preview-Token header (HMAC-SHA256), Redis one-time (SETNX+TTL), TTL max 5 min, no-store, UA blocklist, X-Robots-Tag. |
| 10 | Pagination/sort/filter normalized. X-Total-Count + Link (RFC 5988). |
| 11 | Media: presigned PUT ≤ 10 MiB, HEAD post-upload + backoff, DELETE if out-of-range, metadata, SSE (S3/KMS), tenant quotas. |
| 12 | OpenAPI /v1 export CI + Spectral lint + contract hash + x-openapi-rev header + /contract-hash endpoint + Problem RFC 7807. |
| 13 | RateLimiter: auth/public keys RGPD-safe (pepper), Retry-After, whitelists, quotas per role. Pepper rotation tests. |
| 14 | Cache-Control/ETag + Vary (Origin, Accept-Language, Accept-Encoding). no-store if Authorization present. |
| 15 | /healthz: ping DB + JWKS cache + clock skew + ICU version exposed. |
| 16 | PHPUnit ≥ 80% coverage on critical domain paths. |