Putora

A job marketplace with four production surfaces: iOS and Android, the API, a web portal, an admin panel. I built all of it, and I still run it.

status
live in production
role
sole engineer, architecture through operation
surfaces
mobile app · api · web portal · admin panel
client
Putora LLC
timeline
september 2025 → present
build
3 months backend · 4 mobile · 1 qa

what i own

mobile app
Flutter · BLoC/Cubit · offline-first
backend
Node · Express 5 · Socket.IO · PostgreSQL
web portal
React · Vite · TanStack Router + Query
admin panel
React · Vite · role-gated
infrastructure
AWS — ALB, EC2, nginx, RDS Aurora, S3 static hosting, GitHub Actions
third-party
RevenueCat billing · SendGrid email

Every row above is mine.

what it is

Putora is a job marketplace for people who work while they travel. They find roles, companies find them, and the two talk inside the app. It ships as an iOS and Android app carrying both sides, a web portal, and an admin surface behind it. The product is the client’s. This page is about the engineering.

Three Putora screens on iPhone: sign-in, account creation, and the job discovery feed
the appfig. 1

Screenshots are from a demo build. Every name, face, company, listing and message in them is seed data. No real account appears on this page.

how it fits together

Three clients, one backend, a load balancer in front. The app tier answers the REST calls and holds the sockets. Managed Postgres keeps the data, object storage keeps uploads and the built web bundles. Billing and email are bought, not written.

Putora system overviewThree client surfaces behind a load balancer, an application server serving API and realtime traffic, backed by managed Postgres and object storage. CLIENT SURFACESMobile appFlutter · BLoC · offline-firstWeb portalReact · Vite · TanStackAdmin panelReact · role-gated moderationLoad balancerApplication serverAPI and realtimeMANAGED DATA SERVICESManaged Postgresprimary storeObject storageuploads
surfaces, backend and datafig. 2

the hard parts

Four surfaces, one backend, one engineer.

Two kinds of user in one native app, plus the portal, the admin panel and the API all three share. With no team to negotiate with, the only thing holding them together is convention: one HTTP client, one state pattern, one deploy path. Add a field to a response and it reaches every surface the same afternoon.

Billing changed providers mid-flight.

There were paying subscribers on both sides of the cut, so the swap had to happen on a live revenue path with the old and the new provider both authoritative for a while. Entitlements resolved through the whole migration. Nobody lost access to a subscription they had already paid for, which is the only part of this a user is ever meant to see.

Three Putora screens on iPhone: the subscription plan picker, an interview detail, and a job description
subscriptions and schedulingfig. 3

Native and web, inside one app.

A few screens are shared with the web surface instead of being built a second time in Flutter, so there is one implementation and nothing to drift. The seam between the two runtimes is a contract like any other: defined on both sides, changed on both sides, never one without the other. On screen it reads as one app.

Three Putora screens on iPhone: a company profile, a user profile, and a job detail
profiles and listingsfig. 4

the mobile app

Offline-first. The app keeps its own copy of what the user has already seen. Screens paint from that copy first and correct themselves when the network answers, so opening the app on bad hotel wifi shows the last known state instead of a spinner. Messaging runs over a socket. Everything else is plain HTTP.

Three Putora screens on iPhone: a user profile with plan status, the notifications list, and jobs in list view
profile, notifications, listingsfig. 5
Three Putora screens on iPhone: a confirmation screen, a candidate profile, and a detail view
the seeker sidefig. 6

the company side

Companies get the other half of the same app: post a role, work through the applicants, book the interviews, watch the numbers. One binary, one backend. The account decides which app you land in.

Three Putora screens on iPhone: the message inbox, a company's posted roles, and the company dashboard
inbox, roles, dashboardfig. 7
Three Putora screens on iPhone: a role's statistics, an application form, and the interview calendar
statistics, applications, calendarfig. 8

admin and delivery

The admin panel is where the client’s own team works: moderation, verification, support, reporting. It calls the same API the apps do, so an action taken there is live in the app, not waiting on a sync.

Nothing reaches the server until the type-check and the production build have both passed in CI. Either one red and the release stops. Mobile waits on store review on top of that. It is the same pipeline every time, which is what makes shipping boring.

see it

what the client said

Honestly, Yassine's a wizard — he knows his stuff.
StefanFounder & CEO, PutoraVerified · Upwork

the fine print

The product belongs to the client, so its internals stay with them. Everything above is my half.