I spent a few weeks building PingClass — institute-management software for small tuition and coaching centers in India (1–5 teachers, under ~200 students). The kind of businesses that still run on a patchwork of Google Sheets, paper registers, and four WhatsApp groups.
The interesting part isn't the product though, it's how it's built: no framework, no frontend build step, static HTML files, a Postgres database, and a free CDN. I want to share the stack and what I learned, because this is the least-discussed way to ship a SaaS that runs and ranks.
The constraints that pushed me here
I'm a solo maker shipping in evenings. I didn't want a toolchain I have to babysit.
The customers are offline-first small business owners. They open a link, it should just work, load fast, and not break.
I wanted the site's marketing pages to be instantly crawlable by Google, Bing, and the AI search bots — static HTML is the most undisputed, indexable thing that exists.
The stack
Static HTML + vanilla JS -> Vercel (free tier, global CDN)
Supabase (Postgres + Auth) -> tenant data, users, reviews
JSON-LD structured data -> SEO / AI answer engines
llms.txt -> explicit signal for AI crawlers
IndexNow -> instant Bing re-crawl on deploy
Why static HTML
Every page is a real .html file. There's no hydration, no #app shell, no client routing. Googlebot, ClaudeBot, PerplexityBot and GPTBot all just read the HTML — headings, text, structured data — directly. The marketing site lives in the most defensible form SEO can have.
The interactive parts (auth, dashboards) are separate static pages that talk to Supabase with client-side JS.
Supabase for everything data
A single Supabase project handles:
Postgres — core tables: students, batches, attendance, fees, announcements, parents.
Auth — email-based sign-in with admin/teacher/parent roles.
RLS policies — row-level security so an institute only ever sees its own rows, enforced at the database level.
The fee module auto-generates monthly dues per student × batch and lets owners send due reminders — that's where the "fewer spreadsheets" pitch actually lands.
One query the site runs for its public reviews section:
const { data: reviews } = await supabase
.from('reviews')
.select('author_name, quote, rating, institute')
.eq('status', 'approved')
The tricky bit: reviews are loaded client-side, so they'd be invisible to crawlers. I solved it by rendering the approved reviews as static HTML on the homepage too, and having JS skip authors that are already statically present. Same for the aggregateRating structured data — crawlers get the facts front-and-center.
What I'd do differently (maybe)
Payment gateway. Ledgers and reminders work; actual collection is still manual. A Razorpay integration is the next obvious wedge.
Mobile app. Parents want an app. Web-first was the right place to start, but "Is there an app?" is the #1 question.
Validate before building as much. The fee/attendance/parent-communication triangle seems right, but I'd have liked real signed-up centers earlier rather than a polished product first.
The meta-lesson
You don't need React + a queue system + Kubernetes for a tool that two dozen tuition centers might use. Static HTML + a managed Postgres + a CDN handled everything, cost almost nothing, and made the "will people find it?" problem dramatically easier — because every page is HTML that search engines and LLMs read natively.
If you're building a small vertical SaaS and feel the pull toward a heavier stack, ask whether the extra machinery earns its keep.
PingClass is live — free tier up to 20 students, then ₹249/mo and ₹599/mo. As also featured on Product Hunt and G2. Happy to answer questions about the stack or the tuition-center niche.
Top comments (1)
Hi everyone — I'm Godwin, the maker here. One thing the article skips: I built this because I watched real tuition centers near me run on notebooks and WhatsApp groups. Happy to go deep on anything — the llms.txt / AI-crawler side especially, the Razorpay gap, or pricing for small institutes. Thanks for reading!