2026-02-27 15:22:42 +08:00
# Backend Development Rules
This document defines Python/FastAPI backend development constraints.
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
2026-02-27 15:22:42 +08:00
## TDD Workflow
2026-02-05 15:13:06 +08:00
### Coverage Requirements
2026-02-27 15:22:42 +08:00
2026-02-05 15:13:06 +08:00
- Minimum coverage: 80%
- Required test types:
- Unit: isolated functions, utilities, components
- Integration: API endpoints, database operations
- E2E: critical user flows (Playwright)
### Limited Exceptions
2026-02-27 15:22:42 +08:00
2026-02-05 15:13:06 +08:00
- 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
2026-02-27 15:22:42 +08:00
2026-02-05 15:13:06 +08:00
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
2026-02-27 15:22:42 +08:00
2026-02-05 15:13:06 +08:00
- 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
2026-02-27 15:22:42 +08:00
## Code Style
### Immutability
**ALWAYS create new objects, NEVER mutate. **
``` python
# WRONG: Mutation
def update_user ( user , name ) :
user [ " name " ] = name
return user
# CORRECT: Immutability
def update_user ( user , name ) :
return { * * user , " name " : name }
```
### File Organization
- Many small files over few large files
- 200-400 lines typical, 800 max per file
- Extract utilities from large components
### Error Handling
Always handle errors comprehensively:
``` python
try :
result = risky_operation ( )
return result
except Exception as exc :
logger . exception ( " Operation failed " )
raise RuntimeError ( " Detailed user-friendly message " ) from exc
```
## Security
### Mandatory Security Checks
Before ANY commit:
- [ ] No hardcoded secrets (API keys, passwords, tokens)
- [ ] All user inputs validated (use Pydantic)
- [ ] SQL injection prevention (parameterized queries)
- [ ] Authentication/authorization verified
### Secret Management
``` python
# NEVER: Hardcoded secrets
api_key = " sk-proj-xxxxx "
# ALWAYS: Environment variables
api_key = os . environ . get ( " OPENAI_API_KEY " )
if not api_key :
raise ValueError ( " OPENAI_API_KEY not configured " )
```
2026-02-05 15:13:06 +08:00
## Database Development Rules
2026-02-27 15:22:42 +08:00
### Architecture
2026-02-05 15:13:06 +08:00
- **Supabase**: authentication (JWT source of truth)
- **Backend**: business authorization (service layer)
- **SQLAlchemy ORM**: data access layer (async + asyncpg, service_role connection)
2026-02-27 15:22:42 +08:00
### Code Organization
2026-02-05 15:13:06 +08:00
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
2026-02-27 15:22:42 +08:00
2026-02-05 15:13:06 +08:00
- 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
2026-03-06 18:25:18 +08:00
### Soft Delete
**Soft delete marks data as invisible, not cascade delete. **
- Use `deleted_at: datetime | None` column (via `SoftDeleteMixin` )
- **Query filtering**: Repository `_apply_soft_delete_filter()` auto-excludes deleted records
- **No automatic cascade**: Related data stays intact; visibility controlled by JOIN filtering
- **Cascade only for strong dependencies**: When parent deletion must invalidate children, implement in Service layer explicitly
- **Recovery**: Only restore the record itself; related data visibility restored automatically via queries
- **Unique constraints**: Use partial indexes excluding `deleted_at IS NOT NULL` to allow re-creation
``` python
# Partial unique index in migration
op . execute ( """
CREATE UNIQUE INDEX ux_user_email
ON users(email)
WHERE deleted_at IS NULL
""" )
```
2026-02-05 15:13:06 +08:00
### Migrations
2026-02-27 15:22:42 +08:00
2026-02-05 15:13:06 +08:00
- **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
2026-02-26 17:59:30 +08:00
### Enum Storage Convention
2026-02-27 15:22:42 +08:00
2026-02-26 17:59:30 +08:00
**Store enum names (strings), not integer values. **
- Use `VARCHAR(20)` + `CHECK` constraint in database
- Use Python `Enum` class with `str` base in code
``` python
class AgentType ( str , Enum ) :
INTENT_RECOGNITION = " INTENT_RECOGNITION "
TASK_EXECUTION = " TASK_EXECUTION "
RESULT_REPORTING = " RESULT_REPORTING "
```
2026-02-27 15:22:42 +08:00
### RLS Policy
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)
2026-02-27 15:22:42 +08:00
2026-02-25 18:04:05 +08:00
- Exemptions are allowed only when a new `public` table is guaranteed not to be exposed to PostgREST clients.
2026-02-27 15:22:42 +08:00
- Exemptions must be explicit in the migration file with rationale and verification notes.
2026-02-25 18:04:05 +08:00
- If exposure is uncertain, do not exempt: enable defensive RLS by default.
2026-02-27 15:22:42 +08:00
#### Migration Checklist
2026-02-25 18:04:05 +08:00
- [ ] 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
2026-03-02 15:05:10 +08:00
## Agent Loop (AG-UI Protocol)
2026-03-02 17:02:09 +08:00
Agent loop functionality MUST follow the AG-UI protocol. **Use the `ag-ui` skill ** for protocol reference and implementation guidance.
## Multi-Agent Orchestration (CrewAI Framework)
Multi-agent orchestration MUST use the CrewAI framework. **Use the `crewai` skill ** for framework reference and implementation guidance.
### Core Principles
- Use CrewAI for orchestrating multiple agents working together
- Define clear agent roles, tasks, and crews
- Leverage built-in collaboration and delegation mechanisms
- Follow CrewAI best practices for agent configuration
### Key Components
- **Agents**: Autonomous units with specific roles and goals
- **Tasks**: Assignments that agents complete
- **Crews**: Teams of agents working together
- **Tools**: Capabilities available to agents
- **Flows**: Workflow orchestration and state management