Skip to content

Latest commit

 

History

History
89 lines (70 loc) · 5.7 KB

File metadata and controls

89 lines (70 loc) · 5.7 KB

AGENTS.md

Repository Layout

  • papyrus/api/routes: FastAPI routers and HTTP-facing request handling.
  • papyrus/services: service-layer business logic. Prefer new domain modules here instead of growing route handlers.
  • papyrus/schemas: Pydantic request and response models.
  • papyrus/models: SQLAlchemy models and metadata exports used by Alembic.
  • papyrus/core: shared infrastructure such as config, database, exceptions, and security.
  • alembic: Alembic environment and migration revisions.
  • tests/api/routes: endpoint behavior and contract tests.
  • tests/services: service-layer tests.
  • tests/conftest.py: shared fixtures and test database setup.

Coding Conventions

  • Keep route handlers thin. They should parse input, enforce dependencies/auth, call a service, translate errors, and return schemas.
  • Put business rules, query orchestration, and transaction-aware logic in papyrus/services, not in route modules.
  • Reuse or extend existing schema modules before creating new top-level packages.
  • Follow existing async patterns with AsyncSession, explicit return types, and Pydantic schemas.
  • Use vertical spacing to separate logical steps inside functions. Keep related statements together, but add a blank line when moving between setup, validation, branching, and side effects.
  • Prefer readable spacing over dense blocks. Short guard clauses, temporary assignments, and context-manager branches should usually be visually separated the way papyrus/services/email.py and papyrus/services/auth/ are structured.
  • Treat any multiline statement or block as a visual boundary inside a function. If one adjacent statement is multiline and both sides are real code, separate the two statements with a blank line.
  • Apply that rule to multiline conditionals, loops, with blocks, try blocks, multiline calls, multiline literals, and multiline return values. Treat if / elif / else as one block.
  • Do not add a blank line just because a docstring appears above the first statement in a function. The multiline-block rule applies between code statements, not between a docstring and the first line of code.
  • Add a blank line between query execution and result extraction, especially around session.execute(...) and subsequent scalar*() reads.
  • Add a blank line before persistence and side-effect boundaries such as session.add(...), send_email(...), commit(), redirects, and returned result objects when they start a new phase of the function.
  • Keep tightly coupled short sequences together when they are clearly one step. Do not add spacing mechanically when it makes a two-line operation harder to read.
  • Prefer extra spacing around state transitions and persistence boundaries rather than packing setup, branching, and writes into a single block.
  • When adding a new router module, register it in papyrus/api/routes/__init__.py.
  • Avoid adding dependencies unless the user explicitly asks for them.
  • Keep changes scoped. Do not refactor unrelated areas as part of a focused fix.
  • Do not leave inline comments. Sufficiently complex behavior that requires explanation should be documented using docstrings.

Runbook

  • Install dependencies: uv sync --extra dev
  • Start Postgres: docker compose up -d database
  • Stop services: docker compose down
  • Run the API locally: uv run uvicorn papyrus.main:app --reload
  • Apply migrations: uv run alembic upgrade head
  • Create a migration: uv run alembic revision --autogenerate -m "<message>"
  • Run all tests: uv run pytest
  • Run integration tests: uv run pytest -m integration
  • Run one test module: uv run pytest tests/api/routes/test_<module>.py
  • Lint: uv run ruff check .
  • Format: uv run ruff format .
  • Preferred typecheck command when available: uv run pyright
  • Current repo-configured fallback typecheck: uv run mypy .

Testing Rules

  • Add or update tests for every behavior change.
  • Prefer route tests for HTTP contract changes and service tests for business logic.
  • If database behavior changes, add the narrowest regression test that proves the query or transaction behavior.
  • Do not claim success without running the most relevant checks, or explicitly stating why they were not run.

Migration Rules

  • Add an Alembic revision for every schema change, constraint change, index change, or persisted-data backfill.
  • Update SQLAlchemy models first, then review autogenerated Alembic output before committing it.
  • Make sure new or changed models are imported from papyrus.models so Alembic metadata can see them.
  • Keep migrations small and pair them with the application code that depends on them.
  • Do not ship destructive or irreversible migrations without explicit user approval.

Completion Criteria

  • Relevant tests pass, or any unrun checks are called out with the reason.
  • Ruff passes on the changed scope.
  • Typechecking is run on the changed scope. Use pyright when available, otherwise use the repo's current mypy setup.
  • Schema changes include a migration and verification.
  • New backend behavior follows thin-route and service-layer separation.
  • No new dependencies were added unless explicitly requested.

Auth Testing

Local auth testing supports Mailpit for SMTP capture, a dev auth sandbox at /__dev/auth-sandbox, and opt-in provider smoke tests.

See docs/auth-testing.md for the exact .env values, Google OAuth setup, and end-to-end test workflow.

For Flutter client integration guidance, see docs/flutter-auth-integration.md.

For the self-hosted PowerSync sandbox and sync validation workflow, see docs/powersync-sandbox.md.

To build the dev sandbox assets without the Vite dev server:

npm --prefix frontend/dev-pages run build