MOB-11 — Media capture & uploads
Camera/gallery capture, compression, EXIF-free uploads to pre-signed URLs with retry, offline upload queue for the delegate app.
| Field | Details |
|---|---|
| Task code | MOB-11 |
| Phase | P0 — Foundations (cadrage, UX/UI, architecture & contract) |
| Product scope | V1 |
| Status | Planned |
| Start | Thu 5 Nov 2026 |
| Due | Sun 8 Nov 2026 |
| Responsible | Imad — Mobile developer (Flutter) |
| Co-responsible | — |
| Effort | 0.75 person-day(s) planned · 3 from scratch · size S |
| Area · app | Mobile foundation · mobile |
| Depends on | MOB-03 |
| Unblocks | MDA-05 |
| Milestones | Mobile foundations ready |
Summary
Camera/gallery capture, compression, EXIF-free uploads to pre-signed URLs with retry, offline upload queue for the delegate app.
Description
Visit photos, façade photos, store documents, payment proofs and claim photos all go through the same pre-signed upload flow, and in the delegate app they must survive having no network (CRM-10, FLD-08, SEC-04). Scope: camera and gallery capture (and PDF pick for documents), compression, EXIF stripping with the capture position kept as separate metadata, upload via files.createUpload → PUT to the pre-signed URL → files.completeUpload with retry, an offline upload queue for the delegate app that feeds the outbox, and private-file display through files.downloadUrl. The screens that attach files are in the feature tasks. It needs the files module (SRV-07) and the FilePurpose values from Anis; no design work beyond the capture sheet in DES-03. MDA-05, MDA-07, MRA-07, MRA-08 and MRA-10 call this service.
Subtasks
| # | Subtask | Owner |
|---|---|---|
| 1 | MediaPicker: in-app camera (camera package) for delegate photos, Android photo picker / image_picker for the gallery, file_picker for PDF documents; camera permission rationale | Imad |
| 2 | Compression with flutter_image_compress: longest edge 1600 px, JPEG quality 80, target under 500 KB, EXIF removed; capture lat/lng/accuracy/time kept as metadata for delegate.visits.addPhoto | Imad |
| 3 | UploadService: files.createUpload (purpose VISIT_PHOTO, STORE_PHOTO, STORE_DOCUMENT, PAYMENT_PROOF or TICKET_ATTACHMENT, contentType, size) → PUT with progress → files.completeUpload; new URL requested when the 10-min URL expires | Imad |
| 4 | pending_uploads drift table (localPath, purpose, fileId, state, attempts, lastError) and an UploadQueue that runs before dependent outbox mutations (addPhoto waits on its upload via dependsOn) | Imad |
| 5 | Retry policy: exponential backoff, Wi-Fi-or-any setting, pause when battery saver is on; failed items visible in the sync centre | Imad |
| 6 | Local storage housekeeping: originals deleted after completeUpload, thumbnails kept for the visit view, low-storage warning | Imad |
| 7 | PrivateImage widget loading files.downloadUrl (5-min signed URL) with cache and refresh on 403 | Imad |
Deliverables
- packages/hoco_core/lib/src/media/ (picker, compressor, upload_service.dart)
- packages/hoco_offline/lib/src/uploads/upload_queue.dart and the pending_uploads table
- packages/hoco_ui/lib/src/components/private_image.dart
Acceptance criteria
- A 12-MP photo is uploaded as a JPEG under 500 KB with no EXIF GPS block; its capture position reaches the server in the addPhoto body (SEC-04, FLD-08)
- Three photos taken in airplane mode upload automatically after reconnection and the visit then shows them as synced
- An upload interrupted mid-way restarts with a fresh pre-signed URL and creates no orphan duplicate after completion
- Private files are only displayed through short-lived signed URLs; an expired URL refreshes transparently
- A PDF store document (RC, NIF) can be attached from the reseller app (CRM-10)
Requirements covered
| Requirement | Title | Release |
|---|---|---|
| CRM-10 | Store photos and documents (façade, interior, RC, NIF, ID) with protected access | V1 |
| FLD-08 | Visit and check-in: time and position at check-in, duration, checklist, note, photos (mandatory by visit type), call; finished visit locked | V1 |
| SEC-04 | Protected documents and uploaded files (private storage, signed URLs, access checks) | V1 |
API surface
| Endpoint group | Operations |
|---|---|
| File uploads & downloads | 3 |
Test measures
- Unit tests of the UploadQueue state machine with a fake files API (expiry, failure, retry, dependency release)
- Test asserting EXIF absence on a compressed sample image
- Device test: five photos offline → reconnect on a weak 3G profile → all uploaded and attached
Risks
- Large photo queues on weak networks drain data and battery — compression first, sequential uploads and a visible queue size
KPI
- Delivered by Sun 8 Nov 2026 within 0.75 person-day(s).
- Every acceptance criterion above demonstrated before hand-off; linked requirements' acceptance criteria pass.
- Zero open critical defects, permission gaps or data-integrity regressions at sign-off.
Generated from content/plan/tasks.json by scripts/generate-team-tasks.mjs. Dates are computed by the scheduler (Sunday–Thursday weeks, holidays excluded) — change the plan, not this page.
MOB-10 — Location, maps & consent foundation
Permission and consent flow, location service with accuracy handling, tolerance check helper, Google Maps setup per flavor, launch of external navigation, GPS-off and out-of-tolerance states.
MRA-01 — Reseller app — home
Greeting, notifications bell, search entry with scanner, banner carousel/daily offer, quick access, popular categories, recommended products, balance/credit tiles.