nexus/.planning/phases/40-job-infrastructure/40-02-SUMMARY.md

97 lines
4.4 KiB
Markdown

---
phase: 40-job-infrastructure
plan: "02"
subsystem: content-jobs
tags: [http-routes, sse, async-jobs, live-events, integration-tests]
dependency_graph:
requires:
- content_jobs DB table (40-01)
- contentJobStore CRUD service (40-01)
- contentJobRunner async dispatcher (40-01)
- subscribeCompanyLiveEvents from live-events.ts
- assertCompanyAccess from authz.ts
provides:
- POST /api/companies/:companyId/content-jobs (202 job submission)
- GET /api/companies/:companyId/content-jobs (list)
- GET /api/companies/:companyId/content-jobs/:jobId (single job)
- GET /api/companies/:companyId/content-jobs/:jobId/events (SSE progress stream)
affects:
- server/src/routes/content-jobs.ts
- server/src/app.ts
- server/src/__tests__/content-jobs-routes.test.ts
- server/src/__tests__/content-jobs-sse.test.ts
tech_stack:
added: []
patterns:
- fire-and-forget dispatch via void contentJobRunner.dispatch()
- SSE with res.flushHeaders() + res.write() + req.on("close") cleanup
- EventEmitter subscription for job progress (no polling)
- Supertest + vitest mocks for route integration testing
key_files:
created:
- server/src/routes/content-jobs.ts
- server/src/__tests__/content-jobs-routes.test.ts
- server/src/__tests__/content-jobs-sse.test.ts
modified:
- server/src/app.ts
decisions:
- SSE streams use EventEmitter subscription not polling — no setTimeout/setInterval
- req.on("close") cleanup prevents listener leaks when client disconnects mid-job
- Terminal jobs (done/failed) end SSE stream immediately after initial status event
- jobType validation rejects empty strings (whitespace-only) as well as missing field
metrics:
duration: "~3 minutes"
completed: "2026-04-04"
tasks_completed: 2
tasks_total: 2
files_created: 3
files_modified: 1
---
# Phase 40 Plan 02: HTTP routes for content job submission and SSE progress Summary
**One-liner:** Four Express route endpoints (POST 202, GET list, GET by ID, GET SSE events) wired to contentJobStore/contentJobRunner/live-events with 13 integration tests covering INFRA-01 through INFRA-04.
## What Was Built
HTTP API surface for content job submission and monitoring:
1. **POST /api/companies/:companyId/content-jobs** — validates jobType, creates job via contentJobStore, dispatches async runner (fire-and-forget), returns 202 `{ jobId, status, createdAt }`.
2. **GET /api/companies/:companyId/content-jobs** — lists all jobs for a company ordered by createdAt desc.
3. **GET /api/companies/:companyId/content-jobs/:jobId** — retrieves a single job, returns 404 if not found.
4. **GET /api/companies/:companyId/content-jobs/:jobId/events** — SSE endpoint: sets `text/event-stream` headers, flushes, sends initial status immediately, ends for terminal jobs, subscribes to `content_job.*` live events for running jobs, cleans up on `req.close`.
5. **app.ts mount**`contentJobRoutes(db, opts.storageService)` added after voiceRoutes.
## Tasks Completed
| Task | Name | Commit | Files |
|------|------|--------|-------|
| 1 | Content job routes and app.ts wiring | 4c6335b7 | content-jobs.ts (created), app.ts (modified) |
| 2 | Integration tests for content job routes and SSE | ae28542b | content-jobs-routes.test.ts, content-jobs-sse.test.ts (both created) |
## Verification
- `pnpm tsc --noEmit --project server/tsconfig.json` — PASS
- `pnpm vitest run src/__tests__/content-jobs-routes.test.ts src/__tests__/content-jobs-sse.test.ts` — 13/13 tests green
- POST /api/companies/:id/content-jobs returns 202 (INFRA-01) — verified
- GET /api/companies/:id/content-jobs/:id/events returns SSE stream (INFRA-02) — verified
- Job created with sourceTaskId shows it in GET response (INFRA-04) — verified
## Deviations from Plan
None — plan executed exactly as written.
## Known Stubs
None in this plan. The `renderContent` stub lives in `content-job-runner.ts` (documented in 40-01-SUMMARY.md) and is intentionally deferred to phases 41-45.
## Self-Check: PASSED
Files verified to exist:
- `/opt/nexus/server/src/routes/content-jobs.ts` — FOUND
- `/opt/nexus/server/src/__tests__/content-jobs-routes.test.ts` — FOUND
- `/opt/nexus/server/src/__tests__/content-jobs-sse.test.ts` — FOUND
Commits verified:
- `4c6335b7` — FOUND (feat(40-02): content job routes and app.ts wiring)
- `ae28542b` — FOUND (test(40-02): integration tests for content job routes and SSE)