2026-02-05 15:13:06 +08:00
## Python Environment
**MUST use uv for dependency management and virtual environment execution. **
- All Python commands: `uv run <command>`
- Add dependencies: `uv add <package>`
- All dependencies declared in `pyproject.toml`
2026-02-25 17:04:17 +08:00
## Code Quality Checks
2026-02-24 16:38:30 +08:00
2026-02-25 17:04:17 +08:00
**Git pre-commit hook enforces code quality before commit. **
2026-02-24 16:38:30 +08:00
2026-02-25 17:04:17 +08:00
Pre-commit hook automatically runs on backend/ directory:
- `ruff check` - code style and linting
- `basedpyright` - type checking with error level
2026-02-24 16:38:30 +08:00
2026-02-25 17:04:17 +08:00
If any error detected, commit is rejected. Fix errors before committing.
Do not bypass or weaken checks (no ignores, disables, or config relaxations). Resolve the underlying issues.
2026-02-24 16:38:30 +08:00
2026-02-05 15:13:06 +08:00
## Logging
**MUST use project logger for all runtime logging. **
- Use project logger from `backend/src/core/logging/*`
- Prohibit: print(), logging.info/warning/error directly
- Required: structured logging with context
- Log levels: DEBUG, INFO, WARNING, ERROR, CRITICAL
## HTTP API Standards
**MUST follow RESTful conventions and RFC 7807 for error responses. **
- Errors must use `application/problem+json` with RFC 7807 fields
- No custom response envelopes for HTTP APIs
- Request and response validation must use Pydantic models
## Environment Variables
**Backend env access MUST go through ** `backend/src/core/config/settings.py` .
- Only use `Settings()` / `config` from `core.config.settings`
- Do not call `os.environ` , `os.getenv` , `dotenv` , or manual parsing in backend runtime code
- Tests can set env vars via `monkeypatch.setenv` , and should read values via `Settings()` unless the test is explicitly validating env plumbing
- Canonical principle: one source of truth per setting; no duplicate/derived env vars in backend code
## TDD First Policy
**Principle: tests before implementation. **
### Coverage Requirements
- Minimum coverage: 80%
- Required test types:
- Unit: isolated functions, utilities, components
- Integration: API endpoints, database operations
- E2E: critical user flows (Playwright)
### Limited Exceptions
- Docs-only changes (README, comments, formatting) may skip integration/E2E
- Non-runtime config changes may skip E2E if no behavior changes
- Any runtime code change requires unit + integration + E2E
- If an exception is used, record the reason in the PR/test notes
### Mandatory TDD Workflow
1. Write tests (RED) - they must fail
2. Run tests - confirm failure
3. Implement minimal code (GREEN) - only to pass
4. Run tests - confirm success
5. Refactor (IMPROVE)
6. Verify coverage - must be 80%+
### Enforcement
- Must use the `tdd-guide` agent for new features
- Do not write implementation before tests
- Do not lower coverage requirements
- Must include unit, integration, and E2E tests
## Database Development Rules
### Core Principle
- **Supabase**: authentication (JWT source of truth)
- **Backend**: business authorization (service layer)
- **SQLAlchemy ORM**: data access layer (async + asyncpg, service_role connection)
### Architecture
Use `schemas / repository / service` pattern:
- `schemas.py` — Pydantic models
- `repository.py` — CRUD only, no auth, no commit (only flush), must receive session (never create session/engine)
- `service.py` — authorization + business logic + transaction boundary (must commit/rollback)
- `dependencies.py` — DI (`get_db` , `get_current_user` )
### Auth & Data Access
- Backend must verify JWT signature and expiration (not just decode)
- Extract `user_id` from JWT `sub` claim
- Backend connects with **service_role ** (bypasses RLS)
- `owner_id` always derived from JWT, never from client
- Scope queries by owner/org; public access must be explicit
- service_role key is backend-only; never expose credentials
- Prohibit calling Supabase Admin API (service_role key) from repository/service layers
### Migrations
- **Alembic is the single source of truth** for schema migrations
- ORM model changes → `alembic revision --autogenerate`
- Raw SQL (policies, triggers, functions) → `op.execute()`
- Migrations must be reversible; no reliance on generated IDs
### RLS Guidance
2026-02-25 18:04:05 +08:00
- Backend does not rely on RLS for correctness (uses service_role), but RLS is mandatory as a defensive boundary for tables in PostgREST-exposed schemas.
- **Mandatory default**: any new business table in `public` must enable RLS in the same Alembic migration.
- The same migration must create policies covering `SELECT/INSERT/UPDATE/DELETE` (minimum requirement).
- Recommended default policy set for `anon, authenticated` : deny all operations first, then open explicit access only when required.
- `alembic_version` must not be exposed to `anon` or `authenticated` .
#### Exemption Rule (strict)
- Exemptions are allowed only when a new `public` table is guaranteed not to be exposed to PostgREST clients.
- Exemptions must be explicit in the migration file with rationale and verification notes (why safe, how exposure is prevented).
- If exposure is uncertain, do not exempt: enable defensive RLS by default.
#### Migration Acceptance Checklist (RLS)
- [ ] New `public` business table has `ALTER TABLE ... ENABLE ROW LEVEL SECURITY` in migration
- [ ] Policies for `SELECT/INSERT/UPDATE/DELETE` are present in migration
- [ ] Policy target roles are explicit (`anon` , `authenticated` , or both)
- [ ] Downgrade path is reversible and does not silently weaken intended production security
- [ ] Any exemption is documented with clear non-exposure evidence