npm package: @remade/nestjs-organization
Description: Multi-tenant organization management module for NestJS with RBAC
Author: remade
Latest version: 0.1.1

# @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

```typescript
import { OrganizationModule } from '@app/organization';

OrganizationModule.forRoot({
  tenantResolution: { strategy: 'header' },
  permissionResolver: { useClass: MyPermissionResolver },
})
```

## Documentation

| Document | Description |
|---|---|
| [Overview & Architecture](./docs/README.md) | Quick start, module options, architecture, design decisions, exports |
| [Entities](./docs/entities.md) | All 4 entities with fields, relationships, and constraints |
| [Tenant Resolution](./docs/tenant-resolution.md) | Multi-tenancy strategies, middleware, TenantContextService |
| [RBAC](./docs/rbac.md) | Guard chain, decorators, PermissionResolver contract, permission keys |
| [API Reference](./docs/api-reference.md) | REST endpoints, DTOs, service methods |
| [Events & Hooks](./docs/events-and-hooks.md) | 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 strategy
```

## Entities

| 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

1. **Consumer-owned permissions** -- Defines permission keys but delegates all checks to a consumer-provided `PermissionResolver`.
2. **`isOwner` is the only structural flag** -- Prevents orphaned organizations. All other roles belong to the consumer.
3. **Tenant context via AsyncLocalStorage** -- Request-scoped org resolution through middleware, avoiding request-scoped providers.
4. **Soft deletes** -- Organizations and members use `@DeleteDateColumn`. Invitations use status transitions.
5. **Hooks for lifecycle extension** -- `before*` hooks can modify data or abort. `after*` hooks are side-effects.
6. **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`