Skip to content

Feature/multi tenant base#85

Open
gbchill wants to merge 30 commits intoopportunity-hack:devfrom
gbchill:feature/multi-tenant-base
Open

Feature/multi tenant base#85
gbchill wants to merge 30 commits intoopportunity-hack:devfrom
gbchill:feature/multi-tenant-base

Conversation

@gbchill
Copy link

@gbchill gbchill commented Mar 24, 2026

This is the first pass at turning EVS into a proper multi-tenant platform.

The three big things:

1. Any org can sign up
There's now a public /org-signup page where a nonprofit can register their organization, pick their animal type, and create their admin account. No manual setup needed on our end.

2. Data is fully isolated between orgs
Every event, animal, and user is scoped to an org. Tested this with two orgs side by side — they can't see each other's data at all.

3. Not just horses anymore
Renamed the Horse model to Animal with a species field. Roles and all the copy throughout the app are now animal-agnostic, so this works for any nonprofit regardless of what animals they work with.

Also added a Super Admin view at /super-admin/orgs to see all orgs in the system with their stats.

To test locally:

  • npm run setup (resets and re-seeds the DB)
  • Visit /org-signup and create a second org
  • Confirm the second org sees only its own data
  • Log back in as kody/kodylovesyou and confirm Tumbling T Ranch data is untouched

gbchill and others added 30 commits March 12, 2026 19:37
- Rename _horses+ route directory to _animals+ with animalId params
- Rename HorseListbox to AnimalListbox in listboxes component
- Rename horseDateConflicts/renderHorseConflictMessage to animal equivalents
- Update createHorse -> createAnimal in db-utils and seed
- Update seed.ts to use prisma.animal.create

Co-Authored-By: George Badulescu <gbadulescu@example.com>
…c copy

- Rename HorseData -> AnimalData, HorseAssignment -> AnimalAssignment
- Update volunteerTypes: horse leaders -> animal handlers with generic copy
- Update siteName to TrotTrack Volunteer Portal, siteBaseUrl to trottrack.org
- Rename getHorseImgSrc -> getAnimalImgSrc in misc.ts
- Update EventWithAllRelations/EventWithVolunteers to use animals, animalHandlers

Co-Authored-By: George Badulescu <gbadulescu@example.com>
- calendar/$eventId.tsx: animals/animalAssignments/animalHandlers, AnimalInfoPopover
- calendar/$eventId.edit.tsx: AnimalListbox, animals, animalHandlersReq
- calendar/index.tsx: animals loader, animalHandlers filter/tooltip, AnimalListbox
- event-register.tsx: animalHandlers role type union
- registration/unregistration emails: animalHandlers role type union
- users.edit: animalHandler role instead of horseLeader
- users.tsx: animal handler column header
- email.tsx: animalHandler field instead of horseLeader
- root.tsx: nav link updated to /admin/animals

Co-Authored-By: George Badulescu <gbadulescu@example.com>
- Add signupOrg() to auth.server.ts: creates Org + admin User atomically
  in a single Prisma session transaction, connecting the admin role
- Add /org-signup route with two-section form (org details + admin account)
  including slug generation, duplicate username/email/org validation
- Add /org-setup redirect page for authenticated users without an org
- Update landing page hero: TrotTrack branding + Register Your Organization CTA
  alongside existing volunteer signup button

Co-Authored-By: George Badulescu <gbadulescu@example.com>
- users.delete: add requireOrgMember, use findFirst with orgId
- users.edit: add requireOrgMember, fix isHorseLeader -> isAnimalHandler
- users.promote: add requireOrgMember, verify userId belongs to org before update
- $eventId.delete: add requireOrgMember, scope event lookup by orgId
- email.tsx: scope getRecipientsFromRoles and getUpcomingEvents by orgId
  ensuring bulk emails only go to users in the same organization
- $eventId.edit: add requireOrgMember, scope instructors/animals/event
  queries by orgId; verify event ownership before update
- super-admin/orgs: new page listing all organizations with user/animal/
  event counts, protected by requireSuperAdmin
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant