Case Study • Curious Puffin
Back to portfolio

Curious Puffin
Retail Capture Platform

A full-stack retail photo capture platform with a Flutter mobile client and Node/Express API, built around field capture reliability, project-based organization, geolocation-assisted workflows, and scalable direct-to-storage uploads.

Node.js + ExpressMongoDB Atlas + MongooseJWT + bcryptCloudflare R2 presigned uploadsFlutter + Providerflutter_secure_storageGeo queries + 2dsphere indexRender-ready deploymentHelmet + CORS + rate limitingStructured JSON logging

Executive Summary

Core Workflow

Mobile photo capture with project + store context and library management

Storage Pattern

MongoDB for metadata, Cloudflare R2 for binaries via direct upload

Field UX

GPS-assisted store detection with manual fallback and retry-friendly uploads

Delivery Signal

Consultancy-led technical implementation with cloud-ready API operations posture

Overview

Product context, role, and domain boundaries.

The Problem

Retail/FMCG field teams need a reliable way to capture store photos with project context, location awareness, and traceable metadata, but upload reliability and field ergonomics are often weak in generic tools.

The Opportunity

Build a mobile-first capture platform with a scalable upload pipeline, portfolio-style project organization, geolocation-assisted store selection, and clear ownership boundaries in the API.

My Role

Technical implementation lead / consultant: managing architecture decisions and delivery across the Flutter mobile client, Node/Express API, storage integration, and operational deployment readiness.

Platform Shape

Flutter mobile app + Node/Express API + MongoDB Atlas for metadata + Cloudflare R2 for binaries, with direct-to-object-storage uploads and environment-driven deployment configuration.

Domain Model Snapshot

Projects

User-owned project records with brand/category/store/notes metadata and archive/restore lifecycle controls.

Photos

Photos carry upload state and metadata, support project tagging/un-tagging after capture, and power previews and history views.

Stores + Location

GPS-assisted store suggestion with manual override fallback, plus nearest-store and text search endpoints for practical field use.

Ownership + Access

Auth-sensitive operations enforce resource ownership checks, with role middleware available for admin-only route protection.

Architecture Decisions

Mobile-first capture product with scalable backend upload boundaries.

The platform is intentionally optimized around the realities of field capture: large image uploads, inconsistent location signals, auth-sensitive data, and the need for direct media handling patterns that scale cleanly.

Core Runtime Flows

  1. 1User authenticates -> mobile stores JWT securely and restores session on app reopen.
  2. 2Capture flow requires active project selection before upload begins.
  3. 3App uses GPS to suggest nearest store, with manual override when detection is wrong or unavailable.
  4. 4init-upload endpoint creates photo metadata and returns R2 pre-signed URL.
  5. 5Mobile uploads image bytes directly to Cloudflare R2 (API is not in file-transfer path).
  6. 6complete-upload endpoint finalizes photo status to uploaded and enables library/detail workflows.
  7. 7Users can later assign/unassign project tags and share downloaded images via native OS share sheet.

Why These Decisions

Split metadata storage and binary storage

Why: Photo binaries and domain metadata have very different scaling and access patterns.

Impact: MongoDB Atlas stores domain metadata while Cloudflare R2 handles media objects, keeping the API focused on orchestration and authorization.

Three-step upload workflow (init-upload -> direct upload -> complete-upload)

Why: The backend should not sit in the hot path for large file transfer.

Impact: Scalable uploads, reduced server bandwidth pressure, and cleaner status transitions for upload lifecycle tracking.

GeoJSON + geospatial indexes for store workflows

Why: Nearest-store suggestions are a core field UX enhancement, not an afterthought.

Impact: Fast nearest-store lookups and a clearer path to richer location-aware features later.

Provider/state + service-layer client architecture

Why: Mobile flows span auth, location, projects, photos, and uploads and need separation of concerns.

Impact: Cleaner feature boundaries in Flutter and easier maintenance/testing of operational flows.

Environment-first, cloud-ready backend setup

Why: The platform needs to be deployable early with predictable operational behavior.

Impact: Render-ready config, health/status probes, structured logging, and environment-driven secrets/rate limits.

Offline-tolerant UX touches before full offline architecture

Why: Field work needs resilience even before a full offline sync engine exists.

Impact: Local capture history and retry-capable uploads improve usability without overbuilding the POC/product stage.

API / Backend

Node/Express + Mongo API for auth, project/photo metadata, and upload orchestration.

The backend coordinates auth, ownership, project and photo metadata, geospatial store lookup, and the pre-signed upload lifecycle while keeping file transfer out of the API request path.

Auth, Accounts, and Password Flows

01

Registration, login, session restore bootstrap support, profile updates, forgot/reset password, and JWT bearer auth form the account foundation.

  • JWT bearer tokens with sub + role claims
  • bcrypt password hashing
  • Forgot/reset password flow
  • Role middleware available for admin-only routes

Project Lifecycle Management

02

Projects support create/edit/archive/restore/delete with metadata fields used to organize capture and library workflows.

  • Brand/category/store/notes metadata
  • Archive + restore lifecycle
  • User ownership checks
  • Unique slug generation per user

Photo Metadata + Library Operations

03

Photo metadata powers list/detail views, sorting/filtering, project previews, store history, and post-upload project assignment changes.

  • Assign/unassign project tags after upload
  • Per-store previous photo retrieval
  • Per-project previews
  • Library list/detail endpoints

Upload Orchestration + R2 Integration

04

API orchestrates upload initialization/finalization while clients upload directly to Cloudflare R2 via pre-signed URLs.

  • init-upload metadata + signed URL
  • Direct mobile upload to R2
  • complete-upload status finalization
  • Backend not in binary transfer hot path

Geospatial and Search Capabilities

05

Store collection uses 2dsphere and text indexes to support nearest-store lookup and text search endpoints for field workflows.

  • 2dsphere index for geospatial queries
  • Text index for store search
  • Nearest-store endpoint
  • Manual fallback store selection path in UX

Security, Reliability, and Middleware

06

Express stack includes Helmet, CORS allowlist, auth/global rate limiting, proxy-aware IP handling, and centralized 404/500 error middleware with structured logs.

  • Helmet + CORS allowlist
  • Auth and global API rate limiting
  • Proxy-aware IP handling
  • Centralized 404/500 middleware

Ops Readiness and Health Endpoints

07

Environment-driven configuration and health/status probes make the API deployable on Render with visible service state.

  • Liveness + status endpoints
  • Mongo connection state in status response
  • Uptime exposure
  • Environment-first configuration strategy

Mobile App (Flutter)

Field capture, library management, and resilient mobile UX.

The Flutter client is where product value is realized in the field: capture, project tagging, store detection, browsing, sorting, and sharing all need to feel fast and forgiving under real usage conditions.

Mobile App Shell + Navigation

01

Bottom navigation app shell organizes Home, Library, Capture, Projects, and Profile flows with service-oriented feature boundaries.

  • Bottom-nav app shell
  • Dedicated flow separation
  • Provider state management
  • Service classes by domain concern

Capture Workflow

02

Capture flow combines camera usage, required project selection, GPS-assisted store detection, and manual override to support real-world field behavior.

  • Required project selection before upload
  • GPS-assisted store detection
  • Manual store override fallback
  • In-app camera capture

Library and Photo Metadata UX

03

Users can browse uploaded photos, filter by store/project, sort oldest/newest, open detail views, and update project assignment metadata after upload.

  • Store/project filters
  • Oldest/newest sort options
  • Photo detail view
  • Post-upload project tag assignment

Sharing and Local Device Integration

04

Remote images can be downloaded to temporary storage and shared through the native OS share sheet for downstream reporting and collaboration.

  • Remote image download to temp storage
  • Native share sheet integration
  • Field-friendly output behavior
  • Works from library/detail flows

Persistence and Resilience

05

Secure token storage plus shared_preferences-backed local UX state improves session continuity and capture/upload resilience.

  • flutter_secure_storage for auth tokens
  • shared_preferences for active project/location state
  • Local capture history
  • Retry-capable upload attempts

Security, Reliability & Ops

Cloud-ready operational posture with clear failure handling paths.

The API stack and deployment model are shaped for practical production readiness: health probes, structured logs, environment config, rate limits, and centralized error handling are already in place during active implementation.

Deployment Model

Cloud-ready backend targeting Render with health/status probes, environment-driven config, and structured logging.

Config Strategy

Secrets and runtime behavior are environment-first: JWT, DB, CORS, rate limits, and R2 credentials are all externally configured.

Observability

Centralized error handling and structured JSON logs support debugging across HTTP and app-level events.

Security Controls

Helmet, CORS allowlist, auth/global rate limiting, proxy-aware IP handling, and ownership checks across auth-sensitive operations.

Tradeoffs & Constraints

Strong architecture direction with visible next-iteration alignment work.

The current implementation already has solid platform decisions. Most remaining issues are tuning and API/UX alignment improvements, which is exactly what you want to see at this stage.

Client/server list alignment still maturing

Rationale: The client sends limit/sort params for photo listing, but the backend currently applies a fixed server-side limit/sort behavior.

Tradeoff: Stable backend behavior now, but API/consumer parameter alignment is an obvious next iteration.

Nearby-store radius tuning is intentionally interim

Rationale: The nearby-store endpoint currently uses a temporary max-distance value (25000) instead of the requested radius.

Tradeoff: Fast geospatial feature delivery now, with clear follow-up tuning/parameter fidelity work later.

Hard-coded widget styling in parts of the mobile UI

Rationale: Some component-level styling is hard-coded while the app overall uses a Material 3 seed-based theme.

Tradeoff: Faster UI delivery during active implementation, but a clear theming consistency cleanup remains.

Mobile-first product surface vs broader back-office tooling

Rationale: The core value is field capture and library workflows, so implementation effort favors mobile-first operational flows.

Tradeoff: Strong field UX early, while deeper analytics/admin tooling can evolve later as usage patterns stabilize.

Outcomes / Metrics

Consultancy-led implementation with strong architecture signal.

Public metrics are not listed here, but the implementation already demonstrates scalable upload patterns, field-ready UX decisions, and an operationally sensible backend foundation.

Outcomes / Delivery Signals

  • Established a clean full-stack architecture separating metadata persistence (MongoDB Atlas) from binary media storage (Cloudflare R2).
  • Implemented a scalable direct-to-object-storage upload pipeline with explicit init/complete lifecycle states.
  • Delivered mobile-first retail capture workflows with GPS-assisted store suggestion and manual fallback for real field conditions.
  • Built portfolio-worthy operational safeguards: ownership checks, rate limiting, structured logs, and environment-driven config.
  • Added geospatial and search capabilities early (2dsphere + text index) to support field usability and future expansion.
  • Kept the codebase roadmap-ready by surfacing clear improvement points without compromising architecture quality.

Quality / Maturity Signals

  • Centralized 404/500 middleware with structured JSON logging
  • Health/status endpoints exposing uptime and Mongo connection state
  • Security middleware stack (Helmet, CORS allowlist, rate limits, proxy-aware IP)
  • Secure token storage on mobile with session restore flow
  • Explicit resource ownership checks on auth-sensitive operations
  • Cloud-ready environment-first deployment setup for Render

What I'd Improve Next

Tighten API-client alignment and expand the platform around proven capture workflows.

The strongest next steps are already visible in the current product: endpoint alignment, geospatial tuning, theming consistency, and deeper testing/telemetry around upload and field capture behavior.

Align list-photos endpoint behavior with client-supplied sort/limit parameters.

Replace temporary nearby-store max distance tuning with request-driven radius handling and better calibration.

Consolidate hard-coded widget colors into the Material 3 seed/theme system for consistency.

Expand analytics/admin surfaces if usage patterns justify deeper reporting beyond current mobile-centric workflows.

Add broader automated API test coverage around uploads, ownership checks, and geospatial endpoints.

Refine upload retry telemetry and failure analytics to guide UX improvements in field conditions.

Contact

Shipping a mobile-first operational product with field capture and media complexity?

I can help manage the technical implementation across mobile UX, backend architecture, and scalable storage/upload patterns.