|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +This is a **monorepo** for the FastAPI Startkit ecosystem — a Laravel/Masonite-inspired framework for building Python applications with FastAPI. It contains four main components: |
| 8 | + |
| 9 | +| Directory | Purpose | Published as | |
| 10 | +|---|---|---| |
| 11 | +| `fastapi_startkit/` | Core framework package | [`fastapi-startkit`](https://pypi.org/project/fastapi-startkit/) on PyPI | |
| 12 | +| `fastapi_startkit.github.io.git/` | Documentation site | GitHub Pages (VitePress) | |
| 13 | +| `example/` | Standalone example apps | Not published — reference only | |
| 14 | +| `application/` | Starter application template | Not published — clone/scaffold target | |
| 15 | + |
| 16 | +### `fastapi_startkit/` — Core Package |
| 17 | + |
| 18 | +The PyPI package (`fastapi-startkit`, currently v0.13.6). Source lives under `src/fastapi_startkit/`. This is the foundational framework all other components depend on. |
| 19 | + |
| 20 | +**Do not modify framework code unless explicitly necessary.** Changes to core abstractions (Container, Application, Model, Provider, Facades) can have broad breaking effects on downstream applications. |
| 21 | + |
| 22 | +Optional extras are installed with pip/uv extras: |
| 23 | + |
| 24 | +``` |
| 25 | +fastapi-startkit[fastapi] # FastAPI + Starlette |
| 26 | +fastapi-startkit[database] # SQLAlchemy async ORM |
| 27 | +fastapi-startkit[postgres] # asyncpg driver |
| 28 | +fastapi-startkit[sqlite] # aiosqlite driver |
| 29 | +fastapi-startkit[mysql] # aiomysql driver |
| 30 | +fastapi-startkit[vite] # Jinja2 for Vite integration |
| 31 | +``` |
| 32 | + |
| 33 | +### `fastapi_startkit.github.io.git/` — Documentation |
| 34 | + |
| 35 | +VitePress site. Docs cover getting started, configuration, console, database, logging, FastAPI integration, frontend, and exception handling. Edit `.md` files under `docs/` and the home page at `index.md`. |
| 36 | + |
| 37 | +### `example/` — Example Applications |
| 38 | + |
| 39 | +Self-contained apps demonstrating specific features. Each subdirectory is an independent uv workspace member: |
| 40 | + |
| 41 | +| App | What it shows | |
| 42 | +|---|---| |
| 43 | +| `config-app/` | Configuration system | |
| 44 | +| `console-app/` | CLI / Cleo commands | |
| 45 | +| `database-app/` | ORM, migrations, seeders | |
| 46 | +| `fastapi-app/` | Minimal FastAPI setup | |
| 47 | +| `inertia-pingcrm-app/` | Full Inertia.js + PingCRM clone | |
| 48 | +| `onefile-app/` | Single-file application | |
| 49 | +| `vite-app/` | Vite + Jinja2 frontend | |
| 50 | + |
| 51 | +### `application/` — Starter Application |
| 52 | + |
| 53 | +The template users clone when starting a new project. Contains the minimal scaffolding: `artisan` entrypoint, `bootstrap/`, `config/`, `providers/`, `routes/`, and `storage/`. It mirrors a typical project layout and is a uv workspace member of this monorepo. |
| 54 | + |
| 55 | +## Commands |
| 56 | + |
| 57 | +```bash |
| 58 | +# Install all workspace dependencies |
| 59 | +uv sync |
| 60 | + |
| 61 | +# Build the core package |
| 62 | +cd fastapi_startkit && uv build |
| 63 | + |
| 64 | +# Run framework tests |
| 65 | +uv run pytest fastapi_startkit/src/fastapi_startkit/tests/ -v |
| 66 | + |
| 67 | +# Run a single test file |
| 68 | +uv run pytest fastapi_startkit/src/fastapi_startkit/tests/configurations/test_config_merge.py -v |
| 69 | + |
| 70 | +# Serve the docs locally |
| 71 | +cd fastapi_startkit.github.io.git && npm run dev |
| 72 | +``` |
| 73 | + |
| 74 | +Tests run with `asyncio_mode = "auto"` (configured in `pyproject.toml`), so all tests are async-capable by default. |
| 75 | + |
| 76 | +## Architecture (Core Package) |
| 77 | + |
| 78 | +### Application Lifecycle |
| 79 | + |
| 80 | +1. `Application(base_path)` initializes the service container and singleton |
| 81 | +2. `.load_environment()` loads `.env` + `.env.{APP_ENV}` (auto-detects `.env.testing` under pytest) |
| 82 | +3. `.configure_paths()` sets config/storage paths |
| 83 | +4. `.register_providers()` → `.load_providers()` (two-phase boot) |
| 84 | +5. `app.fastapi` is lazy-loaded; HTTP routes delegate to the FastAPI instance |
| 85 | + |
| 86 | +### Service Container (`container/container.py`) |
| 87 | + |
| 88 | +Central IoC container. Core API: |
| 89 | +- `bind(key, value)` — register a binding |
| 90 | +- `make(key)` — resolve a binding |
| 91 | +- `resolve(obj)` — auto-wire a callable by inspecting its type-hinted parameters |
| 92 | + |
| 93 | +Hooks (`on_bind`, `on_make`, `on_resolve`) allow intercepting container operations. `collect('Auth*')` returns all bindings matching a wildcard. |
| 94 | + |
| 95 | +### Configuration (`configuration/`) |
| 96 | + |
| 97 | +Define config as a dataclass with fields sourced from environment variables via `env()`: |
| 98 | + |
| 99 | +```python |
| 100 | +from dataclasses import dataclass, field |
| 101 | +from fastapi_startkit.environment import env |
| 102 | + |
| 103 | +@dataclass |
| 104 | +class RedisConfig: |
| 105 | + host: str = field(default_factory=lambda: env('REDIS_HOST')) |
| 106 | + port: int = field(default_factory=lambda: env('REDIS_PORT')) |
| 107 | +``` |
| 108 | + |
| 109 | +`app.load_environment()` applies a two-step merge: `.env` as base, then `.env.{APP_ENV}` on top. |
| 110 | + |
| 111 | +Register in the container for dotted-key access: |
| 112 | + |
| 113 | +```python |
| 114 | +config = app.make('config') |
| 115 | +config.set('redis', RedisConfig()) |
| 116 | + |
| 117 | +Config.get('redis.host') # via facade |
| 118 | +``` |
| 119 | + |
| 120 | +### Provider Pattern (`providers/`) |
| 121 | + |
| 122 | +Providers are the standard way to register services. Each provider has two phases: |
| 123 | +- `register()` — bind things into the container |
| 124 | +- `boot()` — run after all providers are registered (safe to resolve dependencies here) |
| 125 | + |
| 126 | +### FastAPI Routing (`fastapi/routers/router.py`) |
| 127 | + |
| 128 | +`Router` wraps FastAPI's `APIRouter` and adds a `resource()` shortcut. |
| 129 | + |
| 130 | +```python |
| 131 | +from fastapi_startkit.fastapi import Router |
| 132 | + |
| 133 | +router = Router() |
| 134 | +router.get("/path", endpoint) |
| 135 | +router.post("/path", endpoint) |
| 136 | +router.put("/path", endpoint) |
| 137 | +router.patch("/path", endpoint) |
| 138 | +router.delete("/path", endpoint) |
| 139 | +``` |
| 140 | + |
| 141 | +`router.resource(name, controller)` registers standard CRUD routes (index, create, store, show, edit, update, destroy). Use `only=`, `excepts=`, `names=`, `parameters=` to customise. |
| 142 | + |
| 143 | +Group routes by access level using separate `Router` instances: |
| 144 | + |
| 145 | +```python |
| 146 | +# routes/web.py |
| 147 | +from fastapi import Depends |
| 148 | +from fastapi_startkit.fastapi import Router |
| 149 | + |
| 150 | +guest = Router() |
| 151 | +guest.get("/login", auth_controller.create) |
| 152 | +guest.post("/login", auth_controller.store) |
| 153 | + |
| 154 | +auth = Router(dependencies=[Depends(auth_middleware)]) |
| 155 | +auth.get("/", dashboard_controller.index) |
| 156 | +auth.resource("users", users_controller) |
| 157 | +``` |
| 158 | + |
| 159 | +### ORM (`masoniteorm/`) |
| 160 | + |
| 161 | +Async-first fork of Masonite ORM built on SQLAlchemy async: |
| 162 | +- All DB operations are `async`/`await` |
| 163 | +- `Model` auto-pluralizes table names via `inflection` |
| 164 | +- `created_at`/`updated_at` managed as `pendulum` Carbon objects |
| 165 | +- Relationships: `HasOne`, `HasMany`, `BelongsTo`, `BelongsToMany`, `HasOneThrough` |
| 166 | +- `AsyncQueryBuilder` provides the chainable query interface |
| 167 | + |
| 168 | +### Facades (`facades/`) |
| 169 | + |
| 170 | +Static-like access to container-resolved services (`Config.get()`, `Auth.user()`, etc.). Each facade has a `.pyi` stub for IDE type support. Requires a booted Application singleton. |
| 171 | + |
| 172 | +### Console (`commands/`, `masoniteorm/commands/`) |
| 173 | + |
| 174 | +CLI built on [Cleo](https://github.com/python-poetry/cleo). Database commands (migrate, seed, make:model, etc.) live in `masoniteorm/commands/`. Run via `uv run artisan`. |
| 175 | + |
| 176 | +## Key Dependencies |
| 177 | + |
| 178 | +| Package | Purpose | |
| 179 | +|---|---| |
| 180 | +| `fastapi[standard]` | HTTP framework (lazily imported) | |
| 181 | +| `sqlalchemy[asyncio]` | Async ORM backend | |
| 182 | +| `pendulum` | Datetime/timezone (used as Carbon) | |
| 183 | +| `cleo` | CLI commands | |
| 184 | +| `dotty-dict` | Nested dict access via dotted keys | |
| 185 | +| `inflection` | Table name pluralization | |
| 186 | +| `asyncpg` / `aiomysql` / `aiosqlite` | DB drivers | |
0 commit comments