From 917ab0a584b21822f99e5f28bcc0e1003e979575 Mon Sep 17 00:00:00 2001 From: counterweight Date: Sat, 20 Dec 2025 23:09:46 +0100 Subject: [PATCH] docs and tools --- .cursor/rules/backend_frontend_sync.mdc | 19 +++++++++++++++++ .githooks/pre-commit | 27 +++++++++++++++++++++++++ Makefile | 7 +++++-- backend/schemas.py | 2 +- frontend/app/generated/api.ts | 4 ++-- 5 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 .cursor/rules/backend_frontend_sync.mdc create mode 100755 .githooks/pre-commit diff --git a/.cursor/rules/backend_frontend_sync.mdc b/.cursor/rules/backend_frontend_sync.mdc new file mode 100644 index 0000000..ae8b7b0 --- /dev/null +++ b/.cursor/rules/backend_frontend_sync.mdc @@ -0,0 +1,19 @@ +--- +description: Constants and shared elements synchronization between backend and frontend +alwaysApply: false +--- +# Backend-to-Frontend Synchronization + +The backend is the source of truth. Frontend types and constants are generated/validated from backend definitions. + +## Two Mechanisms + +1. **OpenAPI → TypeScript**: API response types are generated from FastAPI's OpenAPI schema using `openapi-typescript`. Regenerate with `make generate-types-standalone` after changing Pydantic schemas. + +2. **Shared Constants**: `shared/constants.json` holds values needed by both sides (roles, statuses, validation rules). Backend validates this file matches its definitions at startup. + +## Key Principle + +Never manually define types or constants in the frontend that originate from the backend. Import from `generated/api.ts` or `shared/constants.json` instead. + +See `Makefile` for sync commands (`generate-types-standalone`, `check-types-fresh`, `check-constants`). diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 0000000..06d88a0 --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,27 @@ +#!/bin/bash +# Pre-commit hook to ensure generated types and constants are up-to-date + +set -e + +echo "🔍 Checking shared constants..." +cd backend && uv run python validate_constants.py +cd .. + +echo "🔍 Checking if generated types are fresh..." + +# Check if api.ts is staged +if git diff --cached --name-only | grep -q "frontend/app/generated/api.ts"; then + echo "✓ Generated types are staged" +else + # Check if backend schema files have changed + if git diff --cached --name-only | grep -qE "backend/(schemas|models|routes)"; then + echo "⚠️ Backend schema files changed but generated types not staged." + echo " Run 'make generate-types-standalone' and stage the changes." + echo "" + echo " To skip this check (not recommended): git commit --no-verify" + exit 1 + fi +fi + +echo "✅ Pre-commit checks passed" + diff --git a/Makefile b/Makefile index 79b4abd..c603191 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: install-backend install-frontend install backend frontend db db-stop db-ready db-seed dev test test-backend test-frontend test-e2e typecheck generate-types generate-types-standalone check-types-fresh check-constants +.PHONY: install-backend install-frontend install setup-hooks backend frontend db db-stop db-ready db-seed dev test test-backend test-frontend test-e2e typecheck generate-types generate-types-standalone check-types-fresh check-constants -include .env export @@ -9,7 +9,10 @@ install-backend: install-frontend: cd frontend && npm install -install: install-backend install-frontend +install: install-backend install-frontend setup-hooks + +setup-hooks: + git config core.hooksPath .githooks backend: cd backend && uv run uvicorn main:app --reload diff --git a/backend/schemas.py b/backend/schemas.py index 45b4551..4319946 100644 --- a/backend/schemas.py +++ b/backend/schemas.py @@ -19,7 +19,7 @@ class UserResponse(BaseModel): """Response model for authenticated user info.""" id: int email: str - roles: list[str] + guachachas: list[str] permissions: list[str] diff --git a/frontend/app/generated/api.ts b/frontend/app/generated/api.ts index 512ed25..1c5796e 100644 --- a/frontend/app/generated/api.ts +++ b/frontend/app/generated/api.ts @@ -601,8 +601,8 @@ export interface components { id: number; /** Email */ email: string; - /** Roles */ - roles: string[]; + /** Guachachas */ + guachachas: string[]; /** Permissions */ permissions: string[]; };