Skip to content
Case study · 05 / 09← All work

Posta

A delivery network in one monorepo: landing, operations admin, three mobile apps and an API.

Role
Design and full-stack development
Stack
React + TanStack Router/Query, tRPC, Hono, Expo, MapLibre GL, Astro
Landing
LandingEnd-to-end types from API to admin
(01) The problem

Posta runs a network of independent couriers for local shops. It found clients through social ads and managed them on WhatsApp. That manual process did not scale. Shops, couriers and end customers each needed their own app, and operations needed one place to watch it all.

My roleI designed and built the monorepo end to end: API, admin, landing and the three Expo apps.
(02) ResultsCounted in the code
6apps in one monorepo
34routes in the admin
22tRPC routers
(03) Architecture

Three decisions that shaped it.

  1. 01

    End-to-end types from API to admin

    Why. The admin imports the AppRouter type from the Hono API and calls it through tRPC. Shared Zod schemas live in one package used by the API and all three mobile apps.

    Trade-off. Admin and API are coupled at build time. The mobile apps still call procedures by name, so they lose part of that safety.

  2. 02

    WebSocket for live data, aligned polling for the rest

    Why. Courier positions and presence arrive over WebSocket and patch the TanStack Query cache. Everything else polls at multiples of 15 seconds. Timers line up, so tRPC batches their calls into one request.

    Trade-off. Two delivery channels to reason about. Polled data can be up to a minute old by design.

  3. 03

    MapLibre with a style built from design tokens

    Why. Mapbox charged per map load and needed the client's key. MapLibre with OpenFreeMap tiles needs no key. The style is built in code from the design tokens, so the map uses the product's colors.

    Trade-off. We depend on a free tile service with no SLA. The tile URL is configurable, so it can move to a paid or self-hosted server.

(04) GalleryKeep scrolling →
Landing
Landing · The public page for shops, in Astro.
Live map
Live map · Couriers on the map, updated over WebSocket, with a heatmap view.
Order detail
Order detail · One order in the admin, with its route on the map.
Customer app
Customer app · The Expo app where end customers find shops and order.
(05) What I'd do next
01Give the three Expo apps the typed tRPC client the admin uses. Today a renamed procedure breaks them only at runtime.
02Remove the type casts on admin queries and let tRPC infer the return types.
03Add tests to the admin. The API has 46 test files and the admin has none.
Next project · 06 / 09
Maderera Juan B. Justo →ERP, point of sale and invoicing, in daily use
Case study · 05 / 09

Posta

A delivery network in one monorepo: landing, operations admin, three mobile apps and an API.

Role
Design and full-stack development
Stack
React + TanStack Router/Query, tRPC, Hono, Expo, MapLibre GL, Astro
Posta
(01) The problem

Posta runs a network of independent couriers for local shops. It found clients through social ads and managed them on WhatsApp. That manual process did not scale. Shops, couriers and end customers each needed their own app, and operations needed one place to watch it all.

My roleI designed and built the monorepo end to end: API, admin, landing and the three Expo apps.
(02) Results
6apps in one monorepo
34routes in the admin
22tRPC routers
(03) Architecture

Three decisions that shaped it.

01

End-to-end types from API to admin

Why. The admin imports the AppRouter type from the Hono API and calls it through tRPC. Shared Zod schemas live in one package used by the API and all three mobile apps.

Trade-off. Admin and API are coupled at build time. The mobile apps still call procedures by name, so they lose part of that safety.

02

WebSocket for live data, aligned polling for the rest

Why. Courier positions and presence arrive over WebSocket and patch the TanStack Query cache. Everything else polls at multiples of 15 seconds. Timers line up, so tRPC batches their calls into one request.

Trade-off. Two delivery channels to reason about. Polled data can be up to a minute old by design.

03

MapLibre with a style built from design tokens

Why. Mapbox charged per map load and needed the client's key. MapLibre with OpenFreeMap tiles needs no key. The style is built in code from the design tokens, so the map uses the product's colors.

Trade-off. We depend on a free tile service with no SLA. The tile URL is configurable, so it can move to a paid or self-hosted server.

(04) Gallery
Landing
Landing · The public page for shops, in Astro.
Live map
Live map · Couriers on the map, updated over WebSocket, with a heatmap view.
Order detail
Order detail · One order in the admin, with its route on the map.
Customer app
Customer app · The Expo app where end customers find shops and order.
(05) What I'd do next
01Give the three Expo apps the typed tRPC client the admin uses. Today a renamed procedure breaks them only at runtime.
02Remove the type casts on admin queries and let tRPC infer the return types.
03Add tests to the admin. The API has 46 test files and the admin has none.
Next projectMaderera Juan B. Justo →
Nahuel SantillánEN