Skip to content

Shared backend for Tripod: FastAPI, JWT auth, app-scoped RBAC, Neon PostgreSQL. Docker + Cloud Run.

License

Notifications You must be signed in to change notification settings

shemaobt/tripod-api

Repository files navigation

tripod-backend

Shared API backend for Tripod — a platform powering multiple language and translation tools. Handles authentication (JWT), app-scoped RBAC, and core data (languages, projects, organizations, phases).

Stack: FastAPI · SQLAlchemy 2 async · Alembic · PostgreSQL (Neon) · uv · Docker · Cloud Run

Architecture

app/
├── api/           # FastAPI routers (one file per domain: auth, languages, orgs, projects, phases, roles)
├── core/          # Config, database engine, middleware, exceptions
├── db/
│   └── models/    # SQLAlchemy ORM models, one file per domain:
│                  #   auth.py · language.py · org.py · phase.py · project.py
├── models/        # Pydantic request/response schemas, mirroring db/models structure
└── services/      # Business logic, one package per domain:
                   #   auth/ · authorization/ · language/ · org/ · phase/ · project/
                   # Each package exposes one function per file.
alembic/           # Database migrations
scripts/           # One-off scripts (e.g. seed_apps_roles.py)
tests/             # Async pytest suite, one file per service domain
http/              # .http request examples (VS Code REST Client / JetBrains)

Each layer has a single responsibility: routers call services, services use db models, Pydantic models handle serialization. No business logic lives in routers; no DB calls live outside services.

CI/CD (GitHub Actions)

Trigger What happens
Pull request ruff check + ruff format + pytest
Push to main Build image → alembic upgrade head → deploy to Cloud Run

Secrets required in GitHub Actions (Settings → Secrets):

Secret Purpose
GCP_PROJECT_ID Artifact Registry & Cloud Run project
GCP_SA_KEY Service account JSON (Cloud Run Admin, Artifact Registry Writer, Secret Manager Accessor)
SECRETS_PROJECT_NUMBER Project number for Secret Manager (tripod_backend_neon_database_url, tripod_backend_jwt_secret)

Config is pulled from GCP Secret Manager at container startup — no env vars are set manually in production or CI.

Local development

Secrets are fetched from GCP Secret Manager via a sidecar (gcp-secrets) on startup.

# 1. Authenticate
gcloud auth application-default login

# 2. Start the stack (SECRETS_PROJECT_ID tells the sidecar which GCP project to read secrets from)
SECRETS_PROJECT_ID=<id> docker compose up --build backend

# 3. In another terminal — apply migrations, seed, run tests
docker compose exec backend sh -c "set -a && . /run/secrets/.env && set +a && uv run alembic upgrade head"
docker compose exec backend sh -c "set -a && . /run/secrets/.env && set +a && uv run python scripts/seed_apps_roles.py"
docker compose exec backend sh -c "set -a && . /run/secrets/.env && set +a && uv run pytest tests"

Use a Neon dev branch for local work to avoid touching production data.

Migrations

# Create (after changing models)
docker compose exec backend sh -c "set -a && . /run/secrets/.env && set +a && uv run alembic revision --autogenerate -m 'short description'"

# Apply locally (manual — never run automatically against local DB)
docker compose exec backend sh -c "set -a && . /run/secrets/.env && set +a && uv run alembic upgrade head"

Production migrations run automatically on deploy (after merge to main).

Lint

uv run ruff check . --fix
uv run ruff format .

Or via Docker: docker compose --profile lint run --rm lint

API examples

http/ contains .http request files for health, auth, and roles. See http/README.md for token usage.

About

Shared backend for Tripod: FastAPI, JWT auth, app-scoped RBAC, Neon PostgreSQL. Docker + Cloud Run.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors