The repeat-service flywheel
Customers don’t care about the technology stack. They care about one thing: “Will this help me get more repeat service jobs and stop losing customers because we forgot to follow up?”
This is the cycle that matters for an AC, RO, appliance, pest-control, solar or maintenance company. Every service job the platform records automatically schedules the next service reminder and a post-service follow-up — building a self-replenishing pipeline of repeat revenue.
Technology stack
A modern, containerised stack: Java 21 + Spring Boot on the backend, Next.js 16 on the frontend, PostgreSQL with row-level security for hard tenant isolation, Redis for performance and RabbitMQ for asynchronous notifications and reminders.
| Layer | Technology | Notes |
|---|---|---|
| Backend runtime | Spring Boot 3.4.8 · Java 21 | REST API mounted under the /api context path; versioned resources under /api/v1 |
| Backend build | Maven (Maven wrapper) · MapStruct 1.6.3 · Lombok | DTO mapping via MapStruct; boilerplate via Lombok |
| Security | Spring Security 6 · jjwt 0.12.6 · bcrypt | JWT access + refresh tokens (HS256), bcrypt password hashing, role-based access control (RBAC) |
| Database | PostgreSQL 16 · Spring Data JPA (Hibernate) · Flyway | Flyway migrations V1–V17 plus dev demo seeds V901–V907; shared-schema multi-tenancy with RLS |
| Cache & rate limit | Redis 7 | Token denylist, rate limiting (with in-memory fallback), hot-read caching |
| Messaging | RabbitMQ 3.13 (AMQP) | Async notification & reminder delivery (dead-letter handling planned) |
| Spring Mail (SMTP) | Verification / reset / reminder emails; MailHog in dev; log-mode when app.mail.enabled=false | |
| Payments | Razorpay (REST) | Subscriptions API + webhooks; simulated mode by default in dev, live mode via env config |
| SMS | Twilio (opt-in) | Activated with SMS_PROVIDER=twilio; fails open to console in dev |
| Frontend | Next.js 16 · React 19 · TypeScript 5.7 | Standalone build served by nginx; app-router pages, server components |
| Frontend UI | Tailwind CSS 4 · TanStack Query 5 | Corporate indigo design system; server-state caching for API data |
| API docs | springdoc-openapi 2.6 | Swagger UI (dev) at /api/swagger-ui.html, OpenAPI JSON at /api/v3/api-docs |
| Testing | JUnit 5 · Testcontainers PostgreSQL · H2 · Vitest · React Testing Library | Backend tests on H2 (PostgreSQL mode) + Testcontainers; frontend unit tests in Vitest |
| Delivery | Docker Compose · GitHub Actions · GHCR · AWS EC2 | Local full stack in docker-compose.yml; production stack via docker-compose.prod.yml on a single EC2 host (Phase 1) |
System architecture
Deployment overview (Phase 1)
Request flow
tenant_id predicates on index-aligned (tenant_id, …) indexes, and PostgreSQL
row-level security enforces the same boundary at the database — so a buggy query can never leak
cross-tenant data.
Asynchronous notifications (RabbitMQ)
JSON via Jackson2JsonMessageConverter; poison-message dead-lettering is planned for Phase 2.
Redis supports rate limiting, the JWT denylist and hot dashboard reads.
Reminder engine
Module boundaries (bounded contexts)
- config — Security, Web MVC, Redis, RabbitMQ, OpenAPI, JPA auditing, Jackson
- shared — ApiResponse/PageResponse, BaseEntity, auditing, exception handling
- tenant — TenantContext (ThreadLocal), filter, interceptor, data source decorator
- auth — login/register/refresh/logout, JWT provider & filter, refresh-token store
- user — users, Role enum (OWNER/MANAGER/TECHNICIAN)
- customer — customers CRUD, tags, search
- equipment — assets, warranty, service frequency, next-service date
- technician — skills, categories, availability, assignments
- job — service jobs, status/assignment transitions, payments
- followup — follow-ups (due/overdue scheduler)
- reminder — reminder rules, engine, logs
- notification — in-app inbox + channel providers
- subscription — plans, limits, Razorpay billing
Security model
- Authentication: short-lived
accessToken(15 min, JWT HS256) + long-livedrefreshToken(7 days) stored hashed (SHA-256) inrefresh_tokenswith rotation and revocation; logout revokes. - Passwords: bcrypt via Spring Security; password reset uses a single-use token valid 2 hours.
- Authorization (RBAC):
OWNER(everything + billing/settings),MANAGER(customers, equipment, jobs, technicians, reminders),TECHNICIAN(assigned jobs, notes, own schedule). - Anti-enumeration: forgot-password always returns the same response; verification tokens for email confirm.
- Rate limiting: Redis keys
auth:login:<email>:<ip>(5 per 15 min) andauth:forgot:<email>(3 per hour) with in-memory fallback; excess returns429. - CSRF/CORS: Bearer-only auth (no cookies) so CSRF is disabled; CORS is permissive in dev, restricted in prod.
- Error contract: RFC-7807-style
401s viaRestAuthenticationEntryPoint; typed errors via global exception handler.
Scalability roadmap
- Extract services — split into
auth-service,notification-service,ai-servicewhen load justifies it (monolith-by-module keeps costs low now). - Kafka — replaces RabbitMQ for higher-volume eventing/replay; the exchange abstraction keeps producers unchanged.
- Kubernetes — Helm + HPA once the single EC2 host saturates; RLS remains the isolation boundary.
- S3 — customer documents & job photos via pre-signed URLs.
- Multi-region / read replicas — read-only replicas for reporting; tenant-aware routing remains the invariant.
Multi-tenancy & data isolation
Model: shared schema + tenant_id column. Every tenant-scoped table carries a
tenant_id UUID and a composite (tenant_id, …) index. One PostgreSQL cluster serves all
tenants — the most cost-efficient model for Phase 1 — while isolation is enforced at two independent layers.
Layer 1 — application context (per request)
TenantFilterresolves the tenant at request entry — theX-Tenant-IDheader, falling back to the authenticated user’s tenant — and stores it inTenantContext, aThreadLocal<UUID>.TenantInterceptorhooks pre/post-controller and always clears the context after the request so async work must propagate the tenant explicitly (never implicitly across threads).
Layer 2 — database connection binding
TenantAwareDataSourcedecorates the connection pool; everygetConnection()returns aTenantAwareConnection.- On acquisition (and prepare-statement/commit paths) the connection runs
SET app.current_tenant = '<tenantId>'and resets it when returned to the pool.
Layer 3 — PostgreSQL row-level security (defense in depth)
Each tenant-scoped table is protected with ENABLE + FORCE ROW LEVEL SECURITY and a single policy:
-- applied to every tenant-scoped table (V14)
ALTER TABLE service_jobs ENABLE ROW LEVEL SECURITY;
ALTER TABLE service_jobs FORCE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON service_jobs
FOR ALL
USING (tenant_id::text = current_setting('app.current_tenant', true))
WITH CHECK (tenant_id::text = current_setting('app.current_tenant', true));
| Table group | RLS protected | Reason |
|---|---|---|
| Customers, equipment, technicians, service jobs, follow-ups, reminder rules/logs, notifications, organizations, subscriptions | ✅ Yes | Tenant-scoped business data |
tenants (registry) | — | Accessed without tenant context |
refresh_tokens (auth) | — | Auth store; no tenant context |
Why this design scales
- Moving to Kubernetes or Kafka later does not touch tenancy — RLS stays the isolation invariant.
- Multi-region read replicas for reporting keep tenant-aware routing intact.
- Trade-off: all tenants share one instance, so Phase-1 capacity planning should target the largest tenant; this is the known cost of the shared-schema model.
Product features
Status legend: Implemented shipped in V1, Partial core shipped / next milestone, Planned roadmap item built into the pricing model.
Roles & Access Control Implemented
- Three built-in roles: OWNER (full access, billing & settings), MANAGER (customers, equipment, jobs, technicians, reminders), TECHNICIAN (assigned jobs, notes, own schedule).
- JWT authentication: 15-minute access token + 7-day refresh token stored hashed with rotation & revocation.
- bcrypt password hashing; email verification; single-use 2-hour password-reset links; no user enumeration.
- Redis-backed rate limiting on login & forgot-password with in-memory fallback.
Customer Management Implemented
- Full CRUD with profile: name, phone, email, address/city/area,
customerType, notes andtags[]. - Paginated search by query (
?q=) and city filter; duplicate-email guard per tenant.
Equipment / Asset Management Implemented
- Assets tracked per customer: asset type, brand, model, serial number, installation & warranty dates.
serviceFrequencyMonthsdrives an automaticnextServiceDatethat feeds the reminder engine.- Asset lifecycle status (ACTIVE, history) with per-asset notes.
Service Management Implemented
- Service jobs with a cluster-wide human-readable
jobNumber(sequential). - Guided status flow:
NEW → SCHEDULED → IN_PROGRESS → COMPLETED | CANCELLED; assign to a technician; priority levels. - Parts used (JSON), labour charges, total amount and payment status per job.
- On completion the system sets
completedAtand computes the next service date from service frequency — automatically spawning the next reminder.
Technician Management Implemented
- Technician profiles: skills, service categories, weekly availability (JSON), status.
- Optional link to a
TECHNICIANuser account for app access. - Filter technicians by service category for smart dispatching.
Automatic Service Reminder System Implemented SMS delivery partial
- Per-tenant
reminder_rules: service category →days_beforethresholds (e.g. 30/15/7/1) and enabled channels. - Background scheduler scans
next_service_datedaily and raises reminders exactly once per equipment/rule/channel/day (idempotent via a dedupe index onreminder_logs). - Delivery channels: IN_APP, EMAIL (SMTP), SMS (Twilio, opt-in); every delivery is audited as SENT or FAILED.
Follow-Up Management Implemented
- Follow-ups per customer with assignee, date/time, notes, priority and opt-in reminders.
- Daily scheduler (
FOLLOWUP_CRON, default 07:00) raises DUE (today) and OVERDUE notifications; each follow-up fires once.
Dashboard Implemented
- Live summary: open jobs, jobs today / this week, active customers & equipment, due follow-ups, upcoming reminders, revenue this month, unpaid revenue and top technician.
- Revenue trend vs previous month (month-over-month comparison).
Calendar Implemented
- Date-based service-job planning view with day-level scheduling and status colouring.
Notifications Implemented
- In-app inbox delivered asynchronously via RabbitMQ (job completed, follow-up due/overdue, reminders).
- Event types:
JOB_COMPLETED,FOLLOW_UP_SCHEDULED,FOLLOW_UP_DUE,FOLLOW_UP_OVERDUE,REMINDER. - Channel codes: IN_APP, EMAIL, SMS, WHATSAPP (reserved), PUSH (reserved); mark one or all as read.
Reports & Analytics Partial
- Reports page with revenue and service-volume metrics; deeper analytics, custom report builders and exports are next milestone.
- Roadmap: churn-risk scoring and predictive service scheduling land with the AI tier.
Subscription & SaaS Billing Implemented Live payments optional
- Plan tiers with server-enforced limits (create operations return 403 once a limit is reached):
| Plan | Max users | Max customers | Max technicians |
|---|---|---|---|
| FREE | 3 | 100 | 5 |
| STARTER | 5 | 1000 | 10 |
| PROFESSIONAL | 10 | 5000 | 25 |
| BUSINESS | 50 | 10000 | 100 |
- Razorpay integration: simulated mode by default (
RAZORPAY_ENABLED=falseactivates plans instantly); live mode creates a Razorpay subscription, setsrequestedPlan, and the plan activates when signature-verified webhooks (subscription.activated,subscription.charged,payment.captured) arrive. Cancellations handled viasubscription.cancelled/subscription.completed. - Webhook security: HMAC-SHA256 signature verification of the raw body using
RAZORPAY_WEBHOOK_SECRET.
AI Features Planned
- Predictive service scheduling, churn-risk scoring and auto-generated service notes.
- Commercial model: monthly AI credits included in Professional / Business; additional usage billed separately.
API & Integration Layer Implemented Advanced planned
- Versioned REST API at
/api/v1with consistentApiResponse<T>/PageResponse<T>envelopes, OpenAPI spec and Swagger UI (dev). - Bearer-token auth, tenant-aware routing, pagination & filtering on every list endpoint.
- Roadmap: API keys, outbound webhooks (Business+), WhatsApp automation, ERP/accounting integration and customer portal.
Recommended India pricing (V1 launch)
Positioning: “Never Miss a Service. Never Miss a Follow-up.” The Professional plan is the featured offer — the tier most customers should land on. Before finalising any price, the per-tenant infrastructure + WhatsApp/SMS + email + AI + support cost should be calculated to confirm gross margin at these price points.
| Plan | Suitable for | Suggested price (monthly) |
|---|---|---|
| Starter | Small service business, 1–3 technicians | ₹999 |
| Professional ★ | Growing business, 4–10 technicians | ₹2,499 |
| Business | 10–25 technicians / multiple teams | ₹4,999 |
| Enterprise | Larger / multi-branch companies | Custom (from ≈ ₹9,999) |
What each plan includes
Starter — ₹999/month
- 1 business / workspace
- Up to 3 users
- Customer management
- Equipment / asset management
- Service jobs
- Basic technician management
- Follow-ups
- Service reminders
- Dashboard & basic reports
Professional — ₹2,499/month ★ featured
Everything in Starter, plus:
- Up to 10 users
- Advanced scheduling / calendar
- Recurring services
- Automated reminders
- WhatsApp / email integrations
- Technician mobile interface
- Invoices & payments
- Advanced reports
- More automation
Business — ₹4,999/month
Everything in Professional, plus:
- Up to 25 users
- Multiple branches
- Advanced roles & permissions
- Advanced analytics
- Workflow automation
- API access & webhooks
- Priority support
- AI features with usage limits
Enterprise — ₹9,999+/month
- Multiple branches / locations
- Custom user limits
- Custom workflows
- Dedicated onboarding
- Advanced API / integrations
- Custom reports
- SLA / support
- Dedicated infrastructure if required
- Custom AI / automation
- One-time implementation / onboarding fee
Annual billing — roughly 10–20% below monthly
Offer an early-adopter annual plan rather than permanently discounting the product.
| Plan | Monthly ₹ | Yearly at 12 × monthly | Annual — 10% off | Annual — 20% off |
|---|---|---|---|---|
| Starter | ₹999 | ₹11,988 | ≈ ₹10,789 | ≈ ₹9,590 |
| Professional | ₹2,499 | ₹29,988 | ≈ ₹26,989 | ≈ ₹23,990 |
| Business | ₹4,999 | ₹59,988 | ≈ ₹53,989 | ≈ ₹47,990 |
| Enterprise | Custom quote (annual pricing negotiated in the contract) | |||
Implementation fees & add-on pricing
One-time implementation / onboarding fees
Implementation is never free for business customers. Fees cover business configuration, user setup, service categories, reminder configuration, data import, initial training, WhatsApp/SMS/email configuration and basic customisation.
| Plan | One-time setup estimate | Notes |
|---|---|---|
| Starter | ₹2,500 – ₹5,000 | Standard self-setup + guided onboarding |
| Professional | ₹5,000 – ₹15,000 | Includes data import & channel configuration |
| Business | ₹15,000 – ₹30,000 | Multi-branch setup, automation & API onboarding |
| Enterprise | ₹30,000 – ₹1,00,000+ | Dedicated onboarding, custom workflows & integrations |
Add-ons (usage-based — never unlimited in base plans)
| Add-on | Pricing model |
|---|---|
| Additional users | ≈ ₹199 – ₹399 / user / month |
| Additional branches | ≈ ₹999 – ₹2,499 / branch / month |
| Extra storage | Usage-based (bytes stored per month) |
| Pass-through at actual provider / conversation / template costs + optional MageTech platform fee | |
| SMS | Pay-as-you-go or prepaid credits (actual provider cost) |
| AI usage | Monthly credits included in Professional / Business; additional usage billed separately |
ServiceFlow Custom — separate software offering
Some companies won’t want SaaS at all; they will ask MageTech to customise ServiceFlow for their business. A dedicated “Custom Software” line protects SaaS pricing while capturing these deals.
| Offering | Price range | What drives the bill |
|---|---|---|
| ServiceFlow SaaS | ₹999 – ₹9,999+ / month | Standard multi-tenant platform, subscription plans |
| ServiceFlow Custom | ₹2,00,000 – ₹10,00,000+ | Custom workflows · custom UI · ERP integration · CRM migration · accounting integration · WhatsApp automation · mobile application · customer portal · advanced AI · third-party integrations · multi-country requirements |
Large enterprise implementations are quoted significantly higher based on scope. A one-time implementation / onboarding fee always applies.
International pricing (US / UK / UAE / Australia / Canada)
Do not simply convert ₹2,499 into dollars. A separate international price structure — adjusted by market and customer size — protects margin where willingness-to-pay is higher.
| Plan | International starting price |
|---|---|
| Starter | $19 / month |
| Professional | $49 / month |
| Business | $99 / month |
| Enterprise | Custom |
