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

4.4 KiB

phase plan subsystem tags dependency_graph tech_stack key_files decisions metrics
40-job-infrastructure 02 content-jobs
http-routes
sse
async-jobs
live-events
integration-tests
requires provides affects
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
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)
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
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
created modified
server/src/routes/content-jobs.ts
server/src/__tests__/content-jobs-routes.test.ts
server/src/__tests__/content-jobs-sse.test.ts
server/src/app.ts
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
duration completed tasks_completed tasks_total files_created files_modified
~3 minutes 2026-04-04 2 2 3 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 mountcontentJobRoutes(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)