Skip to content
The foundation under itData foundation

Sign-in and roles

Only our team, only our project, and the server decides.

Growth-OS holds our pipeline, our meeting transcripts, our decisions and our finance ledger. You sign in once, and from there the server works out which teammate you are and which project you are in. What the browser claims counts for nothing. Your role decides whether you can edit a decision or open the budget.

  • 1

    path that decides who you are

  • 4

    access levels behind every role name

  • 0

    project IDs trusted from the browser

The problem this solves

Without a shared foundation, every team rebuilds these edge cases, differently.

The sheet with one setting: whoever has the link

A pipeline spreadsheet cannot tell salary lines apart from a prospect list. Everyone who can open it can read all of it, and nobody can tell you who did. Growth-OS resolves membership per project on every read and every write.

Role rules that drift apart

When each screen writes its own check, they slowly disagree. Finance opens to someone who was only meant to read, and nobody notices until an awkward conversation. One ranking function keeps every screen consistent.

The leaver with a tab still open

Access checked once, when a page loaded, never expires. Here membership is resolved on the request itself, so removing someone from the project actually removes them.

How it works

The mechanism end to end, as implemented in the repository.

  1. 1

    Clerk confirms the session

    Sign-in runs through Clerk once per request. Without a session, nothing after this step runs at all.

  2. 2

    The session maps to a teammate

    The server looks that login up in our own users table. A login with no teammate record gets a clear error rather than a free pass.

  3. 3

    Membership is checked next to the data

    The same database call that reads or writes your record confirms you belong to that organization and project. There is no gap between the check and the work.

  4. 4

    One function ranks the roles

    roleAtLeast ranks viewer, editor, admin and owner, and every WISEPIM role name maps onto one of them. Organization owners keep access to every project; otherwise a project membership wins, falling back to the organization one.

Interactive example

See it working

This walkthrough demonstrates the implemented backend contract without using an account, credentials, or provider calls.

Interactive example

Explore the decisions this makes

Choose a sample state
Read and discuss

Deterministic sample data only. No account, provider, or network connection is used by the interaction.

Highlights

Why it matters

The server decides who you are

Every request is matched to a real teammate row in our own database. A session that maps to nobody stops at the door.

Seven role names, four levels

Owner, Founder, Admin, Editor, First hire, Advisory, Viewer. They rank into four access levels, compared by one function that every screen uses.

Locked unless you belong

No session, no teammate record, or no membership in the project, and the request stops with a plain error instead of falling through to a default.

Engineering guarantees

What this does and does not promise

Safety boundary

Clerk runs the sign-in itself, so its availability is not ours to promise. What this proves is the server-side boundary: which teammate you are, and what that lets you touch.

Implementation evidence

The boundary above is code, not a claim. These files carry the contract:

  • src/server/auth.ts
  • src/server/permissions.ts
  • src/policies/roles.ts
Questions

Frequently asked questions

What sign-in and roles rests on

The docs describe the same contracts this page demonstrates.