Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,39 @@ jobs:

echo "Repository hygiene checks passed."

api-contract:
name: API Contract Drift
needs: repository-hygiene
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: apps/frontend/package-lock.json

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.13"
cache: pip

- name: Install frontend dependencies
run: npm ci --prefix apps/frontend

- name: Install backend dependencies
run: |
python -m pip install -r apps/backend/requirements-dev.txt
python -m pip install -e apps/backend --no-deps

- name: Check generated frontend API contract
run: npm --prefix apps/frontend run generate:api-contract -- --check

frontend:
name: Frontend
needs: repository-hygiene
Expand Down
4 changes: 3 additions & 1 deletion apps/backend/app/schemas/ai.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from datetime import UTC, datetime
from typing import Literal

from pydantic import Field

from app.schemas.base import CamelModel

AiProvider = Literal["openai", "anthropic", "gemini", "openrouter", "ollama"]
Expand Down Expand Up @@ -65,4 +67,4 @@ class AiProviderTestRequest(CamelModel):
class AiProviderTestResponse(CamelModel):
ok: bool
message: str
checked_at: datetime = datetime.now(UTC)
checked_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
8 changes: 8 additions & 0 deletions apps/frontend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,17 @@ npm --prefix apps/frontend run lint # eslint
npm --prefix apps/frontend run test # vitest, with coverage
npm --prefix apps/frontend run test:watch
npm --prefix apps/frontend run build # tsc -b && vite build
npm run generate:api-contract # regenerate DTOs from FastAPI OpenAPI
npm --prefix apps/frontend run generate:api-contract -- --check # fail on drift
npm run test:prototype # disposable fixtures + Playwright journeys
```

The generated contract lives at
`src/shared/services/api/generated.ts` and must not be edited directly. The
generator imports backend module `app.main:app` from `apps/backend`, strips only import-time dynamic
datetime defaults, and runs the pinned `openapi-typescript@7.13.0` tool. The CI
API Contract Drift job installs both app lockfiles and runs the check command.

From the repository root: `npm run dev:frontend`, `npm run lint:frontend`,
`npm run build:frontend`, and `npm run test:prototype`. There is no root alias
for the Vitest suite — run `npm --prefix apps/frontend run test`.
Expand Down
Loading
Loading