Skip to main content

spaps-server-quickstart

Reusable FastAPI, SQLAlchemy, Celery, auth, and operational scaffolding for SPAPS-aligned Python services. This is the active backend package in this repository.

Examples in this README use placeholders such as https://api.example.test and local-only database URLs. Replace them with values from your own environment.

Install

pip install spaps-server-quickstart

This package targets Python 3.12+.

When It Fits

Need Package gives you
A real FastAPI starting point create_app, settings loaders, request logging, and startup checks
Shared auth and RBAC SPAPS auth middleware, auth channels, cookies, and role dependencies
Async database plumbing SQLAlchemy 2 async session helpers and Alembic support
Operational scaffolding Celery setup, deploy templates, local-mode helpers, and service SDK utilities

Quick Start

from fastapi import APIRouter

from spaps_server_quickstart import create_app
from spaps_server_quickstart.settings import (
    BaseServiceSettings,
    create_settings_loader,
)


class ExampleSettings(BaseServiceSettings):
    app_name: str = "Example Service"
    spaps_auth_enabled: bool = False


router = APIRouter()


@router.get("/health")
async def health() -> dict[str, bool]:
    return {"ok": True}


app = create_app(
    settings_loader=create_settings_loader(ExampleSettings),
    api_router=router,
)

What the Package Ships

Area Highlights
App lifecycle create_app, startup validation, logging, CORS wiring
Auth SpapsAuthMiddleware, auth cookies, auth channel service, local mode
Routing and RBAC Base router builder, authenticated-user dependencies, require_roles, has_required_roles
Database Async sessionmaker factory, migration runner, Alembic helpers
Tasks Celery app factory plus notification and ping task helpers
Service SDK helpers Admin token cache, server-side SPAPS clients, trusted-service middleware, feature evaluation
Templates Domain examples, tests, deployment scaffolding, and local operations helpers
Reference contract The golden_path app blueprint, seeded paid-access policy, and downstream runbook for the core auth -> billing -> entitlement -> access loop

Golden App Pack

If you want one SPAPS-native reference contract instead of a blank scaffold, start with the golden_path blueprint.

It is the canonical pack for:

  • browser auth and one-call session bootstrap via GET /api/auth/session-context
  • Stripe checkout or subscription flows
  • entitlement projection into paid_access
  • policy-gated access through the seeded access-paid-features rule
  • an operator runbook under docs/downstream_apps/golden-path-reference/

Local Development Mode

For the SPAPS app in this repo, SPAPS_LOCAL_MODE is the canonical local auth/persona switch. It controls the route dependencies in middleware/spaps_deps.py: missing API keys fall back to the local test application, missing JWTs fall back to the selected test persona, explicit API keys still validate normally, and real JWTs still win when present.

ENV SPAPS_LOCAL_MODE SPAPS app behavior
prod / production unset or false local mode off; real API key/JWT required
prod / production true startup fails; bypass is not allowed
dev / development / test unset local mode on by default
dev / development / test true local mode on
dev / development / test false local mode off
staging / ci unset local mode off unless explicitly enabled
unknown env any production-strict; local bypass is disabled

Check the resolved state with /health/local-mode, /health/ready, or the X-SPAPS-Mode response header. X-SPAPS-Environment carries the normalized environment used for the safety decision.

DEVELOPMENT_ENVIRONMENT=local is the base quickstart/template knob for services that explicitly wire LocalAuthMiddleware; it is not the SPAPS app runtime switch.

from spaps_server_quickstart.local_mode import (
    LocalAuthMiddleware,
    get_default_registry,
)
from spaps_server_quickstart.settings import BaseServiceSettings

settings = BaseServiceSettings(development_environment="local")

if settings.is_local_development:
    app.add_middleware(LocalAuthMiddleware, registry=get_default_registry())

Default personas:

Persona Token Roles
Admin local-admin admin, user
User local-user user

Configuration

Common settings exposed through BaseServiceSettings:

Setting Purpose
spaps_local_mode Canonical SPAPS app local auth/persona switch
development_environment Base-template LocalAuthMiddleware switch when set to local; not the SPAPS app mode switch
spaps_auth_enabled Turns SPAPS auth middleware on or off
spaps_auth_exempt_paths Comma-separated paths that skip SPAPS auth
cors_allow_origins Shared CORS configuration
database_url Async SQLAlchemy database URL
redis_url Redis URL used by Celery defaults
secure_messages_enabled Enables secure-messaging gateway support

For per-process local origins that should not live in environment settings, pass them to the app factory:

app = create_app(
    settings_loader=create_settings_loader(ExampleSettings),
    api_router=router,
    extra_cors_origins=["http://localhost:5173"],
)

When settings origins are empty, extra_cors_origins enables CORS only for those explicit origins. It does not add the wildcard origin unless CORS is enabled manually without any configured origins.

Example environment:

SPAPS_LOCAL_MODE=true
# Only set DEVELOPMENT_ENVIRONMENT=local for downstream services that wire LocalAuthMiddleware.
SPAPS_API_URL=https://api.example.test
SPAPS_API_KEY=spaps_sec_example
DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/service
SPAPS_AUTH_EXEMPT_PATHS=/health,/docs
CORS_ALLOW_ORIGINS=http://localhost:3000,http://localhost:5173

Recurring Operations

spaps-recurring-operations-status --compact prints the configured background jobs, cadences, ownership, and inspection surfaces without opening a database, contacting a provider, or instantiating runtime settings. It reports configuration; worker liveness, backlog, provider state, and scheduler deployment remain unchecked.

The shared factory installs seven default jobs. The SPAPS app adds two x402 reconcilers, the token-gate renewal and transfer-log jobs, application-account erasure reconciliation, and verified guest-purchase attachment. Importing task modules leaves other Celery apps unchanged; explicit registration helpers remain available for consumer apps. Schedule overrides passed to the factory still win.

spaps.entitlements.reconcile_guest_conversions runs every 60 seconds in the SPAPS schedule. It attaches eligible purchases after conversion, verified email, checkout payment, and the pending grant have committed. It reports scanned, claimed, failed, and skipped counts; failed purchases remain pending for a later pass. A database advisory guard skips overlapping ticks (skipped=1 with zero purchase counts); queued ticks expire after 60 seconds. Each purchase commits or rolls back separately. Reconciliation adds no provider work to authentication handlers, although authentication can wait on the shared account fence while a claim is in progress. Source registration does not prove an installed scheduler or worker has run it; production activation and webhook-to-access proof remain separate release checks.

Validation

From the repository root, the Makefile is the canonical workflow:

make install
make pytest
make lint
make typecheck
make pytest-cov
make test

make install installs both this checkout's Python client and server as editable packages. Test setup checks the client's resolved import path and repairs a missing, registry-installed, or other-checkout client before running tests. This validates local source integration; published-package compatibility needs separate artifact evidence.

Shared PostgreSQL test templates reuse a schema only when its Alembic heads and stored migration-content fingerprint match. Editing an unpublished migration without changing its revision rebuilds the disposable template before worker cloning; unchanged contents reuse it. The existing shared filelock (included in [testing]) protects that lifecycle. Explicit direct test database URLs bypass template provisioning; production databases are unaffected.

Useful additional commands:

make pytest-full
make pytest PYTEST_ARGS='tests/properties'
make migration-lint
make migration-downgrade-check
make migrate
make migrate-rehearsal
make perf-bench
make perf-k6
make new-migration MSG="add_example_table"
make local-up

The tests/properties/ suite uses deterministic Hypothesis checks for pure security helpers: wallet canonicalization, nonce parsing, publishable route scope matching, rate-limit tier resolution, one-time auth challenges, and webhook HMAC signing.

make migration-lint checks Alembic migrations changed from BASE_REF for rollback and production-lock hazards. make migrate-rehearsal reuses the existing production-dump restore path, applies migrations, and writes a timing report under .skillbox/reports/. The restore path renders the cached dump through scripts/dev/restore_prod_dump_stream.py so local-only placeholder rows can satisfy FK validation for known historical dump orphans without disabling constraints.

make perf-bench runs the opt-in pytest-benchmark hot-path suite and compares the result with committed budgets under tests/benchmarks/baselines/. make perf-k6 runs the k6 scenario against SPAPS_E2E_TARGET after a local stack is already running. These targets are report-only; normal PR validation does not execute performance measurements.

Troubleshooting

make pytest reports no affected tests

That is expected when testmon sees no impacted tests. Use make pytest-full when you need a full run.

Local auth bypass is not active

For the SPAPS app, check /health/local-mode, /health/ready, X-SPAPS-Mode, and the SPAPS_LOCAL_MODE value. For generated services using the base quickstart middleware, confirm DEVELOPMENT_ENVIRONMENT=local is set before startup and that LocalAuthMiddleware is wired into the app.

Unauthenticated routes still require auth

Check spaps_auth_exempt_paths and make sure the configured paths match the router paths exactly.

Startup fails on environment validation

Review the required settings and any safety checks triggered during startup.

I need a new service quickly

Start from the included templates, then keep the repo-root validation path intact while adapting domain code and settings.

Limitations

  • This package is a scaffold, not a finished application.
  • Downstream services still need their own routers, schemas, repositories, and deployment settings.
  • Some operational templates intentionally need environment-specific edits before production use.

FAQ

Is this the active backend package in this repo?

Yes. This package replaces the old Node/Express stack as the active backend surface.

Does it include local auth bypass support?

Yes. The SPAPS app uses SPAPS_LOCAL_MODE; generated services can still use DEVELOPMENT_ENVIRONMENT=local with the local-mode helpers.

Can I use it without Celery?

Yes. Celery helpers are included, but you can compose only the pieces your service needs.

Does it include RBAC helpers?

Yes. Use require_roles, has_required_roles, and the authenticated-user dependencies.

From the repository root: make pytest, make lint, make typecheck, make pytest-cov, and make test.

Metadata

The metadata below describes this checkout. latest_version is the source package version; it does not establish registry publication or availability.

  • package_name: spaps-server-quickstart
  • latest_version: 0.9.1
  • minimum_runtime: Python >=3.12
  • api_base_url: https://api.sweetpotato.dev

About Contributions

About Contributions: Please don't take this the wrong way, but I do not accept outside contributions for any of my projects. I simply don't have the mental bandwidth to review anything, and it's my name on the thing, so I'm responsible for any problems it causes; thus, the risk-reward is highly asymmetric from my perspective. I'd also have to worry about other "stakeholders," which seems unwise for tools I mostly make for myself for free. Feel free to submit issues, and even PRs if you want to illustrate a proposed fix, but know I won't merge them directly. Instead, I'll have Claude or Codex review submissions via gh and independently decide whether and how to address them. Bug reports in particular are welcome. Sorry if this offends, but I want to avoid wasted time and hurt feelings. I understand this isn't in sync with the prevailing open-source ethos that seeks community contributions, but it's the only way I can move at this velocity and keep my sanity.

License

MIT

Metadata

Release files for spaps-server-quickstart 0.9.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for spaps-server-quickstart 0.9.1
File Size Uploaded Provenance Actions
spaps_server_quickstart-0.9.1.tar.gz 5.1 MB Without provenance Details for spaps_server_quickstart-0.9.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for spaps-server-quickstart 0.9.1
File Interpreter ABI Platform Actions
spaps_server_quickstart-0.9.1-py3-none-any.whl Python 3 none any Details for spaps_server_quickstart-0.9.1-py3-none-any.whl

Total release size: 7.4 MB

Release files / spaps_server_quickstart-0.9.1.tar.gz

Download URL spaps_server_quickstart-0.9.1.tar.gz
Size 5.1 MB
Tags Source
SHA-256 checksum
How to use checksums
c849cbdeefe22605d1195db92e1bf8cd9cd2ee7cd79cd6d0c69744a93b42a7b7
BLAKE2b-256 checksum
How to use checksums
a62502372db879a2296b55d26874af8bb82cb4e7940b1ff4ab016505532e62a4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.15

Release files / spaps_server_quickstart-0.9.1-py3-none-any.whl

Download URL spaps_server_quickstart-0.9.1-py3-none-any.whl
Size 2.2 MB
Tags Python 3
SHA-256 checksum
How to use checksums
2205202e865ceb3bfbecffef4c1a4d60da35c9332652bca1c5872f33a5c77e85
BLAKE2b-256 checksum
How to use checksums
9f5d3036abf3b02ac9b3264ca36b4cf0c4018174e8cc5bb4a2b1d4f3ccdea0e0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.15

Security for spaps-server-quickstart 0.9.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page