Delivered remotely for a business based in Zurich, Switzerland. Names withheld by agreement.
Project Overview
Industry: Workforce and staffing technology — supervised hourly and shift-based work.
Type of solution: A multi-sided marketplace and workflow platform: a token-authenticated REST API with a server-rendered administrative back office, a single-page web application, and two native mobile applications.
Business context: Businesses needing short-notice hourly labour have traditionally used agencies. Agencies are expensive, but they are not expensive for no reason — they absorb risk on both sides. The worker gets certainty of payment; the business gets certainty that hours claimed were hours worked; neither has to hold the other's bank details or chase the other for money. Any platform proposing to replace the agency has to replace that risk absorption too, or it is simply a job board with extra steps.
General users: Hourly and shift workers, the businesses that hire them, supervisors who verify work on the ground, and platform administrators.
General purpose: To make short-notice hourly hiring work end to end — discovery, hiring, verification of hours, and payment — without either side having to trust the other, and without an intermediary taking an agency margin for doing it.
The Business Challenge
Matching is a scheduling problem, not a search problem. A shift is a specific window on a specific day in a specific place requiring specific skills. Matching against it means understanding worker availability as structured data, not as a paragraph on a profile.
Nobody watched the work. Hourly work performed away from the person paying for it creates an asymmetry that has no clean technical answer. A self-reported figure is a claim. A claim is disputable. A dispute at the point of payment is exactly where a marketplace loses both participants at once.
Two parties, and only one of them is present. The business is not on site. The worker is. Asking the business to police hours it cannot observe puts it in an impossible position; asking it to accept whatever is submitted puts it in a worse one.
Money has to sit somewhere in between. If the business pays after the work, the worker carries the risk. If the worker is paid before, the business does. Someone has to hold funds during the gap, which means an internal balance, a ledger, a release condition, identity verification, and a payout path to a real bank account.
Four roles, four clients, one product. Workers are on their phones. Businesses are often at a desk. Supervisors are on site. Administrators are handling disputes and withdrawals. Every one of them needed a coherent experience, and the platform shipped on web, Android and iOS.
Trust has to be visible. Ratings, review history, verified identity and a record of completed work are not features bolted onto a marketplace — they are the reason anyone uses it in preference to a phone call to someone they already know.
Our Approach
Add the missing participant. Rather than trying to solve the verification problem between two parties who each have an interest in the answer, we modelled a third: a supervisor assigned to a job, whose approval is what releases payment. This is how supervised staffing already works off-platform, and modelling it faithfully was the single most consequential decision in the project. It is a first-class account type — its own sign-in, its own application shell on every client, its own notifications, its own back-office management.
Make hours evidenced rather than asserted. Tracked work sessions produce structured artefacts alongside the elapsed time, so an approval or a rejection is a judgement about something rather than a judgement about a claim. Artefacts are captured and uploaded in batches rather than streamed, which respects the constraints of a device carried through a working shift on a variable connection.
Model money as a ledger, not a number. Every movement is a row carrying its own credit, debit, resulting balance, type, initiating party and external reference. A balance that is only a number can be corrected but never explained; a ledger can be reconstructed, reconciled and audited.
Delegate the regulated parts. Identity verification, connected-account creation and payout execution are handled by an established payments provider rather than built in-house. This is not a shortcut — it is the correct boundary for a platform that moves money between individuals and businesses.
Encrypt personal data at the application layer. Personal fields on the user record are encrypted before they reach the database and decrypted on read, with the key held outside the codebase. This costs the ability to index or query those columns directly, which we accepted deliberately: the trade is worth making when the data in question identifies individuals.
Give the web client a real state architecture. The web application was built on a full unidirectional state store with a slice per domain concept, effects isolating all server interaction, and route resolvers prefetching data before a view activates. In a marketplace this data-dense, ad-hoc component state becomes unmaintainable well before feature-complete.
Build both mobile clients natively. Android in Kotlin with MVVM, data binding and a repository layer; iOS in Swift with MVVM and modules mirroring the platform's roles. Both clients depend heavily on camera, location and background behaviour, which is where native implementations earn their cost.
Give the marketplace a public face. Job listings and worker profiles are viewable without an account, so the platform has an indexable surface and a route from search to sign-up rather than a wall.
The Solution
Structured job posting. A job carries a skill and sub-category classification, a geographic location drawn from a country/state/city hierarchy, a rate type, a rate, a date and time window and a total-hours figure — enough structure to match a real shift rather than approximate one.
Availability as data. Workers maintain a calendar of available dates that appears on their public profile and can be matched against a shift's window.
Discovery in both directions. Businesses browse and search workers, favourite them and build a shortlist; workers search and filter jobs by category, skill and criteria, save the interesting ones and suppress the rest. Both sides can initiate: workers apply, businesses invite.
A hiring lifecycle, not a status field. Jobs move through posting, interview, award and completion, with applications, invitations, acceptances and rejections all recorded as their own events.
Supervisor assignment. A business assigns one or more supervisors to a job. Supervisors sign in to their own application experience across web, Android and iOS.
Tracked work sessions. Workers start and stop tracking against a job, with verification artefacts captured during the session and uploaded in batches. Elapsed time and the resulting charge are computed against the job's agreed rate.
Timesheets and approval. Tracked time becomes a timesheet, submitted for supervisor review and either approved or rejected, with a path for the worker to request an extension when a shift runs long. Both hourly and fixed-rate work are supported.
Wallet and ledger. Businesses fund jobs into a wallet balance. Approved work triggers release from the business wallet to the worker wallet. Every movement is recorded in a transaction ledger with a running balance.
Identity-verified payouts. Workers complete identity verification through the payments provider, connecting a bank account. Withdrawal requests are reviewed and paid out to that account.
Reputation. Bidirectional ratings and written reviews attach to completed jobs and accumulate into a public work history, alongside portfolio items and certifications.
Messaging and notifications. Direct and group messaging with read state and unread counts, a separate support channel to platform administrators, and push notifications with per-user, per-type preferences.
Administrative back office. Management of accounts across all roles, jobs, the skill and geographic taxonomies, transactions, withdrawal approvals, reported jobs, messaging, email templates and platform settings.
Key Features
Supervised timesheet approval A named third party assigned per job reviews tracked work and approves or rejects it, and that approval is what gates payment — replacing a two-party dispute with a three-party process.
Evidenced time tracking Tracked work sessions produce structured verification artefacts alongside elapsed time, uploaded in batches suited to a mobile device on a variable connection, so approval decisions rest on evidence rather than assertion.
Escrow-style wallet with a running-balance ledger Businesses fund work up front; funds release to the worker on approval; every movement is a ledger row carrying credit, debit, resulting balance, type and external reference.
Identity-verified payouts Identity verification and connected-account creation are handled through an established payments provider, with withdrawal requests reviewed before payout to the worker's own bank account.
Structured availability matching Worker availability is a calendar of dates rather than free text, so it can be matched against a shift's specific window instead of read and interpreted.
Role-specific experiences on every client Worker, business, supervisor and administrator each get a distinct navigation shell and feature set, implemented across a web application and two native mobile applications.
Bidirectional reputation and verified work history Ratings and reviews flow both ways and accumulate into a public profile alongside portfolio and certification records, giving both sides something to evaluate before committing.
Application-layer encryption of personal data Personal fields are encrypted before persistence and decrypted on read, with key material held outside the codebase, so the database alone does not yield readable personal information.
Public marketplace surface Job listings and worker profiles are viewable without an account, giving the platform an indexable presence and a direct route from search to registration.
Technical Architecture
Client layer. A single-page web application built on a unidirectional state store with a slice per domain concept, effects isolating server interaction, route resolvers prefetching data before view activation, and route guards separating the worker, business and supervisor route trees. Progressive Web App configuration caches the application shell. Alongside it, a native Android client in Kotlin using MVVM with view models, data binding, a navigation graph and a repository layer over a typed HTTP client; and a native iOS client in Swift using MVVM with modules mirroring the platform's roles.
API layer. A token-authenticated REST API using OAuth2 bearer tokens, with controllers partitioned by audience over shared base controllers and route definitions split by feature. The same application serves a session-authenticated, server-rendered administrative back office.
Domain layer. Marketplace (jobs, applications, invitations, hiring), verification (tracking sessions, artefacts, timesheets, supervisor approval), money (wallets, ledger, funding, release, withdrawals), identity (accounts, roles, verification, reputation) and communication (messaging, notifications, templated email).
Data layer. A relational database with the job and worker taxonomies, a geographic hierarchy, the transaction ledger, verification records and messaging, with personal fields stored as ciphertext.
Integration layer. An established payments provider for charges, connected accounts, identity verification and transfers; a push notification service for device delivery; three social identity providers plus native platform sign-in; SMTP for transactional email.
Delivery. Continuous-integration-triggered releases to versioned deployment directories with environment configuration and key material linked in from outside the release, followed by cache clearing and application server reload.
Flow: Web SPA / Android / iOS → OAuth2 bearer token → REST API → relational database → payments provider (funding, verification, payouts) + push and email delivery, with an administrative back office over the same domain.
Technology Stack
| Category | Technology |
|---|---|
| Backend language | PHP |
| Backend framework | Laravel |
| Database | MySQL with Eloquent ORM and migration-managed schema |
| API authentication | OAuth2 bearer tokens (Laravel Passport) |
| Administrative back office | Blade server-rendered views with Laravel Mix asset pipeline |
| Web framework | Angular with TypeScript |
| Web state management | NgRx store, effects and entity — a slice per domain concept |
| Web data loading | Route resolvers with role-based route guards |
| Web UI | Angular Material and CDK, Bootstrap, calendar, range slider, tag input, pagination and date/time picker components |
| Web delivery | Progressive Web App with service worker shell caching |
| Android | Kotlin, MVVM with ViewModel and LiveData, Data Binding, Navigation Component |
| Android networking | Retrofit with reactive adapters and an OkHttp logging interceptor |
| Android media | Image loading and caching, image picker and cropper |
| iOS | Swift, MVVM, CocoaPods dependency management |
| iOS networking & media | HTTP client with JSON handling, image loading and caching |
| Payments | Established payments provider — charges, connected accounts, identity verification, transfers, payouts |
| Push notifications | Firebase Cloud Messaging with native platform push handling |
| Identity providers | Facebook, Google and native platform sign-in |
| Location & camera | Platform location services and camera access on both mobile clients |
| Data protection | Application-layer encryption of personal fields; bcrypt password hashing |
| CI/CD | Continuous integration triggering versioned, scripted releases |
Technical Challenges & Solutions
| Challenge | Our Approach |
|---|---|
| Paying for hours nobody at the business observed | Introduced a third participant — a supervisor assigned per job whose approval gates payment — modelled as a first-class account type with its own sign-in and its own application shell on every client, rather than asking two interested parties to agree. |
| A self-reported number is a claim, and claims get disputed | Tracked work sessions produce structured verification artefacts alongside elapsed time, so approval is a judgement about evidence. Artefacts upload in batches rather than continuously, respecting battery and connectivity on a device carried through a shift. |
| Neither side wants to carry payment risk | An internal wallet holds funds from posting until approval, with release triggered by the supervisor's decision — replacing the mutual trust an agency used to supply. |
| A balance can be corrected but not explained | Modelled money as a running-balance ledger: every movement is a row with credit, debit, resulting balance, type, initiating party and external reference, so the position can be reconstructed and reconciled rather than merely read. |
| Moving money to individuals brings regulated obligations | Identity verification, connected-account creation and payout execution delegated to an established payments provider, keeping the platform on the correct side of a boundary it should not be building itself. |
| Matching against a shift, not a project | Structured the job around a date and time window, location, rate type and total hours, and structured worker availability as a calendar of dates — so matching is a query rather than an interpretation. |
| Four roles across four codebases | Role-partitioned route trees with dedicated guards on the web client, and role-specific navigation shells on both native clients, sharing one API contract while keeping each role's experience focused. |
| Marketplace-scale client state | A full unidirectional store on the web client with a slice per domain concept, effects isolating all server interaction, and resolvers prefetching route data — chosen over component-local state, which becomes unmaintainable well before a marketplace is feature-complete. |
| Personal data at rest | Application-layer encryption of personal fields with key material held outside the codebase, accepting the loss of direct queryability on those columns as a deliberate trade. |
Security & Reliability
Token-based authentication. The API authenticates clients with OAuth2 bearer tokens, with registration, verification, password recovery and account deactivation flows, plus federated sign-in through established identity providers.
Role separation across clients. The web application partitions its route tree by role behind dedicated guards; the mobile clients present role-specific shells; the administrative back office sits behind its own authentication boundary.
Personal data encrypted at rest. Personal fields on the user record are encrypted at the application layer before persistence and decrypted on read, with key material held outside the codebase, so database contents alone do not yield readable personal information. Passwords are stored as bcrypt hashes.
Verification delegated to a specialist. Identity verification and connected-account onboarding run through an established payments provider rather than being implemented in-house, keeping regulated identity handling with a party equipped for it.
An auditable money trail. Funding, release and withdrawal each produce ledger rows carrying their own credit, debit, resulting balance, type, initiating party and external reference, so financial position can be reconstructed rather than inferred.
Supervision as a control. The supervisor approval step is a security control as much as a workflow one: it places an independent party between a claim for payment and the payment itself.
Separation of configuration from code. Environment configuration and key material are linked into each release from outside the deployed tree, so credentials live with the environment rather than with the application.
Repeatable releases. Deployments run through continuous integration into versioned release directories with previous releases retained, giving a defined rollback path.
Scalability & Performance
Stateless application tier. Token authentication and externalised configuration keep application instances free of per-user state, so the API tier scales horizontally without session affinity.
Client-side state as a cache. The web application's store holds normalised domain data across components and route changes, so navigating the marketplace does not re-fetch what the client already holds.
Prefetched route data. Resolvers load what a view needs before it activates, removing the sequence of loading states that otherwise characterises a data-dense marketplace on a slow connection.
Batched upload from the field. Tracked intervals and verification artefacts are accumulated and uploaded in batches rather than streamed continuously, reducing request volume and tolerating the intermittent connectivity of a device carried through a working shift.
Paginated and filtered listings. Job, worker and history listings are filtered and paginated at the database rather than in the client, keeping result sets bounded.
Cached media on mobile. Both native clients cache remote imagery locally — profile photography, portfolio items and job media are the bulk of what these screens transfer.
An application shell that survives the network. Progressive Web App configuration caches the web application shell, so the interface loads on a poor connection and only data has to travel.
Business Outcomes
- Hourly work off-site became payable with confidence, because approval rests on an independent supervisor reviewing evidence rather than on one party accepting the other's word.
- The agency's risk-absorption role was replaced by mechanism — funds held from posting to approval, released against verified work, paid out to a verified account.
- Shifts are matched, not advertised, because both the job's window and the worker's availability are structured data.
- Disputes have something to resolve against, since tracked sessions, timesheets, approvals, rejections and every fund movement are all retained.
- All four roles have a coherent product, on the device each of them actually uses, from a phone on site to a desk in an office.
- Financial position is reconstructable, because money is recorded as a ledger rather than as a mutable balance.
- Both sides have something to evaluate before committing, through bidirectional reputation, verified identity and a visible history of completed work.
- The marketplace is discoverable, with public listings and profiles providing a route from search to registration.
Why it worked
Two-sided marketplaces are a well-understood pattern. The interesting work starts when two sides are not enough — when the transaction only closes because someone neither side controls is willing to attest to what happened. Getting that third participant right is a modelling problem before it is an engineering one, and getting it wrong produces a platform that looks complete and is quietly unusable, because the payment step never resolves.
Our team builds for that. We identified that supervised hourly work needs a supervisor in the data model, not a checkbox in a form, and gave that role its own identity, its own sign-in and its own product on every client we shipped. We treated tracked hours as something that must produce evidence rather than a number, and designed capture around the reality of a phone carried through a shift. We modelled money as a ledger because a marketplace that cannot explain a balance will eventually be asked to. And we drew the line at the regulated boundary, delegating identity verification and payout execution to a provider equipped for it rather than accumulating obligations the product did not need.
Our teams work across Laravel and modern PHP, large multi-client API design, Angular with rigorous state architecture, native Android in Kotlin and native iOS in Swift, payments and payout integration, and the workflow modelling that decides whether a marketplace closes its transactions or stalls at the last step.
Final Summary
Short-notice hourly staffing ran through agencies for a long time, and it ran through them for a reason: someone had to absorb the risk that sits between a business that cannot watch the work and a worker who cannot be certain of payment. A job board does not absorb that risk. It just moves the phone call online.
Our team built a platform that absorbs it structurally. Shifts are posted with a real window, a real location and a real rate, and matched against worker availability held as structured data. Hiring runs as a lifecycle rather than a status field, initiated from either side. Work is tracked in sessions that produce verification artefacts, and those hours are reviewed not by the business and not by the worker but by a supervisor assigned to the job — a third participant modelled as a first-class role with its own sign-in and its own product experience on every client. Approval releases funds that were held from the moment the job was posted, recorded as ledger entries rather than as an adjusted number, and paid out to an identity-verified account through an established payments provider.
Around that sit the things a marketplace needs to be used twice: bidirectional reputation, verified work history, portfolio and certification records, direct and group messaging, granular notification preferences, and public listings that give the platform a route from search to sign-up. It was delivered as a token-authenticated API with an administrative back office, a single-page web application built on a full unidirectional state architecture, and native Android and iOS clients — each of them carrying a distinct experience for every role on the platform. The result replaces the agency's margin with mechanism, which is the only substitution that actually works.