npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@venturialstd/tenant

v0.0.2

Published

Multi-tenant SaaS Platform Module for Venturial

Readme

@venturialstd/tenant

A comprehensive Multi-Tenant SaaS Platform Package, developed by Venturial, that provides complete tenant management capabilities with user isolation for building scalable SaaS applications. This package follows the Venturial architecture pattern and integrates seamlessly with TypeORM and NestJS.


Features

  • Multi-Tenant Management: Create and manage multiple tenants with isolated data
  • User-Tenant Relationships: Complete user isolation per tenant with role-based access control
  • Role-Based Access Control (RBAC): Owner, Admin, Member, and Viewer roles
  • Subscription Plans: Support for Free, Starter, Professional, and Enterprise plans
  • Trial Period: Configurable trial periods for new tenants
  • Custom Domains: Optional custom domain support for tenants
  • Invitation System: Invite users to tenants with pending invitation management
  • Ownership Transfer: Transfer tenant ownership between users
  • User Suspension: Suspend and reactivate user access to tenants
  • Guards & Decorators: Built-in guards and decorators for easy tenant isolation
  • CRUD Operations: Full TypeORM CRUD service integration
  • Settings Management: Dynamic tenant-level settings with @venturialstd/core

Installation

npm install @venturialstd/tenant
# or
yarn add @venturialstd/tenant

Basic Usage

1. Import the TenantModule in your application

import { Module } from '@nestjs/common';
import { TenantModule } from '@venturialstd/tenant';

@Module({
  imports: [
    TenantModule,
    // ... other modules
  ],
})
export class AppModule {}

2. Use the services in your application

import { Injectable } from '@nestjs/common';
import { TenantService, TenantUserService, TenantUserRole } from '@venturialstd/tenant';

@Injectable()
export class YourService {
  constructor(
    private readonly tenantService: TenantService,
    private readonly tenantUserService: TenantUserService,
  ) {}

  async createNewTenant(userId: string) {
    // Create tenant
    const tenant = await this.tenantService.createTenant(
      'Acme Corp',
      'acme-corp',
      'acme.example.com',
      'A leading software company',
      userId
    );

    // Add user as primary owner
    await this.tenantUserService.addUserToTenant(
      tenant.id,
      userId,
      TenantUserRole.OWNER
    );

    await this.tenantUserService.setPrimaryOwner(tenant.id, userId);

    return tenant;
  }

  async inviteUserToTenant(tenantId: string, userId: string, invitedBy: string) {
    return this.tenantUserService.inviteUserToTenant(
      tenantId,
      userId,
      TenantUserRole.MEMBER,
      invitedBy
    );
  }
}

3. Use Guards and Decorators for tenant isolation

import { Controller, Get, UseGuards } from '@nestjs/common';
import { 
  TenantGuard, 
  TenantRoleGuard, 
  TenantId, 
  UserId,
  Roles,
  TenantUserRole 
} from '@venturialstd/tenant';

@Controller('data')
@UseGuards(TenantGuard) // Ensure user has access to tenant
export class DataController {
  constructor(private readonly dataService: DataService) {}

  @Get()
  async getData(@TenantId() tenantId: string, @UserId() userId: string) {
    // tenantId and userId are automatically extracted and validated
    return this.dataService.getTenantData(tenantId, userId);
  }

  @Delete(':id')
  @Roles(TenantUserRole.OWNER, TenantUserRole.ADMIN) // Only owners and admins
  @UseGuards(TenantRoleGuard) // Enforce role-based access
  async deleteData(@TenantId() tenantId: string, @Param('id') id: string) {
    return this.dataService.deleteData(tenantId, id);
  }
}

Entity Structures

Tenant Entity

The Tenant entity includes the following fields:

  • id: UUID primary key
  • name: Tenant name (required, unique)
  • slug: URL-friendly identifier (required, unique)
  • domain: Custom domain (optional)
  • description: Tenant description (optional)
  • isActive: Active/inactive status (default: true)
  • settings: JSON field for tenant-specific settings
  • ownerId: Reference to the owner user
  • plan: Subscription plan (free, starter, professional, enterprise)
  • trialEndsAt: Trial period expiration date
  • subscriptionEndsAt: Subscription expiration date
  • createdAt: Creation timestamp
  • updatedAt: Last update timestamp

TenantUser Entity

The TenantUser entity manages user-tenant relationships:

  • id: UUID primary key
  • tenantId: Reference to tenant (indexed)
  • userId: Reference to user (indexed)
  • role: User role (OWNER, ADMIN, MEMBER, VIEWER)
  • status: User status (ACTIVE, INVITED, SUSPENDED)
  • isPrimary: Whether user is the primary owner
  • invitedBy: User who sent the invitation
  • invitedAt: Invitation timestamp
  • joinedAt: Join timestamp
  • permissions: JSON field for custom permissions
  • createdAt: Creation timestamp
  • updatedAt: Last update timestamp

Unique constraint: (tenantId, userId) - A user can only be added once per tenant


Available Methods

TenantService Methods

createTenant(name, slug, domain?, description?, ownerId?)

Creates a new tenant with validation and default settings.

const tenant = await tenantService.createTenant(
  'My Company',
  'my-company',
  'mycompany.com',
  'Company description',
  'owner-uuid'
);

getTenantBySlug(slug)

Retrieve a tenant by its slug.

const tenant = await tenantService.getTenantBySlug('my-company');

getTenantByDomain(domain)

Retrieve a tenant by its custom domain.

const tenant = await tenantService.getTenantByDomain('mycompany.com');

updateTenantSettings(tenantId, settings)

Update tenant-specific settings.

await tenantService.updateTenantSettings('tenant-uuid', {
  theme: 'dark',
  language: 'en',
  features: { api: true }
});

setTenantStatus(tenantId, isActive)

Activate or deactivate a tenant.

await tenantService.setTenantStatus('tenant-uuid', false); // Deactivate
await tenantService.setTenantStatus('tenant-uuid', true);  // Activate

updateTenantPlan(tenantId, plan, subscriptionEndsAt?)

Update the tenant's subscription plan.

const endDate = new Date();
endDate.setMonth(endDate.getMonth() + 1);

await tenantService.updateTenantPlan(
  'tenant-uuid',
  'professional',
  endDate
);

getActiveTenants()

Get all active tenants.

const activeTenants = await tenantService.getActiveTenants();

getTenantsByOwner(ownerId)

Get all tenants owned by a specific user.

const tenants = await tenantService.getTenantsByOwner('owner-uuid');

isInTrialPeriod(tenantId)

Check if a tenant is currently in trial period.

const inTrial = await tenantService.isInTrialPeriod('tenant-uuid');

hasActiveSubscription(tenantId)

Check if a tenant has an active subscription.

const isActive = await tenantService.hasActiveSubscription('tenant-uuid');

TenantUserService Methods

addUserToTenant(tenantId, userId, role, invitedBy?)

Add a user to a tenant with a specific role.

await tenantUserService.addUserToTenant(
  'tenant-uuid',
  'user-uuid',
  TenantUserRole.MEMBER,
  'inviter-uuid'
);

inviteUserToTenant(tenantId, userId, role, invitedBy)

Invite a user to a tenant (creates pending invitation).

await tenantUserService.inviteUserToTenant(
  'tenant-uuid',
  'user-uuid',
  TenantUserRole.ADMIN,
  'inviter-uuid'
);

acceptInvitation(tenantId, userId)

Accept a pending tenant invitation.

await tenantUserService.acceptInvitation('tenant-uuid', 'user-uuid');

removeUserFromTenant(tenantId, userId)

Remove a user from a tenant (cannot remove primary owner).

await tenantUserService.removeUserFromTenant('tenant-uuid', 'user-uuid');

updateUserRole(tenantId, userId, newRole)

Update a user's role in a tenant.

await tenantUserService.updateUserRole(
  'tenant-uuid',
  'user-uuid',
  TenantUserRole.ADMIN
);

getUserTenants(userId)

Get all tenants a user belongs to.

const userTenants = await tenantUserService.getUserTenants('user-uuid');

getTenantUsers(tenantId)

Get all users in a tenant (including invited).

const users = await tenantUserService.getTenantUsers('tenant-uuid');

getActiveTenantUsers(tenantId)

Get all active users in a tenant.

const activeUsers = await tenantUserService.getActiveTenantUsers('tenant-uuid');

hasAccess(tenantId, userId)

Check if a user has access to a tenant.

const hasAccess = await tenantUserService.hasAccess('tenant-uuid', 'user-uuid');

hasRole(tenantId, userId, role)

Check if a user has a specific role in a tenant.

const isAdmin = await tenantUserService.hasRole(
  'tenant-uuid',
  'user-uuid',
  TenantUserRole.ADMIN
);

isAdminOrOwner(tenantId, userId)

Check if a user is an admin or owner in a tenant.

const isAdminOrOwner = await tenantUserService.isAdminOrOwner('tenant-uuid', 'user-uuid');

getUserRole(tenantId, userId)

Get a user's role in a tenant.

const role = await tenantUserService.getUserRole('tenant-uuid', 'user-uuid');

setPrimaryOwner(tenantId, userId)

Set a user as the primary owner of a tenant.

await tenantUserService.setPrimaryOwner('tenant-uuid', 'user-uuid');

transferOwnership(tenantId, fromUserId, toUserId)

Transfer tenant ownership between users.

await tenantUserService.transferOwnership(
  'tenant-uuid',
  'current-owner-uuid',
  'new-owner-uuid'
);

getUserInvitations(userId)

Get all pending invitations for a user.

const invitations = await tenantUserService.getUserInvitations('user-uuid');

suspendUser(tenantId, userId)

Suspend a user's access to a tenant.

await tenantUserService.suspendUser('tenant-uuid', 'user-uuid');

reactivateUser(tenantId, userId)

Reactivate a suspended user.

await tenantUserService.reactivateUser('tenant-uuid', 'user-uuid');

Guards and Decorators

TenantGuard

Enforces tenant access control by validating that the authenticated user has access to the requested tenant.

@Controller('api')
@UseGuards(TenantGuard)
export class ApiController {
  @Get('data')
  async getData(@TenantId() tenantId: string) {
    // User access to tenant is already validated
    return this.service.getData(tenantId);
  }
}

TenantRoleGuard

Enforces role-based access control within a tenant. Use with @Roles() decorator.

@Controller('admin')
@UseGuards(TenantGuard, TenantRoleGuard)
export class AdminController {
  @Delete('user/:userId')
  @Roles(TenantUserRole.OWNER, TenantUserRole.ADMIN)
  async removeUser(@TenantId() tenantId: string, @Param('userId') userId: string) {
    // Only owners and admins can access this endpoint
    return this.service.removeUser(tenantId, userId);
  }
}

@TenantId()

Extracts the tenant ID from the request. Checks in order:

  1. request.tenantId
  2. request.headers['x-tenant-id']
  3. request.params.tenantId
  4. request.query.tenantId
@Get()
async getData(@TenantId() tenantId: string) {
  return this.service.getData(tenantId);
}

@UserId()

Extracts the user ID from the authenticated request.

@Get('profile')
async getProfile(@UserId() userId: string, @TenantId() tenantId: string) {
  return this.service.getUserProfile(tenantId, userId);
}

@TenantContext()

Extracts the complete tenant context including tenantId, userId, role, and user object.

@Get()
async getData(@TenantContext() context: { tenantId: string, userId: string, role: TenantUserRole, user: any }) {
  return this.service.getData(context);
}

@Roles(...roles)

Specifies required roles for accessing an endpoint. Must be used with TenantRoleGuard.

@Post('invite')
@Roles(TenantUserRole.OWNER, TenantUserRole.ADMIN)
@UseGuards(TenantGuard, TenantRoleGuard)
async inviteUser(@TenantId() tenantId: string, @Body() dto: InviteUserDto) {
  return this.service.inviteUser(tenantId, dto);
}

Configuration Settings

The module provides the following configurable settings through SettingsService:

General Settings

  • ENABLED: Enable/disable the tenant module (boolean)
  • MAX_TENANTS: Maximum number of tenants allowed (0 = unlimited)
  • DEFAULT_PLAN: Default subscription plan for new tenants
  • TRIAL_DAYS: Number of trial days for new tenants (default: 14)

Feature Settings

  • CUSTOM_DOMAIN: Allow custom domains for tenants
  • API_ACCESS: Allow API access for tenants

Enums and Types

TenantUserRole

enum TenantUserRole {
  OWNER = 'owner',
  ADMIN = 'admin',
  MEMBER = 'member',
  VIEWER = 'viewer',
}

TenantUserStatus

enum TenantUserStatus {
  ACTIVE = 'active',
  INVITED = 'invited',
  SUSPENDED = 'suspended',
}

TENANT_PLAN

enum TENANT_PLAN {
  FREE = 'free',
  STARTER = 'starter',
  PROFESSIONAL = 'professional',
  ENTERPRISE = 'enterprise',
}

TENANT_STATUS

enum TENANT_STATUS {
  ACTIVE = 'active',
  INACTIVE = 'inactive',
  SUSPENDED = 'suspended',
  TRIAL = 'trial',
}

Integration with @venturialstd/core

This package uses @venturialstd/core for:

  • SharedModule: Core functionality and configuration
  • SettingsService: Dynamic settings management
  • AppLogger: Structured logging

TypeORM Integration

The package extends TypeOrmCrudService from @dataui/crud-typeorm, providing:

  • Standard CRUD operations
  • Query builders
  • Pagination support
  • Filtering and sorting capabilities

Example: Complete SaaS Implementation with User Isolation

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { TenantModule, TenantService, TenantUserService } from '@venturialstd/tenant';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      // Your database configuration
    }),
    TenantModule,
  ],
})
export class AppModule {}

// Service for onboarding new tenants
@Injectable()
export class SaasService {
  constructor(
    private readonly tenantService: TenantService,
    private readonly tenantUserService: TenantUserService,
  ) {}

  async onboardNewTenant(data: any, ownerId: string) {
    // Create tenant
    const tenant = await this.tenantService.createTenant(
      data.companyName,
      data.slug,
      data.domain,
      data.description,
      ownerId
    );

    // Add owner to tenant
    await this.tenantUserService.addUserToTenant(
      tenant.id,
      ownerId,
      TenantUserRole.OWNER
    );

    // Set as primary owner
    await this.tenantUserService.setPrimaryOwner(tenant.id, ownerId);

    // Configure tenant settings
    await this.tenantService.updateTenantSettings(tenant.id, {
      theme: data.preferences?.theme || 'light',
      locale: data.preferences?.locale || 'en',
      notifications: true,
    });

    return tenant;
  }

  async inviteTeamMember(
    tenantId: string,
    userId: string,
    invitedBy: string,
    role: TenantUserRole = TenantUserRole.MEMBER
  ) {
    // Verify inviter is admin or owner
    const isAdmin = await this.tenantUserService.isAdminOrOwner(tenantId, invitedBy);
    if (!isAdmin) {
      throw new ForbiddenException('Only admins can invite team members');
    }

    // Invite user
    await this.tenantUserService.inviteUserToTenant(
      tenantId,
      userId,
      role,
      invitedBy
    );

    // Send invitation email (implement your email service)
    // await this.emailService.sendInvitation(userId, tenantId);
  }

  async checkTenantAccess(tenantId: string, userId: string) {
    const tenant = await this.tenantService.repo.findOne({
      where: { id: tenantId }
    });

    if (!tenant.isActive) {
      throw new UnauthorizedException('Tenant is inactive');
    }

    const hasAccess = await this.tenantUserService.hasAccess(tenantId, userId);
    if (!hasAccess) {
      throw new UnauthorizedException('No access to this tenant');
    }

    const hasSubscription = await this.tenantService.hasActiveSubscription(tenantId);
    if (!hasSubscription) {
      throw new UnauthorizedException('Subscription expired');
    }

    return true;
  }
}

// Controller with tenant isolation
@Controller('projects')
@UseGuards(TenantGuard)
export class ProjectsController {
  constructor(private readonly projectsService: ProjectsService) {}

  @Get()
  async list(@TenantId() tenantId: string, @UserId() userId: string) {
    // Automatically scoped to tenant
    return this.projectsService.findByTenant(tenantId);
  }

  @Post()
  async create(
    @TenantId() tenantId: string,
    @UserId() userId: string,
    @Body() dto: CreateProjectDto
  ) {
    return this.projectsService.create(tenantId, userId, dto);
  }

  @Delete(':id')
  @Roles(TenantUserRole.OWNER, TenantUserRole.ADMIN)
  @UseGuards(TenantRoleGuard)
  async delete(@TenantId() tenantId: string, @Param('id') id: string) {
    // Only owners and admins can delete
    return this.projectsService.delete(tenantId, id);
  }
}

Database Migrations

The package requires two database tables: tenant and tenant_user. Create migrations for both:

Tenant Table Migration

npm run typeorm migration:create -- -n CreateTenant
import { MigrationInterface, QueryRunner, Table, TableIndex } from 'typeorm';

export class CreateTenant1234567890123 implements MigrationInterface {
  public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.createTable(
      new Table({
        name: 'tenant',
        columns: [
          { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'uuid_generate_v4()' },
          { name: 'name', type: 'varchar', isUnique: true },
          { name: 'slug', type: 'varchar', isUnique: true },
          { name: 'domain', type: 'varchar', isNullable: true },
          { name: 'description', type: 'text', isNullable: true },
          { name: 'isActive', type: 'boolean', default: true },
          { name: 'settings', type: 'jsonb', isNullable: true },
          { name: 'ownerId', type: 'varchar', isNullable: true },
          { name: 'plan', type: 'varchar', isNullable: true },
          { name: 'trialEndsAt', type: 'timestamptz', isNullable: true },
          { name: 'subscriptionEndsAt', type: 'timestamptz', isNullable: true },
          { name: 'createdAt', type: 'timestamptz', default: 'CURRENT_TIMESTAMP' },
          { name: 'updatedAt', type: 'timestamptz', default: 'CURRENT_TIMESTAMP' },
        ],
      }),
      true,
    );

    await queryRunner.createIndex('tenant', new TableIndex({ name: 'IDX_tenant_slug', columnNames: ['slug'] }));
    await queryRunner.createIndex('tenant', new TableIndex({ name: 'IDX_tenant_domain', columnNames: ['domain'] }));
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.dropTable('tenant');
  }
}

TenantUser Table Migration

npm run typeorm migration:create -- -n CreateTenantUser
import { MigrationInterface, QueryRunner, Table, TableIndex } from 'typeorm';

export class CreateTenantUser1234567890124 implements MigrationInterface {
  public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.createTable(
      new Table({
        name: 'tenant_user',
        columns: [
          { name: 'id', type: 'uuid', isPrimary: true, generationStrategy: 'uuid', default: 'uuid_generate_v4()' },
          { name: 'tenantId', type: 'uuid' },
          { name: 'userId', type: 'uuid' },
          { name: 'role', type: 'enum', enum: ['owner', 'admin', 'member', 'viewer'], default: "'member'" },
          { name: 'status', type: 'enum', enum: ['active', 'invited', 'suspended'], default: "'active'" },
          { name: 'isPrimary', type: 'boolean', default: false },
          { name: 'invitedBy', type: 'uuid', isNullable: true },
          { name: 'invitedAt', type: 'timestamptz', isNullable: true },
          { name: 'joinedAt', type: 'timestamptz', isNullable: true },
          { name: 'permissions', type: 'jsonb', isNullable: true },
          { name: 'createdAt', type: 'timestamptz', default: 'CURRENT_TIMESTAMP' },
          { name: 'updatedAt', type: 'timestamptz', default: 'CURRENT_TIMESTAMP' },
        ],
      }),
      true,
    );

    await queryRunner.createIndex('tenant_user', new TableIndex({ name: 'IDX_tenant_user_tenantId', columnNames: ['tenantId'] }));
    await queryRunner.createIndex('tenant_user', new TableIndex({ name: 'IDX_tenant_user_userId', columnNames: ['userId'] }));
    await queryRunner.createIndex('tenant_user', new TableIndex({ name: 'IDX_tenant_user_tenant_user', columnNames: ['tenantId', 'userId'], isUnique: true }));
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.dropTable('tenant_user');
  }
}

Run migrations:

npm run typeorm migration:run

Testing

The module includes an isolated NestJS test environment for testing all functionality without integrating it into your main application.

Setup Test Environment

  1. Copy environment configuration:

    cd test
    cp .env.example .env
  2. Configure your database in test/.env:

    DB_HOST=localhost
    DB_PORT=5432
    DB_USERNAME=postgres
    DB_PASSWORD=postgres
    DB_DATABASE=tenant_test
    TEST_PORT=3001
  3. Install dependencies (from the module root):

    npm install
  4. Create test database:

    createdb tenant_test
    # or using psql:
    psql -U postgres -c "CREATE DATABASE tenant_test;"

Run Test Server

Start the test server (runs on port 3001 by default):

npm run test:dev

Or with auto-reload on file changes:

npm run test:watch

The server will display all available endpoints:

🚀 Tenant Module Test Server running on: http://localhost:3001

📋 Available endpoints:
  Tenant Management:
    POST   /tenants                        - Create tenant
    GET    /tenants                        - Get all tenants
    GET    /tenants/active                 - Get active tenants
    GET    /tenants/owner/:ownerId         - Get tenants by owner
    GET    /tenants/slug/:slug             - Get tenant by slug
    GET    /tenants/domain/:domain         - Get tenant by domain
    GET    /tenants/:id                    - Get tenant by ID
    PUT    /tenants/:id/settings           - Update tenant settings
    PUT    /tenants/:id/status             - Update tenant status
    PUT    /tenants/:id/plan               - Update tenant plan
    GET    /tenants/:id/trial              - Check if trial is active
    GET    /tenants/:id/subscription       - Check if subscription is active
    DELETE /tenants/:id                    - Delete tenant

  User-Tenant Management:
    POST   /tenant-users/add               - Add user to tenant
    POST   /tenant-users/invite            - Invite user to tenant
    GET    /tenant-users/tenant/:tenantId  - Get all users in tenant
    GET    /tenant-users/user/:userId      - Get user's tenants
    PUT    /tenant-users/update-role       - Update user role
    POST   /tenant-users/transfer-ownership - Transfer ownership
    ... and more

Testing with HTTP Requests

Use the provided test/requests.http file with REST Client (VS Code extension) or Postman:

  1. Create a tenant:

    POST http://localhost:3001/tenants
    Content-Type: application/json
    
    {
      "name": "Acme Corporation",
      "slug": "acme-corp",
      "ownerId": "user-123",
      "domain": "acme.example.com"
    }
  2. Add users to tenant:

    POST http://localhost:3001/tenant-users/add
    Content-Type: application/json
    
    {
      "tenantId": "<tenant-id>",
      "userId": "user-456",
      "role": "member"
    }
  3. Test role-based access:

    GET http://localhost:3001/tenant-users/role/<tenant-id>/user-456

See test/requests.http for a complete set of example requests.

Test Structure

test/
├── .env.example              # Environment configuration template
├── main.ts                   # Test server bootstrap
├── test-app.module.ts        # Test NestJS application module
├── requests.http             # HTTP request examples
└── controllers/
    ├── tenant-test.controller.ts      # Tenant CRUD endpoints
    └── tenant-user-test.controller.ts # User-tenant management endpoints

Development

Build the package

npm run build

Publish the package

npm run release:patch

Dependencies

  • @nestjs/common ^11.0.11
  • @nestjs/typeorm ^10.0.0
  • @venturialstd/core ^1.0.16
  • @dataui/crud-typeorm (for CRUD operations)
  • typeorm ^0.3.20
  • class-validator ^0.14.1
  • class-transformer ^0.5.1

License

This package is part of the Venturial ecosystem and follows the organization's licensing.


Support

For issues, questions, or contributions, please contact the Venturial development team.