Files
neo/docs/TENANT_USER_MANAGEMENT.md
2026-01-05 07:48:22 +01:00

11 KiB

Tenant User Management Implementation

Overview

This document describes the implementation of tenant user management from the central admin interface. Central administrators can now view and create users for any tenant directly from the tenant detail page.

Features

1. View Tenant Users

  • Related list on tenant detail page showing all users for that tenant
  • Displays: email, firstName, lastName, createdAt
  • Fetches data directly from the tenant's database

2. Create Tenant Users

  • Modal dialog for creating new users in a tenant
  • Form fields:
    • Email (required)
    • Password (required)
    • First Name (optional)
    • Last Name (optional)
  • Passwords are automatically hashed with bcrypt
  • Creates user directly in the tenant's database

Architecture

Backend Implementation

File: backend/src/tenant/central-admin.controller.ts

Get Tenant Users Endpoint

GET /central/tenants/:id/users
  • Connects to the tenant's database using TenantDatabaseService
  • Queries the users table
  • Returns array of user records

Create Tenant User Endpoint

POST /central/tenants/:id/users
  • Accepts: { email, password, firstName?, lastName? }
  • Hashes password with bcrypt (10 rounds)
  • Creates user in tenant database with timestamps
  • Returns created user record

Key Implementation Details:

  • Uses tenantDbService.getTenantKnex(tenantId) to get tenant DB connection
  • Connection pooling ensures efficient database access
  • Password hashing is done server-side for security

Frontend Implementation

Components

File: frontend/components/TenantUserDialog.vue

  • Reusable modal dialog for creating tenant users
  • Form validation (email and password required)
  • Loading states and error handling
  • Emits 'created' event on success for list refresh

Props:

  • open: boolean - Dialog visibility state
  • tenantId: string - ID of tenant to create user for
  • tenantName?: string - Display name of tenant

Events:

  • update:open - Sync dialog visibility
  • created - User successfully created

Page Integration

File: frontend/pages/central/tenants/[[recordId]]/[[view]].vue

Added State:

const showTenantUserDialog = ref(false)
const tenantUserDialogTenantId = ref('')

Handler:

const handleCreateRelated = (objectApiName: string, parentId: string) => {
  if (objectApiName.includes('tenants/:parentId/users')) {
    tenantUserDialogTenantId.value = parentId
    showTenantUserDialog.value = true
    return
  }
  // ... standard navigation for other related lists
}

Refresh Handler:

const handleTenantUserCreated = async () => {
  // Refresh current record to update related lists
  if (recordId.value && recordId.value !== 'new') {
    await fetchRecord(recordId.value)
  }
}

Configuration

File: frontend/composables/useCentralEntities.ts

Added to tenantDetailConfig.relatedLists:

{
  title: 'Tenant Users',
  relationName: 'users',
  objectApiName: 'tenants/:parentId/users',
  fields: [
    { name: 'email', label: 'Email', type: 'TEXT', required: true },
    { name: 'firstName', label: 'First Name', type: 'TEXT' },
    { name: 'lastName', label: 'Last Name', type: 'TEXT' },
    { name: 'createdAt', label: 'Created', type: 'DATE_TIME' }
  ],
  canCreate: true
}

Key Details:

  • objectApiName: 'tenants/:parentId/users' - Special format for nested resource
  • :parentId placeholder is replaced with actual tenant ID at runtime
  • canCreate: true enables the "New" button in the related list

File: frontend/components/RelatedList.vue

Dynamic API Path Resolution:

let apiPath = props.config.objectApiName.replace(':parentId', props.parentId)
const response = await api.get(`/${apiPath}`, {
  params: { [parentField]: props.parentId }
})

This allows the component to handle nested resource paths like tenants/:parentId/users.

User Flow

Creating a Tenant User

  1. Navigate to Central Admin → Tenants
  2. Click on a tenant to view details
  3. Scroll to "Tenant Users" related list
  4. Click "New" button
  5. Fill in the form:
    • Enter email address
    • Set password
    • Optionally add first and last name
  6. Click "Create User"
  7. Dialog closes and related list refreshes with new user

Viewing Tenant Users

  1. Navigate to Central Admin → Tenants
  2. Click on a tenant to view details
  3. Scroll to "Tenant Users" related list
  4. View table with all users for that tenant
  5. See email, name, and creation date for each user

Security Considerations

Password Handling

  • Passwords are sent over HTTPS
  • Backend hashes passwords with bcrypt (10 rounds) before storage
  • Passwords never stored in plain text
  • Hashing is done server-side, not client-side

Access Control

  • Only central admin users can access these endpoints
  • Protected by authentication middleware
  • Tenant database connections use secure connection pooling

Database Access

  • Central admin connects to tenant databases on-demand
  • Connections are cached but validated before use
  • No direct SQL injection risk (using Knex query builder)

Database Schema

Tenant User Table Structure

CREATE TABLE users (
  id VARCHAR(36) PRIMARY KEY,
  email VARCHAR(255) UNIQUE NOT NULL,
  password VARCHAR(255) NOT NULL,
  firstName VARCHAR(255),
  lastName VARCHAR(255),
  createdAt DATETIME,
  updatedAt DATETIME
  -- Additional fields may exist in actual schema
)

API Reference

Get Tenant Users

Request:

GET /api/central/tenants/{tenantId}/users
Authorization: Bearer <jwt-token>

Response:

[
  {
    "id": "uuid",
    "email": "user@example.com",
    "firstName": "John",
    "lastName": "Doe",
    "createdAt": "2025-01-26T12:00:00Z",
    "updatedAt": "2025-01-26T12:00:00Z"
  }
]

Create Tenant User

Request:

POST /api/central/tenants/{tenantId}/users
Authorization: Bearer <jwt-token>
Content-Type: application/json

{
  "email": "newuser@example.com",
  "password": "SecurePassword123!",
  "firstName": "Jane",
  "lastName": "Smith"
}

Response:

{
  "id": "uuid",
  "email": "newuser@example.com",
  "firstName": "Jane",
  "lastName": "Smith",
  "createdAt": "2025-01-26T12:00:00Z",
  "updatedAt": "2025-01-26T12:00:00Z"
}

Testing

Manual Testing Steps

  1. Setup:

    • Ensure Docker containers are running
    • Have at least one tenant created
    • Be logged in as central admin
  2. View Users:

    • Navigate to /central/tenants
    • Click on a tenant
    • Verify "Tenant Users" related list appears
    • Verify existing users are displayed
  3. Create User:

    • Click "New" in Tenant Users section
    • Verify dialog opens
    • Fill in required fields (email, password)
    • Click "Create User"
    • Verify success message
    • Verify dialog closes
    • Verify new user appears in list
  4. Error Handling:

    • Try creating user without email
    • Try creating user without password
    • Try creating user with duplicate email
    • Verify appropriate error messages

Automated Testing (Future)

describe('Tenant User Management', () => {
  it('should fetch tenant users', async () => {
    const response = await api.get('/central/tenants/tenant-id/users')
    expect(response).toBeInstanceOf(Array)
  })

  it('should create tenant user', async () => {
    const newUser = {
      email: 'test@example.com',
      password: 'password123',
      firstName: 'Test',
      lastName: 'User'
    }
    const response = await api.post('/central/tenants/tenant-id/users', newUser)
    expect(response.email).toBe(newUser.email)
    expect(response.password).toBeUndefined() // Should not return password
  })
})

Future Enhancements

Planned Features

  1. Full CRUD Operations:

    • Edit tenant user details
    • Delete tenant users
    • Update passwords
  2. Role Management:

    • Assign roles to users during creation
    • View and edit user roles
    • Permission management
  3. User Navigation:

    • Click on user to view details
    • Dedicated user detail page
    • Activity history
  4. Bulk Operations:

    • Create multiple users via CSV import
    • Bulk role assignment
    • Bulk user activation/deactivation
  5. Password Management:

    • Password reset functionality
    • Force password change on next login
    • Password strength indicators
  6. Audit Logging:

    • Track user creation by central admin
    • Log user modifications
    • Export audit logs
  7. Search and Filter:

    • Search users by email/name
    • Filter by role/status
    • Advanced filtering options

Implementation Notes

Design Decisions

  1. Modal vs Navigation:

    • Chose modal dialog over page navigation
    • Reason: Keeps user in context of tenant detail page
    • Better UX for quick user creation
  2. Special API Path Format:

    • Used tenants/:parentId/users format
    • Reason: Indicates nested resource structure
    • Clear relationship between tenant and users
  3. Separate Dialog Component:

    • Created reusable TenantUserDialog component
    • Reason: Could be reused in other contexts
    • Easier to maintain and test
  4. Server-Side Password Hashing:

    • Hash passwords in backend, not frontend
    • Reason: Security best practice
    • Consistent with authentication flow

Known Limitations

  1. No Password Validation:

    • Currently no minimum password requirements
    • Could add password strength validation
  2. No Email Validation:

    • Basic email format check only
    • Could add email verification
  3. No User Status:

    • Users are created as active by default
    • No activation/deactivation workflow
  4. No Role Assignment:

    • Users created without specific roles
    • Role management to be added

Troubleshooting

Common Issues

Issue: "Cannot GET /api/api/central/tenants/:id/users"

  • Cause: Double API prefix
  • Solution: Check that baseUrl in useApi doesn't include /api prefix

Issue: "Dialog doesn't open"

  • Check: showTenantUserDialog state is being set
  • Check: Dialog component is imported correctly
  • Check: v-model:open binding is correct

Issue: "User not appearing in list after creation"

  • Check: handleTenantUserCreated is calling fetchRecord
  • Check: API returning correct data
  • Check: Related list config matches API response fields

Issue: "Cannot create user - validation error"

  • Ensure email and password are filled
  • Check network tab for actual error from backend
  • Verify tenant database schema matches expected structure

Issue: "Password not hashing"

  • Verify bcrypt is installed in backend
  • Check backend logs for hashing errors
  • Ensure password field is being passed to backend