Reinover
From contract to invoice.
Freelance · solo
Built with
- TypeScript
- Next.js
- tRPC
- Drizzle ORM
- PostgreSQL
- Row Level Security
- Redis
- BullMQ
- WebSockets
- Clerk
- Docker

The brief
Reinover runs a commercial cleaning company in Hannover — contracts, recurring jobs, a field crew and monthly invoices. The day-to-day of a business like this usually scatters across spreadsheets, paper and phone calls. Reinover gathers it into one system, from contract to paid invoice. Designed and built single-handedly — and live, in real use.

One platform, three apps
The platform
Three interfaces for three roles, from one codebase: a back-office for operators, a self-service portal for customers, and a mobile app for the cleaners on site. All share one type-safe API, one data model and one design system — a single identity, no per-app drift.

From job to invoice
Workflow
Contracts generate recurring jobs automatically. A planner proposes crews by skill, conflicts and workload; the cleaners complete their jobs in the app. Invoices follow — generated automatically, rendered as PDFs, and tracked across their whole lifecycle to ‘paid’.


What runs when nobody is looking
Background
Invoices don't happen inside a web request. A separate service plans the runs, a Redis-backed queue works through them, and a renderer turns them into PDFs. Because this part handles money, every step sits behind an idempotency key: a repeated run doesn't produce a second invoice, and a payment attempt delivered twice doesn't book twice. Invoice numbers come from their own per-tenant sequence, so there are no gaps and no duplicates. Reminders and recurring billing go the same way.
Enterprise-grade, by one engineer
Under the hood
Under the surface, the platform behaves like enterprise software. A tRPC API with shared Zod schemas makes the API contract the type system, so the three apps can't drift apart. Business logic lives in its own domain layer, decoupled from the interface and testable on its own. Data access goes through Drizzle, sign-in through Clerk. Tenants are kept apart by Postgres row-level security, a per-request org context and consistently org-scoped queries, with a two-level, deny-by-default permission model on top. Live updates run through an outbox-backed, idempotent event relay into LISTEN/NOTIFY and WebSockets.
Four languages, including Arabic
Reach
The whole platform speaks four languages — German, English, Arabic and Turkish — with full right-to-left layout for Arabic and light and dark themes on every screen. From one design system, with no per-app exceptions. For a workforce as diverse as the city it serves.

