- 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>
94 lines
2.9 KiB
Markdown
94 lines
2.9 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
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 is `server.app:app`.
|
|
|
|
## PostgreSQL setup (production)
|
|
|
|
```sql
|
|
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`:
|
|
|
|
```ini
|
|
[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
|
|
```
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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
|
|
```
|