Files
smoa/backend/docs/BACKEND-GAPS-AND-ROADMAP.md

106 lines
6.0 KiB
Markdown
Raw Permalink Normal View History

# 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**
- **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.
### 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 (POST valid/invalid, 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:** 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.
- **API versioning:** Keep /api/v1; when introducing breaking changes, add /api/v2 and document deprecation.
---
## 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, **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).