LastVet iOS Architecture Notes¶
API client¶
The veteran app talks to Configuration.apiBaseURL using Bearer JWT session exchange. Networking lives in LastVet/Core/Networking/LastVetAPIClient.swift.
| Build | LastVetAPIEnvironment |
API base URL |
|---|---|---|
| Debug (scheme LastVet) | production |
https://api.last.vet/api |
| Release (scheme LastVet archive) | production |
https://api.last.vet/api |
| Staging (scheme LastVet-Staging) | sandbox |
https://api-staging.last.vet/api |
LASTVET_API_ENVIRONMENT is set in checked-in Configuration/*.xcconfig. Session exchange secrets are per-environment in gitignored Secrets.xcconfig (VETERAN_SESSION_EXCHANGE_SECRET_STAGING / _PRODUCTION). Staging tester soak: docs/testflight/MERIDIAN_ASK_STAGING.md.
Imaging storage (envelope encryption)¶
As of the envelope encryption integration, veteran imaging uploads use Pattern B (API-mediated):
| Flow | Endpoint | Client behavior |
|---|---|---|
| Upload | POST /veteran/me/documents/imaging/upload |
Multipart form (file, title, documentType, optional description / documentDate). Plaintext over TLS. Server encrypts with AES-256-GCM + wrapped DEK. |
| Download | GET /veteran/me/documents/:id/download |
Inline decrypted stream from API (minio_envelope). No client-side object-store URLs. |
Implementation:
ImagingEnvelopeUpload.swift— multipart temp file +URLSessionUploadTaskprogress/cancelLastVetAPIClient.uploadImagingDocument— Wi‑Fi guard (>50 MB), envelope POST, error mappingLastVetAPIClient.downloadDocument— inline stream from API (envelope decrypt on server)
Backend requirement¶
Staging and production API hosts must run with:
When envelope mode is active, retired presigned endpoints (/imaging/upload/init, /complete, abandon DELETE) return 410 Gone. The iOS client treats 410 on abandon as success (local dismiss of stale pending-upload banners).
Caddy on lastvet-edge uses 20 minute read/write timeouts to support 512 MiB uploads over slow uplinks.
Limits and UX¶
- Server max object size: 512 MiB per imaging study
- Client Wi‑Fi gate: 50 MiB on cellular (see
UploadConnectivity.swift) - Upload progress: real percentage via
URLSessionUploadTask; user can cancel mid-upload
Further reading¶
- Design plan:
docs/ENVELOPE_ENCRYPTION_INTEGRATION_PLAN.md(Session 1) - Canonical crypto spec:
lastvet-gates/docs/security/IMAGING_ENVELOPE_ENCRYPTION.md - R940 platform topology (API hosts, env lanes, deploy gates):
lastvet-gates/docs/deployment/R940_ENVIRONMENT_TOPOLOGY.md
Provider portal (separate repo)¶
last.vet-provider downloads veteran documents via GET /provider/:id/veteran/:veteranId/documents/:documentId/download and expects an inline Blob. It does not implement the retired veteran presigned multipart upload flow. Envelope streaming downloads should work without provider changes; provider-originated uploads use the standard document POST (non-imaging types only in UI today).
Community tab (content-gated)¶
Org-side (last1.app register, listing, monthly attest) is Phase 1 outreach. The veteran tab stays off until at least one org has a current attestation. Spec: lastvet-gates/docs/lastvet/COMMUNITY_DIRECTORY_SPEC.md. Do not add a Community tab, Find Care mix-in, or Meridian-style matching until that unlock is real.
Tests¶
LastVetTests/NetworkingTests/ImagingEnvelopeUploadTests.swift covers multipart temp-file writing, imaging error mapping, and 410 abandon dismiss behavior.