# 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`. - [x] **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. - [x] **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. - [x] **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. - [x] **Step 4: Run the query test and confirm GREEN** Run the command from Step 2. Expected: PASS. - [x] **Step 5: Write failing production-loader tests** Add tests proving: ```ts 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. - [x] **Step 6: Run the loader tests and confirm RED** Run the command from Step 2. Expected: FAIL because production definitions only expose generic summaries. - [x] **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. - [x] **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. - [x] **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. - [x] **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. - [x] **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. - [x] **Step 4: Run command tests and confirm GREEN** Run the command from Step 2. Expected: PASS. - [x] **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. - [x] **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. - [x] **Step 7: Implement the minimal field support** Add `datetime-local` to the field union and map it to ``; keep the existing bounded string parser. - [x] **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. - [x] **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. - [x] **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. - [x] **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. - [x] **Step 4: Run workflow tests and confirm GREEN** Run the command from Step 2. Expected: PASS for list/state tests. - [x] **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`. - [x] **Step 6: Run workflow tests and confirm RED** Run the command from Step 2. Expected: FAIL because create/detail workflow sections are incomplete. - [x] **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. - [x] **Step 8: Run workflow tests and confirm GREEN** Run the command from Step 2. Expected: PASS for create/detail tests. - [x] **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. - [x] **Step 10: Run workflow tests and confirm RED** Run the command from Step 2. Expected: FAIL until type management is implemented. - [x] **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. - [x] **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. - [x] **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. - [x] **Step 2: Run the full test suite with coverage** Run: `yarn.cmd test` Expected: zero failing test files and zero failing tests. - [x] **Step 3: Run the production build** Run: `yarn.cmd build` Expected: exit code 0 with canonical `/ase-next` routes generated. - [x] **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. - [x] **Step 5: Commit and push exact paths** Commit query/command/UI/test/plan files with a scoped message, then push `codex/housekeeping-rebuild-stepwise`. - [x] **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.