You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Backend development instructions for Python/FastAPI service. Use when: modifying Python code, API endpoints, database models, migrations, adapters, backend services, or backend tests.
applyTo
backend/**/*.py
backend/pyproject.toml
backend/Dockerfile
Backend Development Instructions
Project Structure
The backend uses a src-layout: application source code lives under backend/src/, not directly in backend/
The package is declared in backend/pyproject.toml with [tool.setuptools.packages.find] where = ["src"] (or equivalent for the build backend in use)
Tests live in backend/tests/ (outside src/) and import from the installed or editable package
Alembic migration files live in backend/alembic/
Python Version Compatibility
Target Python version: >= 3.10
All code must remain compatible with Python 3.10 and newer versions
Do not use Python features that require versions newer than 3.10 unless explicitly approved
Dependency Management
Explicit approval required before adding new packages to pyproject.toml
Dependencies are declared in pyproject.toml under [project.dependencies]
When suggesting new dependencies, explicitly ask for approval and explain why the dependency is needed
Prefer using existing dependencies when possible
Testing Requirements
Test Framework
Use only unittest module from Python standard library
Do not import pytest, nose, or other testing frameworks without explicit approval
Test Execution
All tests must be discoverable and runnable with: python -m unittest discover
Tests are located in backend/tests/ directory
Test files must follow the pattern test_*.py
Test classes must inherit from unittest.TestCase
Test Coverage
New modules must include corresponding unit tests
New functions and methods should be covered by tests
Tests should verify both success and error cases
Use descriptive test method names
Modifying Existing Tests
Critical: Only modify unit tests when the expected output of the tested method changes
When refactoring code without changing behavior:
Do NOT modify the tests – they verify the contract remains intact
Only modify the implementation being tested
Modify tests only when:
The method's public API changes (parameters, return type)
Variable names, function names, class names in English
Comments and docstrings in English
Error messages and log messages in English
Non-English languages are only allowed for user-facing text via the frontend localization system
Conventions
Strict type hints are mandatory on all function signatures (parameters and return types), class attributes, and variables where the type is not immediately obvious
Use from __future__ import annotations at the top of files where needed for forward references
Use async/await for all database operations (SQLAlchemy async)
Follow PEP 8 style guidelines
Use meaningful variable and function names
Keep functions focused and single-purpose
Imports
Group imports: standard library, third-party, local imports
Use absolute imports from the app package
Avoid wildcard imports (from module import *)
Error Handling
Use appropriate exception types
Log errors using the configured logger
Provide meaningful error messages
Handle database errors gracefully
Database Migrations (Alembic)
General Rules
All schema changes must be managed via Alembic migrations – never modify the database schema directly
Migration scripts live in alembic/versions/
The alembic.ini and alembic/env.py must be kept in sync with the SQLAlchemy models
Creating Migrations
Auto-generate migrations from model changes: alembic revision --autogenerate -m "<description>"
Always review auto-generated migrations before applying – autogenerate can miss or misinterpret changes (e.g., renamed columns, custom types, constraints)
Use a short, descriptive slug in the revision message (e.g., add_user_email_index, drop_legacy_tokens_table)
Migration Conventions
One logical change per migration file – do not bundle unrelated schema changes
Provide both upgrade() and downgrade() implementations unless a downgrade is genuinely not possible; in that case, raise NotImplementedError with an explanation
Never delete or edit a migration that has already been applied to any environment
Use server_default instead of default for database-level defaults in column definitions
Prefer nullable=False with a server_default over allowing nulls when adding columns to existing tables
Naming Conventions
Constraint names must be explicit and follow this pattern:
Use Pydantic models for request/response validation
Routers are thin: they handle HTTP concerns only (input parsing, response shaping, status codes)
Business logic must not live inside routers – extract it into dedicated service modules
Service Layer
Shared logic (e.g., database access, business rules, external calls) belongs in service modules, not in routers
A service is a plain Python module or class with typed functions – no FastAPI dependencies
Multiple routers may depend on the same service; never duplicate logic across routers
Services receive dependencies (e.g., DB sessions) via parameters, not by importing global state
Response Models
Define clear Pydantic schemas with strict type hints for all endpoints
Use proper HTTP status codes
Return meaningful error messages
Authentication
Endpoints are protected by default. Every endpoint requires a valid authenticated session unless explicitly declared public.
Public endpoints must be marked clearly, e.g. by applying a dedicated public dependency or by documenting the intent with a comment.
Authentication is enforced via a FastAPI dependency (e.g., Depends(get_current_user)) injected at the router or endpoint level.
The dependency resolves the current user from the request (e.g., via a JWT bearer token or session cookie) and raises HTTP 401 if the credential is missing or invalid.
Endpoints that require specific roles or permissions raise HTTP 403 when the authenticated user lacks the required access.
Never rely on obscurity – omitting auth from an endpoint must be a conscious, documented decision.
Token Lifecycle
JWTs must carry an exp claim. Tokens without an expiry are not permitted.
Use a sliding expiry pattern: on every authenticated request, if the token is still valid but within a configurable renewal window (e.g., the remaining lifetime is less than half the total TTL), issue a fresh token with a new exp and return it to the client (e.g., via a response header or response body field).
The total token TTL and the renewal threshold must be configurable via environment variables – never hard-coded.
The client is responsible for storing the refreshed token and using it for subsequent requests.
Expired tokens must be rejected with HTTP 401; the client must then redirect to the login flow.
Minimize changes: Only modify code that is directly relevant to the task
Targeted edits: Make the smallest possible changes to achieve the goal
Refactoring: Allowed when it meaningfully improves code quality, maintainability, or performance
Preserve behavior: Existing functionality must not break unless explicitly requested
Code Quality
Write clean, readable, and idiomatic code
Follow existing code patterns and conventions in the project
Maintain consistent formatting with the existing codebase
Add comments only when the code's intent is not self-evident
Testing
New features and modules should be covered by appropriate tests
Bug fixes should include tests to prevent regression when applicable
Follow project-specific testing guidelines (see backend/frontend instructions)
Documentation
Update relevant documentation when making functional changes
Keep inline documentation concise and meaningful
Document complex algorithms or non-obvious design decisions
API Consistency
When modifying API endpoints (either in backend or frontend):
Ensure changes are synchronized between backend implementation and frontend consumption
Update both sides to maintain API contract compatibility
Verify request/response schemas match on both ends
Test the complete request/response cycle after changes
Backend API changes require corresponding frontend updates and vice versa
Breaking API changes must be communicated and coordinated
Project Layout
/frontend – all frontend code
/backend – all backend code
/docs – all documentation
/docs/manual – end-user documentation
/docs/dev – developer documentation (architecture, API contracts, setup guides, etc.)
Do not place source code outside these directories.
Technology Constraints
Backend
Python >= 3.10 (minimum version)
FastAPI, Pydantic
Alembic for PostgreSQL schema migrations
No new dependencies without explicit approval
Frontend
Vue 3 with Material Design 3 (Google's official MD3 library)
Vite as build tool
No additional frameworks without explicit approval
Docker Environment
The application runs in Docker containers. Configuration is managed via .env file based on .env.example if present.
Networking
Services communicate over the internal Docker Compose network
Ports are exposed within the Compose network only – never published to the host unless explicitly required for development access
External port bindings (ports:) must be kept to the minimum necessary
Database
If a database is required, use PostgreSQL as a dedicated Docker Compose service
The database container is only accessible from within the Compose network – never bind its port to the host in production configurations
Only the backend may connect to the database. The frontend must never communicate with the database directly, not even indirectly via a shared connection string
Database credentials and connection URLs are managed via environment variables, never hard-coded
Frontend development instructions for Vue 3 application. Use when: modifying Vue components, views, router, stores, API client, styles, or frontend configuration.
applyTo
frontend/**/*.vue
frontend/**/*.js
frontend/**/*.ts
frontend/index.html
frontend/vite.config.js
frontend/package.json
Frontend Development Instructions
Technology Stack
Vue 3 – Composition API (<script setup>) is the required style
Vue Router – client-side routing
vue-i18n – internationalization
@material/web – Google's official Material Design 3 web components (MD3)
Open Props – CSS design token library (spacing, shadows, typography, animations) by Adam Argyle (ex-Google)
Vite – build tool
No additional UI frameworks (no Vuetify, Quasar, PrimeVue, etc.) without explicit approval
No CSS frameworks (no Tailwind, Bootstrap, Pico CSS, etc.) without explicit approval
Mapping: if map rendering is required, use MapLibre GL JS (maplibre-gl). Any additional MapLibre plugins or related packages still require explicit approval.
Dependency Management
Explicit approval required before adding new packages to package.json
When suggesting new dependencies, explain why no existing dependency covers the need
Prefer native browser APIs and Vue built-ins over external libraries
Component Authoring
General Rules
Use <script setup> syntax for all components – no Options API
Keep components focused: one responsibility per component
Extract reusable logic into composables (use*.js in src/composables/)
Props must have explicit types; use defineProps with type declarations
Emit events with defineEmits; name events in kebab-case
Styling is token-based, class-light, and framework-free. It follows a three-layer model:
MD3 design tokens (--md-sys-color-*, --md-ref-typeface-*) – theming and interactive component appearance. Always prefer MD3 tokens over custom values for anything an MD3 component consumes.
Open Props tokens (--shadow-*, --size-*, --radius-*, --font-size-*, --ease-*, etc.) – structural design primitives for layout, spacing, typography scale, shadows, and animation. Use these instead of hard-coding raw values.
Custom layout CSS (src/assets/layout.css) – structural layout rules and project-specific custom properties (prefixed --mk-* to avoid collisions). Only add custom properties here when neither MD3 nor Open Props provides what's needed.
Open Props ships as CSS custom properties only – no HTML classes, no JavaScript, no conflict with MD3 web components (which use Shadow DOM).
Rules
Never add inline styles for layout or theming – use CSS classes or tokens
Inline styles are acceptable only for truly one-off values (e.g., max-width on a single element) where creating a class would be overkill
Component-scoped <style scoped> blocks are for component-local structural tweaks only, not for overriding global theme or layout
Do not introduce utility-class frameworks (Tailwind, Bootstrap, etc.) without explicit approval
Responsive design is achieved with CSS custom properties, clamp(), Open Props fluid sizes, flexbox, and grid – no breakpoint framework required
When a design value is needed (shadow, spacing, radius, easing), check Open Props first before writing a custom value
MD3 Tokens
Theme colors are set via --md-sys-color-* tokens on :root
Typography typefaces are set via --md-ref-typeface-brand and --md-ref-typeface-plain
Use MD3 component variants as intended (e.g., md-filled-button for primary actions, md-text-button for low-emphasis actions)
Open Props Tokens
Use Open Props variables for structural primitives instead of hard-coded values:
Project-specific tokens (prefixed --mk-*) in src/assets/layout.css are used only for values not covered by MD3 or Open Props. Consume them via variables, never duplicate them inline.
Using MD3 Components
Import @material/web components at the entry point (main.js) or in the relevant component – never duplicate imports
Use the appropriate component for the semantic intent (buttons, text fields, dialogs, icons, etc.)
Icon names come from the @material-symbols/font-400 icon font; use <md-icon> to render them
Do not wrap MD3 components in unnecessary container components just to rename them
Frontend vs. Backend Responsibility
The frontend is UI only. Its sole responsibility is rendering data and capturing user input.
All business logic, calculations, data transformations, and aggregations must run on the backend. If a computation is not purely presentational (e.g., formatting a date for display), it belongs in the backend.
Do not replicate backend logic in the frontend. If you need a derived value that isn't returned by the API, extend the API – do not compute it client-side.
Validation in the frontend is for immediate user feedback only (e.g., required field hints). Authoritative validation always runs on the backend.
Routing
All routes are defined in src/router/index.js
Protected routes require authentication; use a navigation guard to enforce this
Public routes (e.g., login) must be explicitly marked (e.g., meta: { public: true })
Lazy-load route components with dynamic import() to keep the initial bundle small
State Management
Use Vue's built-in reactivity (reactive, ref) for shared state – no external state management library is required
Shared state is implemented as plain reactive singletons exported from src/stores/ modules
Do not put UI state (loading spinners, open dialogs) in shared stores unless it needs to be shared across multiple components; keep it local with ref/reactive
Do not introduce Pinia or Vuex without explicit approval
API Communication
All HTTP calls go through a central API client (src/api/client.js)
Never call axios or fetch directly from a component or store – always use the client module
The client handles base URL, auth headers, and error normalization centrally
API functions are grouped by domain (e.g., src/api/items.js, src/api/auth.js)
Internationalization (i18n)
All user-facing strings must be externalized into locale files (src/locales/)
Never hard-code display text in components – always use $t('key') or t('key')
Locale files are the only place where non-English natural language is permitted
Add keys to all locale files simultaneously to avoid missing translations
Code Style
Language
All code (variable names, function names, comments) must be written in English
Non-English natural language is only allowed in locale files
Conventions
Use const by default; let only when reassignment is necessary
Prefer async/await over .then() chains
Use destructuring for props and object access where it improves readability
Keep template expressions simple – move complex logic to computed properties or methods
Before Committing
Ensure all new user-facing strings have entries in every locale file
Check that no new dependencies were added without approval