Field photography client
Manzoni
A mobile image-intake client with a persistent upload queue and delivery receipts from Colombo.
I designed and built this project independently, using my own resources.
01 / Context
The problem behind the project
A photograph captured in the field should remain queued after an application relaunch, and an accepted upload should not be mistaken for completed delivery.
Manzoni is the field client for Colombo’s upload contract. A captured image must survive an application restart and a bad network before the server has accepted it; after acceptance, the client must avoid sending a duplicate simply because it cannot currently read the receipt.
The interface therefore needs more than an upload progress bar. Accepted, delivered, confirmed by the newsroom, failed, expired, and unknown delivery are different states with different safe actions.
02 / Implementation
Design and implementation
I build the mobile intake and queue workflow, including the current Expo migration and its integration with Colombo.
I built the mobile capture and queue workflow with app-owned media copies, SQLite persistence, secure credential storage, and the current React Native/Expo implementation. The earlier Flutter application remains a separate rollback/reference path.
After an HTTP acceptance, the required operation ID becomes the reconciliation identity. The client polls Colombo on launch, foreground return, a real offline-to-online transition, a slow foreground interval, or an explicit Check delivery action. Automatic triggers respect backoff; an operator refresh can ask immediately.
The domain reconciliation rules prevent a local timeout, an unavailable status endpoint, or an unrecognized receipt from becoming a false failure or success. Existing queue schemas migrate in place so pending rows and media copies survive an application update.
03 / Architecture
Architecture and workflow
Capture locally
Copy media into application-owned storage and persist the queue entry before attempting the upload.
Obtain durable acceptance
Send the authenticated upload and require HTTP 202 plus Colombo’s operation ID.
Reconcile delivery
Advance only on authoritative receipt states, preserving unknown state when the server cannot answer.
Retry safely
Allow a new upload only after a terminal failed/expired outcome; retain accepted work that may still be processing.
04 / Approach
Engineering decisions
Own the queued media
Camera captures and selected images are copied into application storage and recorded in SQLite before upload.
Separate credentials from queue data
SecureStore holds credentials; the queue contains media metadata and lifecycle state.
Follow the delivery receipt
The client records Colombo’s accepted operation and follows it through to a terminal outcome. The original Flutter client remains as a rollback/reference implementation.
05 / Evidence
Evidence and outcomes
The repository checks receipt mapping, reconciliation triggers, schema migration, and mobile build/export contracts. The important failure case is an accepted upload followed by a status outage: the client must keep the existing operation rather than create a duplicate.
The internal-distribution guard requires an exact published Thompson package and registry integrity. The retained documentation records that this guard can block a candidate until the package is actually available; a successful development build is not substituted for distribution acceptance.
Source and technical notes
06 / Current scope
Where it stands
The public branch now contains the Expo/TypeScript migration. Physical camera behavior and internal distribution have their own release requirements.
The Flutter path is not the durable Expo queue described here. Migration, package publication, signed internal builds, and physical-device checks remain distinct tasks.
Delivery unknown is intentional. It is safer and more accurate than guessing that an accepted file failed because the network cannot return its receipt.