Case study · My startup · Laravel · React · React Native
Building an exam platform alone, where a new exam is data and not code.
Score Delta is my startup. This is how it went from a scope document on 19 October 2026 to a live site with ten exams, and the decisions, mistakes and numbers along the way, including what is still not proven.
The problem
An exam-prep idea that was right, in a product that wasn't.
I started from an existing exam-prep site whose idea I liked: tests organised by topic, repeatable practice, and a report at the end that shows where you lost marks. Its design and the way it felt to use were what I did not like. So the brief I wrote for myself was to keep the idea and rebuild the product around it, for phones and for Hindi and English readers.
There was a business reason too. I wanted one product I could take from the first line of code to the first paying student, because my own bottleneck is marketing and sales and I would rather learn that on something I own. That is why this is a startup and not a client job.
The decision everything follows from
An exam is data, not code.
The mistake I wanted to avoid is common in single-exam sites: the exam's rules, subjects and prices are written into the code, so every new exam needs a developer. In Score Delta an exam is a record with a pattern (sections, timing, marking, negative marking) and a syllabus mapped to topics. The scoring code only ever reads the pattern. It never asks which exam it is scoring.
That made the rule testable on its own: scoring is covered by unit tests for each question type against each marking rule, including partial marks and optional questions. It also made the content side scriptable, because a whole exam bank, with its mocks, sectional tests and topic tests, can be built from one command that reads the exam's pattern. The same data is what the website, the app and the admin panel show, so there is no second copy to keep in sync.
Three front doors
One backend instead of three.
A student meets Score Delta in three places: the public pages that Google and a first-time visitor see, the logged-in web app, and the Android app. The public pages are plain server-rendered Laravel views, because that is the fastest thing for a phone on a weak connection and the easiest for a search engine to read. The logged-in app is React with Inertia, so there is no second API to build for the website. The Android app is React Native and talks to a versioned API under /api/v1.
All three go through the same rules: the same plans, the same scoring, the same checks on who can open which test. The admin panel is Filament on the same codebase, with roles, a mandatory second factor for staff and an audit log. The cost of this choice is that a rule change touches every door, so the tests matter more than they would in a smaller product.
Plans
I had six prices per exam. A student couldn't find what they had bought.
The first version had periods of 1, 3, 6 and 12 months, a combo pass for every Himachal exam and several packs. On paper it was flexible. In practice I bought a plan myself while testing and could not find where it had gone: it appeared in My Plans, but I could not tell what it unlocked or where to use it. If the person who built it gets lost, a student will too.
So I cut it to two plans per exam, and removed everything else: a Mock Pack at Rs 259, one time, valid for 6 months, that opens the full mocks, and an Exam Pass at Rs 499 a month that opens everything for that exam. The tests list now says what is free, what is locked and what your plan opened, and the free and paid tests are mixed on the first page so a student can see what paid contains before deciding. The same change had to be made in the website, the saved FAQ and guide text, and the Android app.
The bugs that taught me something
Four things that broke in the first weeks.
- The queue
- Push notifications, OTPs, scoring and payment confirmations did not arrive on time. The background worker was running, but only the default queue, and those jobs are sent to a separate high-priority queue. The fix was a worker that reads both, in that order. The lesson is that "the worker is running" and "the right queue is being worked" are different facts.
- A stale cache
- A page started failing with a missing settings key. A second app that shared the same database and cache had written an older version of the settings. I deleted that site, and I also made the code rebuild the cache entry when a key is missing, so one bad write can no longer take a page down.
- Only one exam showed
- On the live site only one of the ten exams was visible. An earlier command, run to hide exams that had no tests yet, kept them hidden after their tests were loaded. Loading an exam's tests now switches the exam on, and the load command prints which exams are shown, so I see the result instead of assuming it.
- A popup on log out
- Logging out from the student app opened the home page inside a popup. The student app is a single-page app that expects one of its own pages back, and the public home page is not one. Leaving the student area is now a full page visit.
Speed
Mobile performance from 73 to 100, by removing things.
I measured the live site with Lighthouse on a simulated phone. The home page scored 73 for performance, with first paint at 4.5 seconds. The page was small, only about 43 KB, but it waited on an external font stylesheet that pulled many font files from a second host, and my own security policy blocked those files, so they were requested, refused and logged as console errors.
The fix was to host the three fonts on the site itself as variable files, loaded only for the scripts a page uses, and to drop the two external hosts from the policy. I also fixed two contrast failures and a link whose label did not match its visible text. On 11 November 2026 the pages I measured scored 100 on mobile for performance, accessibility, best practices and SEO, and the desktop home page scored 99 for performance. Part of that depends on the server's response time and the network, so I treat it as a measurement, not a guarantee.
How it was checked
Tests for the rules, my own eyes for the screens.
The project has about 400 automated tests in its main suite: scoring, plans and prices, access to tests, the API, login, the admin panel and the public pages. Each change is run through the style check, the type check, the build and the tests on my own machine before it goes to the server. The checks run locally, and the hosted pipeline is set to manual only.
The weak spot is the same as in many one-person projects: the screens. A test can say a page renders, not that it feels right on a small phone, so I look at the live pages and the app on a real device.
What isn't proven
Things I won't claim yet.
There is no evidence yet that students do better with it: it is new and I have no outcome data. The question banks are built by scripts and checked by automated tests, and I have not had each of the 14,000+ questions reviewed by a subject teacher. Only ten Himachal Pradesh exams are live. The Android app runs on my own phone but is not on Google Play yet. And the Lighthouse scores are one day's measurement of public pages, not of the logged-in screens.
The architecture
What's actually running under it.
- Backend
- Laravel 12 on PHP 8.4, a MySQL database and a queue worker with a high-priority queue for payments, sign-in codes and scoring. About 45,000 lines of PHP in the application code and 31 migrations.
- Public site
- Server-rendered Blade views with a content security policy that uses a nonce for scripts, self-hosted fonts, and structured data for the home page, exam pages and guide articles.
- Student app
- React and TypeScript through Inertia, about 11,000 lines, with Hindi and English text from one translation file.
- Android
- React Native, about 6,500 lines of TypeScript, an answer outbox for weak connections, Firebase push notifications, Google sign-in and a force-update check.
- Admin
- Filament, with least-privilege roles, a mandatory second factor for staff, masked personal data for content roles and an audit log of who changed what.
- Data protection
- Phone numbers and emails are encrypted in the database and looked up through a blind index. Public identifiers are random, not sequential. A student can delete their own account.
- Payments
- Razorpay on the website with coupons, receipts and a My Plans page where a monthly plan can be cancelled.
The outcome
Honest about where it actually is.
In about three weeks, one person took Score Delta from a scope document to a live site with ten exams, thousands of mock tests, two plans per exam, an admin panel and an Android app. A new exam can be added from the admin panel and loaded with one command, and a student can go from a Google sign-in to a first free test and a weak-topic report without help.
What it isn't yet is a business with a track record. The next steps are the ones a startup has to do and no commit can do for it: get the Android app onto Google Play, add the next exams, and get real students to use it and tell me what is wrong.
Preparing for a Himachal Pradesh exam, or building something like this yourself?
Try Score Delta