This note captures the current state of the GP Booking App project and the SIAAS infrastructure model, as understood from:
wiki.veripath.co.uk/en/infrastructure/SIAAS/client_vps_setup/home/matthew/Projects/gp_booking_app/home/matthew/Documents/Obsidian_Vault/The SIAAS (Secure Infrastructure as a Service) model provisions isolated client VPS instances with zero public exposure:
┌──────────────────────────────┐ WireGuard Tunnel ┌──────────────────────────────┐
│ Primary Infrastructure │◄─────────────────────────────►│ Client VPS (Isolated) │
│ VPS (veripath.co.uk) │ 10.0.0.1 ◄────────► 10.0.0.x│ │
│ │ │ ┌────────────────────────┐ │
│ ┌────────────────────────┐ │ │ │ PostgreSQL 16 │ │
│ │ GP Booking App │ │ │ │ (bind: wg0 only) │ │
│ │ Patient Portal │ │ │ └────────────────────────┘ │
│ │ OpenCode Agent │ │ │ │
│ └────────────────────────┘ │ │ ┌────────────────────────┐ │
│ │ │ │ UFW: DENY all public │ │
│ ┌────────────────────────┐ │ │ │ ALLOW: SSH from CIO │ │
│ │ Security Dashboard │ │ │ │ ALLOW: DB on wg0 only │ │
│ └────────────────────────┘ │ │ └────────────────────────┘ │
└──────────────────────────────┘ └──────────────────────────────┘
| Principle | Detail |
|---|---|
| No public ports | Client VPS has zero public-facing ports except SSH (locked to client office IP) |
| Tunnel-only DB | Database listens only on WireGuard interface (wg0) |
| Client holds keys | Client holds root SSH keys and client_db_admin credentials — we hold neither |
| Restricted app user | App connects via fh_app_user (SELECT/INSERT/UPDATE/DELETE only, no DDL) over tunnel |
| Kill-switch | Client can run sudo systemctl stop wg-quick@wg0 to sever our access instantly |
apt update && apt upgrade -y)wg0.conf)fh_app_user — restricted, tunnel-only)client_db_admin — full DB privileges)Server-side (Primary VPS):
[Interface]
Address = 10.0.0.1/24
PrivateKey = <primary-private-key>
ListenPort = 51820
[Peer]
# Client VPS
PublicKey = <client-public-key>
AllowedIPs = 10.0.0.x/32
Client-side:
[Interface]
Address = 10.0.0.x/24
PrivateKey = <client-private-key>
[Peer]
# Primary VPS
PublicKey = <primary-public-key>
Endpoint = <primary-public-ip>:51820
AllowedIPs = 10.0.0.0/24
PersistentKeepalive = 25
Key design: Client VPS initiates the outbound connection — no public ports needed on client side for the tunnel.
listen_addresses = '10.0.0.x' (client's tunnel IP only)fh_app_user — GRANT CONNECT, SELECT, INSERT, UPDATE, DELETE on all tablesclient_db_admin — GRANT ALL PRIVILEGES with default privileges| Layer | Measure |
|---|---|
| UFW | Default deny incoming; SSH from client office IP only; DB access via tunnel only (implicit via bind-address) |
| SSH | Non-default port; PermitRootLogin prohibit-password; PasswordAuthentication no; PubkeyAuthentication yes; AllowUsers clientadmin |
| Key handover | Temporary SSH key deployed during provisioning; client replaces with their own key; deployment key deleted |
/opt/backup-client.pypg_dump --clean) — 14-day retention in /var/backups/practice/daily/dpkg -l) — 14-day retentionWhen a new client VPS is ready, provide:
client_db_admin user/password) for data migrationsudo systemctl stop wg-quick@wg0https://gp.veripath.co.uk/integrations/infrastructure//etc/cron.d/backup-health| Component | Version/Detail |
|---|---|
| Python | 3.11 |
| Django | 5.2.12 |
| Database | PostgreSQL 15 (local Docker), PostgreSQL 16 (VPS/SIAAS model) |
| ORM Encryption | django-encrypted-model-fields 0.6.5 |
| REST Framework | djangorestframework 3.16.1 |
| Auth | Session + Token auth; Keycloak/OIDC planned |
| Containerization | Docker Compose (Postgres + Django/Gunicorn + Nginx) |
| Gunicorn | 22.0.0, 3 workers |
| Nginx | 1.25, SSL termination with security headers |
| PostgreSQL SSL | Enabled via snakeoil certs |
| App | Purpose | Key Models |
|---|---|---|
users |
Custom user with 5 roles, encrypted PII fields | CustomUser |
appointments |
Appointment booking & configuration | Appointment, AppointmentType, ProviderSession, BookingConfig |
clinical_data |
Clinical notes, prescriptions, EPS | ClinicalNote, Prescription, PatientHealthProfile |
slot_management |
Clinic slots & templates | Clinic, SlotTemplate |
pcn_booking |
PCN cross-booking | PCNClinic |
onboarding |
Staff onboarding, JML, IAR, ROPA | ICB, Practice, StaffRoleRecord, Invitation, InformationAssetRegister, RecordOfProcessingActivity |
staff_management |
Staff lifecycle management | LeaveRequest, PracticeTeam, TeamMembership |
auditing |
Immutable audit logging | AuditLog |
reporting |
ICB contracts, CQC analytics | ICBContract, CQCAnalyticsCache, ComplianceActivity |
dashboards |
7 role-based dashboards | Dashboard, DashboardPermission, FormalRole, UserRole |
notifications |
Appointment reminders | ReminderLog |
clinical_safety |
DCB0129 Hazard Log | HazardLog |
integrations |
NHS/email config | NHSIntegrationConfig, EmailIntegrationConfig |
core |
Middleware, permissions, mixins | (No models) |
pcn_booking |
PCN cross-booking | PCNClinic |
| Integration | Status | Endpoint |
|---|---|---|
| GP Connect | Sandbox | https://sandbox.api.service.nhs.uk |
| PDS | Sandbox | https://sandbox.api.service.nhs.uk |
| EPS | Mock mode (USE_MOCK_EPS=True) |
FHIR prescribing + tracking paths |
| NHS OAuth2 | Configured | JWT-signed authentication |
| NHS Notify | Configured | Appointment reminders (SMS/Email) |
| Feature | Status |
|---|---|
| RBAC middleware | ✅ core.middleware.RBACMiddleware (global URL-prefix to role mapping) |
| View-level permissions | ✅ core.permissions.*, dashboards.mixins.* |
| DRF permission classes | ✅ Per-API-endpoint |
| PII encryption at rest | ✅ django-encrypted-model-fields |
| Audit logging | ✅ AuditLog model (CREATE, UPDATE, DELETE, VIEW, LOGIN, GP_CONNECT) |
| Docker containerization | ✅ |
| SSL/TLS (Postgres + Nginx) | ✅ |
| HTTP security headers | ✅ HSTS, CSP, X-Frame-Options, X-Content-Type-Options |
| Staff JML lifecycle | ✅ Starters/Movers/Leavers via StaffRoleRecord |
| IAR / ROPA / Retention | ✅ Complete |
| CQC compliance analytics | ✅ |
| Dependency scanning | ✅ pip-audit configured |
| MFA | ⏳ Planned |
| CIS2/Spine integration | ⏳ Planned |
| Container | Status | Port |
|---|---|---|
gp_booking_postgres |
✅ Up | 5433→5432 |
gp_booking_app |
❌ Exit 255 | — |
gp_booking_nginx |
❌ Exit 255 | — |
forgejo |
✅ Up | 3001→3000, 2222→22 |
open-webui |
✅ Up (healthy) | 3000→8080 |
maingp_app/main (21 commits ahead)60b9835 Update_10_04_26templates/registration/login.html + 6 new password reset template filesThe VPS is 21 commits ahead, suggesting significant development work. Based on the project structure and recent updates, likely VPS changes include:
gp_app/main (21 commits ahead)ALLOWED_HOSTS, NHS API keys, etc.gp_app/main to get the 21 commits.env, settings.py, templates).env with VPS environment variables (different NHS API keys, hosts, etc.)gp_booking_app and gp_booking_nginx containers are Exit 255 — need startup diagnosisgp_app/main — need to pull and mergeThe Wiki.js instance at wiki.veripath.co.uk serves as the auditor/client-facing knowledge base. The DSPT Standard 4 page records:
"Wiki.js KB: OpenCode (AI Assistant) has Full Read/Write: All pages via Bearer API Token"
Current Wiki.js structure includes:
Note: There is no
/development/section yet in Wiki.js. This page serves as the content for that new section.
These are the specific data points and actions needed from the VPS to unblock the local sync. Run each command and return the output.
git push gp_app main
Why: The local machine is 21 commits behind
gp_app/main. I need those commits available to fetch and merge.
git log --oneline -25
Why: I need to see what changed — new apps? migration files? config changes? template updates? This tells me what to expect when merging.
.env file (sanitised)cat /path/to/gp_booking_app/.env
Why: I need to compare VPS environment variables against the local
.envto spot differences inALLOWED_HOSTS, NHS API keys/endpoints, database credentials, and any new env vars that were added.
⚠️ Security: Review the output before sharing — redact any secrets you wouldn't normally commit. I mainly need to see the keys and structure (which vars exist, their format).
python manage.py showmigrations
Why: I need to know which migrations are applied on the VPS so the local database schema can be brought into alignment.
The local gp_booking_app and gp_booking_nginx containers are in Exit 255. If the VPS is running the same Docker Compose setup, grab the logs:
docker logs gp_booking_app --tail 100
docker logs gp_booking_nginx --tail 100
docker-compose logs app --tail 50
docker-compose logs nginx --tail 50
Why: The startup failure logs will tell me what's broken locally — missing env vars, Python import errors, database connection failures, port conflicts, etc.
The DSPT Standard 4 page records: "Wiki.js KB: OpenCode (AI Assistant) has Full Read/Write: All pages via Bearer API Token"
I need to know:
# How is the Wiki.js API token stored?
# Options to check: Docker secrets, environment variable, file on disk
# Try:
echo $WIKIJS_API_TOKEN # env var?
docker secret ls # Docker secret?
ls -la /path/to/wikijs/.env # config file?
Specific questions for you to answer:
- Where is the Wiki.js Bearer API Token stored? (env var, Docker secret, file?)
- What is the Wiki.js GraphQL endpoint URL? (typically
https://wiki.veripath.co.uk/graphql)- Does the token have permission to create pages under a
/development/path?- What is the Wiki.js API token value (or the env var name that holds it)?
Why: Once I have this, I can write pages directly into Wiki.js from this local machine, keeping the knowledge base in sync without manual steps.
pwd # confirm current working directory
ls -la # confirm project structure matches
git remote -v # confirm git remotes
Why: I need to confirm the VPS project lives at the same relative path as locally, so file references between environments are consistent.
| # | Task | Command | Purpose |
|---|---|---|---|
| 1 | Push commits | git push gp_app main |
Make VPS changes available locally |
| 2 | Show log | git log --oneline -25 |
Reveal what changed |
| 3 | Export env | cat .env |
Compare environment configs |
| 4 | Migrations | python manage.py showmigrations |
Align database schemas |
| 5 | Docker logs | docker logs gp_booking_app --tail 100 |
Diagnose Exit 255 failures |
| 6 | Wiki.js token | Find the Bearer API Token | Enable direct Wiki.js write access |
| 7 | Confirm path | pwd && git remote -v |
Ensure consistent project layout |
Local reference paths (for context):
/home/matthew/Projects/gp_booking_app//home/matthew/Documents/Obsidian_Vault//home/matthew/Documents/Obsidian_Vault/development/001_gp_app_vps_sync_analysis.mdhttps://wiki.veripath.co.uk/gp_app/main