- server/: FastAPI app with SQLAlchemy models for sops, work_packages, comments - Endpoints for SOP/WP upsert+list+get+delete and comment create+list; /api/feedback kept as an alias so the existing client keeps working - Portable across engines (PostgreSQL prod, SQLite dev fallback) - requirements.txt, .env.example, and server/README.md (Postgres + systemd) - NGINX now proxies /api/ to the API (replaces the Power Automate hop; comments persist to SQL) - Rewrite DEPLOYMENT.md for the API + database architecture - Add .gitignore for venv/.env/sqlite Phase 2 (wire the client apps to the API) is next. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Work Package Suite API
A small Python (FastAPI) service that stores project SOPs, Work Packages,
and comments in PostgreSQL. NGINX serves the static site and proxies /api/
to this service.
browser → NGINX ──serves──> static site (index.html, …)
└─proxy /api/─> this API (uvicorn/gunicorn :8000) → PostgreSQL
Endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /api/health |
liveness check |
| POST | /api/sops |
create/update a SOP (upsert by id) |
| GET | /api/sops |
list SOP summaries |
| GET | /api/sops/latest?complete=true |
most recent (complete) SOP |
| GET | /api/sops/{id} |
full SOP document |
| DELETE | /api/sops/{id} |
delete a SOP |
| POST | /api/wps |
create/update a Work Package (upsert by id) |
| GET | /api/wps?sop_id=… |
list WPs (optionally for one SOP) |
| GET | /api/wps/{id} |
full WP document |
| DELETE | /api/wps/{id} |
delete a WP |
| POST | /api/comments (and /api/feedback) |
add a comment |
| GET | /api/comments?source=&sop_id=&wp_id=&step= |
list comments |
Interactive docs once running: /api/docs.
The full client document is stored in each row's data (JSON) column; common
fields (name, number, status, …) are promoted to columns for listing/filtering.
Local dev
cd server
python -m venv .venv && . .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
# No DATABASE_URL → uses a local sqlite file, so you can start immediately:
uvicorn server.app:app --reload --port 8000 # run from the PROJECT ROOT
Then open http://localhost:8000/api/docs.
Run uvicorn/gunicorn from the project root (the folder that contains the
server/directory), because the import path isserver.app:app.
PostgreSQL setup (production)
CREATE DATABASE wpsuite;
CREATE USER wpsuite WITH PASSWORD 'CHANGE_ME';
GRANT ALL PRIVILEGES ON DATABASE wpsuite TO wpsuite;
Tables are created automatically on first startup. (For future schema changes, introduce Alembic migrations rather than editing tables by hand.)
Run in production (gunicorn + systemd)
/etc/systemd/system/wp-suite-api.service:
[Unit]
Description=Work Package Suite API
After=network.target
[Service]
User=www-data
WorkingDirectory=/opt/wp-suite
Environment="DATABASE_URL=postgresql+psycopg://wpsuite:CHANGE_ME@localhost:5432/wpsuite"
ExecStart=/opt/wp-suite/.venv/bin/gunicorn -k uvicorn.workers.UvicornWorker -b 127.0.0.1:8000 server.app:app
Restart=always
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now wp-suite-api
NGINX already proxies /api/ to 127.0.0.1:8000 (see nginx-wp-suite.conf).
Quick test
curl -X POST http://127.0.0.1:8000/api/comments \
-H 'Content-Type: application/json' \
-d '{"type":"home_feedback","name":"Test","text":"hello"}'
curl http://127.0.0.1:8000/api/comments