
Technaut Aqua Track — Water Distribution SaaS
Multi-Tenant SaaS · Distribution
Runs a gym from the front desk — memberships, check-ins, dues and stock — with a separate app for members, trainers and the owner.
Gym management for Indian gyms: memberships and plans, attendance, billing and point of sale, inventory, expenses and reporting, served from a NestJS API to a Next.js dashboard and three role-specific Flutter apps.

Technaut Gym covers what a gym owner actually watches day to day: who is active, whose membership expires this week, what came in today, and who still owes. The dashboard leads with those numbers — total and active members, expiries inside seven days, today's attendance and revenue, pending payments and low stock — because they are the questions asked before anything else.
Three Flutter apps sit beside the web dashboard, each aimed at one role: members see their plan and check-ins, trainers work the desk with a QR scanner, and the owner gets the business view. All three share one core package holding the theme, API client, auth and push handling, and each app refuses accounts of any other kind at sign-in rather than hiding UI after login.
Membership state is modelled as more than active/expired — frozen is a first-class status, because pausing a membership for travel or injury is routine and a system that only knows the two extremes gets worked around with spreadsheets.
Where integrations are not configured, the reminder queue parks the job with a reason the admin can read, instead of reporting a WhatsApp or push message as sent.
Gyms track memberships in a register and dues in the owner's head. Expiries are noticed after a member has already stopped coming, personal-training packs are counted manually, and there is no single place that answers what came in today against what is still owed.
Sat with the questions an owner asks first — who is active, who lapses this week, what did we collect, who owes — and made those the dashboard rather than burying them under navigation.
Built a multi-tenant NestJS platform with a Next.js dashboard and three role-specific Flutter apps sharing one core package. Membership state, dues and attendance are one model, so the expiry list and the collections figure come from the same records.
NestJS 11 + Prisma 6 over MySQL 8.4, with a shared TypeScript/Zod contract package
Next.js 16 dashboard with React Query, Tailwind and shadcn/ui
Three Flutter apps — member, trainer (with mobile_scanner), owner — over a shared apps/core package
One theme, one API client and one login flow in core; each app rejects other roles at sign-in
pnpm workspaces + Turborepo for TypeScript, Docker Compose for local MySQL
Reminder queue behind a channel abstraction — unconfigured providers park rather than fake a send
Modelling membership as active or expired forced staff into workarounds every time someone paused for travel or injury, and those pauses ended up tracked outside the system.
Made frozen a first-class membership state with its own expiry arithmetic, so a pause is recorded, resumes correctly and still shows in the expiry forecast.
Three apps that each implemented their own theme, API client and auth drifted apart, and a contract change meant three separate fixes.
Extracted theme, API client, auth and push into a single Dart core package that all three apps depend on, leaving each app as a thin role-specific shell.
A member app, a trainer app and an owner app all authenticating against the same endpoint let anyone sign into any of them and simply see less.
Each app declares the single role it serves and rejects accounts of any other kind at sign-in, rather than authenticating first and hiding UI afterwards.
The owner opens one dashboard and sees active members, this week's expiries, today's collections, outstanding dues and low stock. Front-desk check-in is a QR scan, and members see their own plan without asking the desk.







