Javis OS
Javis OS is an Agentic AI that assists entrepreneurs in business tasks, helping them grow their work.
AI translation
Crewspace is the people-and-permissions register for Sevyn Labs: who is in it, which team they work in, what their role lets them do, and a signed record of every change.
BusinessTypeScript · PLpgSQLGitHub @xopperskOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Multi-tenant team admin with RBAC and immutable audit log (Next.js + Supabase)
Taken from the repository README
Loading the full README.
Read the full README ↗Crewspace is a multi-tenant team workspace where organizations manage who can do what — members, teams, custom roles with a granular permission matrix, and an immutable audit trail of every privileged action. The core loop is invite → assign → verify: an owner creates a workspace, invites teammates by email, assigns roles whose permissions are explicit and discoverable, and every change lands in an append-only audit log.
This is a portfolio flagship built to demonstrate production-grade RBAC engineering: multi-tenant data isolation via PostgreSQL Row Level Security, defense-in-depth authorization (UI gating → server re-check → RLS), realtime presence, and a tokenized invitation lifecycle.
One outcome metric: authorization p95 ≤ 50 ms — the 95th-percentile latency of the full permission-check path (
user_permissions()resolution plus therequireOrgAccessassertion inside a Server Action). The[orgSlug]layout resolves permissions once per request; RLS carries per-row enforcement with zero extra round trips.
org-logos / avatars buckets, signed URLsBrowser → Next.js Server Action → requireOrgAccess(orgId, permission) → RLS → Postgres
│
▼
user_permissions(org_id, user_id)
SECURITY DEFINER SQL function returning
the union of permission keys — called once
per request in the [orgSlug] layout,
cached per request, never cached grants
Three enforcement layers (threat model assumes an authenticated low-privilege member):
usePermissions(), with plain-language explanations.requireOrgAccess, which re-reads the user, reloads the membership, and re-asserts the permission. No raw Supabase client creation in handlers.auth.uid() → active memberships → org_id. A forged request can never outrun the user's real grants.Database-level guardrails (fire even for service-role connections): prevent_last_owner_loss() trigger (last owner can't be demoted/removed), membership_update_guard() (column-level: role_id changes need members:change_role, is_active needs members:deactivate, never on one's own row), audit_log_no_modify() (audit history is immutable — no UPDATE/DELETE policy exists).
PermissionMatrix UI (resource × action grid, keyboard-operable, dirty-state review bar with diff + affected-member count); role wizard; "My access" transparency panelPrerequisites: Node 22+, pnpm 10+, a Supabase project (or the Supabase CLI).
pnpm install
cp .env.example .env.local # fill in your Supabase URL + keys
# Apply migrations: supabase/migrations/00001_init.sql … 00014_transfer_ownership.sql
# (in order — later files reference objects created earlier)
# Then run supabase/seed.sql for the "Hale & Fern Studio" demo org
pnpm dev
Environment variables (see .env.example): NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY (server only — never in client bundles; CI fails the build if it appears there), RESEND_API_KEY (invitation emails; currently stubbed — accept URLs log in dev).
| Gate | Result |
|---|---|
tsc --noEmit | 0 errors |
eslint | 0 errors, 0 warnings |
vitest run | 18 files, 250 tests, all passing |
next build | 26/26 pages |
| Bundle gate | app shell ~9 KB gzipped (≤180 KB budget) |
Test highlights: 50-test RLS static-analysis suite (RLS enabled on all 10 tenant tables, audit_log has zero update/delete policies, self-role-edit guards, all 18 permission keys seeded, migration-ordering regression tests), invitation state machine (replay/tamper/cross-org/expiry), permission-diff computation, audit-sentence formatters for all 26 audited actions, ownership-transfer validation.
invitation.sent → invitation.accepted → membership.role_changed, each with actor, diff, and IP.role_id vs is_active needing different permissions) can't live in policies alone; it needs the trigger layer (membership_update_guard).SECURITY DEFINER check must actually be definer. role_org_matches_membership() was caught during review: roles RLS hides cross-org roles, so a non-definer check would pass vacuously. Regression-tested."use server" modules — pure constants live in sibling modules (the same trap, twice: invitations constants and transfer validation).user_permissions() — role changes take effect on the member's next fetch, no stale sessions.Built with AI assistance (multi-agent: foundation, invitations, RBAC, directory/teams, audit/settings workers + a QA/hardening pass), with the six planning documents (PRD, technical requirements, app flow, design brief, database schema, implementation plan) as the source of truth. All AI output was reviewed against the specs: every privileged action traced to an audit producer, every RLS policy asserted by the static suite, and the full gate suite (typecheck, lint, 250 tests, build) run before commit. The design follows the project's own design brief (calm B2B admin, indigo accent, mobile-first at 390px).
supabase db push against a scratch project first.sendInvitationEmail() logs the accept URL in dev) until RESEND_API_KEY is wired.