Monorepo: Gitea CI, docs, auth/sync, backend APIs, gitignore
- Add Gitea Actions workflow; point README to gitea.d-bis.org/Sankofa_Phoenix/SMOA - Expand .gitignore for Spring H2 data, secrets, Kotlin .kotlin/, tooling - Track docs/api/generated ReDoc bundle; refresh api docs README - Android: network/auth/sync, UI shell, tests; backend credentials/integrity APIs - Docs, scripts (generate-api-docs), modules and core updates Made-with: Cursor
This commit is contained in:
@@ -45,10 +45,10 @@ The backend implements the **sync contract** expected by the mobile app (POST sy
|
||||
- **Gap:** Backend returns remoteData as base64; client must decode.
|
||||
- **Done:** Documented in OpenAPI description that remoteData is base64-encoded JSON when conflict=true.
|
||||
|
||||
### 5. **Production and ops**
|
||||
### 5. **Production and ops** ✅ Done (baseline)
|
||||
|
||||
- **Gap:** H2 console enabled in all profiles; no explicit prod profile with console off and stricter settings.
|
||||
- **Recommendation:** Add application-prod.yml: disable H2 console, set logging, optionally require API key. Document PostgreSQL (or other DB) and env vars.
|
||||
- **Done:** `application-prod.yml` disables H2 console, sets `ddl-auto: validate`, Flyway on, stricter logging.
|
||||
- **Done:** `org.postgresql:postgresql` on the runtime classpath; set `SPRING_DATASOURCE_*` (see `application-prod.yml` and backend README) for PostgreSQL. Dev/test keep H2 unless overridden.
|
||||
|
||||
### 6. **Rate limiting** ✅ Done
|
||||
|
||||
@@ -63,7 +63,7 @@ The backend implements the **sync contract** expected by the mobile app (POST sy
|
||||
### 8. **Tests** ✅ Done
|
||||
|
||||
- **Gap:** No backend unit or integration tests.
|
||||
- **Done:** DirectorySyncServiceTest (create, conflict/remoteData, delete); GlobalExceptionHandlerTest (500); SyncControllerIntegrationTest (POST valid/invalid, health); application-test.yml (H2 in-memory, rate limit off); mockk for unit tests.
|
||||
- **Done:** DirectorySyncServiceTest (create, conflict/remoteData, delete); GlobalExceptionHandlerTest (500); SyncControllerIntegrationTest (directory, credential type validation, health); application-test.yml (H2 in-memory, rate limit off); mockk for unit tests.
|
||||
|
||||
### 9. **Ids and authorization**
|
||||
|
||||
@@ -79,10 +79,11 @@ The backend implements the **sync contract** expected by the mobile app (POST sy
|
||||
|
||||
## Optional improvements
|
||||
|
||||
- **Pagination:** For any future GET list endpoints, use page/size or limit/offset and document in OpenAPI.
|
||||
- **ETag / If-None-Match:** For GET-by-id or list endpoints, support caching with ETag.
|
||||
- **Request ID:** Add a filter to assign and log a request ID for tracing.
|
||||
- **Pagination:** Pull endpoints use `limit`/`since`; extend with cursor or page/size if lists grow very large.
|
||||
- **ETag / If-None-Match:** ✅ `ShallowEtagHeaderFilter` on `/api/v1/**` (see `WebConfig`).
|
||||
- **Request ID:** ✅ `RequestIdFilter` assigns/propagates `X-Request-Id`.
|
||||
- **API versioning:** Keep /api/v1; when introducing breaking changes, add /api/v2 and document deprecation.
|
||||
- **Credential types:** ✅ `@Pattern` on `CredentialSyncRequest.credentialType` (`SmoaCredentialType.CREDENTIAL_TYPE_PATTERN`).
|
||||
|
||||
---
|
||||
|
||||
@@ -102,4 +103,4 @@ The backend implements the **sync contract** expected by the mobile app (POST sy
|
||||
|
||||
## Summary
|
||||
|
||||
The backend is **ready for mobile sync** with: push and **delete** sync, **pull/GET** endpoints, **conflict handling**, **enum validation**, **rate limiting**, **audit logging**, **tests**, and a **Dockerfile**. Remaining optional work: **prod profile and DB** (PostgreSQL, H2 console off), **unit/tenant scoping** (filter by unit from API key or header), and **migrations** (Flyway/Liquibase with ddl-auto: validate).
|
||||
The backend is **ready for mobile sync** with: push and **delete** sync, **pull/GET** endpoints (with **ETag**), **conflict handling**, **enum validation** (including **credential types**), **rate limiting**, **audit logging**, **request IDs**, **tests**, **Dockerfile**, **prod profile**, **PostgreSQL driver**, and **Flyway** with `ddl-auto: validate` in prod. Remaining: **strong tenant isolation** (per-tenant credentials, RLS, or JWT claims) — see `docs/security/TENANT-THREAT-MODEL.md`.
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
# Proxmox LXC layout for SMOA backend and client endpoint mapping
|
||||
|
||||
This document describes **Linux containers (LXC)** on a **Proxmox VE guest VM** used to host all SMOA backend-related components, how **FQDNs** map to those services, and a **JSON contract** operators can use as the canonical list of endpoints and settings for client builds or a future runtime bootstrap.
|
||||
|
||||
For **hardware sizing** of the same components (VM-level), see [../../docs/infrastructure/PROXMOX-VE-TEMPLATE-REQUIREMENTS.md](../../docs/infrastructure/PROXMOX-VE-TEMPLATE-REQUIREMENTS.md). For API behavior, see [../README.md](../README.md).
|
||||
|
||||
---
|
||||
|
||||
## 1. Design goals
|
||||
|
||||
- **Isolation:** Separate OS instances for edge (TLS, static files), API (Spring Boot), and database (PostgreSQL).
|
||||
- **Clear DNS:** One stable FQDN per outward-facing role; internal-only names for DB and API when the edge reverse-proxies to them.
|
||||
- **Client contract:** A single JSON document per environment (e.g. production, staging) that lists base URLs and optional WebRTC-related settings, aligned with Android `BuildConfig` fields today (`SMOA_BACKEND_BASE_URL`, `SMOA_API_KEY`, `SMOA_STUN_URLS`, `SMOA_SIGNALING_URLS`).
|
||||
|
||||
---
|
||||
|
||||
## 2. Recommended LXC inventory
|
||||
|
||||
Run these on a single Proxmox **VM** (the “infrastructure VM”) or spread across multiple VMs if you need stronger isolation. Each row is one **unprivileged LXC** (recommended) on Debian 12 or Ubuntu 22.04 LTS templates.
|
||||
|
||||
| CT ID (example) | Hostname (internal) | Role | Outward FQDN (example) | Listens (internal) | Notes |
|
||||
|-----------------|---------------------|------|-------------------------|---------------------|--------|
|
||||
| **100** | `smoa-edge` | Reverse proxy + TLS + config CDN | `api.smoa.example.gov` (API), `config.smoa.example.gov` (JSON) | `443` (public), upstream to API | Nginx, Caddy, or Traefik; terminates TLS; serves `/.well-known/` or `/smoa/` static JSON. |
|
||||
| **101** | `smoa-api` | Spring Boot `smoa-backend` | (none public; only via edge) | `8080` → proxy to `http://smoa-api.lan:8080` | `SPRING_PROFILES_ACTIVE=prod`, `SMOA_API_KEY`, JDBC URL to DB container. |
|
||||
| **102** | `smoa-db` | PostgreSQL 15+ | (none public) | `5432` (LAN only) | Database for production; Flyway migrations from the backend JAR. |
|
||||
| **103** | `smoa-turn` | Coturn or equivalent TURN | `turn.smoa.example.gov` | `3478` (UDP/TCP), TLS if used | Optional; for WebRTC media relay when not using a third-party TURN. |
|
||||
| **104** | `smoa-signal` | Signaling server (if self-hosted) | `signal.smoa.example.gov` | `443` or app-specific | Optional; only if you host signaling instead of a SaaS or peer mesh. |
|
||||
|
||||
**Minimal production set:** **100 (edge)**, **101 (api)**, **102 (db)**. Add **103/104** when meetings/WebRTC are anchored to your infra.
|
||||
|
||||
**Small lab / pilot:** One LXC running API + PostgreSQL + Nginx (all-in-one) is acceptable; split into the table above before production traffic or compliance review.
|
||||
|
||||
---
|
||||
|
||||
## 3. Resource hints per container
|
||||
|
||||
| Container | vCPU | RAM | Root disk | Data volume |
|
||||
|-----------|------|-----|-----------|-------------|
|
||||
| `smoa-edge` | 1 | 512 MiB–1 GiB | 8–16 GiB | Optional: ACME cert store, access logs |
|
||||
| `smoa-api` | 2–4 | 2–4 GiB | 16 GiB | Optional: app logs if not shipped to syslog |
|
||||
| `smoa-db` | 2 | 2–4 GiB | 16 GiB | **Dedicated:** PostgreSQL data (SSD-backed) |
|
||||
| `smoa-turn` | 2–4 | 1–2 GiB | 10 GiB | Logs; sizing scales with concurrent sessions |
|
||||
| `smoa-signal` | 1–2 | 1–2 GiB | 10 GiB | App-specific |
|
||||
|
||||
Tune using [PROXMOX-VE-TEMPLATE-REQUIREMENTS.md](../../docs/infrastructure/PROXMOX-VE-TEMPLATE-REQUIREMENTS.md).
|
||||
|
||||
---
|
||||
|
||||
## 4. Networking on Proxmox
|
||||
|
||||
1. **Bridge:** Attach all LXCs to the same VM bridge (e.g. `vmbr0` inside the guest, or a Proxmox bridge on the host with a VLAN per tenant).
|
||||
2. **DNS (internal):** Resolve `smoa-api.lan`, `smoa-db.lan` (or your internal suffix) to static LXC IPs. The edge proxies to `http://smoa-api.lan:8080` only from the edge host.
|
||||
3. **Firewall:** From the internet, allow **443** (and **3478** if TURN is public). **Do not** publish PostgreSQL or raw API :8080 to untrusted networks.
|
||||
4. **TLS:** Issue certificates on `smoa-edge` (Let’s Encrypt internal ACME or org PKI) for every public FQDN.
|
||||
|
||||
---
|
||||
|
||||
## 5. FQDN → service mapping (operator checklist)
|
||||
|
||||
Use this table when creating DNS records and reverse-proxy `server_name` / upstream blocks.
|
||||
|
||||
| FQDN | Points to | Backend / purpose |
|
||||
|------|-----------|-------------------|
|
||||
| `api.smoa.example.gov` | `smoa-edge` public IP | Proxy `location /` → `http://smoa-api.lan:8080` (Spring Boot context path `/`). Health: `GET /health`, sync: `/api/v1/...`. |
|
||||
| `config.smoa.example.gov` | `smoa-edge` public IP | Static file or small JSON generator: **client config** (see §6). Prefer path such as `https://config.smoa.example.gov/smoa/client-config.json`. |
|
||||
| `turn.smoa.example.gov` | `smoa-turn` (or edge with UDP pass-through) | TURN `urls` for ICE (often `turn:turn.smoa.example.gov:3478?transport=udp`). |
|
||||
| `signal.smoa.example.gov` | `smoa-signal` | WebSocket/WebRTC signaling base URL(s) if applicable. |
|
||||
|
||||
**Android app today:** Retrofit uses `SMOA_BACKEND_BASE_URL`, which should be the **public API base**, e.g. `https://api.smoa.example.gov/` (trailing slash optional at build; the app normalizes). See `app/build.gradle.kts` and `AppModule.kt`.
|
||||
|
||||
---
|
||||
|
||||
## 6. Client configuration JSON
|
||||
|
||||
### 6.1 Purpose
|
||||
|
||||
- **Operations:** Single file per environment describing which FQDNs clients should use.
|
||||
- **Build pipeline:** CI reads this JSON (or a copy in git) and passes Gradle properties:
|
||||
`-Psmoa.backend.baseUrl=...` `-Psmoa.api.key=...` `-Psmoa.stun.urls=...` `-Psmoa.signaling.urls=...`
|
||||
- **Future:** The app could fetch this URL at first launch (bootstrap) and cache settings; that is not implemented in the current codebase—this document defines the **contract** so you can implement it or generate `BuildConfig` consistently.
|
||||
|
||||
### 6.2 Security notes
|
||||
|
||||
- **Do not** put long-lived API keys in a **world-readable** JSON on the public internet unless your threat model accepts it (e.g. key is only a device enrollment token with tight scope). Prefer: public JSON without secrets + **MDM / enterprise** delivery of `api_key`, or short-lived tokens from an identity service.
|
||||
- Serve `client-config.json` over **HTTPS** only.
|
||||
- Optionally add a **`config_signature`** (JWS) or host the file on object storage with signed URLs.
|
||||
|
||||
### 6.3 Schema (informal)
|
||||
|
||||
| Field | Type | Required | Maps to Android (today) | Description |
|
||||
|-------|------|----------|-------------------------|-------------|
|
||||
| `schema_version` | string | yes | — | e.g. `"1.0"`. Bump when fields change. |
|
||||
| `environment` | string | yes | — | e.g. `"production"`, `"staging"`. |
|
||||
| `api_base_url` | string (URL) | yes | `SMOA_BACKEND_BASE_URL` | Public REST base, e.g. `https://api.smoa.example.gov` (no trailing slash required). |
|
||||
| `api_key` | string \| null | no | `SMOA_API_KEY` | Omit or null if auth is device-only or injected elsewhere. |
|
||||
| `stun_urls` | string | no | `SMOA_STUN_URLS` | Comma-separated STUN URLs for ICE, e.g. `stun:stun.l.google.com:19302`. |
|
||||
| `signaling_urls` | string | no | `SMOA_SIGNALING_URLS` | Comma-separated signaling/WebSocket bases if used by communications module. |
|
||||
| `turn_urls` | string | no | (future / custom) | Comma-separated TURN URLs, e.g. `turn:turn.smoa.example.gov:3478?transport=udp`. |
|
||||
| `well_known_health_url` | string | no | — | Optional; e.g. `https://api.smoa.example.gov/health` for monitoring scripts. |
|
||||
| `openapi_url` | string | no | — | Optional; e.g. `https://api.smoa.example.gov/swagger-ui.html` for admins. |
|
||||
|
||||
### 6.4 Example: `client-config.json`
|
||||
|
||||
Host at a stable URL, e.g. `https://config.smoa.example.gov/smoa/client-config.json`. A copy-checked example lives in this repo at [examples/smoa-client-config.example.json](examples/smoa-client-config.example.json).
|
||||
|
||||
```json
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"environment": "production",
|
||||
"api_base_url": "https://api.smoa.example.gov",
|
||||
"api_key": null,
|
||||
"stun_urls": "stun:stun.l.google.com:19302",
|
||||
"signaling_urls": "wss://signal.smoa.example.gov/ws",
|
||||
"turn_urls": "turn:turn.smoa.example.gov:3478?transport=udp",
|
||||
"well_known_health_url": "https://api.smoa.example.gov/health",
|
||||
"openapi_url": "https://api.smoa.example.gov/swagger-ui.html"
|
||||
}
|
||||
```
|
||||
|
||||
**Gradle mapping example (CI or local):**
|
||||
|
||||
```text
|
||||
-Psmoa.backend.baseUrl=https://api.smoa.example.gov
|
||||
-Psmoa.api.key=<from-secret-store>
|
||||
-Psmoa.stun.urls=stun:stun.l.google.com:19302
|
||||
-Psmoa.signaling.urls=wss://signal.smoa.example.gov/ws
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. `smoa-api` environment variables (reference)
|
||||
|
||||
Typical production settings for LXC **101** (adjust names to match your JDBC host):
|
||||
|
||||
| Variable | Example |
|
||||
|----------|---------|
|
||||
| `SPRING_PROFILES_ACTIVE` | `prod` |
|
||||
| `SERVER_PORT` | `8080` |
|
||||
| `SMOA_API_KEY` | `<secret>` |
|
||||
| `SMOA_CORS_ORIGINS` | `https://trusted-web-origin.example.gov` |
|
||||
| `SPRING_DATASOURCE_URL` | `jdbc:postgresql://smoa-db.lan:5432/smoa` |
|
||||
| `SPRING_DATASOURCE_USERNAME` | `smoa` |
|
||||
| `SPRING_DATASOURCE_PASSWORD` | `<secret>` |
|
||||
| `SPRING_DATASOURCE_DRIVER_CLASS_NAME` | `org.postgresql.Driver` |
|
||||
|
||||
Ensure `application-prod.yml` (or overrides) use PostgreSQL and `ddl-auto: validate` with Flyway, per [../README.md](../README.md).
|
||||
|
||||
---
|
||||
|
||||
## 8. Quick Proxmox LXC creation notes
|
||||
|
||||
1. Create CT from Debian 12 / Ubuntu 22.04 template; enable **nesting** only if you run Docker inside the CT (not required for JAR + systemd).
|
||||
2. **Static DHCP or CT config:** Fixed IPv4 for `smoa-api`, `smoa-db`, `smoa-edge`.
|
||||
3. **Backups:** Include `smoa-db` data volume in Proxmox backup jobs; test restore.
|
||||
4. **Updates:** Patch guest OS per org baseline; restart API after JVM or jar updates.
|
||||
|
||||
---
|
||||
|
||||
## 9. Related paths in this repository
|
||||
|
||||
| Topic | Location |
|
||||
|-------|----------|
|
||||
| Backend API and env | [../README.md](../README.md) |
|
||||
| Docker image (optional alternative to bare JAR in LXC) | [../Dockerfile](../Dockerfile) |
|
||||
| Proxmox VM sizing | [../../docs/infrastructure/PROXMOX-VE-TEMPLATE-REQUIREMENTS.md](../../docs/infrastructure/PROXMOX-VE-TEMPLATE-REQUIREMENTS.md) |
|
||||
| Android backend URL wiring | `app/build.gradle.kts`, `app/.../di/AppModule.kt` |
|
||||
|
||||
This file is the **LXC + FQDN + JSON contract** reference; keep it updated when you add services (e.g. object storage, IdP callbacks, or push notification gateways).
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"environment": "production",
|
||||
"api_base_url": "https://api.smoa.example.gov",
|
||||
"api_key": null,
|
||||
"stun_urls": "stun:stun.l.google.com:19302",
|
||||
"signaling_urls": "wss://signal.smoa.example.gov/ws",
|
||||
"turn_urls": "turn:turn.smoa.example.gov:3478?transport=udp",
|
||||
"well_known_health_url": "https://api.smoa.example.gov/health",
|
||||
"openapi_url": "https://api.smoa.example.gov/swagger-ui.html",
|
||||
"tls_pin_spec": "api.smoa.example.gov|sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
|
||||
"classification_watermark_primary": "OFFICIAL USE ONLY",
|
||||
"classification_watermark_secondary": "CONTROLLED UNCLASSIFIED"
|
||||
}
|
||||
Reference in New Issue
Block a user