{"id":50849684,"url":"https://github.com/polepos/poleposition","last_synced_at":"2026-06-14T13:00:16.117Z","repository":{"id":353140580,"uuid":"1186388899","full_name":"polepos/poleposition","owner":"polepos","description":"A lifecycle CLI for starting and growing enterprise FastAPI projects with uv, Alembic, SQLAlchemy, and module/integration scaffolding.","archived":false,"fork":false,"pushed_at":"2026-06-11T15:34:27.000Z","size":6580,"stargazers_count":2,"open_issues_count":8,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-06-11T17:13:41.624Z","etag":null,"topics":["alembic","api","cli","fastapi","framework","gunicorn","python","sqlalchemy","uv","uvicorn"],"latest_commit_sha":null,"homepage":"https://polepos.github.io/poleposition/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/polepos.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-03-19T15:17:03.000Z","updated_at":"2026-06-11T15:34:06.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/polepos/poleposition","commit_stats":null,"previous_names":["erenertemden/poleposition","polepos/poleposition"],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/polepos/poleposition","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/polepos%2Fpoleposition","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/polepos%2Fpoleposition/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/polepos%2Fpoleposition/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/polepos%2Fpoleposition/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/polepos","download_url":"https://codeload.github.com/polepos/poleposition/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/polepos%2Fpoleposition/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34322074,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-14T02:00:07.365Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["alembic","api","cli","fastapi","framework","gunicorn","python","sqlalchemy","uv","uvicorn"],"created_at":"2026-06-14T13:00:14.332Z","updated_at":"2026-06-14T13:00:16.066Z","avatar_url":"https://github.com/polepos.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PolePosition | A lifecycle CLI for FastAPI projects\n\n[![PyPI version](https://img.shields.io/pypi/v/poleposition?label=PyPI)](https://pypi.org/project/poleposition)\n[![Python versions](https://img.shields.io/pypi/pyversions/poleposition?label=Python)](https://pypi.org/project/poleposition)\n[![Package status](https://img.shields.io/pypi/status/poleposition?label=Status)](https://pypi.org/project/poleposition)\n[![Downloads](https://img.shields.io/pypi/dm/poleposition?label=Downloads)](https://pypi.org/project/poleposition)\n[![License](https://img.shields.io/github/license/polepos/poleposition?label=License)](https://raw.githubusercontent.com/polepos/poleposition/refs/heads/main/LICENSE)\n[![CI](https://github.com/polepos/poleposition/actions/workflows/ci.yml/badge.svg)](https://github.com/polepos/poleposition/actions/workflows/ci.yml)\n[![E2E](https://github.com/polepos/poleposition/actions/workflows/e2e.yml/badge.svg)](https://github.com/polepos/poleposition/actions/workflows/e2e.yml)\n[![Release](https://github.com/polepos/poleposition/actions/workflows/release.yml/badge.svg)](https://github.com/polepos/poleposition/actions/workflows/release.yml)\n[![Deploy Docs](https://github.com/polepos/poleposition/actions/workflows/docs.yml/badge.svg)](https://github.com/polepos/poleposition/actions/workflows/docs.yml)\n[![Docs](https://img.shields.io/badge/docs-published-blue)](https://polepos.github.io/poleposition/)\n[![FastAPI native](https://img.shields.io/badge/FastAPI-native-009688?logo=fastapi\u0026logoColor=white)](https://fastapi.tiangolo.com/)\n[![uv first](https://img.shields.io/badge/workflow-uv--first-261230)](https://docs.astral.sh/uv/)\n[![Alembic migrations](https://img.shields.io/badge/database-Alembic%20migrations-orange)](https://alembic.sqlalchemy.org/)\n\n![PolePosition logo](https://raw.githubusercontent.com/polepos/poleposition/main/assets/logo/poleposition-logo.png)\n\nA project lifecycle CLI that puts teams in pole position when starting, growing, and maintaining enterprise FastAPI projects.\n\nFastAPI speed, Spring/.NET-style project discipline, without turning FastAPI into a heavy framework.\n\nPolePosition helps you keep [FastAPI](https://fastapi.tiangolo.com/)'s speed while avoiding the usual setup drag of enterprise backend work. It does more than render a project template: it gives teams commands for project creation, module growth, project checks, and migration workflows as the codebase evolves.\n\n\u003cfigure\u003e\n  \u003cimg\n    src=\"https://raw.githubusercontent.com/polepos/poleposition/main/assets/gif/demo.gif\"\n    alt=\"PolePosition terminal demo: project creation\"\n    width=\"760\"\n  /\u003e\n  \u003cfigcaption\u003eStarting a PolePosition project.\u003c/figcaption\u003e\n\u003c/figure\u003e\n\n## Installation\n\nPolePosition recommends a `uv`-first workflow for installation, dependency\nsync, migrations, and local development. It also works with `pip` and a normal\nPython virtual environment.\n\n```bash\nuv tool install poleposition\n```\n\nor\n\n```bash\npip install poleposition\n```\n\n---\n\n## Quick Start\n\nRecommended `uv` workflow:\n\n```bash\npolepos start myapp --install\ncd myapp\ncp .env.example .env\npolepos db upgrade\n\nuv run python -m myapp.run\n```\n\nOpen your API documentation:\n\n```text\nhttp://127.0.0.1:8000/docs\n```\n\nFor manual setup, Docker, and detailed command usage, see the sections below or\nthe [Getting Started](https://github.com/polepos/poleposition/blob/main/docs/getting-started.md) guide.\n\n---\n\n## Example Output\n\n```bash\n$ polepos start myapp --install\nCreated project: myapp\n\nInstalling project dependencies...\nDependencies installed successfully with uv.\n\nNext steps:\n  cd myapp\n  cp .env.example .env\n  polepos db upgrade\n  uv run python -m myapp.run\n```\n\n## Why PolePosition?\n\nPolePosition is named for the same reason teams use it: to start enterprise FastAPI development from pole position and keep it there as the project grows.\n\nFastAPI projects should start fast, clean, and predictable, then stay easy to extend when the target is a larger production system.\n\nPolePosition provides:\n\n* A scalable project structure\n* Environment-based configuration\n* Alembic-based database migrations\n* Lifecycle commands for project creation, module growth, project checks, and database migrations\n* Built-in logging\n* JWT-based endpoint authentication foundations\n* Testing setup\n* Module-oriented organization for growing codebases\n* A ready-to-run FastAPI application\n\nLess boilerplate at project creation. Less lifecycle friction as the app grows.\n\n---\n\n## Coming From Spring Boot or ASP.NET Core?\n\nPolePosition is useful for teams coming from [Spring Boot](https://spring.io/projects/spring-boot) or [ASP.NET Core](https://dotnet.microsoft.com/en-us/apps/aspnet) who\nlike explicit project structure, migration workflows, configuration boundaries,\nlogging conventions, tests, and module-oriented growth, but want to keep the\nspeed and directness of FastAPI.\n\nIt is not a heavy framework on top of FastAPI. It gives FastAPI projects a\npredictable lifecycle: start the project, add modules, validate structure, and\nmanage migrations without hiding the application code.\n\n---\n\n## Why not just FastAPI?\n\nFastAPI is excellent, but turning it into a team-ready backend lifecycle often involves:\n\n* Recreating the same structure\n* Setting up logging and configuration\n* Defining module boundaries\n* Wiring database foundations\n* Organizing modules manually\n* Adding new modules without drifting from conventions\n* Keeping database migrations and model imports aligned\n\nPolePosition removes that overhead with CLI workflows that create the project, grow the codebase, validate the project contract, and keep migrations first-class.\n\n---\n\n## Documentation Map\n\nUse these files to understand the repo quickly:\n\n* [Published Docs](https://polepos.github.io/poleposition/)\n* [Source Repository](https://github.com/polepos/poleposition)\n* [Getting Started](https://github.com/polepos/poleposition/blob/main/docs/getting-started.md)\n* [CLI Reference](https://github.com/polepos/poleposition/blob/main/docs/cli.md)\n* [Module Templates](https://github.com/polepos/poleposition/blob/main/docs/module-templates.md)\n* [Auth Workflow](https://github.com/polepos/poleposition/blob/main/docs/auth-workflow.md)\n* [Configuration Reference](https://github.com/polepos/poleposition/blob/main/docs/configuration.md)\n* [Data Structures](https://github.com/polepos/poleposition/blob/main/docs/data-structures.md)\n* [Database and Migrations](https://github.com/polepos/poleposition/blob/main/docs/database.md)\n* [Spring and .NET Module Guide](https://github.com/polepos/poleposition/blob/main/docs/spring-dotnet-module-structure.md)\n* [Architecture](https://github.com/polepos/poleposition/blob/main/docs/architecture.md)\n* [Feature Status](https://github.com/polepos/poleposition/blob/main/docs/feature-status.md)\n* [Project Checks](https://github.com/polepos/poleposition/blob/main/docs/project-checks.md)\n* [Upgrade Reports](https://github.com/polepos/poleposition/blob/main/docs/upgrade-command.md)\n* [Integration Guides](https://github.com/polepos/poleposition/blob/main/docs/integrations/index.md)\n* [Troubleshooting and FAQ](https://github.com/polepos/poleposition/blob/main/docs/troubleshooting.md)\n* [Release and Upgrade Notes](https://github.com/polepos/poleposition/blob/main/docs/release-upgrade-notes.md)\n* [Examples](https://github.com/polepos/poleposition/blob/main/docs/examples/index.md)\n* [Changelog](https://github.com/polepos/poleposition/blob/main/CHANGELOG.md)\n* [Agent Guide](https://github.com/polepos/poleposition/blob/main/AGENTS.md)\n\nBuild the documentation site locally:\n\n```bash\nnpm install\nnpm run start\n```\n\nThe documentation site uses Docusaurus and requires Node.js `\u003e=20`.\n\n## Usage\n\n### Create a project\n\n```bash\npolepos start myapp --install\n```\n\n`--install` runs `uv sync --extra dev` when `uv` is available. If `uv` is not\navailable, it creates `.venv` and installs the generated project with `pip`. It\ndoes not run migrations; after copying `.env.example` to `.env`, run\n`polepos db upgrade`.\n`--no-bytecode` configures generated migration and runtime commands to start\nwith `PYTHONDONTWRITEBYTECODE=1`, preventing bytecode cache writes from\ninterpreter startup during common local workflows.\n\nUse `--db` to choose the generated database posture without an interactive\nprompt:\n\n```bash\npolepos start myapp --db sqlite\npolepos start myapp --db postgres\npolepos start myapp --db none\n```\n\n`sqlite` is the default and preserves the standard DB-ready starter. `postgres`\nuses a PostgreSQL `DATABASE_URL` and matching Docker database name. `none`\nomits SQLAlchemy, Alembic, `DATABASE_URL`, migrations, and generated `db/`\nwiring; use `--api-only` modules until you intentionally add persistence.\n\nProject names:\n\n* Must not be empty\n* Must not contain whitespace\n* Must not contain path separators like `/` or `\\`\n* May use hyphens like `my-app`\n* Are normalized to a Python package name like `my_app`\n\n### Manual setup\n\nWith `uv`:\n\n```bash\npolepos start myapp\ncd myapp\n\ncp .env.example .env\nuv sync --extra dev\npolepos db upgrade\n\nuv run python -m myapp.run\n```\n\nWith `pip`:\n\n```bash\npolepos start myapp\ncd myapp\n\ncp .env.example .env\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install -e \".[dev]\"\npolepos db upgrade\n\npython -m myapp.run\n```\n\n### Add modules\n\n```bash\npolepos add module garage\npolepos add module customers --template crud --pagination --timestamps\npolepos add module accounts --template crud --tenant-scoped --auth-required\npolepos add module assistant --template ai-prompt\npolepos add module webhook --api-only\n```\n\n`standard` is the default template for REST and domain modules.\n`crud` generates list/create/get/update/delete routes and can opt into\nenterprise CRUD concerns such as pagination, timestamps, soft delete, explicit\ntenant scoping, and bearer-auth protection.\n`ai-prompt` adds a provider-agnostic LLM endpoint skeleton with module-local\nprompt orchestration and shared `integrations/llm` adapters.\n`api-only` generates router, schemas, a module-local `services/` package, and\ntests without model, repository, or database wiring. Use `--api-only` as a\nshortcut for `--template api-only`.\n\nGenerated module routes are local to their module router. For example, the\nstandard and API-only starters use `@router.get(\"/\")` inside the module, then\nPolePosition registers that router in `src/\u003cpackage\u003e/api/router.py` with a\nmodule prefix:\n\n```python\napi_router.include_router(customers_router, prefix=\"/customers\", tags=[\"customers\"])\n```\n\nWith the generated API prefix, that route becomes `GET /api/v1/customers/`.\nAnother module can also define `@router.get(\"/\")` because it is registered with\nits own prefix.\n\nGenerated module schemas are starting contracts, not final domain design.\nDatabase-backed templates generate names such as `CustomerCreate`,\n`CustomerUpdate`, and `CustomerRead`; API-only templates generate\n`CustomerRequest` and `CustomerResponse`; AI prompt modules generate\n`CustomerPromptRequest` and `CustomerPromptResponse`. You can rename or replace\nthose schemas after generation, but update the module router, service,\nrepository, generated tests, and migrations together. `polepos check` validates\ngenerated lifecycle wiring, while `pytest` validates schema imports, request\nfields, service behavior, and response shapes. See\n[Module Templates](docs/module-templates.md#generated-schema-contracts) for the\nfull schema contract guidance.\n\nCRUD feature options are documented in\n[Module Templates](docs/module-templates.md#crud-feature-options). They require\n`--template crud` and can be combined:\n\n```bash\npolepos add module customers --template crud \\\n  --pagination \\\n  --timestamps \\\n  --soft-delete \\\n  --tenant-scoped \\\n  --auth-required\n```\n\n### Remove modules\n\n```bash\npolepos remove module garage\npolepos remove module garage --trace\npolepos remove module garage --force\npolepos remove module garage --wiring-only\n```\n\n`remove module` deletes the module directory and generated tests, then removes\nthe module export, router include, database-backed module model import, and\n`.poleposition.toml` module entry from the managed files. It stops before\ndeleting files if the module wiring has drifted away from a managed layout, or\nif the module directory or generated tests appear to contain custom changes.\n\nCRUD modules generated with options record those options in the manifest, for\nexample `crud[pagination,timestamps,tenant-scoped]`. `remove module` uses that\nmetadata when deciding whether the generated CRUD files are still pristine.\n\nOnly the PolePosition-generated wiring is removed automatically. If\n`api/router.py`, `db/models.py`, or `modules/__init__.py` also contains custom\nreferences to the same module, the command reports the unmanaged reference and\nleaves the module directory in place. Remove or rewrite those custom references\nexplicitly, then rerun the command.\n\nIf the module directory was already deleted manually, rerun\n`polepos remove module \u003cname\u003e` to clean remaining generated tests, manifest\nmetadata, and managed router, model, and export wiring.\n\nUse `--trace` to preview the files that would be removed or updated without\nchanging the project. Use `--force` only when you intentionally want to remove a\ncustomized module directory. If an expected generated file has become\nundecodable as text, PolePosition treats it as a modified generated file; a\nnormal remove stops, and `--force` can still remove the module directory.\n\nUse `--wiring-only` when you want to keep a customized module directory but\nremove PolePosition-managed references to it. This mode cleans module exports,\nrouter wiring, database-backed module model imports, and generated tests. It does not\ndelete the module directory or shared integration scaffold. If the preserved\ndirectory should no longer be part of the PolePosition lifecycle, move, delete,\nor rewire it before expecting `polepos check` to pass.\n\nThe command does not change the live database. If a removed database-backed module had\na table and you want that table removed too, create and review a migration after\nthe code cleanup:\n\n```bash\npolepos db revision -m \"remove garage table\"\npolepos db upgrade\n```\n\nIf you want to keep the table or data, stop after `polepos remove module` and\ndo not generate a drop-table migration.\n\n### Delete a project\n\n```bash\npolepos delete myapp\npolepos delete myapp --trace\npolepos delete myapp --force\n```\n\n`delete` removes a whole generated project directory, including the in-project\n`.venv`. Use it to discard a project created with the wrong name or\nconfiguration and start over.\n\nIt only deletes a directory that contains a `.poleposition.toml` manifest, so it\nwill not remove an unrelated folder, and it refuses to delete the current\ndirectory or a parent of it. Run it from outside the project, for example from\nthe directory where you ran `polepos start`. Without `--force` it asks for\nconfirmation and aborts on any answer other than `y`. Use `--trace` (alias\n`--dry-run`) to preview, and `--force` (alias `-y`) to skip the prompt.\n\n`delete` removes local files only; it never changes a database.\n\n### Add integrations\n\n```bash\npolepos add integration kafka\npolepos add integration rabbitmq\npolepos add integration redis\npolepos add integration rq\n```\n\nIntegration commands add helper modules, test doubles, settings,\n`.env.example` values, and transport dependencies. Kafka uses `aiokafka`,\nRabbitMQ uses `aio-pika`, Redis uses `redis`, and RQ uses `rq` for Redis-backed\nbackground jobs. Long-running consumers and workers are intentionally left as\nexplicit runtime code instead of being started inside the API process.\n\n### Data structures\n\nPolePosition also exposes a small runtime namespace for structures Python does\nnot provide as first-class built-in containers:\n\n```python\nfrom polepos.data import IndexedPriorityQueue, LRUCache, SortedDict, Trie\n```\n\nThese structures are dependency-free and process-local. Use them for local\nindices, bounded caches, scheduling helpers, graph workflows, and test doubles.\nUse Redis, PostgreSQL, Kafka, RabbitMQ, or RQ when state must be shared across\nworkers or persisted outside the process.\n\n### Project checks\n\n```bash\npolepos check\npolepos check --json\npolepos check --fix\n```\n\n`check` runs the core project health checks for the current PolePosition\nproject. It validates project identity, generated structure, Alembic config,\nmanaged markers, starter module router wiring, added module lifecycle wiring,\norphan generated references, and opt-in integration wiring used by commands\nsuch as `polepos add module`, `polepos remove module`, and\n`polepos add integration`.\n\nWhen `.poleposition.toml` is present, generated integration entries must use\nunquoted TOML booleans such as `kafka = true` or `kafka = false`.\nIntegration settings and env values are matched as active keys, not comments or\nloose substrings. A commented required value such as\n`# KAFKA_BOOTSTRAP_SERVERS=...` is reported as missing, while optional generated\nexamples such as `# KAFKA_COMPRESSION_TYPE=` and `# LLM_MAX_TOKENS=` may stay\ncommented until needed.\n\nUse it after adding modules or integrations, after resolving merge conflicts in\nmanaged files, and before handing a project to another teammate or coding\nagent. The default command is read-only: it reports drift but does not rewrite\nfiles, install dependencies, run migrations, or contact external services.\nUse `polepos check --fix` when you want PolePosition to restore safe managed\nmarkers before checking again. For `api/router.py`, marker repair keeps\n`# polepos:router-includes` outside complete `api_router.include_router(...)`\ncalls, including multi-line includes.\n\nFailed checks include stable `PPCHK` issue codes and `Fix:` hints so humans,\ncoding agents, and CI logs can refer to the same remediation.\n\nUse `polepos check --json` in CI or agent workflows when you need a\nmachine-readable result. The JSON output includes `passed`, `project_root`,\n`package_name`, and an `issues` list with `code`, `message`, and `remediation`.\n\nThe checks are organized into three layers:\n\n* Core checks for project identity, generated structure, Alembic files, and managed markers\n* Lifecycle checks for starter routing, added module router/model/test wiring, and orphan remnants\n* Integration checks for Kafka, RabbitMQ, Redis, RQ, LLM, and auth workflow files, active settings/env values, and dependencies\n\nSee [Project Checks](https://github.com/polepos/poleposition/blob/main/docs/project-checks.md) for detailed user guidance and the\nagent-facing check contract.\n\n### Safe customization boundaries\n\nGenerated projects are normal FastAPI projects. Edit module internals for the\nreal domain: models, schemas, repositories, services, routers, migrations, and\ntests.\n\nWhen changing generated module schemas, treat the schema, router, service,\nrepository, and generated tests as one contract. Deleting or renaming\n`\u003cClassName\u003eCreate`, `\u003cClassName\u003eRead`, `\u003cClassName\u003eRequest`, or similar schema\nclasses without updating their imports usually breaks pytest or app startup.\n\nAvoid changing the lifecycle contract unless the team intentionally owns that\nsurface manually:\n\n* Do not remove or rename `# polepos:*` managed markers.\n* Do not rewrite managed router includes, model imports, module exports,\n  integration settings, or `.env.example` values into a shape the CLI cannot\n  recognize.\n* Keep required generated settings and env values active; use comments only for\n  optional examples or explanatory notes.\n* Do not delete generated module directories by hand. Use\n  `polepos remove module \u003cname\u003e` so generated wiring and tests are cleaned too.\n* Do not move generated core files such as `api/router.py`, `db/models.py`,\n  `settings.py`, `.env.example`, `.poleposition.toml`, or Alembic files.\n* Do not create database tables during app startup; keep schema changes in\n  Alembic migrations.\n\nAfter structural edits or merge-conflict resolution, run `polepos check`.\n\n### Database commands\n\n```bash\npolepos db upgrade\npolepos db revision -m \"add garage table\"\npolepos db downgrade -1\n```\n\nDatabase commands prefer `uv run alembic ...` when `uv` is available. Without\n`uv`, they run Alembic through the active virtualenv, the project `.venv`, or\nthe first `python` on `PATH`.\n\nUse `polepos db` for the normal local lifecycle. It wraps Alembic while keeping\nthe command flow consistent with `polepos start`, module add/remove commands,\nand `polepos check`. For advanced Alembic flags, you can still run\n`uv run alembic ...` directly.\n\nAlembic works through SQLAlchemy dialects. The practical migration-managed\ndatabase targets are PostgreSQL, MySQL/MariaDB, SQLite, Microsoft SQL Server,\nand Oracle. Stores with external SQLAlchemy dialects, such as ClickHouse, should\nusually be treated as explicit integrations unless the project owns and reviews\ntheir custom DDL workflow.\n\nSee [Database and Migrations](https://github.com/polepos/poleposition/blob/main/docs/database.md) for the full migration workflow.\n\n### Docker workflow\n\nGenerated projects include a `Dockerfile`, `.dockerignore`, and `compose.yaml`\nso you can start the app with PostgreSQL in containers.\n\n```bash\ncp .env.example .env\ndocker compose up --build\ndocker compose run --rm app uv run alembic upgrade head\n```\n\nThe compose setup uses the generated `run.py` entrypoint and overrides\n`DATABASE_URL` so the app talks to the bundled PostgreSQL service. If you\nalready have PostgreSQL on `5432`, change `POSTGRES_PORT` in `.env` before\nstarting the compose stack.\n\nThe Docker example runs Alembic directly inside the generated app container\nbecause that image contains the generated application dependencies, not the\nPolePosition CLI.\n\n### Logging\n\nGenerated projects use `get_logger(__name__)` from `bootstrap.logging` as the preferred logging entrypoint.\n\n```python\nfrom shop_api.bootstrap.logging import get_logger\n\nlogger = get_logger(__name__)\n```\n\n### Runtime configuration\n\nGenerated projects include `src/\u003cpackage\u003e/run.py` as the preferred local and production-friendly entrypoint.\n\nUse:\n\n```bash\nuv run python -m shop_api.run\n```\n\nRuntime code is split intentionally:\n\n* `app.py` defines `create_app()` and wires FastAPI, middleware, exception\n  handlers, logging, and the API router when the factory is called.\n* `main.py` creates the ASGI-level `app` used by Uvicorn import strings such as\n  `shop_api.main:app`.\n* `run.py` is the local process entrypoint that reads runtime settings, prints\n  the startup table, and starts Uvicorn.\n\n`get_settings()` and `setup_logging()` are evaluated inside `create_app()`, not\nat `app.py` import time. This keeps tests and dynamic environment overrides\nfrom inheriting stale import-time configuration.\n\nThe runner is configured from `settings.py` and `.env`, including:\n\n* `APP_HOST`\n* `APP_PORT`\n* `APP_RELOAD`\n* `LOG_LEVEL`\n* `UVICORN_WORKERS`\n* `UVICORN_ACCESS_LOG`\n* `UVICORN_PROXY_HEADERS`\n* `UVICORN_FORWARDED_ALLOW_IPS`\n* `UVICORN_SERVER_HEADER`\n* `UVICORN_DATE_HEADER`\n* `UVICORN_TIMEOUT_KEEP_ALIVE`\n* `UVICORN_TIMEOUT_GRACEFUL_SHUTDOWN`\n* `UVICORN_TIMEOUT_WORKER_HEALTHCHECK`\n* `UVICORN_LIMIT_CONCURRENCY`\n* `UVICORN_LIMIT_MAX_REQUESTS`\n* `UVICORN_LIMIT_MAX_REQUESTS_JITTER`\n* `UVICORN_BACKLOG`\n\nWhen the generated runner starts, it prints a compact startup table with the\ncurrent service name, environment, API prefix, database backend, host, port,\nworker count, and docs URL.\n\n### CORS\n\nGenerated projects include settings-driven CORS support with development\ndefaults for common localhost frontend origins.\n\nYou can control it from `.env` with:\n\n* `CORS_ENABLED`\n* `CORS_ALLOW_ORIGINS`\n* `CORS_ALLOW_ORIGIN_REGEX`\n* `CORS_ALLOW_CREDENTIALS`\n* `CORS_ALLOW_METHODS`\n* `CORS_ALLOW_HEADERS`\n* `CORS_EXPOSE_HEADERS`\n* `CORS_MAX_AGE`\n\nThe list-style fields accept JSON arrays in `.env`.\n\n### Authentication\n\nGenerated projects include a minimal JWT-based authentication foundation with:\n\n* a public `GET /api/v1/status` endpoint\n* `get_current_user` and `require_roles(...)` helpers\n\nRelevant auth settings:\n\n* `AUTH_SECRET_KEY`\n* `AUTH_ALGORITHM`\n* `AUTH_ACCESS_TOKEN_EXPIRE_MINUTES`\n* `AUTH_ISSUER`\n\n### JSON logging\n\nGenerated projects support both text and JSON logging formats.\n\nUse:\n\n* `LOG_FORMAT=text` for local development\n* `LOG_FORMAT=json` for structured production logging\n\nThe JSON formatter includes:\n\n* `timestamp`\n* `level`\n* `logger`\n* `message`\n* `app_name`\n* `environment`\n* `request_id`\n\n### When to use which command\n\nPolePosition is a lifecycle CLI, so the commands are meant to be used over time, not only on day one:\n\n* `polepos start` when you want to create a new FastAPI project with the PolePosition structure\n* `polepos add module` when you want to add a new REST/domain module, CRUD module, API-only module, or AI prompt module to an existing project\n* `polepos add auth` when you want to add the optional database-backed registration and token workflow\n* `polepos remove module` when you want to remove a generated module and its managed wiring\n* `polepos delete` when you want to delete a whole generated project directory and start over\n* `polepos add integration kafka` when you want Kafka producer and consumer wiring in an existing project\n* `polepos add integration rabbitmq` when you want RabbitMQ publisher and consumer wiring in an existing project\n* `polepos add integration redis` when you want shared Redis cache helpers in an existing project\n* `polepos add integration rq` when you want Redis-backed background job helpers in an existing project\n* `polepos check` when you want to validate the project contract: generated structure, Alembic config, managed markers, module wiring, and integration wiring\n* `polepos check --fix` when safe managed markers should be restored before validation\n* `polepos db status` when you want to inspect current and target Alembic revisions\n* `polepos db upgrade` when you want to apply migrations to the database\n* `polepos db revision -m \"...\"` when you changed models and need a new migration\n* `polepos db downgrade` when you need to roll back a migration\n* `polepos upgrade` when you want a read-only project upgrade readiness report\n\n### Examples\n\nConcrete scenario guides live in [Examples](https://github.com/polepos/poleposition/blob/main/docs/examples/index.md):\n\n* auth foundation workflow\n* PostgreSQL-backed HTML swap workflow\n* Kafka quick-start producer/consumer workflow\n* RabbitMQ quick-start publisher/worker workflow\n* Redis cache-aside workflow\n* OpenAI prompt endpoint workflow\n\n### Help and version\n\n```bash\npolepos help\npolepos help start\npolepos help add module\npolepos help db revision\npolepos version\n```\n\n`polepos help` prints the full CLI usage and command reference. Pass a command\npath to get focused help for one command, similar to `polepos help remove\nmodule`.\n\n---\n\n## CLI\n\n```bash\npolepos help\npolepos help \u003ccommand\u003e [subcommand]\npolepos start \u003cname\u003e [--install] [--no-bytecode] [--db sqlite|postgres|none]\npolepos startproject \u003cname\u003e [--install] [--no-bytecode] [--db sqlite|postgres|none]\npolepos add module \u003cname\u003e\npolepos add module \u003cname\u003e --template crud\npolepos add module \u003cname\u003e --template crud [--pagination] [--timestamps]\npolepos add module \u003cname\u003e --template crud [--soft-delete] [--tenant-scoped]\npolepos add module \u003cname\u003e --template crud [--auth-required]\npolepos add module \u003cname\u003e --template ai-prompt\npolepos add module \u003cname\u003e --api-only\npolepos add auth\npolepos remove module \u003cname\u003e [--force] [--trace] [--wiring-only]\npolepos delete \u003cname\u003e [--force] [--trace]\npolepos add integration kafka\npolepos add integration rabbitmq\npolepos add integration redis\npolepos add integration rq\npolepos check\npolepos check --json\npolepos check --fix\npolepos db status\npolepos db upgrade [target]\npolepos db revision -m \"\u003cmessage\u003e\"\npolepos db downgrade \u003ctarget\u003e\npolepos upgrade\npolepos version\n```\n\nFor option-by-option behavior, examples, and lifecycle notes, see the\n[CLI Reference](https://github.com/polepos/poleposition/blob/main/docs/cli.md).\n\n---\n\n## Project Structure\n\n```text\nmyapp/\n├─ AGENTS.md\n├─ Dockerfile\n├─ compose.yaml\n├─ .poleposition.toml\n├─ alembic.ini\n├─ migrations/\n│  └─ versions/\n├─ pyproject.toml\n├─ .dockerignore\n├─ .env.example\n├─ src/\n│  └─ myapp/\n│     ├─ run.py\n│     ├─ main.py\n│     ├─ app.py\n│     ├─ settings.py\n│     ├─ bootstrap/\n│     ├─ api/\n│     ├─ db/\n│     ├─ domain/\n│     └─ modules/\n│        └─ status/\n└─ tests/\n   ├─ integration/\n   └─ unit/\n```\n\n---\n\n## Status Endpoint\n\nCheck if your service is running:\n\n```http\nGET /api/v1/status\n```\n\n```json\n{\n  \"status\": \"ok\",\n  \"service\": \"myapp\",\n  \"environment\": \"development\",\n  \"version\": \"0.1.0\",\n  \"uptime_seconds\": 12,\n  \"timestamp\": \"2026-04-26T12:00:00Z\"\n}\n```\n\n---\n\n## Philosophy\n\nPolePosition is built around a few principles:\n\n* Lifecycle-oriented: supports project creation, growth, checks, and migrations\n* Minimal: no unnecessary abstractions\n* Opinionated: sensible defaults\n* Extensible: easy to grow into larger systems\n\nThe CLI is intentionally lightweight and avoids heavy templating engines. Templates are an implementation detail; the product surface is the project lifecycle.\n\n---\n\n## Example Workflow\n\nHere is a concrete example for a new PostgreSQL-backed FastAPI REST API project.\n\nCreate the project and install dependencies:\n\n```bash\nuv tool install poleposition\npolepos start shop-api\ncd shop-api\ncp .env.example .env\nuv sync --extra dev\n```\n\nOr use the generated Docker workflow:\n\n```bash\ndocker compose up --build\ndocker compose run --rm app uv run alembic upgrade head\n```\n\nThat Docker command runs Alembic directly inside the generated app container.\nFor the host workflow, use `polepos db upgrade` after configuring `.env`.\n\nPoint the project to PostgreSQL in `.env`:\n\n```env\nDATABASE_URL=postgresql+psycopg://postgres:postgres@localhost:5432/shop_api\n```\n\nApply the initial migration and start the API:\n\n```bash\npolepos db upgrade\nuv run python -m shop_api.run\n```\n\nAdd a new REST module:\n\n```bash\npolepos add module customers\n```\n\nExtend `src/shop_api/modules/customers/model.py` and `schemas.py` for your domain, then generate and apply a migration:\n\n```bash\npolepos db revision -m \"add customers table\"\npolepos db upgrade\n```\n\nAt that point, your project has:\n\n* FastAPI app structure\n* PostgreSQL-ready SQLAlchemy setup\n* Alembic migration workflow\n* A generated REST module with router, schemas, module-local services, repository, and tests\n\nThat is the core PolePosition flow: start fast, add modules as the API grows, and evolve the database schema through the CLI.\n\n### Example: build a `users` REST API\n\nIf you want a REST API that returns users, the flow is:\n\nGenerate the module:\n\n```bash\npolepos add module users\n```\n\nUpdate `src/shop_api/modules/users/model.py` with user fields such as:\n\n```python\nclass Users(Base):\n    __tablename__ = \"users\"\n\n    id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)\n    email: Mapped[str] = mapped_column(String(255), unique=True)\n    full_name: Mapped[str] = mapped_column(String(120))\n    is_active: Mapped[bool] = mapped_column(default=True)\n```\n\nUpdate `schemas.py` so the API returns those fields, then create and apply a migration:\n\n```bash\npolepos db revision -m \"create users table\"\npolepos db upgrade\n```\n\nAt that point, you already have the generated router shape for:\n\n```text\nGET  /api/v1/users/\nPOST /api/v1/users/\n```\n\nThose paths come from the module-local `@router.get(\"/\")` and `@router.post(\"/\")`\nhandlers being included once under the `/users` prefix in `api/router.py`.\n\nFrom there, you refine the generated module for your actual domain instead of starting from an empty project structure.\n\n---\n\n## Python Support\n\nThe PolePosition CLI supports Python `\u003e=3.10`.\n\nGenerated FastAPI projects target Python `\u003e=3.11`, as declared in the generated\nproject `pyproject.toml`. This lets the CLI remain lightweight while generated\napplications use a modern FastAPI, Pydantic, SQLAlchemy, and Alembic baseline.\n\nThe repository CI currently runs the CLI test suite on Python `3.10`, `3.11`,\n`3.12`, `3.13`, and `3.14`. Generated-project e2e coverage runs on Python\n`3.11`.\n\n## Test And CI Automation\n\n| Workflow | Trigger | What it runs |\n|---|---|---|\n| `CI` | push, pull request, manual dispatch | Ruff lint + format check (Google Python Style Guide); repo test suite on Python `3.10`, `3.11`, `3.12`, `3.13`, and `3.14`; Docusaurus production build |\n| `E2E` | release tags, relevant pull requests, manual dispatch | Generated-project non-Docker e2e smoke tests on Python `3.11` |\n| `Release` | published GitHub release | Build and verify Python distributions, then publish to PyPI with Trusted Publishing |\n| `Deploy Docs` | pushes to `main`, manual dispatch | Docusaurus production build and GitHub Pages deploy |\n\nThe `CI` workflow runs `pytest` with `pytest-cov`, prints a terminal coverage\nreport, and uploads `coverage.xml` as a per-Python-version workflow artifact.\nCoverage is currently informational; no minimum threshold is enforced yet.\n\nDocker e2e coverage exists as an opt-in local or release-readiness smoke path\nvia the `docker_e2e` pytest marker. It is intentionally not run on every pull\nrequest because it requires Docker and a compose-capable environment.\n\nThe `Release` workflow uses PyPI Trusted Publishing, so it does not require a\n`PYPI_API_TOKEN` repository secret. PyPI must trust the\n`polepos/poleposition` repository, `.github/workflows/release.yml`, and the\n`pypi` GitHub Actions environment before the first publish.\n\n---\n\n## Contributing\n\nContributions are welcome.\nFeel free to open an\n[issue](https://github.com/polepos/poleposition/issues) or submit a\n[pull request](https://github.com/polepos/poleposition/pulls).\n\nSee [`CONTRIBUTING.md`](CONTRIBUTING.md) and the\n[Contributing guide](docs/contributing.md) for development setup, running the\ntests (including opt-in end-to-end tests), project layout, and common tasks.\n\n### Code style\n\nPython code follows the\n[Google Python Style Guide](https://google.github.io/styleguide/pyguide.html),\nenforced automatically with [Ruff](https://docs.astral.sh/ruff/) (80-column\nlines, sorted imports, `pep8-naming`, and exception chaining). The `CI` workflow\ngates every pull request on it. Before pushing:\n\n```bash\nruff check pole_position polepos\nruff format pole_position polepos\n```\n\nSee [Code Style](docs/code-style.md) for the full rule set and rationale.\n\n---\n\n## License\n\nMIT\n\n[License](https://raw.githubusercontent.com/polepos/poleposition/refs/heads/main/LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpolepos%2Fpoleposition","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpolepos%2Fpoleposition","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpolepos%2Fpoleposition/lists"}