- Backend: ShallowEtagHeaderFilter for /api/v1/*, API-VERSIONING.md, README (tenant, CORS, Flyway, ETag) - k8s: backend-deployment.yaml (Deployment, Service, Secret/ConfigMap) - Web: scaffold with directory pull, 304 handling, touch-friendly UI - Android 16: ANDROID-16-TARGET.md; BuildConfig STUN/signaling, SMOAApplication configures InfrastructureManager - Domain: CertificateManager revocation stub, ReportService signReports, ZeroTrust/ThreatDetection minimal docs - TODO.md and IMPLEMENTATION_STATUS.md updated; communications README for endpoint config Co-authored-by: Cursor <cursoragent@cursor.com>
6.0 KiB
6.0 KiB
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(optionalunit,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 andapi/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).