OneShiksha is built by a solo developer using Next.js, Prisma, PostgreSQL, and a lot of late nights. Here are the architecture decisions, tradeoffs, and lessons learned along the way.
OneShiksha started as a side project. I was building tools for a relative who ran a small school
in Satara and was drowning in paperwork. The first version was a PHP script that took attendance
and sent SMS. It had a form, a MySQL table, and a cron job. It was ugly, but the school loved
it because it saved them 10 hours a week.
Two years later, that PHP script has become a full-stack Next.js application serving 500+
schools, handling 8.4 lakh students, and processing lakhs of rupees in fee payments every month.
Here is what the stack looks like now, and why it evolved the way it did.
99.9%
Uptime over the last 12 months
< 200ms
Average API response time
1
Developer (full-time now)
Stack Choices: What I Picked and Why
The frontend and API layer run on Next.js 15 with the App Router. I chose it because it
gives me server-side rendering (critical for SEO), server actions (no separate API routes
for simple mutations), and a single codebase for dashboard, public website, and API.
The database is PostgreSQL via Supabase. The ORM is Prisma. I wasted months in the early
days debugging raw SQL queries for multi-tenant data isolation. Prisma's type safety
catches schema errors at compile time — a massive productivity gain when you're the only
person writing code.
Authentication is handled by Clerk (migration to Better Auth is in progress). I chose
Clerk initially because it handled org-based multi-tenancy out of the box — school admins,
teachers, students, and parents all under one organizational umbrella with role-scoped
access.
- Next.js 15 App Router for SSR, server actions, and unified codebase
- PostgreSQL + Prisma for type-safe multi-tenant queries
- Clerk for org-based auth with role-scoped access control
- Cloudinary for image/video storage; Uploadthing for file uploads
Multi-Tenancy: The Hardest Problem I Solved
The biggest technical challenge was data isolation. School A should never see School B's
data — not through an API bug, not through a misconfigured query, not ever.
Every table in the database has an organization_id column. Every Prisma query includes
a where: { organization_id: currentOrgId } clause. I built a helper function early on
that automatically appends the org filter to every query — forgetting it once would be
a data leak.
For the public website (this blog, pricing page, features), data is either static or
fetched from separate non-tenant tables. The dashboard routes are all behind middleware
that verifies org membership and role before rendering a single component.
- Every query scoped by organization_id — enforced at the helper function level
- Public website and dashboard are architecturally separated
- Role-based access control (Admin/Teacher/Student/Parent) scoped within each org
- No cross-org data can leak even through a misconfigured API call
The Things That Surprised Me
Two things I didn't expect when I started:
First, the notification system (SMS + WhatsApp + Email + Push) turned out to be more
complex than the core school management features. Each channel has different rate limits,
templates, delivery guarantees, and cost structures. WhatsApp Business API requires
template approval. SMS gateways have different reliability in different states. I ended
up building a notification engine with retry logic, channel fallback, and delivery
tracking.
Second, Indian schools have wildly different workflows. A CBSE school in Mumbai runs
differently from a state board school in rural Maharashtra from a coaching center in
Kota. Building for "Indian schools" means building flexible enough to handle all of them,
which often means more configuration options than I'd like.
Conclusion
OneShiksha is still a work in progress. There are features I want to build, performance
bottlenecks I want to fix, and code I want to rewrite. But the platform handles millions of
requests a month, stays above 99.9% uptime, and — most importantly — actually helps schools
run better. If you're curious about any specific technical decision, I've tried to document
it in our GitHub discussions. Or just reach out — I'm always happy to talk school software
architecture.