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

238 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 `<input type="datetime-local">`; 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.