Files
EpicNext-Cms/docs/superpowers/plans/2026-09-01-housekeeping-content-events-vertical.md
T
Simo b20adfeee5
CI / runtime-diagnostics (pull_request) Skipped
CI / check (pull_request) Successful in 37s
CI / release (pull_request) Skipped
CI / deploy (pull_request) Skipped
docs(housekeeping): complete events delivery checklist
2026-09-01 21:17:16 +02:00

11 KiB
Raw Blame History

Housekeeping Content Events Vertical Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Deliver a complete ASE event and event-type operator workflow backed by real database data and existing audited mutations.

Architecture: Keep the generic Content query/command foundation, add strict route-specific event payloads, and render them through a focused ContentEventWorkflow. Use the existing event tables and mutation runtime; introduce dedicated delete command IDs only to enforce reason confirmation.

Tech Stack: Next.js 16, React 19, TypeScript, Drizzle/MySQL, Zod, Vitest, React server actions

Spec: docs/superpowers/specs/2026-09-01-housekeeping-content-events-vertical-design.md

Global Constraints

  • Work directly on codex/housekeeping-rebuild-stepwise; do not create a worktree.
  • Preserve /admin/events and all unrelated local/untracked files.
  • Do not add dependencies or change the database schema.
  • Keep Polls and Prefixes behavior unchanged.
  • Write and run a failing test before each production behavior change.
  • Keep every destructive event or event-type action reason-protected and auditable.

Task 1: Typed event query payloads and production loading

Files:

  • Modify: src/features/housekeeping/domains/content/queries/content-queries.ts
  • Modify: src/features/housekeeping/domains/content/queries/content-queries-production.ts
  • Test: src/features/housekeeping/domains/content/queries/content-queries.test.ts

Interfaces:

  • Produces: ContentEventTypePayload, ContentEventSummaryPayload, ContentEventDetailPayload, and their public type guards.

  • Produces: validated private payloads for list, create, detail, and type routes.

  • Consumes: ContentQueryItem.privatePayload, normalized params.id, list.search, list.status, list.pageSize, and list.offset.

  • Step 1: Write failing contract tests

Add literal fixtures proving that malformed event payloads fail closed, event list input normalizes a bounded status, and a detail adapter returning more than one item is rejected.

  • Step 2: Run the query test and confirm RED

Run: yarn.cmd vitest run src/features/housekeeping/domains/content/queries/content-queries.test.ts

Expected: FAIL because event payload guards and status normalization do not exist.

  • Step 3: Implement the minimal event contracts

Add route-specific interfaces with JSON-safe primitive fields and type guards. Extend list input with status, normalized to lowercase and at most 32 characters. Extend isValidData so each event route accepts only its corresponding payload and detail accepts at most one selected item.

  • Step 4: Run the query test and confirm GREEN

Run the command from Step 2. Expected: PASS.

  • Step 5: Write failing production-loader tests

Add tests proving:

expect(list.items[0]?.privatePayload).toMatchObject({
  typeName: "Tournament",
  registrationCount: 12,
});
expect(detail.items).toHaveLength(1);
expect(detail.items[0]?.privatePayload).toMatchObject({
  description: "Complete event",
  eventTypes: [{ id: "2", name: "Tournament" }],
  prizes: [{ id: "4", prizeType: "badge" }],
  winners: [{ userId: "9", username: "Alice" }],
  registrations: [{ userId: "10", username: "Bob" }],
});

Also assert that the serialized detail SQL binds the requested ID and that status filtering is bound, not interpolated.

  • Step 6: Run the loader tests and confirm RED

Run the command from Step 2. Expected: FAIL because production definitions only expose generic summaries.

  • Step 7: Implement production event loaders

Update event list and type definitions to project full safe summaries. Load event-create options from active event types. Add a dedicated detail loader that performs bounded, parameterized reads for the selected event, event types, prizes, winners with usernames, and registrations with usernames. Return not-found as an empty successful result.

  • Step 8: Run the loader tests and confirm GREEN

Run the command from Step 2. Expected: PASS.

Task 2: Event command safety and form field semantics

Files:

  • Modify: src/features/housekeeping/domains/content/commands/content-commands.ts
  • Modify: src/features/housekeeping/domains/content/pages/content-command-form.tsx
  • Test: src/features/housekeeping/domains/content/commands/content-commands.test.ts
  • Test: src/features/housekeeping/domains/content/pages/content-pages.test.tsx

Interfaces:

  • Produces: content.engagement.event.delete and content.engagement.event-type.delete, both mapped to existing mutations with requiresReason: true.

  • Produces: ContentCommandField.type === "datetime-local", submitted as the normalized browser value.

  • Step 1: Write failing command-policy tests

Assert the two delete command IDs exist, use event.change and event-type.change, retain PERMS.EVENTS_EDIT, and require reasons while non-destructive change commands do not.

  • Step 2: Run command tests and confirm RED

Run: yarn.cmd vitest run src/features/housekeeping/domains/content/commands/content-commands.test.ts

Expected: FAIL because the dedicated delete commands are absent.

  • Step 3: Implement command metadata

Extend the command definition tuple with an optional requiresReason flag and register both dedicated delete command IDs without adding mutation operations.

  • Step 4: Run command tests and confirm GREEN

Run the command from Step 2. Expected: PASS.

  • Step 5: Write a failing date/time form test

Render a field with type: "datetime-local" and assert the real input type and default value. Submit it and assert the existing server action receives the exact normalized date/time string.

  • Step 6: Run page tests and confirm RED

Run: yarn.cmd vitest run src/features/housekeeping/domains/content/pages/content-pages.test.tsx

Expected: FAIL because datetime-local is not supported.

  • Step 7: Implement the minimal field support

Add datetime-local to the field union and map it to <input type="datetime-local">; keep the existing bounded string parser.

  • Step 8: Run page tests and confirm GREEN

Run the command from Step 6. Expected: PASS.

Task 3: Complete Event workflow UI

Files:

  • Create: src/features/housekeeping/domains/content/pages/event-workflow.tsx
  • Modify: src/features/housekeeping/domains/content/pages/engagement.tsx
  • Create: src/features/housekeeping/domains/content/pages/event-workflow.test.tsx
  • Modify: src/features/housekeeping/domains/content/pages/content-pages.test.tsx

Interfaces:

  • Produces: ContentEventWorkflow(props) for the four event routes.

  • Consumes: typed payload guards from Task 1 and command IDs/field semantics from Task 2.

  • Step 1: Write failing list and state tests

Render real HousekeepingResult fixtures and assert loading, forbidden, dependency-error, empty, and ready states. The ready list must expose search, status filtering, result count, type, schedule, capacity, registrations, create/type links, and bounded previous/next links.

  • Step 2: Run workflow tests and confirm RED

Run: yarn.cmd vitest run src/features/housekeeping/domains/content/pages/event-workflow.test.tsx

Expected: FAIL because the component does not exist.

  • Step 3: Implement the list/state slice

Create the focused workflow component and route the four event route IDs to it from ContentEngagementPage, leaving Polls and Prefixes on the existing generic implementation.

  • Step 4: Run workflow tests and confirm GREEN

Run the command from Step 2. Expected: PASS for list/state tests.

  • Step 5: Write failing create/detail tests

Assert create uses real type options and date/time inputs. Assert detail prepopulates title, description, selected type, schedule, capacity, room, status, recurrence, and image; automatically binds event IDs for prizes/winners; renders usernames for registrations; and exposes a reason-required delete form using content.engagement.event.delete.

  • Step 6: Run workflow tests and confirm RED

Run the command from Step 2. Expected: FAIL because create/detail workflow sections are incomplete.

  • Step 7: Implement create/detail

Build field factories from the validated payload. Render not-found separately from dependency failure. Keep related forms and lists inside the selected event detail; never expose manual event-ID inputs.

  • Step 8: Run workflow tests and confirm GREEN

Run the command from Step 2. Expected: PASS for create/detail tests.

  • Step 9: Write failing event-type tests

Assert a create form and one prefilled update form per type, plus a reason-required delete form using content.engagement.event-type.delete; no operator-entered type ID field is allowed.

  • Step 10: Run workflow tests and confirm RED

Run the command from Step 2. Expected: FAIL until type management is implemented.

  • Step 11: Implement event-type management and refactor

Add create/update/delete sections using typed payloads. Extract small field and formatting helpers while all tests stay green.

  • Step 12: Run focused Content tests and confirm GREEN

Run:

yarn.cmd vitest run src/features/housekeeping/domains/content/queries/content-queries.test.ts src/features/housekeeping/domains/content/commands/content-commands.test.ts src/features/housekeeping/domains/content/pages/content-pages.test.tsx src/features/housekeeping/domains/content/pages/event-workflow.test.tsx

Expected: all focused tests PASS.

Task 4: Full verification and draft PR update

Files:

  • Modify: docs/superpowers/plans/2026-09-01-housekeeping-content-events-vertical.md
  • Modify: draft PR 53 body in English and Dutch

Interfaces:

  • Consumes: all deliverables from Tasks 1–3.

  • Produces: verified commit(s), pushed branch, and current bilingual PR evidence.

  • Step 1: Run static and targeted checks

Run the repository TypeScript, Biome, Knip, focused test, and Housekeeping matrix commands from package.json and the existing Housekeeping evidence workflow. Fix only failures caused by this vertical.

  • Step 2: Run the full test suite with coverage

Run: yarn.cmd test

Expected: zero failing test files and zero failing tests.

  • Step 3: Run the production build

Run: yarn.cmd build

Expected: exit code 0 with canonical /ase-next routes generated.

  • Step 4: Review the exact diff

Run: git diff --check, git status --short, and git diff --stat origin/main...HEAD after committing. Confirm .remember/ and .superpowers/brainstorm/ remain untouched and untracked.

  • Step 5: Commit and push exact paths

Commit query/command/UI/test/plan files with a scoped message, then push codex/housekeeping-rebuild-stepwise.

  • Step 6: Update and verify the draft PR

Add the Events vertical and fresh verification counts to PR 53 in English and Dutch. Confirm the remote head matches local HEAD and inspect CI status without claiming deployment.