Fyboard - A deep dive into the architecture and decisions I made & why!
Fyboard is three product families - A workspace platform, a tools suite, and service workflows running on one backend. Same account, same billing, same files, same entitlements. People assume the hard part of that is building the features. It isn't.
The hard part is keeping one backend coherent when this many surfaces depend on it. Here's how it's actually engineered.
First, the scale, not as a flex, but because it's the reason coherence is the whole game.
The platform is around 1.7M lines of TypeScript across roughly 10,000 source files: ~1.07M on the frontend, ~632K on the backend.
Underneath sits a Prisma schema with 633 models and 434 enums, 89 migrations, and close to 30,000 lines of migration SQL. The backend alone runs 1,443 route definitions across 322 service files, 45 controllers, and 35 job processors. At this size, raw output stops being the constraint.
Nobody is impressed by line count, and they shouldn't be at 600+ models the real danger isn't writing too little code, it's the same idea getting implemented six slightly different ways across six surfaces.
Every number here is really a count of places something can drift out of sync. That's why the rest of this is about structure, not volume.
________
THE CORE PROBLEM: Every concept wants to fork.
The failure mode in multi-product isn't bad code.
It's the same concept getting redefined in every layer.
"Product" becomes a string in a frontend component, a constant in a pricing file, a different object in checkout, and a fourth thing in the access check. Four definitions, zero foreign keys between them. Each one was correct the day it was written.
Then someone edits one and the others silently fall behind. That's exactly how you end up shipping a paid tier whose page promises batch export while nothing on the server enforces it. The bug isn't in any single layer, it's in the gap between them.
So the whole architecture is built to close those gaps structurally, not by remembering to keep them in sync.
________
DECISION-1: The platform is registry-driven.
Products, plans, tools, services, and entitlements are relational data with canonical keys, not copy scattered across the frontend.
There is one model that answers: what products exist, which are public, which plan belongs to which product, what a plan unlocks, whether it's personal- or org-scoped, whether a capability needs backend processing, whether a feature should appear in public pricing. Public pages, checkout, and access checks all read that same model.
The registry isn't a convenience layer, it's a correctness layer. Without it you get the classic drift bugs: a tool that exists in the dashboard but not the public directory, a pricing page claiming a feature the backend can't honor, an offer applied to the wrong product, a checkout plan that doesn't match the listed price.
Make product concepts relational and those entire bug classes stop being possible.
The rule that falls out of this: a capability isn't "available" because a button renders. It's available because the entitlement resolves. The frontend reflects state, it never defines it.
_______
DECISION-2: Business logic lives in services, never controllers.
The same behavior gets triggered from multiple entry points, a dashboard action, a public checkout, a webhook, a job processor, an admin API, an internal utility. If that logic lives in a controller, you copy it into every entry point, and the copies drift.
One gets a bug fix the others don't. One enforces a limit the others forget. So controllers stay deliberately thin: authenticate, validate, resolve account context, call the service, return the response.
The service owns everything that's actually the product, creating records, enforcing entitlement rules, resolving user-vs-org ownership, coordinating file processing, queueing jobs, calling the AI layer, talking to payment providers, updating usage, normalizing output, handling retries and domain errors.
One implementation, many callers. The webhook and the dashboard run the exact same code path because they call the exact same service.
________
DECISION-3: One file pipeline, no exceptions.
Fyboard is file-heavy by nature, PDFs, screenshots, invoices, payroll exports, generated outputs, uploads, transformed files. The tempting move is to let each tool handle its own uploads.
That's the move that quietly destroys you. Six months in you've got inconsistent access control, broken deletion, duplicated storage code, and an audit trail you can't trust because every tool wrote files differently.
So every file regardless of which tool or module touches it goes through one pipeline: upload middleware โ storage driver resolution โ folder resolution โ prepared metadata โ ownership-aware persistence โ access rules โ generated-output linking.
A PDF tool and an org-scoped module look completely different in the UI and share the identical storage path underneath. That's what makes security, cleanup, billing, auditability, and future storage migration tractable instead of a per-tool nightmare.
________
DECISION-4: Browser vs backend is a hard architectural line, not a preference.
Some tools can run entirely in the browser.
That's the right call when the transform is small, local, needs no persistence, and has no server-side dependency.
But the moment a tool stores files, persists output, enforces a paid limit, runs a long job, touches large files, uses AI, or needs history later it requires backend APIs. Non-negotiable.
This turned out to be a major launch-readiness pass, and the question was never "does the page render." It was "does this tool's claimed capability actually live in the right place?"
A tool whose pricing promises saved history or cloud storage cannot remain frontend-only, the claim and the architecture have to agree. Pricing tiers, in other words, dictate architecture. The capability boundary a plan advertises is a structural requirement on where the code lives.
________
DECISION 5: AI is infrastructure, not helper code.
The easy version is calling an AI provider directly wherever a feature needs intelligence.
The result: duplicated prompts, inconsistent error handling, no usage accounting, provider lock-in, and zero observability.
The moment you want to swap providers or audit cost, you're refactoring every tool. So there's one shared AI service layer that owns provider abstraction, model selection, request normalization, response normalization, timeout handling, retry policy, usage accounting, privacy controls, prompt/output guardrails, and logging that never leaks sensitive data.
Each surface, PDF intelligence, screenshot analysis, invoice extraction, document assistance implements its specific behavior on top of that layer.
Switching providers becomes a config change in one place instead of a codebase-wide migration. AI gets treated exactly like storage: a utility you plug into, not logic you sprinkle around.
_______
DECISION 6: Ownership is subject-aware from the ground up.
Organization accounts are created through user accounts. That one fact has consequences everywhere. The platform constantly has to know whether a thing belongs to a person or an organization files, subscriptions, tool outputs, module access, entitlements, billing.
Get this ambiguous and every layer turns fragile at once, pricing, access, storage, support, exports, deletion, auditability all start producing subtly wrong answers. So a signed-in user resolves to a working context - personal or organizational and every capability resolves against the correct subject.
Files are owned by the right subject. Entitlements check against the right subject. Billing is scoped to the right subject. This reads like a backend detail, it's actually one of the biggest sources of bugs in SaaS, and it's why the resolution is built in from the start rather than retrofitted.
________
DECISION 7: Billing is provider-agnostic by design.
Fyboard runs Stripe and Razorpay, because payment expectations differ across markets. The mistake would be letting provider object models leak into product logic.
So the split is strict.
The product cares about: plan, subject, entitlement, subscription state, active-vs-inactive access.
The provider integration cares about: checkout creation, payment confirmation, provider IDs, webhook verification, status mapping, retries.
The product never hard-codes to one provider's shape, so adding a third later doesn't touch product logic.
Two related rules. Offer/discount creation is a platform-admin capability behind an admin guard users can redeem eligible offers, never create platform offers, and offers attach to canonical products and plans rather than floating as loose metadata.
And trials exist as a disabled-by-default capability: the architecture is ready, but no public page advertises a "14-day trial" the backend can't actually honor. Future-ready, never over-promised.
_________
DECISION 8: Slow work never lives in a request handler.
Long-running work - file processing, exports, cleanup, expiry, AI workflows, heavy transforms, billing state transitions doesn't block HTTP. The request validates eligibility, persists intent, returns a clear state.
A job processor does the expensive part and updates status. This is what keeps the platform reliable under load and recoverable after failure: a crashed request doesn't lose work that was already committed as intent.
_________
THE THROUGHLINE:
Every one of these is the same instinct applied to a different layer: define each concept once, enforce it at the backend, and make every surface inherit from a shared spine instead of reimplementing it.
Registry over scattered copy.
Services over controllers.
One file pipeline over per-tool uploads.
One AI layer over sprinkled provider calls.
Subject-aware ownership over ambiguous ownership. Provider-agnostic billing over hard-coded integrations.
The product doesn't get to say one thing, render a second, and enforce a third. Build the spine once, make every surface inherit it, enforce at the backend not the button.
That's the difference between launching a pile of tools and launching a platform...
India Celebrates Rockets, But Forgets the Engineers Who Built Them ๐๐๐ฅโค๏ธ
India doesn't have a talent problem. It has a priority problem.
The engineers who helped build the infrastructure behind missions like #Chandrayaan3 reportedly went months without salaries, while we celebrated the achievement as a nation.
If the people building India's future aren't valued, paid on time, and respected, don't blame them for leaving. Brain drain isn't inevitable ,,,, it's a policy choice.
#HEC #BrainDrain #Engineering #India
Aise Buddhoo ki wajh Se he Pura Desh Barbaad Ho Rakha hai , Internet Use Par Rok Lagao Buddho ke ๐คก ๐
But Yuva Ab Jaag chuka hai , 12 saal ka Continuos Propaganda Fail Hota dikhae De Raha hai ๐ฅ๐ฅ๐ฅ๐ฅ๐ฅ
@gnr466
Maharashtra Chief Minister Devendra Fadnavis has directed the state's Home Department to withdraw police cases and revoke FIRs registered against students who participated in recent protests over examination-related issues: SOURCES
@RuchaKanolkar15 shares more details with @HeenaGambhir
I agree with you. But what about the police personnel and others who were assaulted by the so-called peaceful protesters?
Letโs be clear, @abhijeet_dipke , whether it is a police officer or a protester, anyone who harasses, assaults, or unlawfully arrests another person should be held accountable in accordance with the law.
The Constitution of India guarantees the right to peaceful protest, not the right to indulge in violence.
@ANI This is what we need!
Jail those criminals who created rucuks at peaceful students protest! And as well those policemen who SA womens and pelted guns on peaceful students!
Distinction should be made so that no student shouube jailed and criminal should be behind bars!
@Devillawyee@roshandinesh19@confuciussays9@JaipurDialogues well i guess if u do then there isn't any law by which i can supress you!
And btw modi isn't a religion! He's just a public *servant*, applicable for abuses if he fuck up something!
So go and do rr to your paww pawww
@Anilkumar_1973@ragebait_krungi Waahhh re bhakt! Thoda constitution and FOS k baare me pd le!
Ye jo moral policing vaale sanghi jo hagte rehte hai online and those abuses! Unko dekh
@roshandinesh19@confuciussays9@JaipurDialogues Ohh so abusing a PM is an cognizable offense under which section? Btw 352, 53... Vagerah mt chipkana!
19(a) pad lena and 19(b) k restrict as how much freedom is allowed.
Dumb andhbhakts