feat: IDEA-118 copilot-integratie (Fase 5 Deel B) — @s4m-kit + /copilot + app-tools #75

Merged
janpeter merged 5 commits from claude/copilot-fase5-ops-integration into main 2026-06-12 10:24:11 +02:00
Owner

Samenvatting

Integreert de IDEA-118 in-app copilot in het Ops-dashboard (pilot-app) — Deel B van Fase 5 (Deel A = de centrale service-deploy op 154, apart). Het plan is DUBBEL-GO na 4 cross-model-reviewrondes; deze implementatie is per-taak build-geverifieerd + holistisch code-reviewed (GO).

  • B1 — vendor @s4m-kit als submodule (vendor/scrum4me-copilot, Forgejo) + tsconfig (@s4m-kit/*-path + verplichte exclude voor de vendored tests / service-workspace / geneste scrum4me-shared-submodule, zodat de brede **/*.ts-include geen Ops-vreemde deps trekt) + zod@^4.
  • B2next.config.ts webpack extensionAlias (.js.ts, de Turbopack-fix) + package.json-scripts op --webpack.
  • B3app/api/s4m/[...path]/route.ts: createS4MRoutes-proxy (SSE pass-through + server-side app-key) met 2 read-only app-tools (recente_deploys, deploy_details) op FlowRun/FlowStep. User-scoped: beide handlers re-fetchen getCurrentUser() + filteren op user_id.
  • B4/copilot-paneel (nav-suite Chat·Documentatie·Ideas·Jobs via @s4m-kit) + AppNav-item.
  • B5deploy/ops-agent/baseline/flows/update_ops_dashboard.yml uitgebreid met één stap git_submodule_update (ná git_pull, vóór prisma_migrate_deploy_ops_dashboard); migrate/build/up/smoke ongewijzigd.
  • B6 (review-fix C1) — proxy.ts: /api/s4m/* vrijgesteld van de CSRF double-submit-gate.

⚠️ Security-noot (CSRF-exemptie — bewust, graag mee-reviewen)

proxy.ts stelt /api/s4m/* vrij van de double-submit CSRF-header-check. De kit-hook (generiek pakket) kan Ops' CSRF-token niet injecteren, waardoor élke chat/tool-POST anders 403'd zou worden. Veilig omdat ops_session sameSite: 'strict' is (een cross-site POST draagt geen sessie → getCurrentUser() = null → de route's requireSession geeft 401) én de app-tools read-only zijn. De double-submit-check is voor deze route dus redundant; de exemptie is prefix-scoped (/api/s4m + /api/s4m/..., geen sibling-over-match).

Verificatie

  • git submodule update --init --recursive vendor/scrum4me-copilot && npx tsc --noEmit0 errors (de exclude houdt vendored tests/service + de geneste scrum4me-shared-lib — die yaml importeert — buiten de typecheck, óók met de geneste submodule aanwezig).
  • npm run build (next build --webpack) → Compiled successfully; /copilot + /api/s4m/[...path] in de route-list, geen module-resolution-errors (bewijst @s4m-kit/* + ../protocol/src resolutie onder webpack extensionAlias).
  • Volledige docker build (clean-context: Alpine, npm ci incl. zod, prisma generate, submodule-COPY, bundle) → exit 0.
  • Holistische code-review → GO (user-scoping correct in beide handlers, kit-API + Prisma-velden correct, geen scope-creep; de CSRF-blocker C1 gevonden, gefixt in B6, en herbevestigd).

Na de merge (154 — Fase-5 Task A5, door 154-claude)

De live /etc/ops-agent/flows/update_ops_dashboard.yml syncen met deze baseline (de extra git_submodule_update-stap) + S4M_COPILOT_URL=http://scrum4me-copilot:8100 & S4M_COPILOT_APP_KEY=<COPILOT_APP_OPS_KEY> in /srv/scrum4me/ops-dashboard/.env, dan de update_ops_dashboard-flow draaien. Daarna de browser-e2e (Deel C).

Test Plan

  • Merge → 154 synct de flow + zet de twee envs → update_ops_dashboard-flow draait groen (submodule-init in de build-context; curl_smoke_ops_dashboard /login OK).
  • Browser /copilot: één chat-beurt streamt SSE; "toon de recente deploys" → app-tool-round-trip (Ops-FlowRun); Documentatie/Ideas/Jobs-tabs laden Ops-product-data (cmp43iaoi000h6o7rxklqivl5).

🤖 Generated with Claude Code

## Samenvatting Integreert de **IDEA-118 in-app copilot** in het Ops-dashboard (pilot-app) — Deel B van Fase 5 (Deel A = de centrale service-deploy op 154, apart). Het plan is **DUBBEL-GO** na 4 cross-model-reviewrondes; deze implementatie is per-taak build-geverifieerd + holistisch code-reviewed (**GO**). - **B1** — vendor `@s4m-kit` als submodule (`vendor/scrum4me-copilot`, Forgejo) + `tsconfig` (`@s4m-kit/*`-path + verplichte `exclude` voor de vendored tests / `service`-workspace / geneste `scrum4me-shared`-submodule, zodat de brede `**/*.ts`-include geen Ops-vreemde deps trekt) + `zod@^4`. - **B2** — `next.config.ts` webpack `extensionAlias` (`.js`→`.ts`, de Turbopack-fix) + `package.json`-scripts op `--webpack`. - **B3** — `app/api/s4m/[...path]/route.ts`: `createS4MRoutes`-proxy (SSE pass-through + server-side app-key) met 2 read-only app-tools (`recente_deploys`, `deploy_details`) op `FlowRun`/`FlowStep`. **User-scoped**: beide handlers re-fetchen `getCurrentUser()` + filteren op `user_id`. - **B4** — `/copilot`-paneel (nav-suite Chat·Documentatie·Ideas·Jobs via `@s4m-kit`) + AppNav-item. - **B5** — `deploy/ops-agent/baseline/flows/update_ops_dashboard.yml` uitgebreid met één stap `git_submodule_update` (ná `git_pull`, vóór `prisma_migrate_deploy_ops_dashboard`); migrate/build/up/smoke ongewijzigd. - **B6** (review-fix C1) — `proxy.ts`: `/api/s4m/*` vrijgesteld van de CSRF double-submit-gate. ## ⚠️ Security-noot (CSRF-exemptie — bewust, graag mee-reviewen) `proxy.ts` stelt `/api/s4m/*` vrij van de double-submit CSRF-header-check. De kit-hook (generiek pakket) kan Ops' CSRF-token niet injecteren, waardoor élke chat/tool-POST anders 403'd zou worden. **Veilig** omdat `ops_session` `sameSite: 'strict'` is (een cross-site POST draagt geen sessie → `getCurrentUser()` = null → de route's `requireSession` geeft 401) én de app-tools read-only zijn. De double-submit-check is voor deze route dus redundant; de exemptie is prefix-scoped (`/api/s4m` + `/api/s4m/...`, geen sibling-over-match). ## Verificatie - `git submodule update --init --recursive vendor/scrum4me-copilot && npx tsc --noEmit` → **0 errors** (de `exclude` houdt vendored tests/service + de geneste `scrum4me-shared`-lib — die `yaml` importeert — buiten de typecheck, óók met de geneste submodule aanwezig). - `npm run build` (`next build --webpack`) → **Compiled successfully**; `/copilot` + `/api/s4m/[...path]` in de route-list, geen module-resolution-errors (bewijst `@s4m-kit/*` + `../protocol/src` resolutie onder webpack `extensionAlias`). - **Volledige `docker build`** (clean-context: Alpine, `npm ci` incl. zod, `prisma generate`, submodule-`COPY`, bundle) → **exit 0**. - Holistische code-review → **GO** (user-scoping correct in beide handlers, kit-API + Prisma-velden correct, geen scope-creep; de CSRF-blocker C1 gevonden, gefixt in B6, en herbevestigd). ## Na de merge (154 — Fase-5 Task A5, door 154-claude) De live `/etc/ops-agent/flows/update_ops_dashboard.yml` syncen met deze baseline (de extra `git_submodule_update`-stap) + `S4M_COPILOT_URL=http://scrum4me-copilot:8100` & `S4M_COPILOT_APP_KEY=<COPILOT_APP_OPS_KEY>` in `/srv/scrum4me/ops-dashboard/.env`, dan de `update_ops_dashboard`-flow draaien. Daarna de browser-e2e (Deel C). ## Test Plan - [ ] Merge → 154 synct de flow + zet de twee envs → `update_ops_dashboard`-flow draait groen (submodule-init in de build-context; `curl_smoke_ops_dashboard` /login OK). - [ ] Browser `/copilot`: één chat-beurt streamt SSE; "toon de recente deploys" → app-tool-round-trip (Ops-`FlowRun`); Documentatie/Ideas/Jobs-tabs laden Ops-product-data (`cmp43iaoi000h6o7rxklqivl5`). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
- submodule vendor/scrum4me-copilot (Forgejo, recursive incl. nested scrum4me-shared)
- tsconfig: @s4m-kit/* path + verplichte exclude (service, vendor [geneste shared],
  tests/vitest-configs) zodat de brede **/*.ts include geen Ops-vreemde deps trekt (B-C1)
- next.config: webpack extensionAlias .js->.ts (Turbopack heeft die niet)
- scripts: next dev/build --webpack
- zod@^4 (Ops had geen zod)

Verified: git submodule update --init --recursive + prisma generate + npx tsc --noEmit
= 0 errors (0 in vendor) op een verse worktree-clone.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- app/api/s4m/[...path]/route.ts: createS4MRoutes proxy (SSE pass-through + server-side
  app-key) met 2 read-tools recente_deploys/deploy_details op FlowRun/FlowStep
- user-scoped: beide handlers re-fetchen getCurrentUser() + filteren op user_id
  (ToolRegistry.run geeft alleen input door, niet de session-user)
- .env.example: S4M_COPILOT_URL + S4M_COPILOT_APP_KEY

Verified: npx tsc --noEmit = 0 errors; npm run build (next build --webpack) =
Compiled successfully, /api/s4m/[...path] in route-list, geen module-resolution errors
(bewijst @s4m-kit/* + ../protocol/src resolutie onder webpack extensionAlias).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- app/copilot/page.tsx: server-page, getCurrentUser-gate -> redirect /login
- app/copilot/copilot-panel.tsx: 'use client' nav-suite (Chat/Docs/Ideas/Jobs)
  via @s4m-kit (S4MNavBar + S4MChatWindow/S4MDocsPage/S4MIdeasPage/S4MJobsPage)
- AppNav: Copilot toegevoegd aan PRIMARY_ITEMS (always-on, geen cap; net als Dashboard)

Verified: npx tsc --noEmit = 0 errors; npm run build = Compiled successfully,
/copilot + /api/s4m/[...path] in de route-list.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- baseline/flows/update_ops_dashboard.yml: git_submodule_update toegevoegd NA git_pull,
  VOOR prisma_migrate_deploy_ops_dashboard; alle andere stappen (migrate/build/up/smoke)
  byte-voor-byte ongewijzigd. Geen parallelle top-level flow (behoudt drift-check).
- command git_submodule_update bestaat al in baseline/commands.yml (regel 421).
- Dockerfile: GEEN wijziging nodig — COPY . . includeert de geinitieerde submodule-source,
  npm run build = next build --webpack (al correct), en .dockerignore excludeert vendor niet.
- Live /etc/ops-agent/flows/update_ops_dashboard.yml-sync = 154-taak (Task A5, na PR-merge).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
De kit-hook useS4MChat POST't naar /api/s4m/chat* zonder x-csrf-token header (generiek
pakket, kan Ops' double-submit token niet injecteren) -> elke chat/tool-POST kreeg 403
van proxy.ts vóór de route-handler. Voeg /api/s4m toe als prefix-exempt.

Veilig: ops_session is sameSite=strict (cross-site POST draagt geen sessie -> getCurrentUser()
= null -> 401), en createS4MRoutes dwingt requireSession server-side af; de app-tools zijn
read-only. De double-submit CSRF-check is voor deze route dus redundant.

Gevonden door de holistische code-review (C1).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
janpeter/Ops-dashboard!75
No description provided.