7.0 KiB
7.0 KiB
Task 002: Shared Domain Contracts
Development description: Implement the shared domain schema package that defines workflow statuses, role names, API DTOs, and validation contracts used consistently by backend, frontend, runner, and tests.
Implementation Details
- Define canonical enums for:
- Roles:
ADMIN,EDITOR. - Article workflow statuses from
ARTICLE_BRIEF_CREATEDthroughPUBLISH_COMMIT_CREATED. - Agent job statuses and error categories.
- Claim support statuses and risk levels.
- Publishing statuses.
- Roles:
- Define shared request/response schemas for:
- Article create/list/detail.
- Target site config.
- Script/config version.
- Agent job.
- Research artifact manifest.
- Plan, draft, evidence, asset, review, and publish commit summaries.
- Choose one source of truth for validation:
- Recommended implementation: Pydantic models in backend plus generated OpenAPI client/types for frontend.
- Shared package may hold OpenAPI schema snapshots and TypeScript types generated from backend.
- Add schema validation tests for representative valid and invalid payloads.
Public Interface
- Backend exposes OpenAPI JSON with the canonical contracts.
- Frontend imports generated API types instead of duplicating DTO shapes.
- Runner consumes backend contracts for job input/output validation.
Acceptance Criteria
- TDD pre-requirement: before implementation, write a failing contract test for one externally visible DTO and one invalid payload; proceed one schema at a time and record red-green evidence in
Result. - Workflow status transitions use shared constants rather than string literals spread across apps.
- Role names are exactly
ADMINandEDITOR. - Generated frontend types match backend OpenAPI.
- Contract tests fail on missing required fields and invalid enum values.
- Runner job output schemas can be validated without importing frontend code.
Verification
- Run backend schema tests.
- Generate frontend API types.
- Run a typecheck in frontend against generated types.
Result
- Status: Completed.
- TDD plan:
- Add one backend public OpenAPI contract test before implementation.
- Verify
POST /api/articlesexposesArticleCreateRequestas an external request DTO. - Verify
ArticleCreateRequestrequiresbrief_descriptionandtarget_site_id. - Verify
Roleenum is exactlyADMINandEDITOR. - Verify the OpenAPI contract validation surface rejects a missing required article-create payload and invalid enum values once the schemas exist.
- Red evidence:
- Command:
/private/tmp/pupline-contract-venv/bin/python -m unittest apps/backend/tests/contracts/test_public_openapi_contract.py - Note: system Python did not have FastAPI installed; the red run used a temporary venv with
fastapi==0.115.6. No Docker or HTTP server was used. - Result:
FAILED (failures=1) - Failure summary:
components.schemas.ArticleCreateRequest is missingPOST /api/articles must expose ArticleCreateRequest as its JSON request body; got no request bodycomponents.schemas.Role is missingcomponents.schemas.ArticleWorkflowStatus is missing
- Command:
- Green evidence:
- Command:
/private/tmp/pupline-contract-venv/bin/python -m unittest apps/backend/tests/contracts/test_public_openapi_contract.py - Result:
OK - Command:
/private/tmp/pupline-contract-venv/bin/python -m unittest discover -s apps/backend/tests - Result:
Ran 6 tests in 0.015s/OK - Command:
/private/tmp/pupline-contract-venv/bin/python -m unittest discover -s apps/runner/tests - Result:
Ran 3 tests in 0.044s/OK
- Command:
- Refactor notes:
- Added backend domain contract package under
apps/backend/src/domain/contracts/as the Pydantic source of truth. - Added shared workflow transition constants in
apps/backend/src/domain/contracts/workflow.py. - Kept presentation thin:
POST /api/articlesimports domain request/response schemas and delegates deterministic placeholder response creation to application code. - Added OpenAPI injection for canonical contract components so schemas not yet backed by business endpoints are still public in
/openapi.json. - Added runner job-output validation that loads backend contract models directly and does not import frontend code.
- Regression fix: runner Docker image now installs
apps/runner/requirements.txtbefore copying source, so runner validation dependencies are present in the image. - Regression fix: runner Docker image now bundles the backend contract package under
/app/backend_contracts/contracts; the validator resolves that image path first, with monorepo fallback for local tests. - Added a generated-artifact contract test to keep
packages/shared/openapi.jsonin sync with backend OpenAPI. - Replaced shared package exports with generated API types and wired frontend to import
ArticleListResponsefrom@pipeline/shared. - Regression fix: rewrote
apps/frontend/Dockerfileto install from the repository root with pnpm workspace manifests, so Docker understands@pipeline/shared: workspace:*. - Regression fix: pinned root
packageManagertopnpm@10.27.0, copied.npmrcinto the frontend image, and usednode:22-slimplus linux SWC optional dependencies so Next does not try to download SWC at request time.
- Added backend domain contract package under
- Verification output:
- Command:
make contracts PYTHON=/private/tmp/pupline-contract-venv/bin/python - Result:
wrote /Users/gavrilovdev/tmp/pupline/packages/shared/openapi.jsonwrote /Users/gavrilovdev/tmp/pupline/packages/shared/src/api-types.ts
- Command:
pnpm install - Result:
Done in 8.4s using pnpm v10.27.0 - Command:
pnpm install --frozen-lockfile - Result:
Lockfile is up to date/Done in 13.3s using pnpm v10.27.0 - Command:
pnpm typecheck - Result:
@pipeline/sharedand@pipeline/frontendtsc --noEmitcompleted successfully. - Regression command:
bash tests/smoke/public-health.sh - Regression red result before fix:
npm error code EUNSUPPORTEDPROTOCOLUnsupported URL Type "workspace:": workspace:*
- Regression green result after fix:
RUN pip install --no-cache-dir -r requirements.txtSuccessfully installed ... pydantic-2.13.4 ... pydantic-core-2.46.4RUN pnpm install --frozen-lockfileDone in 10.8s using pnpm v10.27.0pupline-frontend Builtbackend health okrunner health okfrontend health okbackend dependencies okpublic health smoke ok
- Runner image validation command:
docker compose run --rm runner python -c "from src.application.job_output_validation import validate_agent_job_output; result = validate_agent_job_output({'status':'SUCCEEDED'}); print(result.status.value)" - Runner image validation result:
SUCCEEDED - OpenAPI spot check:
POST /api/articlesrequest body is#/components/schemas/ArticleCreateRequest.Roleenum is['ADMIN', 'EDITOR'].ArticleWorkflowStatusstarts atARTICLE_BRIEF_CREATEDand ends atPUBLISH_COMMIT_CREATED.
- Command: