feat: organization dashboard (multi-tenant) — issue #23#82
Open
rathorevaibhav wants to merge 22 commits into
Open
feat: organization dashboard (multi-tenant) — issue #23#82rathorevaibhav wants to merge 22 commits into
rathorevaibhav wants to merge 22 commits into
Conversation
Design for multi-tenant organizations: a session-scoped active org with a membership pivot (admin/member roles), platform super-admin tier, direct organization_id on monitors and groups, and explicit forOrganization() scoping + scoped route-model binding + policies (no global scope, so console/background checks stay unscoped). Includes the existing-data backfill into a default org and a TDD test plan. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
12 TDD tasks covering schema, membership/roles, the CurrentOrganization service, explicit forOrganization() scoping, scoped route-model binding, policies, the org switcher, registration disable, super-admin onboarding, org-scoped user management, and the default-org backfill. Incorporates an adversarial review pass: the design is now middleware-order independent (binding self-resolves via resolveFor + 404; lazy Inertia auth prop; policy ownership re-checks), and the MonitorHistory test migration is sequenced so every commit stays green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…mport Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #23.
Introduces a multi-tenant Organization boundary so each organization gets its own scoped dashboard, with admin/member roles and a platform super-admin tier — without changing the background uptime/cert/domain checks, which run in a console context with no HTTP session.
What's in here
organizations+organization_usermembership pivot (per-membershipadmin/memberrole);users.is_super_admin; directorganization_idonmonitorsandgroups(group stays an optional sub-grouping within an org).SetActiveOrganizationmiddleware into aCurrentOrganizationrequest singleton; an org switcher in the nav (desktop + mobile).forOrganization()scoping + org-scoped route-model binding (cross-org URL → 404) + policies/gates (Gate::beforesuper-admin bypass; member = read-only). Three independent isolation barriers./registerdisabled; super-admins onboard an org + its first admin; org-admins self-manage users (find-or-link by email, detach-not-delete) and can rename their org.organization_idNOT NULL.Key design decision — no global scope
Spatie's scheduled checks and our console commands enumerate monitors through
MonitorRepository::query()with no session. A session-keyed global scope would silently filter every background check to zero. So no global Eloquent scope was added — web paths scope explicitly; console paths stay unscoped. This invariant is locked by a regression test asserting the repository's enumeration entry point still sees all orgs' monitors with no active org bound.The active-org resolution is also middleware-ordering-independent: a single pure
CurrentOrganization::resolveFor()is shared by the middleware, the route binding (which runs before the middleware), and the lazy Inertiaauthprop (resolved after it).Testing
npm run buildsucceeds.Deferred (fast-follow, non-blocking)
Design spec and full implementation plan are committed under
plans/.🤖 Generated with Claude Code