diff --git a/.codex/PHASES.md b/.codex/PHASES.md index 1d03266..7a0f41f 100644 --- a/.codex/PHASES.md +++ b/.codex/PHASES.md @@ -19,10 +19,10 @@ | Field | Value | |------------|--------------------------------| -| Block ID | R-02 | -| Title | Documentation and workflow consistency | -| Status | in-progress | -| File | `.codex/blocks/BLOCK-TEMPLATE.md` | +| Block ID | R-03 | +| Title | Launch checklist | +| Status | done | +| File | `.codex/blocks/R-03.md` | --- @@ -60,8 +60,8 @@ | ID | Block | Status | |------|-------------------------------|---------| | R-01 | Visual polish + regression | in-progress | -| R-02 | Performance + QA | in-progress | -| R-03 | Launch checklist | pending | +| R-02 | Performance + QA | done | +| R-03 | Launch checklist | done | --- @@ -73,4 +73,4 @@ --- -_Last updated: 2026-04-13_ +_Last updated: 2026-04-20_ diff --git a/.codex/SNAPSHOT.md b/.codex/SNAPSHOT.md index bf58b4a..1575124 100644 --- a/.codex/SNAPSHOT.md +++ b/.codex/SNAPSHOT.md @@ -1,9 +1,13 @@ # Snapshot — Portfolio Project -Date: 2026-04-13 -Status: Production ready (public site + CMS + case content) +Date: 2026-04-16 +Status: Production-ready site + active V2 CMS/AI acceleration track Source of truth: this file (`.codex/SNAPSHOT.md`) +## Workflow State +- `.codex` phase/block/task routing is synchronized: active block `R-02` now points to `.codex/blocks/R-02.md`. +- Session work follows approval gates: Change Plan -> user `yes` -> implementation -> separate commit/push confirmations. + ## Product Context - Portfolio for product designer (Dima Ginzburg) - Positioning: product-first, minimal/brutalist, content-driven @@ -25,12 +29,15 @@ Source of truth: this file (`.codex/SNAPSHOT.md`) - `/admin` — custom GitHub-backed CMS - `/perf-test` — diagnostics page - `/api/cases`, `/api/contact`, `/api/save-content`, `/api/upload-image`, `/api/theme` +- `/api/intake/github` — AI draft intake from GitHub signals +- `/api/intake/github/runtime-import` — runtime screenshot import into case assets ## Content Model - Content source: `src/content/` JSON + typed loader (`src/content/cases.ts`) - Case files: `src/content/cases/*.json` - Homepage source: `src/content/home.json` - Case block types: `paragraph`, `list`, `link`, `media` +- Case structure target for AI drafts: Context, Problem, Constraints, Role, Approach, Solution, Outcome ## Current Case Slugs (ordered) 1. `travel-booking-platform` @@ -39,19 +46,45 @@ Source of truth: this file (`.codex/SNAPSHOT.md`) 4. `my-perfect-greek-vacation` 5. `design-system-runtime` -## CMS Status +## CMS + AI Status - Admin UI: `src/app/admin/page.tsx` - Save pipeline: GitHub API commit flow via `/api/save-content` - Image upload: `/api/upload-image` - Auth: basic auth vars (`CMS_ADMIN_USER`, `CMS_ADMIN_PASSWORD`) in `middleware.ts` +- GitHub AI intake implemented (MVP): + - Signals: repo metadata + README + merged PRs + closed issues + - Modes: `llm` (default) and `heuristic` + - Evidence links + route candidates + runtime screenshot plan are exposed in UI + - Draft-only application with user confirmation remains default behavior +- Runtime screenshot import implemented: + - Extractor command `import_runtime_screenshot` + - Uploads to `public/cases//...` + - Auto-applies imported assets into `Visual Artifacts` + +## AI Runtime/Config Notes +- Required for LLM mode: `OPENAI_API_KEY` +- Optional model override: `GITHUB_INTAKE_LLM_MODEL` (default in code: `gpt-4.1-mini`) +- Optional screenshot template: `GITHUB_INTAKE_SCREENSHOT_TEMPLATE` +- GitHub write path for CMS/extractor: `GITHUB_PAT`, `GITHUB_REPO`, `GITHUB_BRANCH` + +## Roadmap Gap Status (as of 2026-04-16) +- 4.1 Repo -> Case Draft: baseline implemented +- 4.2 Narrative Gap Detector: pending +- 4.3 Artifact-to-Block Auto Mapper: partial (runtime screenshot import + media/link merge present) +- 4.4 Case Consistency QA Bot: pending +- 4.5 One-Click Case Starter: pending + +## Workspace Hygiene Notes +- Unexpected duplicate files with suffix ` 2` were detected in `src/`, `cms-extract/`, and `public/`. +- Most are byte-identical copies; some are older intermediate revisions. +- They are not part of the active source-of-truth paths and should be cleaned in a dedicated hygiene pass. ## Git/Workspace Notes -- Main branch: `main` (local was behind `origin/main` during this snapshot) -- Local worktrees were used for parallel agent edits under `.claude/worktrees/` +- Main branch: `main` - Canonical workflow files: `.codex/*` - Legacy assistant workflow files are retained but should not be used as active status tracking ## Known Follow-ups - Keep `.codex/SNAPSHOT.md` updated after meaningful project changes -- Keep `README.md` aligned with real project state (not starter template text) -- Avoid tracking local worktree paths in Git index +- Keep `README.md` aligned with real project state (including AI intake env vars) +- Resolve duplicate `* 2.*` files in a controlled cleanup pass diff --git a/.codex/blocks/R-02.md b/.codex/blocks/R-02.md new file mode 100644 index 0000000..6fc87e0 --- /dev/null +++ b/.codex/blocks/R-02.md @@ -0,0 +1,658 @@ +# Block: R-02 — Performance + QA + +> Detail file for this block. Created by `init-block `. +> `PHASES.md` tracks block status only. All task detail lives here. + +--- + +## Block Goal + +Stabilize CMS + AI intake quality workflow with deterministic planning, explicit approval gates, and verifiable QA signals before merge. + +## Definition of Done + +Active CMS+AI sprint tasks are executed through approved Change Plans, verified by tests/lint, and integrated with commit/push confirmation gates. + +--- + +## Tasks + +| ID | Task | Status | Done When | +|---------|-------------------------------------------|-------------|-----------| +| R-02-T1 | Sync `.codex` workflow state to active block | done | `PHASES.md` points to `.codex/blocks/R-02.md`, active task is explicit, and snapshot records sync status | +| R-02-T2 | Finalize and commit Sprint S1 changes via approval gates | done | User approves commit after review; commit includes snapshot + sprint plan + S1 implementation files | +| R-02-T3 | Implement S2 intake confidence signals | done | `/api/intake/github` returns typed confidence summary and admin displays it in AI intake panel | +| R-02-T4 | Harden artifact-to-block auto-mapper (S3) | done | Runtime import does not produce uncontrolled duplicates; Visual Artifacts merge is deterministic; tests cover repeated import and route collisions | +| R-02-T5 | Rule-based consistency QA bot MVP (S4) | done | API + admin expose rule-based consistency checks (tone/order/evidence) with tests for core rules | +| R-02-T6 | One-click case starter MVP shell (S5) | done | API returns starter title/subtitle variants; admin requires explicit Apply action before replacing current form | +| R-02-T7 | Section-level evidence coverage for intake drafts | done | `/api/intake/github` returns `evidenceBySection` and admin shows section coverage summary/details | +| R-02-T8 | Blueprint cover candidate in intake flow | done | Intake returns deterministic blueprint cover candidate and admin supports explicit apply of cover fields | +| R-02-T9 | Sticky save bar + unsaved state UX in admin | done | Admin shows sticky save controls and explicit unsaved/synced state relative to repository baseline | +| R-02-T10 | Live inline validation and save readiness state | done | Admin shows live validation issues and save is enabled only when form is ready | +| R-02-T11 | Modularize AI Intake panel in admin editor | done | AI Intake UI block is extracted into `AiIntakePanel` component with no behavior regression and passing verification checks | +| R-02-T12 | Narrative rewrite suggestions for weak/missing sections | done | Intake returns deterministic rewrite suggestions with confidence and admin shows actionable section-level rewrite guidance | +| R-02-T13 | One-click apply for rewrite suggestions | done | Admin can apply section rewrite suggestions in one action, updating existing section paragraph or creating missing section deterministically | +| R-02-T14 | Modularize sections editor into standalone component | done | Sections editing UI (blocks/media/drag controls) is moved from `admin/page.tsx` to `SectionsEditor` component without behavior regressions | +| R-02-T15 | Bulk apply rewrite suggestions with deterministic helper | done | Admin can apply all rewrite suggestions at once via deterministic section update/create helper covered by unit tests | +| R-02-T16 | Add optimistic save locking via `baseSha` | done | Admin sends `baseSha`, save API rejects stale writes before PUT, and successful/skipped responses return the current `sha` | +| R-02-T17 | Add concurrent-save race coverage for optimistic locking | done | Tests cover two save attempts with same `baseSha`, where first succeeds and second deterministically returns `CONTENT_CONFLICT` | +| R-02-T18 | Extend `Retry-After` handling in GitHub retry helper | done | `fetchGitHubWithRetry` supports `Retry-After` seconds and HTTP-date formats with tested fallback to exponential backoff | +| R-02-T19 | Add structured CMS audit logs for save and upload APIs | done | Save and upload routes emit structured audit entries containing who/what/when/path/result and commit SHA on successful writes | +| R-02-T20 | Add malicious and edge SVG fixture coverage | done | SVG utility rejects broken control chars, data URI payloads, unsafe tags, and excessive path-node complexity with deterministic tests | +| R-02-T21 | Harden upload path policy in media API | done | Upload API accepts only `public/cases//` image paths and rejects traversal/out-of-scope/unsupported extensions with tests | +| R-02-T22 | Remove legacy `variant` fallback from save pipeline | done | Save API rejects media blocks carrying legacy `variant` field instead of silently normalizing it out | +| R-02-T23 | Add orphan cleanup for partial upload/save failures | done | CMS can trigger safe cleanup for orphaned `public/cases/*` uploads after ambiguous upload failures and after successful saves when tracked paths are no longer referenced | +| R-02-T24 | Add E2E smoke flow for upload/save/reload in admin | done | Admin smoke test verifies SVG upload feedback, successful save, and persisted media path after admin reload | +| R-02-T25 | Close legacy embed/variant cleanup in schema, admin, and content | done | Validation blocks legacy embed placeholders/URLs, admin has regression guard for no variant dropdown, and migration test confirms no `variant`/`FIGMA_EMBED_*` leftovers across `src/content/**/*.json` | +| R-02-T26 | Close lint debt checkpoint and handoff to next release block | done | Global `eslint` passes, remaining R-02 backlog items are closed, and `PHASES.md` advances active block from R-02 to R-03 | + +> New tasks are added here as the block progresses via `init-task`. + +--- + +## Active Task + +| Field | Value | +|-----------|-------| +| Task ID | R-02-T26 | +| Title | Close lint debt checkpoint and handoff to next release block | +| Status | done | +| Done When | Global `eslint` passes, remaining R-02 backlog items are closed, and `PHASES.md` advances active block from R-02 to R-03 | + +--- + +## Change Plans + +> One entry per task. Written by agent before coding. Approved by user before execution. + +### R-02-T1 — Sync `.codex` workflow state to active block + +**Files to modify:** +- `.codex/PHASES.md` — point active block to real file and align metadata. +- `.codex/SNAPSHOT.md` — record workflow-state sync note. + +**Files to create:** +- `.codex/blocks/R-02.md` — active block detail with tasks and session state. + +**Files NOT touched:** +- business code and non-`.codex` docs. + +**Approach:** +Restore deterministic phase/block/task routing by creating the missing active block file, wiring `PHASES.md` to it, and documenting the synchronization in snapshot context. This keeps future `init-task` sessions predictable and approval-driven. + +**Risks:** +Task definitions may require refinement once S2/S3 scope is confirmed; mitigated by keeping tasks atomic and editable via future approved `init-task` cycles. + +### R-02-T2 — Finalize and commit Sprint S1 changes via approval gates + +**Files to modify:** +- `.codex/blocks/R-02.md` — task status progression and session notes. + +**Files to create:** +- none. + +**Files NOT touched:** +- duplicate `* 2.*` artifacts and any unrelated workspace files. + +**Approach:** +Run sync-check and validation commands, stage only approved Sprint S1 files through explicit path list, show staged delta for review, then commit only after user confirmation. + +**Risks:** +Accidental inclusion of duplicate artifacts or unrelated worktree files. Mitigated by explicit `git add` whitelist and staged diff review. + +### R-02-T3 — Implement S2 intake confidence signals + +**Files to modify:** +- `.codex/blocks/R-02.md` — task status and change-plan log. +- `src/lib/case-draft-quality.ts` — add reusable intake confidence summary helpers. +- `src/lib/__tests__/case-draft-quality.test.ts` — add confidence-focused tests. +- `src/app/api/intake/github/route.ts` — include typed confidence payload in intake response. +- `src/app/admin/page.tsx` — render confidence summary in AI intake panel. + +**Files to create:** +- none (unless helper extraction becomes necessary during implementation). + +**Files NOT touched:** +- duplicate `* 2.*` artifacts and unrelated CMS/upload files. + +**Approach:** +Build confidence from existing draft-quality signals in one shared lib function, return it from intake API, and render it in admin with compact overall and section-level diagnostics. + +**Risks:** +Overly noisy confidence output can reduce clarity; mitigate with concise section summaries and capped detail display. + +### R-02-T4 — Harden artifact-to-block auto-mapper (S3) + +**Files to modify:** +- `.codex/blocks/R-02.md` — task status and change-plan log. +- `src/lib/github-case-extractor.ts` — deterministic route-key merge and dedupe protection. +- `src/app/admin/page.tsx` — align runtime import merge with dedupe + deterministic append behavior. + +**Files to create:** +- `src/lib/__tests__/github-case-extractor.test.ts` — route-collision and repeated-import coverage. + +**Files NOT touched:** +- duplicate `* 2.*` artifacts and unrelated CMS/upload files. + +**Approach:** +Normalize route keys, dedupe imported artifacts by route (last import wins), upsert existing visual media deterministically, and append only missing media/link pairs in stable order. Mirror the same behavior in admin runtime-import reconciliation. + +**Risks:** +Over-normalization may collapse distinct routes unexpectedly; mitigated by exact normalized-key matching tests. + +### R-02-T5 — Rule-based consistency QA bot MVP (S4) + +**Files to modify:** +- `.codex/blocks/R-02.md` — task status and session tracking. +- `src/lib/case-draft-quality.ts` — add rule-based consistency report generator. +- `src/lib/__tests__/case-draft-quality.test.ts` — add core rule tests. +- `src/app/api/intake/github/route.ts` — include consistency in intake payload. +- `src/app/admin/page.tsx` — render consistency summary and top findings in AI Intake panel. + +**Files to create:** +- none. + +**Files NOT touched:** +- runtime extractor dedupe logic and duplicate `* 2.*` artifacts. + +**Approach:** +Introduce deterministic rule checks for section order, narrative tone/verbosity, and evidence-backed claims; expose typed report from API and show compact diagnostics in admin. + +**Risks:** +Rule sensitivity may produce noisy warnings; mitigated by conservative thresholds and capped findings list. + +### R-02-T6 — One-click case starter MVP shell (S5) + +**Files to modify:** +- `.codex/blocks/R-02.md` — task status and session tracking. +- `src/app/api/intake/github/route.ts` — include starter variants in intake payload. +- `src/app/admin/page.tsx` — render starter variants and explicit Apply action. + +**Files to create:** +- `src/lib/case-starter.ts` — deterministic title/subtitle variant generator. +- `src/lib/__tests__/case-starter.test.ts` — starter variant generation tests. + +**Files NOT touched:** +- extractor runtime import route and duplicate `* 2.*` artifacts. + +**Approach:** +Generate deterministic starter variants from draft + intake context in API response, then require explicit user Apply action in admin before replacing current form values. Keep save/publish unchanged. + +**Risks:** +Variant text quality may be generic on sparse repos; mitigated by conservative fallbacks and deterministic formatting. + +### R-02-T7 — Section-level evidence coverage for intake drafts + +**Files to modify:** +- `.codex/blocks/R-02.md` — task status and session tracking. +- `src/app/api/intake/github/route.ts` — include `evidenceBySection` in intake payload. +- `src/app/admin/page.tsx` — render section-level evidence coverage summary/details in AI Intake panel. + +**Files to create:** +- `src/lib/case-section-evidence.ts` — deterministic section evidence mapper. +- `src/lib/__tests__/case-section-evidence.test.ts` — evidence mapping tests. + +**Files NOT touched:** +- runtime extractor dedupe flow and duplicate `* 2.*` artifacts. + +**Approach:** +Build a deterministic mapper that combines provided evidence links with direct section links and infers section-level coverage by source type. Expose this in API and show compact coverage in admin. + +**Risks:** +Heuristic mapping may under-link sparse repositories; mitigated by using direct section links first and conservative type fallback rules. + +### R-02-T8 — Blueprint cover candidate in intake flow + +**Files to modify:** +- `.codex/blocks/R-02.md` — task status and session tracking. +- `src/app/api/intake/github/route.ts` — include `coverCandidate` in intake payload. +- `src/app/admin/page.tsx` — preview and explicit apply action for blueprint cover candidate. + +**Files to create:** +- `src/lib/blueprint-cover-candidate.ts` — deterministic blueprint candidate + SVG renderer. +- `src/lib/__tests__/blueprint-cover-candidate.test.ts` — candidate and renderer tests. +- `src/app/api/cover/blueprint/route.ts` — GET endpoint returning SVG by query. +- `src/app/api/cover/blueprint/route.test.ts` — route response contract tests. + +**Files NOT touched:** +- runtime import flow and duplicate `* 2.*` artifacts. + +**Approach:** +Create deterministic blueprint cover candidate derived from intake draft + focus, expose it in API payload, render preview SVG via dedicated route, and require explicit apply action before changing `coverSrc/coverAlt`. + +**Risks:** +Dynamic SVG cover URLs may be less CDN-friendly than static assets; mitigated by deterministic query params and cache headers. + +### R-02-T9 — Sticky save bar + unsaved state UX in admin + +**Files to modify:** +- `.codex/blocks/R-02.md` — task status and session tracking. +- `src/app/admin/page.tsx` — add repo-baseline dirty tracking and sticky save bar UX. + +**Files to create:** +- none. + +**Files NOT touched:** +- intake extraction logic, cover generation logic, and duplicate `* 2.*` artifacts. + +**Approach:** +Track server baseline snapshot on load/save, compute dirty state from current form content, disable save when no changes, and convert save controls block into sticky bar with clear state messaging. + +**Risks:** +Snapshot comparison can produce false positives if object shape/order is unstable; mitigated by using single source object updates and consistent JSON serialization. + +### R-02-T10 — Live inline validation and save readiness state + +**Files to modify:** +- `.codex/blocks/R-02.md` — task status and session tracking. +- `src/app/admin/page.tsx` — switch to live validation issue list and readiness-aware save UX. + +**Files to create:** +- none. + +**Files NOT touched:** +- intake APIs, cover candidate logic, and duplicate `* 2.*` artifacts. + +**Approach:** +Convert case validation from single error string to issue list, surface issues inline in sticky save bar, and disable save while issues exist. + +**Risks:** +Stricter client-side save gating may block workflows unexpectedly; mitigated by clear issue text and deterministic validation criteria. + +### R-02-T11 — Modularize AI Intake panel in admin editor + +**Files to modify:** +- `.codex/blocks/R-02.md` — task status and session tracking. +- `src/app/admin/page.tsx` — replace inline AI Intake block with component usage. + +**Files to create:** +- `src/app/admin/components/AiIntakePanel.tsx` — extracted AI Intake presentation and local display helpers. + +**Files NOT touched:** +- intake API contracts, cover generation logic, and duplicate `* 2.*` artifacts. + +**Approach:** +Extract the full AI Intake block into a dedicated component with explicit props and localize intake-specific visual helper functions inside it, keeping existing handlers/state orchestration in `page.tsx`. + +**Risks:** +Type mismatches between page state and extracted props can break build; mitigated by explicit prop typing and full test/lint/build verification. + +### R-02-T12 — Narrative rewrite suggestions for weak/missing sections + +**Files to modify:** +- `.codex/blocks/R-02.md` — task status and session tracking. +- `src/lib/case-draft-quality.ts` — add deterministic rewrite suggestion model and builder. +- `src/lib/__tests__/case-draft-quality.test.ts` — add tests for rewrite suggestion generation. +- `src/app/api/intake/github/route.ts` — include rewrite suggestions in intake response. +- `src/app/admin/page.tsx` — store and pass rewrite suggestions in AI intake state. +- `src/app/admin/components/AiIntakePanel.tsx` — render rewrite suggestions in AI intake panel. + +**Files to create:** +- none. + +**Files NOT touched:** +- extractor command execution path, cover SVG route implementation, and duplicate `* 2.*` artifacts. + +**Approach:** +Generate deterministic section-level rewrite suggestions from existing quality findings (missing required sections, weak constraints/outcome, evidence gaps), attach confidence and concise rewrite text, and surface them in admin as actionable guidance before apply/save. + +**Risks:** +Suggestion noise could reduce trust; mitigated by strict cap on top suggestions, severity-based ordering, and concise rationale. + +### R-02-T13 — One-click apply for rewrite suggestions + +**Files to modify:** +- `.codex/blocks/R-02.md` — task status and session tracking. +- `src/app/admin/components/AiIntakePanel.tsx` — add apply action per rewrite suggestion. +- `src/app/admin/page.tsx` — add deterministic handler that applies suggestion to current draft sections. + +**Files to create:** +- none. + +**Files NOT touched:** +- intake extractor flow, blueprint cover route, and duplicate `* 2.*` artifacts. + +**Approach:** +Wire an explicit per-suggestion apply button in AI Intake panel. On apply, update the first paragraph block in the matched section; if section does not exist, append a new section with a paragraph block from suggested rewrite, then persist to local draft state. + +**Risks:** +Applying suggestion to wrong section due to title mismatch; mitigated by normalized title matching and deterministic fallback section creation. + +### R-02-T14 — Modularize sections editor into standalone component + +**Files to modify:** +- `.codex/blocks/R-02.md` — task status and session tracking. +- `src/app/admin/page.tsx` — replace inline sections editor block with component usage. + +**Files to create:** +- `src/app/admin/components/SectionsEditor.tsx` — standalone sections editor UI with block/media controls. + +**Files NOT touched:** +- intake API routes, quality analyzers, and duplicate `* 2.*` artifacts. + +**Approach:** +Extract the full sections editor JSX (section title editing, block editing, media upload controls, drag-to-reorder UX) into a dedicated component and keep mutation handlers/source state orchestration in `page.tsx` via explicit callbacks. + +**Risks:** +Prop interface mismatch may break block mutation flows; mitigated by keeping callback signatures aligned with existing handlers and full test/lint/build verification. + +### R-02-T15 — Bulk apply rewrite suggestions with deterministic helper + +**Files to modify:** +- `.codex/blocks/R-02.md` — task status and session tracking. +- `src/app/admin/page.tsx` — switch rewrite apply flow to helper and add bulk apply action handler. +- `src/app/admin/components/AiIntakePanel.tsx` — add explicit `Apply All Rewrites` action in suggestions panel. + +**Files to create:** +- `src/lib/rewrite-suggestion-apply.ts` — deterministic section apply helpers. +- `src/lib/__tests__/rewrite-suggestion-apply.test.ts` — helper behavior tests. + +**Files NOT touched:** +- intake API contracts, extractor logic, and duplicate `* 2.*` artifacts. + +**Approach:** +Implement pure helper functions that apply one or many rewrite suggestions to sections with normalized title matching and deterministic create/update behavior, then wire single and bulk apply actions in admin UI. + +**Risks:** +Bulk apply order may produce unstable output; mitigated by deterministic section-order preserving algorithm and unit tests for repeated application. + +### R-02-T16 — Add optimistic save locking via `baseSha` + +**Files to modify:** +- `.codex/blocks/R-02.md` — task status and session tracking. +- `src/app/api/cases/[slug]/route.ts` — include source `sha` in case payload. +- `src/app/api/save-content/route.ts` — enforce `baseSha` conflict check and return current `sha` on success/skipped. +- `src/app/admin/page.tsx` — track `lastSyncedSha`, send `baseSha` on save, refresh local SHA after successful save. +- `src/app/api/save-content/route.test.ts` — add optimistic-locking and `sha` response tests. +- `src/app/admin/page.test.tsx` — align upload recovery expectation with sticky save state labels. + +**Files to create:** +- none. + +**Files NOT touched:** +- intake analyzer logic, extractor flow, and duplicate `* 2.*` artifacts. + +**Approach:** +Expose repository `sha` at load-time, pass it as `baseSha` when saving, and reject stale saves with deterministic `CONTENT_CONFLICT` before write. Return updated `sha` so client baseline stays in sync after save or unchanged skip. + +**Risks:** +False conflicts if SHA baseline is missing/stale; mitigated by explicit reload flow and unchanged-content short-circuit before conflict evaluation. + +### R-02-T17 — Add concurrent-save race coverage for optimistic locking + +**Files to modify:** +- `.codex/blocks/R-02.md` — task status and session tracking. +- `src/app/api/save-content/route.test.ts` — add race-condition scenario for two save attempts using the same `baseSha`. +- `BACKLOG.md` — mark optimistic locking and race-condition coverage items as completed. + +**Files to create:** +- none. + +**Files NOT touched:** +- runtime save logic, intake pipelines, and duplicate `* 2.*` artifacts. + +**Approach:** +Simulate two sequential save requests that share the same initial `baseSha`: first request updates content and receives a new SHA, second request reuses stale SHA and must fail with deterministic `CONTENT_CONFLICT`. + +**Risks:** +Over-mocked sequencing may miss production edge timing; mitigated by asserting request ordering and response codes on the API contract level. + +### R-02-T18 — Extend `Retry-After` handling in GitHub retry helper + +**Files to modify:** +- `.codex/blocks/R-02.md` — task status and session tracking. +- `src/lib/github-api.ts` — parse `Retry-After` as either seconds or HTTP-date, fallback to exponential backoff on invalid values. +- `src/lib/__tests__/github-api.test.ts` — add coverage for seconds/date parsing and invalid-header fallback behavior. +- `BACKLOG.md` — mark `Retry-After` hardening item as completed. + +**Files to create:** +- none. + +**Files NOT touched:** +- admin UI flows, save-content API contracts, and duplicate `* 2.*` artifacts. + +**Approach:** +Introduce a dedicated parser for `Retry-After` values that handles numeric seconds and RFC date strings, returns non-negative delay in milliseconds, and keeps existing exponential retry as deterministic fallback. + +**Risks:** +Date parsing can produce large delays if clocks diverge; mitigated by clamping date-based delay to non-negative values and preserving fallback behavior for invalid headers. + +### R-02-T19 — Add structured CMS audit logs for save and upload APIs + +**Files to modify:** +- `.codex/blocks/R-02.md` — task status and session tracking. +- `src/lib/cms-audit-log.ts` — add reusable audit logging helpers (actor resolution + structured event output). +- `src/lib/__tests__/cms-audit-log.test.ts` — verify actor parsing and structured payload output. +- `src/app/api/save-content/route.ts` — emit audit logs for success/skipped/conflict/error outcomes. +- `src/app/api/upload-image/route.ts` — emit audit logs for success/conflict/error outcomes. +- `BACKLOG.md` — mark audit-log backlog item as completed. + +**Files to create:** +- `src/lib/cms-audit-log.ts` +- `src/lib/__tests__/cms-audit-log.test.ts` + +**Files NOT touched:** +- admin UI components, intake analyzers, and duplicate `* 2.*` artifacts. + +**Approach:** +Centralize audit payload generation in a shared helper and call it from both mutation APIs on all terminal paths. Keep response contracts unchanged and log commit SHA when GitHub returns it. + +**Risks:** +Additional log volume in server runtime; mitigated by compact JSON payloads and no large content blobs in audit details. + +### R-02-T20 — Add malicious and edge SVG fixture coverage + +**Files to modify:** +- `.codex/blocks/R-02.md` — task status and session tracking. +- `src/lib/svg-upload.ts` — tighten SVG safety checks for control chars, data URI hrefs, high path-node count, and invalid parser output handling. +- `src/lib/__tests__/svg-upload.test.ts` — add deterministic edge fixtures for unsafe tags, data URI overload, broken encoding, and heavy path count. +- `BACKLOG.md` — mark malicious/edge SVG fixture item as completed. + +**Files to create:** +- none. + +**Files NOT touched:** +- admin UI, case save flow, and duplicate `* 2.*` artifacts. + +**Approach:** +Expand SVG guardrails in the utility layer and verify with focused fixtures representing known hostile/high-risk payload patterns. + +**Risks:** +Stricter SVG policy may reject previously accepted but questionable assets; mitigated by explicit error messages and targeted thresholds. + +### R-02-T21 — Harden upload path policy in media API + +**Files to modify:** +- `.codex/blocks/R-02.md` — task status and session tracking. +- `src/app/api/upload-image/route.ts` — validate upload path shape and file extension before GitHub operations. +- `src/app/api/upload-image/route.test.ts` — add tests for traversal/out-of-scope paths and unsupported extensions. +- `BACKLOG.md` — split combined path-policy/orphan-cleanup line and mark path-policy part complete. + +**Files to create:** +- none. + +**Files NOT touched:** +- save-content API, admin UI, and duplicate `* 2.*` artifacts. + +**Approach:** +Restrict uploads to `public/cases//` with allowlisted image extensions and reject unsafe path patterns before any upstream network call. + +**Risks:** +Overly strict filename policy could block rare but valid names; mitigated by allowing alphanumeric plus `._-` and clear validation errors. + +### R-02-T22 — Remove legacy `variant` fallback from save pipeline + +**Files to modify:** +- `.codex/blocks/R-02.md` — task status and session tracking. +- `src/app/api/save-content/route.ts` — stop stripping `variant` from media values before schema validation. +- `src/app/api/save-content/route.test.ts` — update legacy-variant scenario to expect validation rejection. +- `BACKLOG.md` — mark legacy variant removal in save pipeline as completed and leave remaining embed/model cleanup tasks explicit. + +**Files to create:** +- none. + +**Files NOT touched:** +- upload-image route, admin UI layout/components, and duplicate `* 2.*` artifacts. + +**Approach:** +Let schema validation fail fast on legacy `variant` fields so outdated payloads are surfaced explicitly instead of silently normalized. + +**Risks:** +Legacy editor payloads may now fail save until migrated; mitigated by explicit `VALIDATION_ERROR` messaging and separate backlog task for content migration. + +### R-02-T23 — Add orphan cleanup for partial upload/save failures + +**Files to modify:** +- `.codex/blocks/R-02.md` — task status and session tracking. +- `BACKLOG.md` — mark orphan cleanup item as completed. +- `src/lib/cms-audit-log.ts` — extend audit event type with cleanup operation. +- `src/app/api/upload-image/cleanup/route.ts` — add cleanup endpoint that checks case references and deletes orphaned uploads via GitHub API. +- `src/app/api/upload-image/cleanup/route.test.ts` — add deterministic coverage for invalid path, referenced skip, successful delete, and missing-file skip. +- `src/app/admin/page.tsx` — track uploaded media paths, run best-effort cleanup after ambiguous upload failures, and prune orphaned tracked paths after successful save. + +**Files to create:** +- `src/app/api/upload-image/cleanup/route.ts` +- `src/app/api/upload-image/cleanup/route.test.ts` + +**Files NOT touched:** +- intake analyzers, case rendering components, and duplicate `* 2.*` artifacts. + +**Approach:** +Introduce a dedicated cleanup API that only accepts the hardened `public/cases//` pattern, verifies the asset is not referenced in the related case JSON, then deletes it from GitHub when safe. Wire admin uploads/saves to invoke cleanup as a best-effort safety net for ambiguous failures and stale tracked assets. + +**Risks:** +Over-cleanup could remove still-needed media if reference detection is wrong; mitigated by strict path scope plus pre-delete reference check against current case content in repository. + +### R-02-T24 — Add E2E smoke flow for upload/save/reload in admin + +**Files to modify:** +- `.codex/blocks/R-02.md` — task status and session tracking. +- `BACKLOG.md` — mark E2E smoke flow item as completed. +- `src/app/admin/page.test.tsx` — add smoke scenario covering upload, save, and reload persistence. + +**Files to create:** +- none. + +**Files NOT touched:** +- runtime intake APIs, save/upload route implementations, and duplicate `* 2.*` artifacts. + +**Approach:** +Add a single deterministic integration-style Jest test on `AdminPage` that simulates server state, performs SVG media upload, executes save, remounts the admin page, and verifies persisted media path remains present after reload. + +**Risks:** +UI smoke test could become brittle if button labels/messages change; mitigated by checking stable behavior markers (API calls and media path value) alongside user-facing status text. + +### R-02-T25 — Close legacy embed/variant cleanup in schema, admin, and content + +**Files to modify:** +- `.codex/blocks/R-02.md` — task status and session tracking. +- `BACKLOG.md` — mark remaining Admin UX cleanup items as completed. +- `src/lib/case-content-validation.ts` — reject legacy embed placeholders/URLs in media block `src`. +- `src/lib/__tests__/case-content-validation.test.ts` — add checks for `FIGMA_EMBED_*` and embed URLs rejection. +- `src/lib/__tests__/content-legacy-migration.test.ts` — enforce repository-wide absence of legacy `variant`/embed placeholders in content JSON (including `src/content/home.json`). +- `src/app/admin/page.test.tsx` — add regression guard that legacy variant options are not rendered in admin. + +**Files to create:** +- `src/lib/__tests__/content-legacy-migration.test.ts` + +**Files NOT touched:** +- save/upload API implementations, runtime intake flow, and duplicate `* 2.*` artifacts. + +**Approach:** +Harden schema validation to block legacy embed sources, then protect against regressions with two guard layers: admin UI test for missing variant dropdown options and content migration audit test over all JSON content. + +**Risks:** +Stricter media `src` validation may reject rare but intentional external embeds; mitigated by explicit migration policy that media blocks must reference uploaded image assets only. + +### R-02-T26 — Close lint debt checkpoint and handoff to next release block + +**Files to modify:** +- `.codex/blocks/R-02.md` — add closure task and session notes. +- `.codex/PHASES.md` — mark `R-02` done and set `R-03` as active block. +- `.codex/blocks/R-03.md` — initialize next block detail file for launch checklist work. +- `BACKLOG.md` — mark lint debt checkpoint completed. +- `src/content/home.json` — include approved home resource title update from current working tree. + +**Files to create:** +- `.codex/blocks/R-03.md` — launch checklist block skeleton with pending tasks. + +**Files NOT touched:** +- API routes, admin editor behavior, and duplicate `* 2.*` artifacts. + +**Approach:** +Confirm lint baseline is green, close the final R-02 backlog checkbox, capture approved content copy tweak in `home.json`, and move workflow routing to R-03 so subsequent sessions start from launch checklist scope. + +**Risks:** +Switching active block too early can lose stabilization context; mitigated by closing R-02 only after lint verification and explicit task completion notes. + +--- + +## Refactor Backlog + +- Clean duplicate `* 2.*` files in a dedicated scoped task with explicit approval. + +--- + +## Session Log + +> One line per session. Written by agent on `/fi`. + +| Date | Task ID | Status | Note | +|------------|---------|-------------|------| +| 2026-04-16 | R-02-T1 | in-progress | Workflow sync task started with approved Change Plan. | +| 2026-04-16 | R-02-T1 | done | Active block routing fixed: `PHASES.md` now points to `R-02.md`. | +| 2026-04-16 | R-02-T2 | in-progress | Started staged validation + review flow for Sprint S1 commit. | +| 2026-04-16 | R-02-T2 | done | Sprint S1 changes committed and pushed with explicit approval gates. | +| 2026-04-16 | R-02-T3 | in-progress | Started S2 confidence signal implementation after sync-check and approved plan. | +| 2026-04-16 | R-02-T3 | done | Added typed confidence summary in API and AI Intake admin panel, with tests. | +| 2026-04-16 | R-02-T4 | pending | Task accepted by user approval and queued for change-plan review. | +| 2026-04-16 | R-02-T4 | in-progress | Started auto-mapper hardening with approved Change Plan. | +| 2026-04-16 | R-02-T4 | done | Added deterministic dedupe/merge for runtime artifacts and route-collision test coverage. | +| 2026-04-17 | R-02-T5 | in-progress | Started rule-based consistency QA implementation after approved Change Plan. | +| 2026-04-17 | R-02-T5 | done | Added rule-based consistency report in lib/API/admin with tests for order/tone/evidence checks. | +| 2026-04-17 | R-02-T6 | in-progress | Started S5 one-click starter implementation with explicit Apply confirmation flow. | +| 2026-04-17 | R-02-T6 | done | Added starter variants in API and explicit Apply Starter Draft flow in admin, with tests. | +| 2026-04-17 | R-02-T7 | in-progress | Started section-level evidence coverage implementation for GitHub intake API/admin. | +| 2026-04-17 | R-02-T7 | done | Added deterministic section evidence mapping in API and section-coverage view in admin with tests. | +| 2026-04-17 | R-02-T8 | in-progress | Started blueprint cover candidate implementation in intake API/admin and dedicated SVG route. | +| 2026-04-17 | R-02-T8 | done | Added deterministic blueprint cover candidate, SVG route, admin preview/apply action, and tests. | +| 2026-04-17 | R-02-T9 | in-progress | Started sticky save bar and unsaved/synced state UX implementation in admin. | +| 2026-04-17 | R-02-T9 | done | Added sticky save bar with repo-baseline dirty tracking and explicit unsaved/synced UX state. | +| 2026-04-17 | R-02-T10 | in-progress | Started live inline validation and save readiness UX implementation in sticky save bar. | +| 2026-04-17 | R-02-T10 | done | Added live validation issue list in sticky save bar and readiness-aware save gating. | +| 2026-04-17 | R-02-T11 | in-progress | Started AI Intake modularization by extracting inline admin panel into dedicated component. | +| 2026-04-17 | R-02-T11 | done | Extracted AI Intake into `AiIntakePanel`, wired props/handlers, and passed test/lint/build checks. | +| 2026-04-17 | R-02-T12 | in-progress | Started deterministic narrative rewrite suggestions flow for weak/missing sections in intake/admin. | +| 2026-04-17 | R-02-T12 | done | Added deterministic rewrite suggestions in quality lib/API/admin panel with tests and full verification pass. | +| 2026-04-18 | R-02-T13 | in-progress | Started one-click apply flow for rewrite suggestions in admin AI Intake panel. | +| 2026-04-18 | R-02-T13 | done | Added one-click apply action for rewrite suggestions with deterministic section update/create and full verification pass. | +| 2026-04-18 | R-02-T14 | in-progress | Started sections editor modularization into standalone admin component. | +| 2026-04-18 | R-02-T14 | done | Extracted sections editor into `SectionsEditor` component and passed tests/lint/build verification. | +| 2026-04-18 | R-02-T15 | in-progress | Started bulk apply rewrite flow using deterministic helper + unit tests. | +| 2026-04-18 | R-02-T15 | done | Added helper-based single/bulk rewrite apply flow with Apply All action and passing test/lint/build checks. | +| 2026-04-18 | R-02-T16 | in-progress | Started optimistic save locking implementation with `baseSha` wiring across admin and save API. | +| 2026-04-18 | R-02-T16 | done | Added `baseSha` conflict checks, SHA-aware save responses, admin SHA baseline tracking, and verification coverage. | +| 2026-04-18 | R-02-T17 | in-progress | Started concurrent-save race coverage for optimistic-locking flow with deterministic API contract checks. | +| 2026-04-18 | R-02-T17 | done | Added two-save stale `baseSha` race test and synced backlog checkboxes for locking coverage. | +| 2026-04-18 | R-02-T18 | in-progress | Started `Retry-After` handling hardening for GitHub retry helper with seconds/date parsing coverage. | +| 2026-04-18 | R-02-T18 | done | Added `Retry-After` seconds/date support with invalid-header fallback tests and synced backlog item status. | +| 2026-04-18 | R-02-T19 | in-progress | Started structured CMS audit logging for save/upload APIs with shared helper and unit coverage. | +| 2026-04-18 | R-02-T19 | done | Added shared audit logger, integrated save/upload route logs across outcomes, and marked backlog audit item complete. | +| 2026-04-18 | R-02-T20 | in-progress | Started malicious/edge SVG fixture coverage and tightened utility safety checks for hostile payload shapes. | +| 2026-04-18 | R-02-T20 | done | Added SVG edge-case fixtures (control chars/data URI/unsafe tags/heavy paths) and completed corresponding backlog item. | +| 2026-04-18 | R-02-T21 | in-progress | Started upload path-policy hardening for media API with path traversal and scope validation tests. | +| 2026-04-18 | R-02-T21 | done | Enforced `public/cases//` path policy with extension allowlist and added reject-path test coverage. | +| 2026-04-18 | R-02-T22 | in-progress | Started removal of legacy `variant` fallback in save pipeline to enforce strict schema validation. | +| 2026-04-18 | R-02-T22 | done | Removed silent `variant` stripping in save normalization and updated tests/backlog for explicit validation rejection path. | +| 2026-04-19 | R-02-T23 | in-progress | Started orphan-cleanup implementation for ambiguous upload failures and post-save stale media paths. | +| 2026-04-19 | R-02-T23 | done | Added cleanup API + tests and integrated admin best-effort orphan cleanup on upload failure/save success with backlog update. | +| 2026-04-19 | R-02-T24 | in-progress | Started admin smoke-flow test for upload -> save -> reload persistence validation. | +| 2026-04-19 | R-02-T24 | done | Added deterministic admin smoke test covering SVG upload feedback, save success, and persisted media path after remount reload. | +| 2026-04-19 | R-02-T25 | in-progress | Started closure pass for remaining Admin UX cleanup items (legacy embed assumptions, variant UI guards, content migration audit). | +| 2026-04-19 | R-02-T25 | done | Added schema/admin/content regression guards for legacy embed/variant patterns and marked Admin UX cleanup backlog items completed. | +| 2026-04-19 | R-02-T26 | in-progress | Started closure checkpoint for lint debt and release-block handoff with approved `home.json` copy update included. | +| 2026-04-19 | R-02-T26 | done | Closed lint debt backlog item, initialized `R-03`, and switched active block routing in `PHASES.md`. | + +--- + +_Last updated: 2026-04-19_ diff --git a/.codex/blocks/R-03.md b/.codex/blocks/R-03.md new file mode 100644 index 0000000..45a0722 --- /dev/null +++ b/.codex/blocks/R-03.md @@ -0,0 +1,146 @@ +# Block: R-03 — Launch checklist + +> Detail file for this block. Created by `init-block `. +> `PHASES.md` tracks block status only. All task detail lives here. + +--- + +## Block Goal + +Ship a final launch checklist with explicit pre-release verification and rollback readiness. + +## Definition of Done + +Launch checklist items are tracked in this block, validated, and ready for release sign-off. + +--- + +## Tasks + +| ID | Task | Status | Done When | +|---------|-------------------------------------------------|---------|-----------| +| R-03-T1 | Define launch checklist scope and release gates | done | Checklist sections and pass criteria are documented and agreed | +| R-03-T2 | Verify production readiness checks | done | Required checks are executed with evidence recorded | +| R-03-T3 | Finalize go-live and rollback playbook | done | Go-live owner/actions and rollback steps are explicit and testable | +| R-03-T4 | Execute final GO/NO-GO review after blockers close | done | G6-G8 blockers are resolved, final sign-off record is filled, and release decision is documented | + +> New tasks are added here as the block progresses via `init-task`. + +--- + +## Active Task + +| Field | Value | +|-----------|-------| +| Task ID | R-03-T4 | +| Title | Execute final GO/NO-GO review after blockers close | +| Status | done | +| Done When | G6-G8 blockers are resolved, final sign-off record is filled, and release decision is documented | + +--- + +## Change Plans + +> One entry per task. Written by agent before coding. Approved by user before execution. + +### R-03-T1 — Define launch checklist scope and release gates + +**Files to modify:** +- `.codex/blocks/R-03.md` — task status, active task, and session log. + +**Files to create:** +- `docs/release/launch-checklist.md` — launch checklist scope, release gates, evidence requirements, and go/no-go protocol. + +**Files NOT touched:** +- app runtime code and ongoing homepage UI edits in parallel files. + +**Approach:** +Define a release-ready checklist document tied to the current stack and CMS workflow, with explicit pass/fail gates and required artifacts. Then mark `R-03-T1` complete and move active focus to readiness execution (`R-03-T2`). + +**Risks:** +Checklist may become stale if delivery scope changes; mitigated by adding required evidence fields and explicit update ownership before go-live. + +### R-03-T2 — Verify production readiness checks + +**Files to modify:** +- `.codex/blocks/R-03.md` — task status, active task, and session log. + +**Files to create:** +- `docs/release/launch-readiness-2026-04-19.md` — evidence-backed readiness report with gate-by-gate outcomes. + +**Files NOT touched:** +- app runtime code and ongoing homepage UI edits in parallel files. + +**Approach:** +Execute release checklist commands (lint/build/targeted tests + env presence), map results to launch gates, and record pass/fail/pending evidence in a dated readiness report before moving to go-live/rollback finalization. + +**Risks:** +Local checks can pass while deployment env remains incomplete; mitigated by explicitly marking unresolved gates as blockers and keeping decision state `NO-GO` until closed. + +### R-03-T3 — Finalize go-live and rollback playbook + +**Files to modify:** +- `.codex/blocks/R-03.md` — task status, active task, and session log. +- `docs/release/launch-checklist.md` — reference finalized playbook and sign-off sequencing. +- `docs/release/launch-readiness-2026-04-19.md` — align next action and blocker closure path. + +**Files to create:** +- `docs/release/go-live-playbook-2026-04-19.md` — explicit owners, commands, decision checkpoints, rollback runbook, and communication protocol. + +**Files NOT touched:** +- app runtime code and ongoing homepage UI edits in parallel files. + +**Approach:** +Create an operational runbook that turns launch gates into an executable timeline with owner roles, cutover checks, rollback triggers, and communication steps. Keep final decision separate in a follow-up task so unresolved blockers remain visible. + +**Risks:** +Operational steps may drift from deployment platform details; mitigated by anchoring commands to repository scripts and documenting required operator verification points. + +### R-03-T4 — Execute final GO/NO-GO review after blockers close + +**Files to modify:** +- `.codex/blocks/R-03.md` — task status, change plan, and session log. +- `docs/release/launch-readiness-2026-04-19.md` — refresh gate evidence and blocker states after re-run. +- `docs/release/launch-checklist.md` — align env checklist and rollback baseline with verified production setup. +- `docs/release/go-live-playbook-2026-04-19.md` — fill rollback baseline and completion checkpoint with current production evidence. + +**Files to create:** +- `docs/release/go-no-go-review-2026-04-19.md` — formal decision record with gate snapshot and unblock actions. + +**Files NOT touched:** +- app runtime code and ongoing homepage UI edits in parallel files. + +**Approach:** +Re-run release baseline checks and runtime smoke on the current branch tip, capture gate-by-gate outcomes, and issue a formal GO/NO-GO decision record. Keep the task in-progress until G6-G8 are fully closed and sign-off fields are complete. + +**Risks:** +Operational inputs (deployment URL, named owners, release environment vars) may be unavailable from local repo context; mitigated by preserving explicit placeholders and blocker ownership in the decision record. + +--- + +## Refactor Backlog + +- none + +--- + +## Session Log + +> One line per session. Written by agent on `/fi`. + +| Date | Task ID | Status | Note | +|------------|---------|-------------|------| +| 2026-04-19 | R-03-T1 | pending | Block initialized after R-02 closure handoff. | +| 2026-04-19 | R-03-T1 | in-progress | Started launch checklist definition with explicit release-gate criteria. | +| 2026-04-19 | R-03-T1 | done | Added launch checklist scope and gate definitions in docs/release/launch-checklist.md. | +| 2026-04-19 | R-03-T2 | in-progress | Started executing readiness gates with command evidence collection from checklist. | +| 2026-04-19 | R-03-T2 | done | Captured gate outcomes in docs/release/launch-readiness-2026-04-19.md; decision remains NO-GO pending env/runtime/rollback gates. | +| 2026-04-19 | R-03-T3 | in-progress | Started go-live/rollback runbook formalization based on readiness blockers and launch gates. | +| 2026-04-19 | R-03-T3 | done | Added executable go-live playbook with owner matrix, rollback triggers, and communication protocol. | +| 2026-04-19 | R-03-T4 | in-progress | Re-ran launch checks on current branch tip, recorded final NO-GO review snapshot, blockers remain on G6-G8. | +| 2026-04-19 | R-03-T4 | in-progress | Closed technical blockers G6-G8 using Vercel/GitHub deployment evidence; final GO awaits explicit owner sign-off. | +| 2026-04-20 | R-03-T4 | done | Revalidated gates on 2026-04-20, recorded owner sign-off, and switched final release decision to GO. | + +--- + +_Last updated: 2026-04-19_ diff --git a/.env.local.example b/.env.local.example new file mode 100644 index 0000000..abff55b --- /dev/null +++ b/.env.local.example @@ -0,0 +1,10 @@ +# CMS authentication +CMS_ADMIN_USER= +CMS_ADMIN_PASSWORD= +CMS_SESSION_SECRET= + +# GitHub integration for CMS content writes +GITHUB_PAT= +GITHUB_REPO= +# Optional, defaults to main +# GITHUB_BRANCH=main diff --git a/.github/workflows/agent-native-seo-check.yml b/.github/workflows/agent-native-seo-check.yml index 3668194..4a98ba6 100644 --- a/.github/workflows/agent-native-seo-check.yml +++ b/.github/workflows/agent-native-seo-check.yml @@ -1,33 +1,50 @@ -name: Agent-Native SEO Check +name: Agent Native SEO Check on: - workflow_dispatch: - schedule: - - cron: "0 6 * * 1" - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" + push: + paths: + - "src/app/robots.ts" + - "src/app/sitemap.ts" + - "src/app/work/page.tsx" + - "src/app/work/[slug]/page.tsx" + - "src/app/contact/page.tsx" + - "src/app/privacy/page.tsx" + - "src/app/terms/page.tsx" + - "src/app/perf-test/layout.tsx" + - "src/lib/seo.ts" + - "scripts/check-agent-native-seo.mjs" + - "package.json" + - ".github/workflows/agent-native-seo-check.yml" + pull_request: + paths: + - "src/app/robots.ts" + - "src/app/sitemap.ts" + - "src/app/work/page.tsx" + - "src/app/work/[slug]/page.tsx" + - "src/app/contact/page.tsx" + - "src/app/privacy/page.tsx" + - "src/app/terms/page.tsx" + - "src/app/perf-test/layout.tsx" + - "src/lib/seo.ts" + - "scripts/check-agent-native-seo.mjs" + - "package.json" + - ".github/workflows/agent-native-seo-check.yml" jobs: - health-check: - name: Run Agent-Native SEO Health Check + seo-check: runs-on: ubuntu-latest - timeout-minutes: 10 - env: - SEO_BASE_URL: ${{ vars.SEO_BASE_URL || 'https://ginzburg.work' }} - SEO_WWW_URL: ${{ vars.SEO_WWW_URL || 'https://www.ginzburg.work' }} steps: - - name: Checkout - uses: actions/checkout@v5 + - name: Checkout repository + uses: actions/checkout@v4 - - name: Setup Node - uses: actions/setup-node@v5 + - name: Setup Node.js + uses: actions/setup-node@v4 with: - node-version: 20 - cache: npm + node-version: "20" + cache: "npm" - name: Install dependencies run: npm ci - - name: Run SEO health check + - name: Run SEO baseline check run: npm run check:seo:agent-native diff --git a/.gitignore b/.gitignore index c668474..b41f90d 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,7 @@ yarn-error.log* # env files (can opt-in for committing if needed) .env* +!.env.local.example # vercel .vercel @@ -40,3 +41,4 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts +.env*.local diff --git a/.legacy/README.md b/.legacy/README.md index 75f900e..a6bb5d7 100644 --- a/.legacy/README.md +++ b/.legacy/README.md @@ -28,7 +28,7 @@ Complete backup of the Keystatic CMS integration that was replaced by the custom 1. Copy files back to original locations 2. Restore `src/lib/keystatic.ts` import in components 3. Re-add Keystatic route checks in `ClientProviders.tsx`, `Layout.tsx`, `ThemeToggle.tsx` -4. Update `middleware.ts` to use `KEYSTATIC_*` env vars exclusively +4. Update `middleware.ts` to use `CMS_*` env vars exclusively 5. Install dependencies: `npm install @keystatic/core @keystatic/next` --- diff --git a/.legacy/keystatic/app/[[...slug]]/KeystaticApp.tsx b/.legacy/keystatic/app/[[...slug]]/KeystaticApp.tsx index 2e5b9fc..f7adb48 100644 --- a/.legacy/keystatic/app/[[...slug]]/KeystaticApp.tsx +++ b/.legacy/keystatic/app/[[...slug]]/KeystaticApp.tsx @@ -10,8 +10,8 @@ export default function KeystaticApp() { ); diff --git a/.legacy/keystatic/keystatic.ts b/.legacy/keystatic/keystatic.ts index 2e9c4b4..46510d4 100644 --- a/.legacy/keystatic/keystatic.ts +++ b/.legacy/keystatic/keystatic.ts @@ -1,21 +1,21 @@ -const githubRepo = (process.env.KEYSTATIC_GITHUB_REPO || +const githubRepo = (process.env.CMS_GITHUB_REPO || "Ultraivanov/portfolio") as `${string}/${string}`; export const keystaticMissingGitHubEnvVars = [ - "KEYSTATIC_GITHUB_CLIENT_ID", - "KEYSTATIC_GITHUB_CLIENT_SECRET", - "KEYSTATIC_SECRET", + "CMS_GITHUB_CLIENT_ID", + "CMS_GITHUB_CLIENT_SECRET", + "CMS_SECRET", ].filter((name) => !process.env[name]); export const isKeystaticGitHubConfigured = keystaticMissingGitHubEnvVars.length === 0; const isDevelopment = process.env.NODE_ENV === "development"; -const forceLocalInAnyEnv = process.env.KEYSTATIC_FORCE_LOCAL === "1"; +const forceLocalInAnyEnv = process.env.CMS_FORCE_LOCAL === "1"; // Avoid server/client mode mismatch: // by default, production uses GitHub and dev can fall back to local. -// KEYSTATIC_FORCE_LOCAL=1 is an emergency switch to disable GitHub mode. +// CMS_FORCE_LOCAL=1 is an emergency switch to disable GitHub mode. export const shouldUseKeystaticLocalStorage = forceLocalInAnyEnv || (isDevelopment && !isKeystaticGitHubConfigured); diff --git a/BACKLOG.md b/BACKLOG.md index 0963a7b..0d57ca9 100644 --- a/BACKLOG.md +++ b/BACKLOG.md @@ -1,18 +1,20 @@ # Backlog ## CMS content stability -- [ ] Add optimistic locking in UI (`baseSha`) for save-content to reduce manual conflict retries. -- [ ] Add audit log for content edits (who/what/when, path + commit SHA + result). -- [ ] Add E2E smoke flow: upload media -> optimize SVG -> save content -> reload admin. -- [ ] Harden upload path policy and orphan cleanup for partial failures. -- [ ] Extend retry/backoff handling with `Retry-After` support for rate limits. -- [ ] Add malicious/edge SVG fixtures (broken encoding, heavy path count, unsafe tags, data URI overload). -- [ ] Add race-condition tests for concurrent save requests. +- [x] Add optimistic locking in UI (`baseSha`) for save-content to reduce manual conflict retries. +- [x] Add audit log for content edits (who/what/when, path + commit SHA + result). +- [x] Add E2E smoke flow: upload media -> optimize SVG -> save content -> reload admin. +- [x] Harden upload path policy for media writes. +- [x] Add orphan cleanup for partial failures in upload/save flows. +- [x] Extend retry/backoff handling with `Retry-After` support for rate limits. +- [x] Add malicious/edge SVG fixtures (broken encoding, heavy path count, unsafe tags, data URI overload). +- [x] Add race-condition tests for concurrent save requests. ## Admin UX cleanup -- [ ] Remove legacy media `variant` model (`diagram/phone/desktop`) and old iframe/embed assumptions from content schema and admin UI. -- [ ] Remove variant dropdown from any remaining admin surface; keep media block focused on image upload + path + alt + caption. -- [ ] Migrate existing content entries with `variant`/`FIGMA_EMBED_*` placeholders to the current media model. +- [x] Remove legacy media `variant` model (`diagram/phone/desktop`) from save-content pipeline. +- [x] Remove old iframe/embed assumptions from content schema and admin UI. +- [x] Remove variant dropdown from any remaining admin surface; keep media block focused on image upload + path + alt + caption. +- [x] Migrate existing content entries with `variant`/`FIGMA_EMBED_*` placeholders to the current media model. ## Existing lint debt -- [ ] Main admin has pre-existing lint errors outside the stability scope; global eslint for this file remains red and should be cleaned separately. +- [x] Main admin has pre-existing lint errors outside the stability scope; global eslint for this file remains red and should be cleaned separately. diff --git a/README.md b/README.md index b0883ea..be0f5d3 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ Required env vars: - `GITHUB_REPO` - `CMS_ADMIN_USER` - `CMS_ADMIN_PASSWORD` +- `CMS_SESSION_SECRET` ## Development ```bash @@ -57,6 +58,15 @@ npm run test npm run lint ``` +## Local Env via Vercel +Use Vercel as the source of truth for secrets and pull them locally: + +```bash +vercel env pull .env.local +``` + +Then restart the dev server so updated env values are picked up. + ## Single Source of Truth (Workflow State) Use only `.codex/*` for project status and phase tracking: - `.codex/SNAPSHOT.md` diff --git a/docs/release/go-live-playbook-2026-04-19.md b/docs/release/go-live-playbook-2026-04-19.md new file mode 100644 index 0000000..f317600 --- /dev/null +++ b/docs/release/go-live-playbook-2026-04-19.md @@ -0,0 +1,103 @@ +# Go-Live Playbook (R-03-T3) + +Date: 2026-04-19 +Branch: `codex/v2-roadmap-cms-ai` +Related docs: +- `docs/release/launch-checklist.md` +- `docs/release/launch-readiness-2026-04-19.md` + +## Roles + +| Role | Responsibility | +|---|---| +| Release Operator | Runs commands, verifies gate evidence, executes deploy/rollback actions | +| Engineering Owner | Technical approval, incident triage owner, rollback authority | +| Product Owner | Final GO/NO-GO business decision and release communications | + +## Preconditions (Must Be True Before GO) + +1. All required env vars are set in release environment: + - `GITHUB_PAT` + - `GITHUB_REPO` + - `CMS_ADMIN_USER` + - `CMS_ADMIN_PASSWORD` +2. Gates G1-G5 are PASS. +3. G7 runtime walkthrough evidence is recorded. +4. Rollback metadata is filled (owner + last known good deployment URL). + +## Execution Timeline + +### T-60 min: Freeze + Baseline + +1. Confirm release candidate commit SHA. +2. Run: + - `npm run lint` + - `npm run build` + - targeted `npm test -- ...` from launch checklist +3. Save command output and timestamp in the readiness report. + +### T-30 min: Runtime Sanity + +1. Manual walkthrough on release deployment: + - `/` + - `/work` + - `/work/[slug]` (at least 2 cases) + - `/admin` login + read sanity +2. Record outcome as PASS/FAIL with notes. + +### T-15 min: Final Gate Review + +1. Release Operator presents G1-G8 table. +2. Engineering Owner confirms technical readiness. +3. Product Owner confirms business readiness. +4. Decision: + - If any gate is FAIL/PENDING: `NO-GO` + - If all gates PASS: `GO` + +### T0: Go-Live + +1. Announce start in release channel. +2. Deploy release candidate (platform-specific deploy flow). +3. Re-run smoke checks on deployed URL. +4. Announce completion + deployment URL + commit SHA. + +## Rollback Triggers + +Trigger rollback immediately when one of these occurs post-deploy: + +1. `/admin` cannot authenticate with expected credentials. +2. Content save/upload API fails for valid requests. +3. Public routes return critical errors or blank render. +4. Data integrity regression is detected in production content. + +## Rollback Procedure + +1. Identify last known good deployment: + - Commit: `7df1162dc814749821878a8feab29891064f451b` + - URL: `https://portfolio-3ubq77fvm-dima-ginzburgs-projects.vercel.app` +2. Release Operator redeploys last known good commit. +3. Run rollback smoke checks: + - `/` + - `/work` + - `/admin` +4. Engineering Owner confirms stabilization. +5. Announce rollback completion and open follow-up issue. + +## Communication Template + +### GO +`GO: deploying to production. Owners: , .` + +### NO-GO +`NO-GO: release blocked by . Next update at