@remade/nestjs-organization
v0.1.1
Published
Multi-tenant organization management module for NestJS with RBAC
Maintainers
Readme
@app/organization
Reusable NestJS library providing multi-tenant organization management with membership, invitations, RBAC, and request-scoped tenant context. Ships as a forRoot() / forRootAsync() dynamic module with a bundled TypeORM adapter.
Quick Start
import { OrganizationModule } from '@app/organization';
OrganizationModule.forRoot({
tenantResolution: { strategy: 'header' },
permissionResolver: { useClass: MyPermissionResolver },
})Documentation
| Document | Description | |---|---| | Overview & Architecture | Quick start, module options, architecture, design decisions, exports | | Entities | All 4 entities with fields, relationships, and constraints | | Tenant Resolution | Multi-tenancy strategies, middleware, TenantContextService | | RBAC | Guard chain, decorators, PermissionResolver contract, permission keys | | API Reference | REST endpoints, DTOs, service methods | | Events & Hooks | Domain events, lifecycle hooks, invitation callback |
Directory Structure
libs/organization/src/
├── organization.module.ts # Dynamic module with forRoot/forRootAsync
├── organization.constants.ts # Injection tokens and permission keys
├── index.ts # Barrel export
├── config/ # Default configuration values
├── entities/ # 4 TypeORM entities
├── dto/ # 9 DTOs with class-validator
├── services/ # 5 services
├── controllers/ # 4 REST controllers
├── guards/ # 3 guards (org, permission, owner)
├── decorators/ # 5 decorators (route + param)
├── middleware/ # Tenant resolution middleware
├── context/ # AsyncLocalStorage tenant context
├── events/ # 10 domain event classes
├── enums/ # InvitationStatus
└── interfaces/ # Module options, PermissionResolver, hooks, tenant strategyEntities
| Entity | Table | Purpose |
|---|---|---|
| Organization | organizations | Core org record with name, slug, logo, metadata |
| OrganizationMember | organization_members | User membership with ownership flag |
| OrganizationDetail | organization_details | Structured key-value metadata per org |
| OrganizationInvitation | organization_invitations | Email-based invitation with token auth |
API Endpoints
All routes prefixed with configurable routePrefix (default: organizations).
| Method | Route | Permission | Description |
|---|---|---|---|
| POST | / | authenticated | Create organization |
| GET | / | authenticated | List organizations |
| GET | /:orgId | org:read | Get organization details |
| PATCH | /:orgId | org:update | Update organization |
| DELETE | /:orgId | org:delete | Soft-delete organization |
| POST | /check-slug | authenticated | Check slug availability |
| PUT | /:orgId/details | org:update | Bulk upsert details |
| GET | /:orgId/details | org:read | Get all details |
| DELETE | /:orgId/details/:key | org:update | Remove a detail |
| GET | /:orgId/members | member:list | List members |
| POST | /:orgId/members | member:add | Add member |
| DELETE | /:orgId/members/:userId | member:remove | Remove member |
| GET | /:orgId/members/:userId | member:list | Get member detail |
| POST | /:orgId/transfer-ownership | owner-only | Transfer ownership |
| POST | /:orgId/invitations | invitation:create | Create invitation |
| GET | /:orgId/invitations | invitation:list | List invitations |
| DELETE | /:orgId/invitations/:id | invitation:cancel | Cancel invitation |
| POST | /:orgId/invitations/:id/resend | invitation:resend | Resend invitation |
| POST | /invitations/:token/accept | authenticated | Accept invitation |
| POST | /invitations/:token/reject | public | Reject invitation |
Exported Services
| Service | Purpose |
|---|---|
| OrganizationService | CRUD organizations, slug availability, list by user |
| OrganizationDetailService | Structured key-value detail management |
| MemberService | Add/remove members, ownership transfer, membership checks |
| InvitationService | Create/accept/reject/cancel/resend invitations |
| TenantContextService | Read/write request-scoped tenant context via AsyncLocalStorage |
Key Design Decisions
- Consumer-owned permissions -- Defines permission keys but delegates all checks to a consumer-provided
PermissionResolver. isOwneris the only structural flag -- Prevents orphaned organizations. All other roles belong to the consumer.- Tenant context via AsyncLocalStorage -- Request-scoped org resolution through middleware, avoiding request-scoped providers.
- Soft deletes -- Organizations and members use
@DeleteDateColumn. Invitations use status transitions. - Hooks for lifecycle extension --
before*hooks can modify data or abort.after*hooks are side-effects. - Detail keys validation -- Optional whitelist restricts which keys can be stored.
Exports
Everything below is exported from @app/organization:
Module: OrganizationModule
Services: OrganizationService, OrganizationDetailService, MemberService, InvitationService, TenantContextService
Guards: OrganizationGuard, RequirePermissionGuard, RequireOwnerGuard
Decorators: RequireOrg, RequirePermission, RequireOwner, CurrentOrg, CurrentMember
Entities: Organization, OrganizationDetail, OrganizationMember, OrganizationInvitation
DTOs: CreateOrganizationDto, UpdateOrganizationDto, CreateInvitationDto, SetDetailsDto, AddMemberDto, TransferOwnershipDto, ListOrganizationsQueryDto, ListMembersQueryDto, PaginationDto
Enums: InvitationStatus
Interfaces (type-only): PermissionResolver, PermissionContext, OrganizationModuleOptions, OrganizationModuleAsyncOptions, OrganizationHooks, TenantResolutionOptions
Events: OrganizationCreatedEvent, OrganizationUpdatedEvent, OrganizationDeletedEvent, MemberAddedEvent, MemberRemovedEvent, OwnershipTransferredEvent, InvitationCreatedEvent, InvitationAcceptedEvent, InvitationRejectedEvent, InvitationCancelledEvent
Constants: ORGANIZATION_PERMISSIONS, ORGANIZATION_MODULE_OPTIONS, PERMISSION_RESOLVER
Context: tenantContextStore, TenantContext
