OpsPilot
A multi-tenant operations dashboard where the permission matrix is enforced by the server, not drawn by the client.
- Role
- Architect & sole engineer
The application
Screens, captured from the running app
Booted against its seeded database and walked route by route — these are the real pages, not mockups.





The problem with most "multi-tenant" dashboards
They are single-tenant apps with a workspaceId column bolted on, and a UI that hides the buttons a Member shouldn't press. Both halves of that are wrong. A column you have to remember to filter on will eventually not be filtered on, and a hidden button is not a permission — it is a suggestion.
OpsPilot was built to get those two things right first and add features second.
Workspace isolation in the data model
Every queryable entity — client, project, task, comment, activity record — hangs off a workspace, and every read path goes through a helper that takes the session's workspace as a required argument rather than an optional filter. There is no code path that can construct a query without one, because the query builder will not compile without it.
That constraint is unglamorous and it is the entire point. It means a new feature cannot accidentally leak across tenants; the type system refuses before a reviewer has to notice.
RBAC that lives on the server
Three roles — Owner, Admin, Member — over a matrix of resource/action pairs. The rules are declared once and consulted in two places:
- Server actions, which refuse before touching the database and return a typed error.
- The settings screen, which renders the same matrix so an Owner can see exactly what each role can do.
The UI never decides anything. It reads the rules and describes them. Hiding a control is a courtesy to the user, not a security boundary — so the control being hidden and the action being refused are derived from one source rather than kept in sync by hand.
Server actions over an API layer
There is no REST layer between the pages and the database. Mutations are server actions: the permission check, the write and the revalidation happen in one function, on the server, in one round trip. It removes an entire class of bug where an endpoint and its caller disagree about who is allowed to do what.
The eight screens
Dashboard, clients, client detail, projects, project detail, tasks, team, reports, settings — seeded with realistic data so the charts have shapes worth looking at and the tables have enough rows to expose layout problems. Recharts throughout; the reporting view runs over the same normalized tables rather than a separate analytics store, which keeps the numbers honest at the cost of some query complexity.
What it demonstrates
Multi-tenant data modelling that fails closed; authorization designed as a single source of truth consulted by both server and UI; Next.js App Router with server actions and React Server Components; Prisma schema design with cascade relations; and enough seeded realism that the screens are worth showing.