Context & Problem
People planning events like weddings and baptisms choose vendors from scattered photos, word of mouth, and phone calls. The client wanted a curated marketplace where real event media does the selling: browse what an organizer actually produced, see packages at luxury-to-budget tiers with indicative costs, and find related products and services in one place. Curation was central to the model — only admins publish content, so the platform needed a serious content-operations console, not just a consumer app.
The product needed three surfaces at once: a consumer mobile app whose core is a smooth photo-and-video feed, a catalog of packages and products with category and budget filtering plus ratings and reviews, and an admin console where the client's team creates and manages all of it. Media had to be stored and served durably, engagement (likes, views, saves) tracked per post, and every post identifiable by a short unique code for admin operations. A two-person team had to build and coordinate all three codebases in parallel against one API.
Design Constraints
- teamA two-person team built three codebases — API, consumer mobile app, and admin web console — in parallel against one contract.
- platformThe consumer experience is media-heavy: mixed photo/video posts had to upload, store, and play back smoothly on mobile.
- complianceAdmin-only publishing was a product rule — every content path needed the curation gate, not an open social-posting model.
Architecture Overview
Structured the backend as a modular NestJS API — separate modules for auth, feed, categories, packages, items, files, and reviews — on MongoDB via Mongoose, with JWT authentication, Socket.IO channels for real-time updates, Swagger-documented endpoints, and Sentry error tracking, deployed under a process manager behind a reverse proxy. Media uploads flow through a file module into Google Cloud Storage rather than living on the API host. The admin console is a React app built with Vite and the Mantine component system — rich-text editing, drag-and-drop media uploads, and catalog forms for categories, packages, and posts — with Redux Toolkit for state and JWT sessions against the same API. The consumer mobile client is an Expo app using file-based routing with tabs for the explore feed, packages, products, and profile, video playback in-feed, and performant long lists.
Key Engineering Decisions
Outcomes & Lessons Learned
Platform Surface
Shared API, consumer mobile app, and admin web console built in parallel
API Capabilities
Socket.IO channels alongside REST, with Swagger-documented endpoints
Storage Architecture
All photo/video content stored in Google Cloud Storage, decoupled from the API host
Retrospective
- Document-database flexibility has a due date: letting references pass as either ObjectId or string was convenient early and became a patch-generating bug class later — the backend history is the receipt. Enforce ID discipline at the API boundary from the first schema, even in Mongo.
- Three surfaces in parallel with two people means every surface moves at a fraction of the team's speed — over the same months the API logged forty-one commits while the admin console logged three. Sequencing surfaces (API + one client to usable, then the next) would have produced a demonstrable slice sooner.
