From Founder to Engineer: What Building CodeMyFYP Taught Me About Systems
2026-05-25 · 7 min read
I started CodeMyFYP as a final-year project assistance service during my BCA. By the time I was mid-way through my MCA, it had become CodeMyFYP Academy — a full multi-tenant EdTech SaaS platform listed on the AICTE National Internship Portal.
This is what I learned engineering it.
Wearing every hat is brutally efficient for learning
When you're the only engineer, there's no handoff. You design the schema, write the API, build the frontend, set up the CI/CD, handle payments, debug production issues at 2am, and talk to users the next morning.
That context continuity — understanding the whole system because you built the whole system — is something I've found genuinely hard to replicate in any other way. Every architectural decision I've made since has been better because I lived through the downstream consequences of my own choices.
The RBAC lesson I learned the hard way
The first version of CodeMyFYP Academy had a simple boolean isAdmin field on the user table. Within three months, I needed five roles: Student, Mentor, Recruiter, Faculty, and Administrator, each with different permissions across different resource types.
Retrofitting RBAC onto a system that assumed a two-role world is painful. The schema migration, the API middleware changes, the frontend permission checks — all of it had to change simultaneously without taking down a live platform with real users.
The lesson: design for role expansion from day one, even if you launch with only two roles. A roles table and a role_permissions table costs two hours to set up correctly and saves weeks of painful retrofitting.
Payments are where you learn to respect external systems
Integrating PhonePe taught me more about defensive programming than anything else. Payment APIs have strict idempotency requirements, webhook signatures to verify, reconciliation edge cases to handle, and regulatory constraints that vary by institution type.
The pattern that saved me: treat your payment integration as a finite state machine. Define every valid state (PENDING, AUTHORIZED, CAPTURED, REFUNDED, FAILED) and every valid transition. Reject anything that violates the machine at the service layer — don't let an invalid transition reach the database.
What multi-tenancy really means at the database level
"Multi-tenant" sounds architectural until you're writing queries. In practice, it means every query must be scoped to the tenant, every API response must be filtered to the caller's tenant, and every test must verify that tenant A can't read tenant B's data.
I enforced this with a middleware pattern: every authenticated request extracts the tenant ID from the JWT, attaches it to the request context, and every repository method receives the tenant ID as a required parameter. There's no way to query without it.
It's verbose. It's also the reason I've never had a tenant data leak.
The thing I'm most proud of
Not the AICTE listing, though that was validating. It's the student onboarding flow that went from 45 minutes of manual admin work per student to zero. Automated verification, automated welcome emails, automated certificate generation — the compounding value of automation on a platform you own completely is genuinely motivating.
That experience is a big part of why I keep building tools that automate real workflows. The feedback loop is immediate and unambiguous.