Files
smoa/backend/docs/BACKEND-GAPS-AND-ROADMAP.md
T
defiQUG a2dc194a49 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
2026-03-23 20:19:24 -07:00

107 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SMOA Backend – Gap Analysis and Roadmap
## Review summary
The backend implements the **sync contract** expected by the mobile app (POST sync endpoints, SyncResponse with conflict/remoteData), with **validation**, **optional API key auth**, **OpenAPI**, **conflict detection**, and **H2 persistence**. Below are covered areas, gaps, and recommendations.
---
## What's in place
| Area | Status |
|------|--------|
| **Sync API contract** | All five sync endpoints (directory, order, evidence, credential, report); request DTOs aligned with app; SyncResponse with success, itemId, serverTimestamp, conflict, remoteData, message. |
| **Conflict detection** | Directory uses lastUpdated; others use clientUpdatedAt; server returns conflict + remoteData when server has newer version. |
| **Validation** | @Valid on all sync bodies; NotBlank/NotNull on required fields. |
| **Auth** | Optional API key via X-API-Key or api_key query; when key is set, all /api/v1/* require it. |
| **Security** | Stateless; CSRF disabled for API; health/info/docs/h2-console permitted without auth. |
| **Persistence** | JPA entities and repositories for all five resource types; H2 file DB; ddl-auto: update. |
| **OpenAPI** | springdoc; /v3/api-docs, /swagger-ui.html; ApiKey scheme documented. |
| **Health** | GET /health with status, application, timestamp, and DB check (up/down). |
| **CORS** | Configurable via smoa.cors.allowed-origins (default *). |
| **Error handling** | Global exception handler: 400 for validation/type errors with JSON body; 500 for other errors. |
---
## Gaps and recommendations
### 1. **Delete / SyncOperation.Delete** ✅ Done
- **Gap:** App has SyncOperation.Create, Update, **Delete**. Backend only does upsert (create/update).
- **Done:** DELETE endpoints added: `/api/v1/sync/directory/{id}`, `/order/{orderId}`, `/evidence/{evidenceId}`, `/credential/{credentialId}`, `/report/{reportId}`; each returns SyncResponse; audit logged.
### 2. **Pull / GET (initial load or refresh)** ✅ Done
- **Gap:** No GET endpoints. App today only pushes from a queue; for "refresh after coming online" or initial load, pull is often needed.
- **Done:** GET list endpoints: `/api/v1/directory` (optional `unit`, `X-Unit`), `/api/v1/orders` (since, limit, jurisdiction / X-Unit), `/api/v1/evidence`, `/api/v1/credentials`, `/api/v1/reports` (since, limit, optional filters). See PullController and `api/dto/PullResponse.kt`.
### 3. **Enum validation** ✅ Done
- **Gap:** orderType, status (orders), evidenceType, reportType are free strings. App uses enums.
- **Done:** @Pattern added for orderType (AUTHORIZATION|…|ADMINISTRATIVE), status (DRAFT|…|REVOKED), evidenceType (PHYSICAL|…|DOCUMENT), reportType (OPERATIONAL|…|REGULATORY), report format (PDF|XML|JSON|CSV|EXCEL).
### 4. **SyncResponse.remoteData format** ✅ Done
- **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** ✅ Done (baseline)
- **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
- **Gap:** No rate limiting on sync or auth.
- **Done:** RateLimitFilter on /api/v1/*; per API key or IP; configurable `smoa.rate-limit.requests-per-minute` (default 120); 429 when exceeded; disabled in test profile.
### 7. **Audit / logging** ✅ Done
- **Gap:** No structured audit log for "who synced what when".
- **Done:** SyncAuditLog entity and SyncAuditService; sync and delete operations logged (resourceType, resourceId, operation, success). SyncController calls audit after each sync/delete.
### 8. **Tests** ✅ Done
- **Gap:** No backend unit or integration 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**
- **Gap:** No tenant/org/unit scoping; any client with a valid API key can read/write any resource.
- **Recommendation:** If the app is multi-tenant or unit-scoped, add unit/tenant to API key or token and filter queries (e.g. directory by unit, orders by unit).
### 10. **Infrastructure** ✅ Done (Dockerfile)
- **Gap:** No Dockerfile or k8s manifests; no migration strategy beyond ddl-auto.
- **Done:** backend/Dockerfile (multi-stage); build from repo root: `docker build -f backend/Dockerfile .`. Optional: Flyway/Liquibase and ddl-auto: validate in prod.
---
## Optional improvements
- **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`).
---
## Quick reference: config
| Property | Default | Purpose |
|----------|---------|---------|
| smoa.api.key | (empty) | API key; empty = no auth |
| smoa.api.key-header | X-API-Key | Header name |
| smoa.cors.allowed-origins | * | CORS origins (comma-separated) |
| smoa.rate-limit.enabled | true | Enable rate limit on /api/v1/* |
| smoa.rate-limit.requests-per-minute | 120 | Max requests per key/IP per minute |
| server.port | 8080 | Port |
| spring.datasource.url | H2 file | DB URL (use PostgreSQL in prod) |
---
## Summary
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`.