Shared FastAPI/Celery scaffolding for Sweet Potato service backends.
Project description
SPAPS Server Quickstart
Reusable scaffolding for Sweet Potato service backends. This package gathers the FastAPI application factory, Celery bootstrap, Pydantic settings base classes, and other utilities that HTMA, Ingredient, and future services can share.
Installation
Use either Poetry (preferred inside this repo) or pip editable installs:
# with poetry
poetry install -C packages/python-server-quickstart
# or with pip (installs package + dev extras)
python3 -m pip install -e 'packages/python-server-quickstart[dev]'
The editable install ensures FastAPI, SQLAlchemy, Celery, and other dependencies are available when the pre-push scripts execute.
Local Development
poetry run -C packages/python-server-quickstart pytest
The shared modules are designed to be imported by individual service packages. Tests live alongside the shared code to guard the common behaviour.
Local Auth Bypass Mode
For local development without external auth services, enable local mode by setting
DEVELOPMENT_ENVIRONMENT=local. This provides pre-configured personas (admin/user)
that bypass SPAPS authentication.
from spaps_server_quickstart.settings import BaseServiceSettings
from spaps_server_quickstart.local_mode import (
LocalAuthMiddleware,
get_default_registry,
)
settings = BaseServiceSettings(development_environment="local")
if settings.is_local_development:
app.add_middleware(LocalAuthMiddleware, registry=get_default_registry())
Available personas:
| Persona | Token | Roles |
|---|---|---|
| Admin | local-admin |
admin, user |
| User | local-user |
user |
Use the token in your Authorization header: Authorization: Bearer local-admin
Optional local auth routes are available under spaps_server_quickstart.templates.domains.auth.local_routes:
from spaps_server_quickstart.templates.domains.auth.local_routes import router as local_auth_router
if settings.is_local_development:
app.include_router(local_auth_router, prefix="/v1/auth", tags=["local-auth"])
This adds:
GET /v1/auth/local-personas- List available personasPOST /v1/auth/local-login- Login with persona code or tokenGET /v1/auth/local-me- Get current persona from Authorization header
Operational Templates
For infrastructure parity with live SPAPS services, the directory
templates/operations contains a ready-to-copy bundle that now includes:
- Makefile with lint/test/deploy shortcuts
- Production
.env.production.example - Docker Compose + reverse-proxy stubs (pre-configured with Docker DNS resolver support)
- Deploy script that reloads the shared proxy in-place after each rollout
- Pre/post deployment checks (
pre-deploy-checks.sh,post-deploy-verify.sh) - Database maintenance scripts (
backup-db.sh,restore-db.sh,new-migration.sh) - Pre-push hook +
scripts/prepush.shmatching live automation - Local Postgres helpers under
scripts/dev/(start-db.sh,stop-db.sh,await_db.py) for pgvector-backed test runs
Deployment Checks
The deployment scripts include automated validation:
Pre-deployment (pre-deploy-checks.sh):
- Docker availability and daemon status
- Port availability for required services
- Disk space validation (configurable minimum)
- Required environment variable validation
- Dev container conflict detection
- Docker network verification
Post-deployment (post-deploy-verify.sh):
- Container running status
- Health endpoint validation with exponential backoff
- Image version verification
- Migration status check (optional)
- Docker healthcheck status
- Service connectivity (Redis, database)
Configuration via environment variables:
| Variable | Description | Default |
|---|---|---|
SERVICE_NAME |
Service identifier for checks | quickstart |
REQUIRED_PORTS |
Comma-separated ports to check | 8000 |
MIN_DISK_SPACE_GB |
Minimum disk space required | 5 |
REQUIRED_ENV_VARS |
Required environment variables | `` |
HEALTH_ENDPOINT |
URL for health check | http://localhost:8000/health |
MAX_HEALTH_WAIT |
Max seconds to wait for health | 60 |
SKIP_PRE_CHECKS |
Skip pre-deployment checks | 0 |
SKIP_POST_CHECKS |
Skip post-deployment checks | 0 |
Database Caching for Local Development
The local-debug-loop.sh script caches seeded database state to speed up make local-up:
# First run: seeds database and creates cache
make local-up
# Subsequent runs: restores from cache if seeds/migrations unchanged
make local-up
# Force full reseed (ignores cache)
make local-up-seed
# Watch mode: auto-reseeds when files change
make local-up-watch
How it works:
- Computes SHA256 hash of
alembic/,scripts/seeds/,fixtures/directories - If hash matches cached version, restores database from
pg_dumpcache - If hash differs, runs full migrations + seeds, then saves new cache
- Cache stored at
~/.cache/${SERVICE_NAME}/db/seeded.sql.gz
Configuration:
| Variable | Description | Default |
|---|---|---|
SERVICE_NAME |
Service name for cache paths | quickstart |
CACHE_ROOT |
Base cache directory | ~/.cache/${SERVICE_NAME} |
FORCE_RESEED |
Force full reseed ignoring cache | 0 |
SKIP_DB_CACHE |
Disable caching entirely | 0 |
CACHE_TARGETS |
Directories to include in hash | alembic scripts/seeds fixtures |
LOCAL_WATCH |
Enable watch mode for auto-reseed | 0 |
Copy the folder into a service repository when adopting the quickstart so CI/CD, GHCR pulls, backup automation,
and the shared reverse proxy follow the same playbook used by Ingredient, HTMA, and Sweet Potato. Update the provided
environment variables (PROJECT_SLUG, DB_SERVICE, etc.) after copying to match the new service naming.
The reverse proxy template adds resolver 127.0.0.11 ipv6=off valid=30s; and marks upstream servers with resolve
so nginx re-resolves Docker service names whenever containers cycle. During deployment the helper issues
docker exec shared-reverse-proxy nginx -s reload (falling back to the legacy ./up.sh script) so configuration
changes take effect without bouncing the proxy container.
When developing locally, start the database with scripts/dev/start-db.sh before running scripts/prepush.sh or
pytest. The helper waits for a pgvector-enabled Postgres on port 5433 and seeds PYTEST_DATABASE_URL,
DATABASE_URL, and SYNC_DATABASE_URL with sensible defaults. Shut it down with scripts/dev/stop-db.sh.
RBAC Helpers & Sample Routers
- Use
spaps_server_quickstart.rbac.require_rolesas a FastAPI dependency to guard admin/staff-only routes. It returns the authenticated user when the role check passes and raisesHTTPException(401/403) otherwise. spaps_server_quickstart.rbac.has_required_rolesprovides a lightweight predicate when you need to branch on roles outside of dependency injection.- Copy the sample routers under
spaps_server_quickstart.templates.domains(users/admin) when spinning up new services—they demonstrate how to wire the RBAC helpers into typical CRUD endpoints.
Configuration Highlights
Services configure behaviour by subclassing BaseServiceSettings. Override fields like
spaps_auth_exempt_paths to expose unauthenticated endpoints or set cors_allow_origins
(and related CORS knobs) to attach the shared CORSMiddleware without writing per-service
plumbing. All list-like settings accept comma-separated environment variables for easy deployment.
Auth Channels (Magic Link & Wallet)
SpapsAuthChannelServicewraps SPAPS magic-link and wallet authentication so services can drop the boilerplate client calls.- Use
send_magic_link/verify_magic_linkfor email links andrequest_wallet_nonce/verify_walletfor Solana or Ethereum sign-ins. - The helpers raise
AuthChannelErrorwithstatus_codeanderror_code, giving your routes enough context to map responses cleanly. - Lifecycle management mirrors the main auth service—call
await service.aclose()during shutdown if you create a long-lived instance.
Secure Messaging Gateway
spaps_server_quickstart.secure_messaging.build_secure_messaging_gatewayreturns an async gateway mirroring HTMA’s SPAPS secure messaging integration. It logs send/list operations and normalises upstream failures intoSecureMessagingGatewayError.provide_secure_messaging_gatewayenforces feature flags and required roles before returning a configured gateway. Wire it into FastAPI dependencies to replicate practitioner-only messaging flows without bespoke plumbing.SecureMessagingContextcarries practitioner/patient identifiers and optional access tokens; the helper merges default metadata (application_id,practitioner_user_id) so downstream analytics remain consistent across services.- Settings expose
secure_messages_enabled,secure_messages_timeout, andsecure_messages_default_page_size, letting each service toggle secure messaging per environment.
Auth Dependencies
spaps_server_quickstart.auth.dependencies.require_authenticated_userretrieves theAuthenticatedUserassigned bySpapsAuthMiddleware, raising a 401 when the request lacks credentials.require_authenticated_role("role")returns a dependency that asserts the subject holds a given role (case-insensitive), raising a 403 otherwise. Use it for common admin/practitioner guardrails without reimplementing role checks.
Environment Reference
| Variable | Description | Notes |
|---|---|---|
DEVELOPMENT_ENVIRONMENT |
Set to local to enable local auth bypass |
Defaults to None |
SPAPS_API_URL |
Base URL for SPAPS API requests | Defaults to https://api.sweetpotato.dev |
SPAPS_API_KEY |
Service API key used for auth + channel helpers | Required when spaps_auth_enabled is true |
SPAPS_APPLICATION_ID |
Application identifier enforced during session validation | Required when spaps_auth_enabled is true |
SPAPS_AUTH_ENABLED |
Toggle for the auth middleware | Enables SpapsAuthMiddleware when true |
SPAPS_AUTH_EXEMPT_PATHS |
Comma-separated paths that bypass auth | Parsed into a tuple automatically |
SPAPS_REQUEST_TIMEOUT |
Timeout (seconds) for SPAPS HTTP calls | Applies to both auth and channel helpers |
CORS_ALLOW_ORIGINS / CORS_ALLOW_METHODS / CORS_ALLOW_HEADERS |
Comma-separated CORS configuration | Leave empty to skip the middleware |
CORS_EXPOSE_HEADERS |
Headers exposed to clients | Defaults to empty tuple |
CORS_ALLOW_CREDENTIALS |
Whether CORS requests include credentials | Defaults to true |
CORS_MAX_AGE |
CORS preflight cache duration | Must be non-negative |
SECURE_MESSAGES_ENABLED |
Toggle SPAPS secure messaging gateway wiring | Defaults to false |
SECURE_MESSAGES_TIMEOUT |
Override secure messaging request timeout | Falls back to SPAPS_REQUEST_TIMEOUT |
SECURE_MESSAGES_DEFAULT_PAGE_SIZE |
Default list_messages page size |
Must be positive |
Lifecycle Hooks
create_app now uses FastAPI's lifespan context to close shared resources (e.g., SPAPS auth
clients). When you need additional startup/shutdown logic, extend the lifespan in your service
by wrapping the provided app with your own context manager or closing resources within your
domain packages. Running tests with TestClient(app) will automatically exercise the shutdown path and catch missing
aclose() implementations. Pair this with spaps_server_quickstart.db.collect_migration_status inside custom health
metrics providers to surface Alembic drift on /health (mirroring HTMA’s practitioner metrics).
Upgrading Downstream Services
Guidance for publishing new versions and upgrading consumer services lives in
docs/UPGRADING.md. Review those steps before bumping the package or
pulling a newer release into htma_server, ingredient_server, or other SPAPS services.
Migrating an Existing Service
See docs/MIGRATION_GUIDE.md for a step-by-step walkthrough of
adopting the shared package inside an existing FastAPI/Celery service. It covers settings
integration, router wiring, database session management, Celery bootstraps, and the final
cleanup checklist.
Release Workflow
- Use the GitHub Action Publish Python Server Quickstart (
.github/workflows/python-server-quickstart-release.yml) to cut releases. It reuses the genericpython-package-releaseworkflow alongsidescripts/manage_python_package_version.py. - Ensure the repository secret
PYPI_SERVER_QUICKSTART_TOKENholds the PyPI API token for this package. - For manual bumps, dispatch the workflow and choose the bump type (major/minor/patch). For automated publishes, pushing a commit that updates
packages/python-server-quickstart/pyproject.tomlwill trigger the workflow.
Status
- Initial package scaffold
- Shared application factories
- Shared Celery bootstrap
- Shared middleware, logging, and settings base classes
- Health endpoint helpers
- Documentation and usage examples
Repository Integration
The root package.json includes lint:python-server-quickstart, typecheck:python-server-quickstart,
and test:python-server-quickstart commands. These run automatically via npm run prepush, and the npm
scripts install packages/python-server-quickstart[dev] on demand so the editable install step is handled
for you.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file spaps_server_quickstart-0.3.0.tar.gz.
File metadata
- Download URL: spaps_server_quickstart-0.3.0.tar.gz
- Upload date:
- Size: 148.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f66bd6493364c38be8e3acc690da548b5fa6d34fd0425720482bb0768bd5e015
|
|
| MD5 |
e06c672dc9cf197fb4159d7b75aa3836
|
|
| BLAKE2b-256 |
09f8a9734ebdf2a5f6f9d5add203a2ba4e13d45a5ef00fae17803c1dc5a98cfd
|
File details
Details for the file spaps_server_quickstart-0.3.0-py3-none-any.whl.
File metadata
- Download URL: spaps_server_quickstart-0.3.0-py3-none-any.whl
- Upload date:
- Size: 118.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d0bc66d180b6915f77afc65fd43911efd48543e398915d8092195f800a0c600c
|
|
| MD5 |
9687d8479ea1cddfe943e8190bae476b
|
|
| BLAKE2b-256 |
0ec3d10d213ee148b32888d39846be75ff3a1f8d1db787f35518e483362bc17f
|