Extending the base repository would have kept an unscoped findMany callable, and TypeScript cannot hide an inherited public method. Making the tenant id the first argument of every method turns a data leak into a compile error.
Eleven NestJS APIs, and the guard stack grew the same way in each: two guards, then three, then seven. What that progression teaches about ordering, and the fail-open bug hiding where row-level security met a permissive default.
A 500 is your backend telling you it hit something it could not handle yet. The distinction that matters is not whether they happen, but whether anyone is listening.
Every endpoint returning the same envelope, success or failure — the response shape worth settling on, and the global interceptor and exception filter that enforce it in NestJS.
Why the default flat src/ falls apart once a project has real features, and the module-driven layout that replaces it — one directory per feature, with common, config and database kept alongside.