Skip to content

Latest commit

 

History

History
95 lines (71 loc) · 3.39 KB

README.md

File metadata and controls

95 lines (71 loc) · 3.39 KB

nagara

Your operating system for data.

CI License Python

Quickstart

Requires uv, docker, just.

just bootstrap          # uv sync + bring up postgres + redis + minio
cp .env.example .env    # edit NAGARA_SECRET_KEY at minimum
just dev                # API on http://127.0.0.1:8000

Open http://127.0.0.1:8000/docs for the interactive OpenAPI playground, /health/live and /health/ready for the Kubernetes-ready probes.

A tagged route in 5 lines

from nagara import APIRouter, APITag

router = APIRouter()

@router.get("/widgets", tags=[APITag.public])
async def list_widgets():
    return {"widgets": []}

APITag.public publishes the route in the OpenAPI spec; APITag.internal keeps it visible in dev /docs only; untagged routes stay out of the spec by default. Raise nagara.NotFound("widget", extra={"id": widget_id}) (or any NagaraError subclass) and the typed-envelope handler returns a structured 4xx with a request_id.

Stack

  • Python 3.14 with uv for env management
  • FastAPI + custom APIRouter (auto-commit + OpenAPI tag filtering)
  • PostgreSQL via SQLAlchemy 2 + asyncpg (async) and psycopg2 (sync, for migrations)
  • Redis for rate limiting
  • MinIO in dev, S3-compatible in prod, for file storage
  • Alembic for migrations (datetime-prefixed, autoformatted)
  • structlog with dev/prod renderers (pretty console / JSON)
  • Sentry for error reporting, slowapi for rate limiting
  • Pytest with coverage tooling (just coverage)

Module map

src/nagara/
├── main.py            FastAPI factory + health endpoints
├── config.py          Layered settings (env > .env > TOML > defaults)
├── exceptions.py      Typed NagaraError envelope
├── routing.py         Custom APIRouter (autocommit + APITag.public/internal)
├── middleware.py      Request-ID, content-size, request-cancel, multipart, etc.
├── logging.py         structlog + dev/prod renderers
├── lifespan.py        @on_startup / @on_shutdown registries
├── rate_limit.py      slowapi limiter (Redis-backed)
├── sentry.py          configure_sentry() (no-op when DSN unset)
├── db/                SQLAlchemy declarative base + session
└── kit/               Reusable building blocks for domain modules
    ├── utils, schemas, pagination, sorting, repository
    ├── pubsub, sse, paths, redis, compression

See CLAUDE.md for the full development guide and module conventions.

Development

just test             # pytest
just coverage         # pytest + branch coverage report
just lint             # ruff check --fix
just typecheck        # ty
just check            # everything CI runs

Contributing

See CONTRIBUTING.md. Issues and PRs welcome — please read CODE_OF_CONDUCT.md first.

Security

Found a vulnerability? See SECURITY.md for the disclosure process. Please don't open public issues for security reports.

License

Apache-2.0 — see LICENSE.