diff --git a/docs/superpowers/plans/2026-06-17-phase-3a-admin-panel.md b/docs/superpowers/plans/2026-06-17-phase-3a-admin-panel.md index 113fe53..75247c3 100644 --- a/docs/superpowers/plans/2026-06-17-phase-3a-admin-panel.md +++ b/docs/superpowers/plans/2026-06-17-phase-3a-admin-panel.md @@ -60,16 +60,23 @@ apps/admin/ NEW workspace (mirror apps/worker) --- -### Task 1: Backend — `role` on `/api/me` +### Task 1: Backend — `role` on `/api/me` + allow the admin origin (CORS) **Files:** - Modify: `packages/shared/src/index.ts` (PublicUser) - Modify: `apps/api/src/routes/me.ts` -- Test: `apps/api/test/me.test.ts` (extend; or `apps/api/src/routes/me.test.ts` — match - where existing route tests live) +- Modify: `apps/api/src/env.ts` (default `WEB_ORIGINS`), `apps/api/.env.example` (comment + + default `CORS_ORIGINS`) +- Test: `apps/api/test/me.test.ts` (extend), `apps/api/test/cors.test.ts` (extend) **Interfaces:** - Produces: `PublicUser` now has `role: Role`; `MeResponse.user.role` is `'worker' | 'admin'`. + The default CORS/trustedOrigins list includes the admin dev origin `http://localhost:5174`. + +**Why CORS:** the admin app runs on dev port 5174 and calls the API on :3000 cross-origin. +`env.WEB_ORIGINS` (used for both `hono/cors` and better-auth `trustedOrigins`) currently +defaults to only `http://localhost:5173`, so without this the admin app's sign-in and every +request are blocked in the browser. - [ ] **Step 1: Write/extend the failing test.** Using the test helpers (`apps/api/test/helpers.ts`: `createTestUser`, `authToken`/`bearer`), assert that @@ -92,10 +99,16 @@ export const PublicUser = z.object({ - [ ] **Step 4: Return `role` from the route.** In `apps/api/src/routes/me.ts`, add to the `user` body: `role: ((session.user as { role?: string | null }).role ?? 'worker') as Role` (import `Role`/`MeResponse` type from `@solelog/shared`). Keep the `MeResponse` typing. -- [ ] **Step 5: Run tests — pass.** Also run `yarn workspace @solelog/api typecheck`. -- [ ] **Step 6: Confirm worker app unaffected** — `yarn workspace @solelog/worker test` +- [ ] **Step 5: CORS — allow the admin origin.** Add `http://localhost:5174` to the + default `WEB_ORIGINS` array in `apps/api/src/env.ts` + (`['http://localhost:5173', 'http://localhost:5174']`) and to the `CORS_ORIGINS=` line + + comment in `apps/api/.env.example`. Extend `apps/api/test/cors.test.ts` with a case + asserting the preflight allows `http://localhost:5174` (parametrize or add a second + origin assertion). Run the cors test — green. +- [ ] **Step 6: Run tests — pass.** Also run `yarn workspace @solelog/api typecheck`. +- [ ] **Step 7: Confirm worker app unaffected** — `yarn workspace @solelog/worker test` still green (it ignores the extra field). -- [ ] **Step 7: Commit** — `feat(api): include role in /api/me response`. +- [ ] **Step 8: Commit** — `feat(api): include role in /api/me + allow admin origin in CORS`. --- diff --git a/docs/superpowers/specs/2026-06-17-phase-3a-admin-panel-design.md b/docs/superpowers/specs/2026-06-17-phase-3a-admin-panel-design.md index dc6fbfa..c2fa19a 100644 --- a/docs/superpowers/specs/2026-06-17-phase-3a-admin-panel-design.md +++ b/docs/superpowers/specs/2026-06-17-phase-3a-admin-panel-design.md @@ -48,12 +48,16 @@ The admin app is a **client only** — it talks to the existing backend over HTT bearer token. No DB access. It mirrors `apps/worker`'s toolchain and conventions exactly so the build can copy proven patterns. -### Backend change (the only one in 3a) +### Backend changes (minimal, in 3a) - `packages/shared/src/index.ts`: add `role: Role` to `PublicUser` (so `MeResponse.user` carries it). - `apps/api/src/routes/me.ts`: include `role` in the response (read from the session user, default `'worker'`). The worker app ignores the extra field — no worker change needed. +- `apps/api/src/env.ts` + `.env.example`: add `http://localhost:5174` (the admin dev + origin) to the default `WEB_ORIGINS` / `CORS_ORIGINS`. Required because `WEB_ORIGINS` + drives both `hono/cors` and better-auth `trustedOrigins`; the admin app at :5174 calls + the API at :3000 cross-origin and would otherwise be blocked. ## Components