97 lines
4.4 KiB
Markdown
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)
|