300+ tables, 700+ stored procedures, and 40+ generic entity types — the shapes you need for users, accounts, content, taxonomy, billing, audit, and translation. Architected by someone who has consolidated databases for the Fortune 500, not stitched together from migration files.
Numbers first, then the architectural decisions that produced them. Both matter equally — the headcount on the schema tells you what to expect; the design tells you why it scales.
300+ tables, 700+ stored procedures, 40+ entity types, 100+ supported languages. The shape of an enterprise schema before you write your first feature.
Every table, every relationship, every index was decided by someone who has consolidated databases for the Fortune 500. Not ORM-generated migrations stitched into a pile — these are hand-tuned T-SQL schemas and 700+ stored procedures, accessed via Dapper + ADO.NET, no EF. Four foundational decisions baked in on day one:
Redis plus .NET in-memory caching layered against the schema for both hot reads and distributed coherence. Cache invalidation derived from the data, not invented per feature.
Agreements, prompts, notify templates, artifact templates — all keep full version history with restore. Soft-delete and entity-suspend are first-class.
40+ entity types share one base table, indexed for the patterns they actually run. New content types become row inserts — no migration required.
The role and permission framework runs inside the stored procs, not just the API. Roles decide which rows a user can see, modify, or aggregate.
The shape that makes everything else possible. Primary keys are stable; foreign keys make ownership explicit; junction tables turn intent into structure. The cost of getting this right once — and never having to re-litigate it.
A typical RBAC slice. Every table has its own primary key; foreign keys spell out exactly who owns what; the junction table turns a many-to-many into something the query planner can index.
Color matches the badge to the table it points at. Follow the emerald, you trace ownership through Users; follow the amber, you trace authorization through Roles.
A real slice of the production data model — entities, ownership, junctions, audit columns, all visible at a glance. Tables don’t lie, and neither do the relationships between them.

Performance is a property of the schema, not a bolt-on layer above it. Stored procedures handle the data shape; Dapper handles the C# round-trip; nothing in between gets in the way.
700+ optimized, parameterized, instrumented stored procs. Every endpoint calls one. The query planner sees stable shapes; the indexes are tuned to match.
-- Account-scoped users with role filter (one of 700+ procs)
EXEC dbo.usp_Users_GetForAccount
@accountId = @currentAccountId,
@roleCode = 'admin',
@page = 1,
@pageSize = 50;
-- Parameterized · indexed · instrumented
-- Avg execution: 6.2ms across 12k accounts
-- Logged to JobRun + System Performance dashboardsLightweight, fast micro-ORM. Every repository has an interface. Tests don’t need a database; production gets raw SQL performance.
public interface IUserRepository
{
Task<User> GetByIdAsync(int id);Task<IEnumerable<User>> GetForAccountAsync(int accountId);Task<int> SaveAsync(User user);
}
// Mockable in tests.
// Every entity has its own IXxxRepository.public class UserRepository : IUserRepository
{
private readonly IDbConnection _db;public Task<User> GetByIdAsync(int id) =>
_db.QuerySingleOrDefaultAsync<User>(
"dbo.usp_Users_GetById",
new { id },
commandType: CommandType.StoredProcedure);
}Versioning and audit history are first-class primitives, not bolted on later. When the auditor asks “what did this look like in March?” the answer is in the schema.
Agreements, prompts, notify templates, artifact templates — full version history with one-click restore. Soft-delete and entity-suspend are first-class.
Every operationally interesting record has its history table from day one. Auditors don’t ask “where’s the trail?” — they read it.
Translation, content typing, access control, taxonomy — generic primitives that any new feature opts into. New languages, new entity types, new roles, new categories all happen as data, not code.
Register any table + column for translation through the registry. Add a new language, run the pending-translation queue, ship. No DDL involved.
One central entity model handles every operationally interesting thing on the platform. Adding a new content type is a row insert, not a migration.
The role and permission framework runs at the schema, not just the API. Roles decide which rows a user can see, modify, or aggregate — enforced inside the stored procs themselves.
-- Inside dbo.usp_Entities_Search
SELECT e.*
FROM Entities e
WHERE e.AccountId IN ( SELECT au.AccountId FROM AccountUsers au WHERE au.UserId = @currentUserId AND au.IsActive = 1);
-- The same filter pattern lives in every cross-account proc.
-- Row visibility is enforced where the data is, not in the API.Parent/child trees, pending-review pipelines, replace-and-delete merge handling. A taxonomy that scales without becoming spaghetti.
Book a 30-minute architecture review. We’ll share-screen through the codebase live and show you where your existing platform plugs in.