Skip to content

Production-style FastAPI service showcasing: OpenAPI, Postgres migrations, Redis caching, background jobs, JWT+RBAC auth, rate limiting, tests, Docker Compose, CI, and basic observability (logs/metrics/tracing).

Notifications You must be signed in to change notification settings

DavidAGInnovation/Backend-Service-User-Org-Subscriptions-API

Repository files navigation

Backend Service (User/Org + Subscriptions API)

Production-style FastAPI service showcasing: OpenAPI, Postgres migrations, Redis caching, background jobs, JWT+RBAC auth, rate limiting, tests, Docker Compose, CI, and basic observability (logs/metrics/tracing).

Quickstart (Docker)

cp .env.example .env
docker compose up --build
  • API: http://localhost:8000
  • Swagger UI: http://localhost:8000/docs
  • Metrics: http://localhost:8000/metrics
  • Frontend console: http://localhost:5173

If you see exec /app/scripts/entrypoint.sh: permission denied, it’s usually because the dev volume mount (.:/app) overrides the executable bit; docker-compose.yml runs it via sh to avoid that.

Local dev (without Docker)

Requirements: Python 3.11+, Postgres, Redis.

python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
alembic upgrade head
uvicorn app.main:app --reload

Note: Python 3.14 is not supported by some common ecosystem packages yet; use Python 3.11–3.13. If you run pytest from a global Python installation, ensure you’ve installed project deps first (prefer a venv).

Run a worker (background jobs):

celery -A app.worker.celery_app worker -l info

Core features

  • Auth: JWT access tokens; org-scoped RBAC (owner, admin, member)
  • DB: Postgres + Alembic migrations
  • Redis: caching + fixed-window rate limiting + Celery broker/backend
  • Background jobs: webhook processing via Celery
  • Observability:
    • structured JSON logs (request id)
    • Prometheus metrics at /metrics
    • OpenTelemetry tracing (optional OTLP exporter; defaults to console exporter)
    • optional Sentry error reporting

API hardening

  • Request body limit: MAX_REQUEST_BODY_BYTES (defaults to 1_000_000) enforced via Content-Length when present.
  • Pagination: GET /orgs/{org_id}/members and GET /orgs/{org_id}/subscriptions support limit/offset and return x-total-count.
  • Filtering: GET /orgs/{org_id}/subscriptions?status=active|canceled|past_due.
  • Webhook idempotency: /webhooks/stripe dedupes by WebhookIn.id (preferred) or x-provider-event-id, else a stable payload hash.

Observability

  • Logs are JSON to stdout; each response includes x-request-id.
  • Metrics are exposed at /metrics (Prometheus scrape target).
  • Tracing: set OTEL_EXPORTER_OTLP_ENDPOINT (for example http://localhost:4317) to export spans over OTLP/gRPC.
  • Sentry: set SENTRY_DSN to enable error reporting (optional).

Health endpoints

  • /livez: process is up.
  • /readyz: dependencies reachable (Postgres + Redis).

Environment variables

See .env.example.

Production notes

  • Secrets: prefer SSM Parameter Store / Secrets Manager; avoid putting secrets directly into Terraform state or CI logs.
  • Rotation: rotate JWT_SECRET_KEY by updating the secret and deploying new tasks; plan a phased rollout if you need to honor existing tokens.
  • Database and Redis: use managed services (RDS / ElastiCache) in production; provide DATABASE_URL and REDIS_URL accordingly.

Deploy (Terraform)

Minimal ECS/Fargate Terraform is in infra/aws-ecs/README.md:1.

Example API flow

  1. Register an org + owner user:
curl -sS -X POST http://localhost:8000/auth/register \
  -H 'content-type: application/json' \
  -d '{"org_name":"Acme","email":"[email protected]","password":"changeme"}'
  1. Use the returned access_token:
TOKEN="..."
curl -sS http://localhost:8000/me -H "authorization: Bearer $TOKEN"
  1. Add a member (RBAC: admin+; owner needed to assign owner):
ORG_ID="..."
curl -sS -X POST "http://localhost:8000/orgs/$ORG_ID/members" \
  -H "authorization: Bearer $TOKEN" \
  -H 'content-type: application/json' \
  -d '{"email":"[email protected]","password":"changeme123","role":"member"}'
  1. Example webhook (enqueue job → updates DB; expects metadata.org_id):
curl -sS -X POST http://localhost:8000/webhooks/stripe \
  -H 'content-type: application/json' \
  -d '{"type":"customer.subscription.created","data":{"object":{"id":"sub_123","metadata":{"org_id":"'"$ORG_ID"'"}}}}'

Tests

Tests expect Postgres + Redis (CI uses service containers).

docker compose up -d postgres redis
pytest -q

Or run tests inside the container:

docker compose run --rm --build test

If DATABASE_URL/REDIS_URL are not set, tests will attempt to start ephemeral Postgres+Redis via testcontainers (requires Docker running and pip install -r requirements.txt).

Frontend (optional)

Run the minimal admin console UI (register/login, members/subscriptions, send test webhook):

docker compose up --build -d frontend

Open http://localhost:5173.

Release

See CHANGELOG.md:1.

CI

GitHub Actions workflow: .github/workflows/ci.yml

About

Production-style FastAPI service showcasing: OpenAPI, Postgres migrations, Redis caching, background jobs, JWT+RBAC auth, rate limiting, tests, Docker Compose, CI, and basic observability (logs/metrics/tracing).

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published