Fly Post: An MVP of a crew-courier air delivery service in ~5 weeks


- Role
- Fullstack Developer, project lead
- Team
- Me and 2 frontend developers
- Timeline
- About 5 weeks, March – April 2025
- Status
- MVP handed over to the client
What I did
- Design and the UI kitDesigned the key desktop and mobile screens and a UI kit in Figma. The team built the screens from ready-made components without approving every element.
- Architecture and backendDefined the stack and the architecture and fixed the API contract in Swagger as the single source of truth for the team. Wrote the REST API in NestJS and set up the infrastructure: Docker, a VPS, GitLab CI.
- FrontendPrepared the Vite and TypeScript skeleton and an MSW mock server so the team could start on day one. Took on the complex parts: localization, sign-in with a confirmation code and the Leaflet map.
- TeamBrought in two frontend developers, broke the work down into tasks in git issues, defined the project structure and the code style, and reviewed the code.
Context
Business
A private client was launching a service for piggyback delivery of documents and small parcels to other cities and countries. Deliveries are made by crew members — flight attendants and pilots who are flying that route anyway. They pick up a shipment at the departure airport, hand it over at the destination and get paid for the delivery.
For the sender it is faster than courier services, for the crew it is extra income. The service is closed: access to it is granted separately.
The situation
Before the service, such deliveries were arranged by hand, through acquaintances and chats. The sender had to find a crew member on the right flight, agree on the price and the meeting, and check where the parcel was in the chat. Neither side had any guarantees: it was unclear who would pick up the shipment and when, and how the delivery would be paid. The service was meant to replace all of this with one process and clear statuses. The project started from scratch.
The goal
in the shortest possible time and on a small budget. The load is low, so the stack is simple: Vue 3, NestJS and PostgreSQL.
Process, architecture and decisions
The parcel flow
The service has two roles: the sender creates a parcel, a courier from the crew takes it on their flight.
- 01ShipmentThe sender creates a parcel for shipment. In development: a form with masks and validation, address search with suggestions through Nominatim
- 02FlightThe courier enters their flight, for example from Moscow to Paris. In development: a flight form with manual entry, a schedule API is planned in the architecture
- 03AirportThe courier picks up the mail at the departure airport. In development: a Leaflet map with markers, clusters and geolocation, shipment status changes through actions in the table
- 04DeliveryDrops the parcel off at the destination and gets paid for the delivery. In development: an order status timeline, role checks by guards in the API, payouts are planned
Architecture
The team was three people, two of them frontend developers, on a tight deadline. So the stack was chosen to keep the whole team on one language and let it start fast. NestJS on TypeScript gave shared contract types on the frontend and the backend, with no second language to learn. The team already knew Vue 3 with Vite, Pinia and Tailwind, and the ready-made daisyUI components sped up the layout work. PostgreSQL is a reliable relational database for orders and users. Docker on a VPS with GitLab CI gives low-cost infrastructure with automatic rollouts.
- CLIENTSPA
Vue 3 on Vite, Pinia, Vue Router, Tailwind and daisyUI. Localization is laid in with vue-i18n, ru/en.
- APIREST in NestJS
The contract is described in Swagger, the sender and courier roles are checked by guards.
- DATAPostgreSQL
The main database with backups.
- INFRADocker on a VPS
The frontend, NestJS and PostgreSQL run in containers, GitLab CI builds the images and rolls them out to the server.
The map and the interface
The UI kit in Figma and on the frontend set one interface language. Screens were built from ready-made components, so new pages came faster and the interface stayed consistent without a separate design review. For the client this means cheaper changes and faster delivery of new features.
Points on the map stay readable even when there are many of them: custom SVG markers, clusters, zoom and geolocation on Leaflet, and address search with suggestions through Nominatim from OpenStreetMap. Users find the right place faster, and the business does not pay for commercial map APIs.
The order's path is shown step by step in a nested collapsible status timeline. Forms have masks and validation, the confirmation code is entered in 4 cells with a resend timer.
On the phone the navigation moves to a bottom tab bar, the shipments table scrolls sideways with a pinned actions column, the details panel and the map open full screen.
Integrations
- Telegram bot · sign-in code
- Nominatim · OpenStreetMap
connected by me
Two more integrations are planned in the architecture for the next stages: a flight schedule API, so the courier picks a flight from a list instead of typing it in, and a payment service for courier payouts. They were not connected in the MVP, and the architecture is designed to add them.
Data security
The service stores the personal data of senders and couriers: full names, phone numbers, addresses and flight details. A leak of such data undermines trust in the service and breaks the personal data law (152-FZ), so protection was built in from day one. Sensitive fields are encrypted in the application with AES-256-GCM before they are written to the database: even if someone gets access to the database or a backup, the data stays unreadable, and GCM prevents it from being tampered with unnoticed. The connection goes over HTTPS only, the database is backed up regularly, sign-in uses a one-time code through a Telegram bot, and access is split between the sender and courier roles at the API level.
Project and process setup
Before development started, I set the project up so three developers could work on one frontend in parallel from the first week: the folder structure is described in the README, ESLint checks the code style, and all code goes through cross-review.
Tests are part of the process: unit tests for the backend and component snapshot tests on Vitest and @vue/test-utils for the frontend. Writing them was handed to AI agents to save the team's time.
I automated code delivery in GitLab CI: the pipeline builds the Docker images and rolls them out to the VPS.
- build Docker images
- deploy VPS
I kept the process light, sized to the team and the deadline: tasks in git issues, direct contact with the client, no sprints.
Challenges
A frontend without a backend
- Problem
- The deadline was tight, the frontend had to start right away, and there was no backend yet.
- Solution
- I gave the team the API contract in Swagger and set up a basic backend on frontend tooling: NestJS on TypeScript with the same contract types as the frontend. While the API grew, the frontend worked through an MSW mock server.
- Result
- Two developers built the screens against the contract without waiting for the API, and the backend on a stack the team already knew went in parallel. The MVP was built in about 5 weeks.
Phone sign-in without SMS
- Problem
- The phone number has to be confirmed, and an SMS provider charges for every message. For an MVP on a small budget this matters.
- Solution
- The confirmation code comes through a Telegram bot. On the frontend there is a phone mask, a role choice, sender or courier, and code entry in 4 cells with a resend timer.
- Result
- The bot is free, and the crews are on Telegram anyway, so the code arrives where it is convenient for them.
Metrics and results
- ~5 wkto the MVP, frontend and backend in parallel
- 3developers on the team
- 2roles: sender and courier
The client accepted the MVP. The project never reached launch, so there are no usage metrics.
Need an MVP in a few weeks or a service with a map and roles?
I will do the design, the frontend and the backend, bring in a team if needed and take the MVP through to handover.