spaps-server-quickstart 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- spaps_server_quickstart-0.0.1/.coverage +0 -0
- spaps_server_quickstart-0.0.1/.gitignore +132 -0
- spaps_server_quickstart-0.0.1/CHANGELOG.md +16 -0
- spaps_server_quickstart-0.0.1/PKG-INFO +102 -0
- spaps_server_quickstart-0.0.1/README.md +71 -0
- spaps_server_quickstart-0.0.1/docs/MIGRATION_GUIDE.md +104 -0
- spaps_server_quickstart-0.0.1/docs/UPGRADING.md +82 -0
- spaps_server_quickstart-0.0.1/pyproject.toml +62 -0
- spaps_server_quickstart-0.0.1/scripts/release.sh +23 -0
- spaps_server_quickstart-0.0.1/src/spaps_server_quickstart/__init__.py +63 -0
- spaps_server_quickstart-0.0.1/src/spaps_server_quickstart/alembic/__init__.py +21 -0
- spaps_server_quickstart-0.0.1/src/spaps_server_quickstart/alembic/naming.py +137 -0
- spaps_server_quickstart-0.0.1/src/spaps_server_quickstart/api/__init__.py +7 -0
- spaps_server_quickstart-0.0.1/src/spaps_server_quickstart/api/health.py +98 -0
- spaps_server_quickstart-0.0.1/src/spaps_server_quickstart/api/router.py +30 -0
- spaps_server_quickstart-0.0.1/src/spaps_server_quickstart/app_factory.py +97 -0
- spaps_server_quickstart-0.0.1/src/spaps_server_quickstart/auth.py +232 -0
- spaps_server_quickstart-0.0.1/src/spaps_server_quickstart/db/__init__.py +17 -0
- spaps_server_quickstart-0.0.1/src/spaps_server_quickstart/db/migration_runner.py +81 -0
- spaps_server_quickstart-0.0.1/src/spaps_server_quickstart/db/session.py +99 -0
- spaps_server_quickstart-0.0.1/src/spaps_server_quickstart/logging.py +69 -0
- spaps_server_quickstart-0.0.1/src/spaps_server_quickstart/middleware.py +50 -0
- spaps_server_quickstart-0.0.1/src/spaps_server_quickstart/schemas/__init__.py +7 -0
- spaps_server_quickstart-0.0.1/src/spaps_server_quickstart/schemas/health.py +23 -0
- spaps_server_quickstart-0.0.1/src/spaps_server_quickstart/settings.py +144 -0
- spaps_server_quickstart-0.0.1/src/spaps_server_quickstart/tasks/__init__.py +13 -0
- spaps_server_quickstart-0.0.1/src/spaps_server_quickstart/tasks/celery_factory.py +40 -0
- spaps_server_quickstart-0.0.1/src/spaps_server_quickstart/tasks/health.py +31 -0
- spaps_server_quickstart-0.0.1/src/spaps_server_quickstart/tasks/notifications.py +41 -0
- spaps_server_quickstart-0.0.1/tests/test_alembic_naming.py +52 -0
- spaps_server_quickstart-0.0.1/tests/test_api_router.py +23 -0
- spaps_server_quickstart-0.0.1/tests/test_app_factory.py +122 -0
- spaps_server_quickstart-0.0.1/tests/test_auth.py +72 -0
- spaps_server_quickstart-0.0.1/tests/test_db_session.py +124 -0
- spaps_server_quickstart-0.0.1/tests/test_health_router.py +74 -0
- spaps_server_quickstart-0.0.1/tests/test_imports.py +28 -0
- spaps_server_quickstart-0.0.1/tests/test_logging.py +39 -0
- spaps_server_quickstart-0.0.1/tests/test_middleware.py +45 -0
- spaps_server_quickstart-0.0.1/tests/test_migration_runner.py +35 -0
- spaps_server_quickstart-0.0.1/tests/test_settings.py +46 -0
- spaps_server_quickstart-0.0.1/tests/test_tasks.py +78 -0
- spaps_server_quickstart-0.0.1/todo.md +56 -0
|
Binary file
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Dependencies
|
|
2
|
+
node_modules/
|
|
3
|
+
*.log
|
|
4
|
+
npm-debug.log*
|
|
5
|
+
yarn-debug.log*
|
|
6
|
+
yarn-error.log*
|
|
7
|
+
lerna-debug.log*
|
|
8
|
+
|
|
9
|
+
# Testing
|
|
10
|
+
coverage/
|
|
11
|
+
*.lcov
|
|
12
|
+
.nyc_output
|
|
13
|
+
packages/python-client/.coverage
|
|
14
|
+
|
|
15
|
+
# Production builds
|
|
16
|
+
dist/
|
|
17
|
+
build/
|
|
18
|
+
out/
|
|
19
|
+
*.tsbuildinfo
|
|
20
|
+
|
|
21
|
+
# Environment files
|
|
22
|
+
.env
|
|
23
|
+
.env.*
|
|
24
|
+
*.env
|
|
25
|
+
**/.env
|
|
26
|
+
**/.env.*
|
|
27
|
+
.env.development
|
|
28
|
+
.env.production
|
|
29
|
+
.env.staging
|
|
30
|
+
.env.deploy
|
|
31
|
+
.env.local
|
|
32
|
+
.env.development.local
|
|
33
|
+
.env.test.local
|
|
34
|
+
.env.production.local
|
|
35
|
+
# Allow committed templates/examples
|
|
36
|
+
!*.env.example
|
|
37
|
+
!*.env.sample
|
|
38
|
+
!*.env.template
|
|
39
|
+
!**/.env.example
|
|
40
|
+
!**/.env.sample
|
|
41
|
+
!**/.env.template
|
|
42
|
+
!**/.env.*.example
|
|
43
|
+
!**/.env.*.sample
|
|
44
|
+
!**/.env.*.template
|
|
45
|
+
!**/*.env.example
|
|
46
|
+
!**/*.env.sample
|
|
47
|
+
!**/*.env.template
|
|
48
|
+
|
|
49
|
+
# IDE
|
|
50
|
+
.vscode/
|
|
51
|
+
.idea/
|
|
52
|
+
*.swp
|
|
53
|
+
*.swo
|
|
54
|
+
*.swn
|
|
55
|
+
.DS_Store
|
|
56
|
+
|
|
57
|
+
# Debug
|
|
58
|
+
debug.log
|
|
59
|
+
*.log
|
|
60
|
+
|
|
61
|
+
# Temporary files
|
|
62
|
+
tmp/
|
|
63
|
+
temp/
|
|
64
|
+
*.tmp
|
|
65
|
+
packages/python-client/**/__pycache__/
|
|
66
|
+
|
|
67
|
+
# Package manager files
|
|
68
|
+
.pnp.*
|
|
69
|
+
.yarn/*
|
|
70
|
+
!.yarn/patches
|
|
71
|
+
!.yarn/plugins
|
|
72
|
+
!.yarn/releases
|
|
73
|
+
!.yarn/sdks
|
|
74
|
+
!.yarn/versions
|
|
75
|
+
|
|
76
|
+
# Next.js specific
|
|
77
|
+
.next/
|
|
78
|
+
next-env.d.ts
|
|
79
|
+
.vercel/
|
|
80
|
+
|
|
81
|
+
# Example projects - ignore build artifacts
|
|
82
|
+
examples/**/.next/
|
|
83
|
+
examples/**/node_modules/
|
|
84
|
+
examples/**/dist/
|
|
85
|
+
examples/**/build/
|
|
86
|
+
examples/**/*.log
|
|
87
|
+
examples/**/.env
|
|
88
|
+
examples/**/.env.local
|
|
89
|
+
|
|
90
|
+
# MCP/Sweetpotato docs build
|
|
91
|
+
mcp-sweetpotato-docs/node_modules/
|
|
92
|
+
mcp-sweetpotato-docs/dist/
|
|
93
|
+
mcp-sweetpotato-docs/build/
|
|
94
|
+
mcp-sweetpotato-docs/.next/
|
|
95
|
+
|
|
96
|
+
# Large test files
|
|
97
|
+
*.jpg
|
|
98
|
+
*.jpeg
|
|
99
|
+
*.png
|
|
100
|
+
*.gif
|
|
101
|
+
*.bmp
|
|
102
|
+
*.mp4
|
|
103
|
+
*.mov
|
|
104
|
+
*.avi
|
|
105
|
+
*.zip
|
|
106
|
+
*.tar
|
|
107
|
+
*.gz
|
|
108
|
+
*.rar
|
|
109
|
+
|
|
110
|
+
# Database files
|
|
111
|
+
*.sqlite
|
|
112
|
+
*.sqlite3
|
|
113
|
+
*.db
|
|
114
|
+
|
|
115
|
+
# OS files
|
|
116
|
+
Thumbs.db
|
|
117
|
+
Desktop.ini
|
|
118
|
+
|
|
119
|
+
# Backup files
|
|
120
|
+
*.bak
|
|
121
|
+
*.backup
|
|
122
|
+
*.old
|
|
123
|
+
|
|
124
|
+
# Test output
|
|
125
|
+
test-results/
|
|
126
|
+
playwright-report/
|
|
127
|
+
playwright/.cache/
|
|
128
|
+
|
|
129
|
+
# Lock files that shouldn't be committed for libraries
|
|
130
|
+
# (keep package-lock.json for applications)
|
|
131
|
+
# yarn.lock
|
|
132
|
+
# pnpm-lock.yaml*.tgz
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented here.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project
|
|
6
|
+
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
- Added FastAPI lifespan handling for SPAPS auth cleanup.
|
|
11
|
+
- Introduced migration guide and upgrading instructions for downstream services.
|
|
12
|
+
- Established comprehensive unit tests across settings, middleware, DB, Celery, and auth helpers.
|
|
13
|
+
|
|
14
|
+
## [0.0.1] - 2025-10-14
|
|
15
|
+
|
|
16
|
+
- Initial scaffold of `spaps-server-quickstart` with shared FastAPI/Celery/DB utilities.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: spaps-server-quickstart
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Shared FastAPI/Celery scaffolding for Sweet Potato service backends.
|
|
5
|
+
Project-URL: Repository, https://github.com/sweet-potato/spaps
|
|
6
|
+
Author-email: Sweet Potato Team <engineering@sweetpotato.dev>
|
|
7
|
+
License: Proprietary
|
|
8
|
+
Keywords: celery,fastapi,quickstart,spaps,sweet-potato
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Requires-Dist: alembic<2.0,>=1.13.1
|
|
11
|
+
Requires-Dist: asyncpg<0.31.0,>=0.30.0
|
|
12
|
+
Requires-Dist: celery<6.0,>=5.4.0
|
|
13
|
+
Requires-Dist: fastapi<0.119.0,>=0.115.0
|
|
14
|
+
Requires-Dist: httpx<0.29.0,>=0.27.0
|
|
15
|
+
Requires-Dist: pydantic-settings<3.0,>=2.3.0
|
|
16
|
+
Requires-Dist: pydantic<3.0,>=2.8.0
|
|
17
|
+
Requires-Dist: redis<6.0,>=5.0.0
|
|
18
|
+
Requires-Dist: spaps>=0.1.2
|
|
19
|
+
Requires-Dist: sqlalchemy<3.0,>=2.0.32
|
|
20
|
+
Requires-Dist: structlog<26.0,>=24.1.0
|
|
21
|
+
Requires-Dist: tenacity<9.0,>=8.3.0
|
|
22
|
+
Requires-Dist: uvicorn<0.38.0,>=0.29.0
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: anyio<5.0,>=4.4.0; extra == 'dev'
|
|
25
|
+
Requires-Dist: mypy<2.0,>=1.10.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest-asyncio<0.24.0,>=0.23.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest-cov<6.0,>=5.0.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest<9.0,>=8.3.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: ruff<1.0,>=0.5.5; extra == 'dev'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# SPAPS Server Quickstart
|
|
33
|
+
|
|
34
|
+
Reusable scaffolding for Sweet Potato service backends. This package gathers the FastAPI
|
|
35
|
+
application factory, Celery bootstrap, Pydantic settings base classes, and other utilities
|
|
36
|
+
that HTMA, Ingredient, and future services can share.
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
Use either Poetry (preferred inside this repo) or pip editable installs:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# with poetry
|
|
44
|
+
poetry install -C packages/python-server-quickstart
|
|
45
|
+
|
|
46
|
+
# or with pip (installs package + dev extras)
|
|
47
|
+
python3 -m pip install -e 'packages/python-server-quickstart[dev]'
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The editable install ensures FastAPI, SQLAlchemy, Celery, and other dependencies are
|
|
51
|
+
available when the pre-push scripts execute.
|
|
52
|
+
|
|
53
|
+
## Local Development
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
poetry run -C packages/python-server-quickstart pytest
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The shared modules are designed to be imported by individual service packages. Tests live
|
|
60
|
+
alongside the shared code to guard the common behaviour.
|
|
61
|
+
|
|
62
|
+
## Lifecycle Hooks
|
|
63
|
+
|
|
64
|
+
`create_app` now uses FastAPI's lifespan context to close shared resources (e.g., SPAPS auth
|
|
65
|
+
clients). When you need additional startup/shutdown logic, extend the lifespan in your service
|
|
66
|
+
by wrapping the provided app with your own context manager or closing resources within your
|
|
67
|
+
domain packages. Running tests with `TestClient(app)` will automatically exercise the shutdown
|
|
68
|
+
path and catch missing `aclose()` implementations.
|
|
69
|
+
|
|
70
|
+
## Upgrading Downstream Services
|
|
71
|
+
|
|
72
|
+
Guidance for publishing new versions and upgrading consumer services lives in
|
|
73
|
+
[`docs/UPGRADING.md`](docs/UPGRADING.md). Review those steps before bumping the package or
|
|
74
|
+
pulling a newer release into `htma_server`, `ingredient_server`, or other SPAPS services.
|
|
75
|
+
|
|
76
|
+
## Migrating an Existing Service
|
|
77
|
+
|
|
78
|
+
See [`docs/MIGRATION_GUIDE.md`](docs/MIGRATION_GUIDE.md) for a step-by-step walkthrough of
|
|
79
|
+
adopting the shared package inside an existing FastAPI/Celery service. It covers settings
|
|
80
|
+
integration, router wiring, database session management, Celery bootstraps, and the final
|
|
81
|
+
cleanup checklist.
|
|
82
|
+
|
|
83
|
+
## Release Workflow
|
|
84
|
+
|
|
85
|
+
- Use the GitHub Action **Publish Python Server Quickstart** (`.github/workflows/python-server-quickstart-release.yml`) to cut releases. It reuses the generic `python-package-release` workflow alongside `scripts/manage_python_package_version.py`.
|
|
86
|
+
- Ensure the repository secret `PYPI_SERVER_QUICKSTART_TOKEN` holds the PyPI API token for this package.
|
|
87
|
+
- 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.toml` will trigger the workflow.
|
|
88
|
+
|
|
89
|
+
## Status
|
|
90
|
+
|
|
91
|
+
- [x] Initial package scaffold
|
|
92
|
+
- [x] Shared application factories
|
|
93
|
+
- [x] Shared Celery bootstrap
|
|
94
|
+
- [x] Shared middleware, logging, and settings base classes
|
|
95
|
+
- [x] Health endpoint helpers
|
|
96
|
+
- [ ] Documentation and usage examples
|
|
97
|
+
|
|
98
|
+
## Repository Integration
|
|
99
|
+
|
|
100
|
+
The root `package.json` includes `lint:python-server-quickstart`, `typecheck:python-server-quickstart`,
|
|
101
|
+
and `test:python-server-quickstart` commands. These run automatically via `npm run prepush`, so make sure
|
|
102
|
+
the editable install step above has been executed before pushing commits.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# SPAPS Server Quickstart
|
|
2
|
+
|
|
3
|
+
Reusable scaffolding for Sweet Potato service backends. This package gathers the FastAPI
|
|
4
|
+
application factory, Celery bootstrap, Pydantic settings base classes, and other utilities
|
|
5
|
+
that HTMA, Ingredient, and future services can share.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Use either Poetry (preferred inside this repo) or pip editable installs:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# with poetry
|
|
13
|
+
poetry install -C packages/python-server-quickstart
|
|
14
|
+
|
|
15
|
+
# or with pip (installs package + dev extras)
|
|
16
|
+
python3 -m pip install -e 'packages/python-server-quickstart[dev]'
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The editable install ensures FastAPI, SQLAlchemy, Celery, and other dependencies are
|
|
20
|
+
available when the pre-push scripts execute.
|
|
21
|
+
|
|
22
|
+
## Local Development
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
poetry run -C packages/python-server-quickstart pytest
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The shared modules are designed to be imported by individual service packages. Tests live
|
|
29
|
+
alongside the shared code to guard the common behaviour.
|
|
30
|
+
|
|
31
|
+
## Lifecycle Hooks
|
|
32
|
+
|
|
33
|
+
`create_app` now uses FastAPI's lifespan context to close shared resources (e.g., SPAPS auth
|
|
34
|
+
clients). When you need additional startup/shutdown logic, extend the lifespan in your service
|
|
35
|
+
by wrapping the provided app with your own context manager or closing resources within your
|
|
36
|
+
domain packages. Running tests with `TestClient(app)` will automatically exercise the shutdown
|
|
37
|
+
path and catch missing `aclose()` implementations.
|
|
38
|
+
|
|
39
|
+
## Upgrading Downstream Services
|
|
40
|
+
|
|
41
|
+
Guidance for publishing new versions and upgrading consumer services lives in
|
|
42
|
+
[`docs/UPGRADING.md`](docs/UPGRADING.md). Review those steps before bumping the package or
|
|
43
|
+
pulling a newer release into `htma_server`, `ingredient_server`, or other SPAPS services.
|
|
44
|
+
|
|
45
|
+
## Migrating an Existing Service
|
|
46
|
+
|
|
47
|
+
See [`docs/MIGRATION_GUIDE.md`](docs/MIGRATION_GUIDE.md) for a step-by-step walkthrough of
|
|
48
|
+
adopting the shared package inside an existing FastAPI/Celery service. It covers settings
|
|
49
|
+
integration, router wiring, database session management, Celery bootstraps, and the final
|
|
50
|
+
cleanup checklist.
|
|
51
|
+
|
|
52
|
+
## Release Workflow
|
|
53
|
+
|
|
54
|
+
- Use the GitHub Action **Publish Python Server Quickstart** (`.github/workflows/python-server-quickstart-release.yml`) to cut releases. It reuses the generic `python-package-release` workflow alongside `scripts/manage_python_package_version.py`.
|
|
55
|
+
- Ensure the repository secret `PYPI_SERVER_QUICKSTART_TOKEN` holds the PyPI API token for this package.
|
|
56
|
+
- 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.toml` will trigger the workflow.
|
|
57
|
+
|
|
58
|
+
## Status
|
|
59
|
+
|
|
60
|
+
- [x] Initial package scaffold
|
|
61
|
+
- [x] Shared application factories
|
|
62
|
+
- [x] Shared Celery bootstrap
|
|
63
|
+
- [x] Shared middleware, logging, and settings base classes
|
|
64
|
+
- [x] Health endpoint helpers
|
|
65
|
+
- [ ] Documentation and usage examples
|
|
66
|
+
|
|
67
|
+
## Repository Integration
|
|
68
|
+
|
|
69
|
+
The root `package.json` includes `lint:python-server-quickstart`, `typecheck:python-server-quickstart`,
|
|
70
|
+
and `test:python-server-quickstart` commands. These run automatically via `npm run prepush`, so make sure
|
|
71
|
+
the editable install step above has been executed before pushing commits.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Migrating a Service to `spaps-server-quickstart`
|
|
2
|
+
|
|
3
|
+
This playbook describes the concrete steps for services like `htma_server` and
|
|
4
|
+
`ingredient_server` to replace local scaffolding with the shared package. Expect a
|
|
5
|
+
single PR per service.
|
|
6
|
+
|
|
7
|
+
## 1. Prepare the Service
|
|
8
|
+
|
|
9
|
+
1. **Pin the dependency**
|
|
10
|
+
- Add `spaps-server-quickstart = "^0.x"` to the service `pyproject.toml`.
|
|
11
|
+
- `poetry update spaps-server-quickstart` (or pip equivalent) and commit the lockfile.
|
|
12
|
+
2. **Install tooling**
|
|
13
|
+
- Ensure the editable install exists locally: `python3 -m pip install -e 'packages/python-server-quickstart[dev]'`.
|
|
14
|
+
- Run the shared package tests once: `npm run test:python-server-quickstart`.
|
|
15
|
+
|
|
16
|
+
## 2. Settings & Configuration
|
|
17
|
+
|
|
18
|
+
1. Replace the local `Settings` class with a subclass of `spaps_server_quickstart.settings.BaseServiceSettings`.
|
|
19
|
+
```python
|
|
20
|
+
from spaps_server_quickstart.settings import BaseServiceSettings, create_settings_loader
|
|
21
|
+
|
|
22
|
+
class Settings(BaseServiceSettings):
|
|
23
|
+
app_name: str = "HTMA Server"
|
|
24
|
+
service_slug: str = "htma-server"
|
|
25
|
+
database_url: str = "postgresql+asyncpg://.../htma"
|
|
26
|
+
# include service-specific fields (e.g., practitioners, ingredient keys)
|
|
27
|
+
|
|
28
|
+
get_settings = create_settings_loader(Settings)
|
|
29
|
+
```
|
|
30
|
+
2. Update imports wherever `Settings` or `get_settings` were used (app factory, dependencies, tasks).
|
|
31
|
+
|
|
32
|
+
## 3. FastAPI Application & Routers
|
|
33
|
+
|
|
34
|
+
1. Remove the local `create_app` factory and import the shared one:
|
|
35
|
+
```python
|
|
36
|
+
from spaps_server_quickstart.app_factory import create_app
|
|
37
|
+
from spaps_server_quickstart.api.router import build_base_router
|
|
38
|
+
from spaps_server_quickstart.api.health import HealthRouterFactory
|
|
39
|
+
```
|
|
40
|
+
2. Compose routers:
|
|
41
|
+
```python
|
|
42
|
+
settings_loader = get_settings
|
|
43
|
+
health_router = HealthRouterFactory(
|
|
44
|
+
settings_loader=settings_loader,
|
|
45
|
+
session_dependency=db_resources.session_dependency,
|
|
46
|
+
extra_metrics_provider=custom_metrics,
|
|
47
|
+
).create_router()
|
|
48
|
+
|
|
49
|
+
api_router = build_base_router(
|
|
50
|
+
health_router,
|
|
51
|
+
(practitioner_router, {"prefix": "/v1", "tags": ["practitioner"]}),
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
app = create_app(
|
|
55
|
+
settings_loader=settings_loader,
|
|
56
|
+
api_router=api_router,
|
|
57
|
+
enable_spaps_auth=True,
|
|
58
|
+
auth_exempt_paths={"/open-metrics"},
|
|
59
|
+
)
|
|
60
|
+
```
|
|
61
|
+
3. Delete redundant local modules (auth, middleware, logging) once replaced.
|
|
62
|
+
|
|
63
|
+
## 4. Database Integration
|
|
64
|
+
|
|
65
|
+
1. Instantiate shared DB resources in a new `core/db.py` or similar:
|
|
66
|
+
```python
|
|
67
|
+
from spaps_server_quickstart.db import DatabaseResources
|
|
68
|
+
|
|
69
|
+
db_resources = DatabaseResources(get_settings())
|
|
70
|
+
get_db_session = db_resources.session_dependency
|
|
71
|
+
```
|
|
72
|
+
2. Update dependencies in API modules (`Depends(get_db_session)`).
|
|
73
|
+
3. Ensure Alembic scripts reuse the shared naming validators if applicable.
|
|
74
|
+
|
|
75
|
+
## 5. Celery & Tasks
|
|
76
|
+
|
|
77
|
+
1. Replace the local `Celery` bootstrap with:
|
|
78
|
+
```python
|
|
79
|
+
from spaps_server_quickstart.tasks import create_celery_app
|
|
80
|
+
|
|
81
|
+
celery_app = create_celery_app(get_settings(), task_modules=["htma_server.tasks"])
|
|
82
|
+
```
|
|
83
|
+
2. Update shared tasks (`build_ping_task`, `build_notification_task`) or keep service-specific overrides as needed.
|
|
84
|
+
|
|
85
|
+
## 6. Test & Validate
|
|
86
|
+
|
|
87
|
+
1. Run unit/integration tests: `poetry run pytest`, `poetry run ruff`, `poetry run mypy`.
|
|
88
|
+
2. Run the root `npm run prepush` to cover shared checks.
|
|
89
|
+
3. Smoke test FastAPI and Celery locally if the service has start scripts.
|
|
90
|
+
|
|
91
|
+
## 7. Cleanup & Review
|
|
92
|
+
|
|
93
|
+
1. Remove unused files (duplicate middleware/auth/logging) and update service README docs to reference the shared package.
|
|
94
|
+
2. Ensure CI passes and request review. Highlight the dependency bump and key refactors in the PR summary.
|
|
95
|
+
|
|
96
|
+
## Appendix: Checklist
|
|
97
|
+
|
|
98
|
+
- [ ] `pyproject.toml` dependency updated and installed.
|
|
99
|
+
- [ ] Settings subclass uses `create_settings_loader`.
|
|
100
|
+
- [ ] FastAPI app uses shared `create_app` and router helpers.
|
|
101
|
+
- [ ] Database dependencies go through `DatabaseResources`.
|
|
102
|
+
- [ ] Celery uses `create_celery_app` with correct task module.
|
|
103
|
+
- [ ] Tests + prepush suite green.
|
|
104
|
+
- [ ] Redundant local scaffolding removed.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Upgrading Downstream Services
|
|
2
|
+
|
|
3
|
+
When `spaps-server-quickstart` publishes new releases, dependent services (e.g.
|
|
4
|
+
`htma_server`, `ingredient_server`) need a predictable upgrade cadence. Follow this
|
|
5
|
+
checklist whenever we cut a release or adopt a newer version downstream.
|
|
6
|
+
|
|
7
|
+
## For the Quickstart Maintainer (Publishing a Release)
|
|
8
|
+
|
|
9
|
+
1. **Triage changes** – confirm whether the release is a patch, minor, or major bump.
|
|
10
|
+
- Patch (x.y.Z) for bug fixes and strictly backwards-compatible tweaks.
|
|
11
|
+
- Minor (x.Y.0) for new features that keep existing APIs stable.
|
|
12
|
+
- Major (X.0.0) for breaking changes; document migration steps clearly.
|
|
13
|
+
2. **Update metadata**
|
|
14
|
+
- Bump `version` in `pyproject.toml`.
|
|
15
|
+
- Add release notes to `CHANGELOG.md` (include migration guidance for non-trivial upgrades).
|
|
16
|
+
3. **Run validation locally**
|
|
17
|
+
- `python3 -m pip install -e '.[dev]'`
|
|
18
|
+
- `python3 -m pytest -q`
|
|
19
|
+
- `python3 -m ruff check src tests`
|
|
20
|
+
- `python3 -m mypy src`
|
|
21
|
+
4. **Publish the package**
|
|
22
|
+
- `npm run build:python-client` is **not** required here; instead run:
|
|
23
|
+
```bash
|
|
24
|
+
cd packages/python-server-quickstart
|
|
25
|
+
python -m build
|
|
26
|
+
python -m twine upload dist/*
|
|
27
|
+
```
|
|
28
|
+
- If the package is private, upload to the internal index configured for SPAPS.
|
|
29
|
+
5. **Announce the release**
|
|
30
|
+
- Share the version, changelog highlights, and any upgrade notes in the engineering
|
|
31
|
+
channel or release tracker.
|
|
32
|
+
|
|
33
|
+
## For Downstream Services (Consuming a Release)
|
|
34
|
+
|
|
35
|
+
1. **Update dependencies**
|
|
36
|
+
- In the service `pyproject.toml`, bump the `spaps-server-quickstart` requirement.
|
|
37
|
+
- Run `poetry update spaps-server-quickstart` (or `pip-compile` if using pip-tools).
|
|
38
|
+
2. **Re-install local environment**
|
|
39
|
+
- `poetry install` (or `python3 -m pip install -e '.[dev]'`) to ensure the new version +
|
|
40
|
+
transitive deps are in the virtualenv.
|
|
41
|
+
3. **Run the validation stack**
|
|
42
|
+
- `npm run prepush` from repo root (covers lint, typecheck, pytest, docs health).
|
|
43
|
+
Minimum checks:
|
|
44
|
+
```bash
|
|
45
|
+
poetry run pytest
|
|
46
|
+
poetry run ruff check src tests
|
|
47
|
+
poetry run mypy src
|
|
48
|
+
poetry run python - <<'PY'
|
|
49
|
+
from spaps_server_quickstart.db import DatabaseResources
|
|
50
|
+
from <service>.core.settings import get_settings
|
|
51
|
+
|
|
52
|
+
resources = DatabaseResources(get_settings())
|
|
53
|
+
assert resources.get_session_factory()
|
|
54
|
+
PY
|
|
55
|
+
```
|
|
56
|
+
- If the service uses Docker images, rebuild them locally to catch runtime regressions.
|
|
57
|
+
4. **Exercise lifecycles**
|
|
58
|
+
- Confirm the FastAPI app starts and shuts down cleanly (`uvicorn`, `pytest` with `TestClient`).
|
|
59
|
+
- Verify Celery workers boot and call `create_celery_app(settings, task_modules=["<service>.tasks"])`.
|
|
60
|
+
5. **Merge and deploy**
|
|
61
|
+
- Once CI is green, merge the dependency bump PR.
|
|
62
|
+
- Roll out through the standard deployment pipeline (staging → production) while watching
|
|
63
|
+
health checks. The shared `HealthRouterFactory` will surface database readiness issues.
|
|
64
|
+
|
|
65
|
+
## Handling Breaking Changes
|
|
66
|
+
|
|
67
|
+
- **Major releases** should ship with migration utilities or example diffs in
|
|
68
|
+
`docs/UPGRADING.md`.
|
|
69
|
+
- If removing or renaming APIs, deprecate in one release cycle first (log a warning),
|
|
70
|
+
then remove in the next major version.
|
|
71
|
+
- Add integration tests in both the quickstart package and dependent services to guard
|
|
72
|
+
behaviour that might regress.
|
|
73
|
+
|
|
74
|
+
## Version Pinning Guidelines
|
|
75
|
+
|
|
76
|
+
- Each service should pin `spaps-server-quickstart` to a compatible minor range,
|
|
77
|
+
e.g. `^0.2.0`.
|
|
78
|
+
- Avoid `*` or wide specifiers. This prevents surprise upgrades when publishing other packages.
|
|
79
|
+
- For hotfixes, release a patch version and bump immediately downstream.
|
|
80
|
+
|
|
81
|
+
By following this flow, the quickstart can evolve confidently while keeping HTMA, Ingredient,
|
|
82
|
+
and future services stable.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.24.0"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "spaps-server-quickstart"
|
|
7
|
+
version = "0.0.1"
|
|
8
|
+
description = "Shared FastAPI/Celery scaffolding for Sweet Potato service backends."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "Proprietary" }
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Sweet Potato Team", email = "engineering@sweetpotato.dev" }
|
|
14
|
+
]
|
|
15
|
+
keywords = ["sweet-potato", "fastapi", "celery", "quickstart", "spaps"]
|
|
16
|
+
dependencies = [
|
|
17
|
+
"fastapi>=0.115.0,<0.119.0",
|
|
18
|
+
"sqlalchemy>=2.0.32,<3.0",
|
|
19
|
+
"asyncpg>=0.30.0,<0.31.0",
|
|
20
|
+
"pydantic>=2.8.0,<3.0",
|
|
21
|
+
"pydantic-settings>=2.3.0,<3.0",
|
|
22
|
+
"structlog>=24.1.0,<26.0",
|
|
23
|
+
"alembic>=1.13.1,<2.0",
|
|
24
|
+
"celery>=5.4.0,<6.0",
|
|
25
|
+
"redis>=5.0.0,<6.0",
|
|
26
|
+
"uvicorn>=0.29.0,<0.38.0",
|
|
27
|
+
"httpx>=0.27.0,<0.29.0",
|
|
28
|
+
"tenacity>=8.3.0,<9.0",
|
|
29
|
+
"spaps>=0.1.2",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.optional-dependencies]
|
|
33
|
+
dev = [
|
|
34
|
+
"pytest>=8.3.0,<9.0",
|
|
35
|
+
"pytest-asyncio>=0.23.0,<0.24.0",
|
|
36
|
+
"pytest-cov>=5.0.0,<6.0",
|
|
37
|
+
"mypy>=1.10.0,<2.0",
|
|
38
|
+
"ruff>=0.5.5,<1.0",
|
|
39
|
+
"anyio>=4.4.0,<5.0",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[project.urls]
|
|
43
|
+
Repository = "https://github.com/sweet-potato/spaps"
|
|
44
|
+
|
|
45
|
+
[tool.hatch.build.targets.wheel]
|
|
46
|
+
packages = ["src/spaps_server_quickstart"]
|
|
47
|
+
|
|
48
|
+
[tool.pytest.ini_options]
|
|
49
|
+
asyncio_mode = "auto"
|
|
50
|
+
addopts = "--cov=spaps_server_quickstart --cov-report=term-missing"
|
|
51
|
+
testpaths = ["tests"]
|
|
52
|
+
|
|
53
|
+
[tool.ruff]
|
|
54
|
+
line-length = 100
|
|
55
|
+
target-version = "py310"
|
|
56
|
+
src = ["src"]
|
|
57
|
+
|
|
58
|
+
[tool.mypy]
|
|
59
|
+
python_version = "3.10"
|
|
60
|
+
packages = ["spaps_server_quickstart"]
|
|
61
|
+
strict_optional = true
|
|
62
|
+
ignore_missing_imports = true
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
PROJECT_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
|
|
5
|
+
|
|
6
|
+
echo "==> Running test suite"
|
|
7
|
+
PYTHONPATH="$PROJECT_ROOT/src" python3 -m pytest -q
|
|
8
|
+
|
|
9
|
+
echo "==> Linting"
|
|
10
|
+
python3 -m ruff check "$PROJECT_ROOT/src" "$PROJECT_ROOT/tests"
|
|
11
|
+
|
|
12
|
+
echo "==> Type checking"
|
|
13
|
+
python3 -m mypy "$PROJECT_ROOT/src"
|
|
14
|
+
|
|
15
|
+
echo "==> Building distribution"
|
|
16
|
+
cd "$PROJECT_ROOT"
|
|
17
|
+
rm -rf dist
|
|
18
|
+
python3 -m build
|
|
19
|
+
|
|
20
|
+
echo "==> Uploading via twine"
|
|
21
|
+
python3 -m twine upload dist/*
|
|
22
|
+
|
|
23
|
+
echo "Release complete."
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Shared service scaffolding for Sweet Potato backend applications.
|
|
3
|
+
|
|
4
|
+
The package gathers reusable FastAPI, Celery, settings, database, logging, and
|
|
5
|
+
authentication helpers that individual services (HTMA, Ingredient, etc.) can consume.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .alembic import allowed_domains, collect_directory_errors, ensure_known_domain, slugify_title, validate_migration_filename
|
|
9
|
+
from .app_factory import create_app
|
|
10
|
+
from .auth import (
|
|
11
|
+
AuthenticationError,
|
|
12
|
+
AuthenticatedUser,
|
|
13
|
+
SpapsAuthMiddleware,
|
|
14
|
+
SpapsAuthService,
|
|
15
|
+
build_spaps_auth_service,
|
|
16
|
+
)
|
|
17
|
+
from .api.health import HealthRouterFactory
|
|
18
|
+
from .api.router import build_base_router
|
|
19
|
+
from .db import (
|
|
20
|
+
AlembicMigrationRunner,
|
|
21
|
+
DatabaseResources,
|
|
22
|
+
create_async_sessionmaker,
|
|
23
|
+
create_migration_runner,
|
|
24
|
+
session_dependency_factory,
|
|
25
|
+
)
|
|
26
|
+
from .logging import configure_logging
|
|
27
|
+
from .middleware import RequestLoggingMiddleware
|
|
28
|
+
from .schemas import HealthResponse
|
|
29
|
+
from .settings import BaseServiceSettings, create_settings_loader, get_settings
|
|
30
|
+
from .tasks import create_celery_app, build_notification_task, build_ping_task
|
|
31
|
+
|
|
32
|
+
__version__ = "0.0.1"
|
|
33
|
+
|
|
34
|
+
__all__ = [
|
|
35
|
+
"create_app",
|
|
36
|
+
"BaseServiceSettings",
|
|
37
|
+
"create_settings_loader",
|
|
38
|
+
"get_settings",
|
|
39
|
+
"configure_logging",
|
|
40
|
+
"RequestLoggingMiddleware",
|
|
41
|
+
"AuthenticationError",
|
|
42
|
+
"AuthenticatedUser",
|
|
43
|
+
"SpapsAuthService",
|
|
44
|
+
"SpapsAuthMiddleware",
|
|
45
|
+
"build_spaps_auth_service",
|
|
46
|
+
"HealthRouterFactory",
|
|
47
|
+
"HealthResponse",
|
|
48
|
+
"build_base_router",
|
|
49
|
+
"DatabaseResources",
|
|
50
|
+
"create_async_sessionmaker",
|
|
51
|
+
"session_dependency_factory",
|
|
52
|
+
"AlembicMigrationRunner",
|
|
53
|
+
"create_migration_runner",
|
|
54
|
+
"create_celery_app",
|
|
55
|
+
"build_ping_task",
|
|
56
|
+
"build_notification_task",
|
|
57
|
+
"validate_migration_filename",
|
|
58
|
+
"collect_directory_errors",
|
|
59
|
+
"ensure_known_domain",
|
|
60
|
+
"allowed_domains",
|
|
61
|
+
"slugify_title",
|
|
62
|
+
"__version__",
|
|
63
|
+
]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Alembic helpers for naming conventions and migration utilities.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .naming import (
|
|
6
|
+
allowed_domains,
|
|
7
|
+
build_revision_message,
|
|
8
|
+
collect_directory_errors,
|
|
9
|
+
ensure_known_domain,
|
|
10
|
+
slugify_title,
|
|
11
|
+
validate_migration_filename,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"validate_migration_filename",
|
|
16
|
+
"collect_directory_errors",
|
|
17
|
+
"ensure_known_domain",
|
|
18
|
+
"allowed_domains",
|
|
19
|
+
"slugify_title",
|
|
20
|
+
"build_revision_message",
|
|
21
|
+
]
|