Skip to content

feat(revamp): Block F — admin program management (closes #46 #47)#57

Draft
sacha-l wants to merge 2 commits intorevamp/block-d-program-applicationsfrom
revamp/block-f-admin-program-management
Draft

feat(revamp): Block F — admin program management (closes #46 #47)#57
sacha-l wants to merge 2 commits intorevamp/block-d-program-applicationsfrom
revamp/block-f-admin-program-management

Conversation

@sacha-l
Copy link
Copy Markdown
Collaborator

@sacha-l sacha-l commented Apr 22, 2026

Block F of the Phase 1 revamp — admin side of the program flow. Closes #46 and #47.

Stacked on #55 (Block D). Target base is revamp/block-d-program-applications while that PR is open. Once #55 merges, I'll rebase this onto develop and retarget.

Block F journey slice (per spec §12)

"Admin can set up Dogfooding and process applications." Admin opens /admin → ProgramsTable → clicks "Create program" → fills form → saves → row appears. Clicks the row → /admin/programs/:slug → clicks Load/refresh → sees applications → Accept one → status flips without reload.

Commits

<sha>#46: admin create / edit programs

  • Validator validateProgram in server/api/utils/validation.js — kebab-case slug, enum programType/status, date validity, cross-field window ordering (apps open < close, event starts ≤ ends), bounds on name/description/location, positive max_applicants. Works in partial mode for PATCH.
  • Repository additions: create, updateBySlug, toSnakeCase helper (writes only provided keys — partial PATCH doesn't null-out untouched columns).
  • Controller: createProgram (UUID id + owner='webzero' enforced; 409 on slug pre-check + DB-race), updateProgram (404 / 422 / 409 / 200).
  • Routes: POST /api/programs + PATCH /api/programs/:slug, both requireAdmin.
  • SIWS statements: Create program on Stadium + Update program on Stadium.
  • 11 server unit tests.
  • Client: api.createProgram + api.updateProgram + new ProgramFormModal (auto-slug from name until user edits; datetime-local inputs → ISO on submit; slug read-only in edit mode so we don't churn FKs). ProgramsTable extended with Create button + per-row Edit + clickable rows navigating to /admin/programs/:slug.

<sha>#47: admin applications queue

  • Controller updateApplicationStatus (status enum check, optional reviewNotes ≤ 2000 chars, 404 on unknown program, PGRST116 → 404 mapping, 200 on success).
  • Route: PATCH /api/programs/:slug/applications/:applicationId (requireAdmin).
  • SIWS statement: Review application on Stadium.
  • 5 more server unit tests.
  • Client: api.updateApplicationStatus, new ApplicationCard component (shows project link, submitter, submitted date, status badge, Dogfooding feedback_focus, review notes, Accept/Reject — visible only when status=submitted), new /admin/programs/:slug AdminProgramPage with filter chips (submitted / accepted / rejected / withdrawn / all) and explicit SIWS-signed Load/refresh (listing applications is admin-gated on the server, so the fetch has to happen after sign).

Test plan

Automated:

  • cd server && npm test48/48 passing (16 new + 32 existing).
  • cd client && npm run build → clean.

Playwright:

  • On /admin without admin wallet, Create / Edit / row-click behaviours don't trigger write flows (admin session guards remain intact).
  • On /admin/programs/dogfooding-2026-berlin without admin wallet, "Admin wallet required" prompt renders.

SIWS-gated (manual QA with an admin wallet):

  • /admin → Create program → fill form → save → new row appears; clicking the row navigates to /admin/programs/<new-slug>.
  • Two programs with same slug → second save fails with 409 surfaced as toast.
  • Edit existing program → slug field read-only; name/status/dates update; row re-renders with new values.
  • On /admin/programs/<slug> → connect admin wallet → Load/refresh → applications appear; Accept one → card re-renders with 'accepted' status; filter chips correctly narrow the list.

Design notes

  • Applications load on explicit click, not on mount, because listing them is SIWS-gated on the server. The alternative — auto-sign + auto-load — felt surprising to users. Explicit Load/refresh is transparent.
  • Slug read-only in edit mode — renaming a program's slug means changing its primary key, which cascades to program_applications.program_id FKs. Out of scope for Phase 1.
  • No comment-back flow on reject (just reviewNotes string). Notifications/email/Telegram are explicitly Phase 2+ per context-doc §64.

Out of scope (deferred)

  • Bulk accept/reject.
  • Per-program-type rendering beyond Dogfooding's feedback_focus.
  • Notifications on accept/reject.
  • Withdraw flow from the builder side.

sacha-l added 2 commits April 23, 2026 00:04
Admins can create and edit programs from /admin. POST and PATCH on
/api/programs, both gated by requireAdmin; SIWS-signed with new
"Create program on Stadium" / "Update program on Stadium" statements.

Phase 1 revamp Block F, issue #46.
See docs/stadium-revamp-phase-1-spec.md §5 Issue 11.

Server:
- server/api/utils/validation.js — validateProgram with partial/full
  modes. Enforces kebab-case slug, enum program_type and status,
  date validity, cross-field application-window and event-window
  ordering, length bounds on description / location / name, positive
  max_applicants.
- server/api/repositories/program.repository.js — create + updateBySlug
  + a toSnakeCase helper that only writes provided keys (partial
  updates don't null-out untouched columns).
- server/api/services/program.service.js — thin wrappers.
- server/api/controllers/program.controller.js — createProgram (UUID
  id + owner='webzero' enforced; 409 on slug pre-check + DB unique
  violation race) and updateProgram (404 on missing, 409 on slug
  change collision, 422 on invalid partial).
- server/api/routes/program.routes.js — POST '/' + PATCH '/:slug',
  both requireAdmin.
- server/api/middleware/auth.middleware.js — adds base SIWS
  statements: "Create program on Stadium",
  "Update program on Stadium", "Review application on Stadium"
  (last one staged for #47).
- server/api/controllers/__tests__/program-admin.test.js — 11 new
  unit tests covering validation errors, slug-conflict 409 (both
  pre-check and DB race), happy-path create with id + owner, update
  404/422/409/200.

Client:
- client/src/lib/api.ts — api.createProgram + api.updateProgram with
  mock-mode fallbacks that enforce slug uniqueness.
- client/src/lib/siwsUtils.ts — three new actions:
  'create-program', 'update-program', 'review-application' (last
  staged for #47).
- client/src/components/admin/ProgramFormModal.tsx (new) — single
  modal for both create and edit. Auto-generates slug from name
  until the user edits it; inline validation mirrors server
  (kebab-case slug, date ordering, positive integer max). Uses
  datetime-local inputs that convert to ISO on submit. Slug is
  read-only in edit mode so we don't churn FKs in this phase.
- client/src/components/admin/ProgramsTable.tsx — "Create program"
  button (visible only when connectedAddress is set), clickable
  rows navigate to /admin/programs/:slug (Phase 1 revamp #47 route,
  landing in the next commit), per-row Edit button.
- client/src/pages/AdminPage.tsx — passes connectedAddress to the
  ProgramsTable from walletState.selectedAccount.

Verification:
- server/npm test: 43/43 passing (11 new + 32 existing).
- client/npm run build: clean.

Out of scope (#47, next commit in this PR):
- /admin/programs/:slug page and application review handlers.
Closes Block F. Admin reviews applications on a per-program page,
accepts or rejects with status transitions stamped with reviewer +
timestamp.

Phase 1 revamp Block F, issue #47.
See docs/stadium-revamp-phase-1-spec.md §5 Issue 12.

Server:
- server/api/controllers/program.controller.js — new
  updateApplicationStatus handler: status enum check, optional
  reviewNotes length bound (≤ 2000), 404 on unknown program, 404
  mapping on PostgREST PGRST116 no-rows error, 200 on success.
- server/api/routes/program.routes.js — PATCH
  /api/programs/:slug/applications/:applicationId (requireAdmin).
- server/api/controllers/__tests__/program-application.test.js —
  5 new tests covering: invalid status 422, too-long reviewNotes
  422, unknown program 404, happy-path with reviewNotes trim, and
  PGRST116 → 404 mapping.

Client:
- client/src/lib/api.ts — api.updateApplicationStatus with mock-mode
  fallback.
- client/src/components/admin/ApplicationCard.tsx (new) — shows
  project link (to /m2-program/:id), submitter, submitted date,
  status badge, Dogfooding feedback_focus, review notes (when
  present), and Accept/Reject buttons that appear only when
  status === 'submitted'. Each action triggers SIWS with the
  'review-application' statement.
- client/src/pages/AdminProgramPage.tsx (new) — /admin/programs/:slug
  admin-gated page. Restores admin_session_account from sessionStorage
  (same pattern as AdminPage); on-demand SIWS-signed Load/refresh
  fetches applications; filter chips (submitted / accepted / rejected
  / withdrawn / all); renders ApplicationCard per row.
- client/src/App.tsx — new /admin/programs/:slug route.

Design notes:
- Filter default is "submitted" so admins land on the work queue.
- Applications are loaded on explicit button click rather than on
  mount, because listing applications is SIWS-gated — the fetch has
  to happen after the admin signs. Alternative: auto-load once after
  a successful wallet connect. Chose explicit for transparency in
  Phase 1.
- Status transitions are final in this phase (no comment-back flow
  yet, no email/Telegram notification — those are explicitly Phase 2+
  per context-doc §64).

Verification:
- server/npm test: 48/48 passing (5 new + 43 existing).
- client/npm run build: clean.

End of Block F. Admin side of the Phase 1 program flow is complete.
@sacha-l sacha-l added enhancement New feature or request revamp-phase-1 Stadium Phase 1 revamp — programs, updates, funding signals, applications labels Apr 22, 2026
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 22, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
stadium Ready Ready Preview, Comment Apr 22, 2026 10:07pm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request revamp-phase-1 Stadium Phase 1 revamp — programs, updates, funding signals, applications

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant