demoda
A clothing marketplace where the hard part was never the catalogue.RoleStaff augmentation — product, mobile, backend and platform
PlatformsiOS · Android · Web
Timeline2022 – 2024
mobilewebapisearchpaymentsstaff augmentation
demoda is a marketplace for clothing and accessories that lets small brands, second-hand stores, fashion designers and individuals sell their products. It covers the entire sales process — discovery, buyer-to-seller messaging, online payments, shipping and order tracking.We joined the team as an embedded engineering group and worked across the whole stack: the Flutter app, the GraphQL API, the Python services behind it and the AWS infrastructure it all runs on.


The problem
Search runs on other people's data
Nobody normalises a marketplace catalogue. Sellers write their own titles and descriptions from their phones — inconsistent casing, misspellings, brand names spelled six ways, Spanish and English mixed in the same listing. Matching a query against that is not a SQL LIKE.Sellers are individuals, not merchants
The seller side had to work for someone photographing a jacket on their bed, not for a warehouse with an ERP. That shapes onboarding, payment setup, image handling and every empty state in the app.What we built
- 01
An order state machine with a timeout on every edge
The order lifecycle is modelled explicitly rather than inferred from a status column, and every state where the system waits on a human has its own timeout handler. Nothing waits forever.- Payment, pickup, shipping and waiting-for-shipment each have a dedicated timeout path
- Unhappy paths are first-class: seller rejects, buyer reports a problem, order is never collected
- Totals are calculated server-side, so the client can never be the source of truth for money
- Every transition is a handler that can be tested in isolation
- 02
Split payments, with each seller paid into their own account
Sellers connect their own MercadoPago account through an OAuth flow, so funds settle to them directly rather than pooling in a platform wallet that has to be reconciled later.- OAuth onboarding per store, with automatic token refresh
- Payment preferences created server-side and reconciled from MercadoPago webhooks
- Webhook events drive order state transitions, not the app
- A separate bank-transfer withdrawal flow for seller balances
- 03
Search on OpenSearch, not on the database
Product search runs against a purpose-built OpenSearch index with its own loader and a query builder that carries its own test suite — because relevance is a thing you regress, and you only notice if you test it.- Dedicated indexing pipeline, decoupled from the transactional database
- Query builder unit-tested against real query shapes
- Machine learning in the pipeline for relevance beyond keyword matching
- 04
Hasura as the API surface, with the schema in version control
The read and write API is GraphQL over PostgreSQL via Hasura. What matters is that none of it lives only in a console: permissions, relationships and actions are committed metadata, reviewed in pull requests like any other code.- Migrations and Hasura metadata committed alongside the application code
- Row-level permissions expressed as data, not scattered through handlers
- Custom business logic behind Hasura Actions, served by Python services
- The Flutter client generates its types from the live schema, so a breaking change fails the build
- 05
One Flutter codebase across iOS, Android and web
The app is organised feature-first — roughly thirty self-contained contexts, each owning its screens, state and queries — which is what makes a codebase this size survive more than one team rotation.- Riverpod for state, Freezed for immutable models, go_router for navigation
- GraphQL types generated from the schema rather than hand-written
- Sentry, Firebase Analytics and Remote Config wired in from the start
- 06
Per-branch environments from infrastructure as code
The AWS footprint is defined in CloudFormation stacks, and every deploy label gets its own API endpoint. Reviewing a change means opening the environment it created, not reading a diff and hoping.- Separate stacks for core services, shared resources and the image pipeline
- Image processing with HEIC support, delivered from a dedicated edge stack
- Secrets held in AWS Secrets Manager, never in the repository
The stack
Mobile & web
FlutterDartRiverpodFreezedgo_routerGraphQL codegen
API
HasuraGraphQLPostgreSQL
Services
PythonFastAPIAWS LambdaPants
Search
OpenSearchTensorFlowTransformers
Payments
MercadoPago
Platform
AWS CloudFormationS3FirebaseSentry
As co-founder of demoda, I am extremely impressed with the work pdelabs did helping in the development of our marketplace. They solved technically challenging problems such as real time messaging, complex order state machines and much more. Their commitment to understanding our vision and their ability to translate it into a functional and user-friendly platform was remarkable.
- Nicolas Ferro, co-founder
- Nicolas Ferro, co-founder
Have something like this to build?
Schedule a call now
We love to take on new challenges, tell us yours.
Schedule a call
Or
if your prefer taking it offline, write us
via email
if your prefer taking it offline, write us
via email