This document describes how to create and manage companies in TGM Manager Server, including storage and OCR configuration.

Table of Contents


Overview

Companies are organizational units within TGM Manager that group users and configure features.

Key Points:

  • Basic information (name, address, contact details)
  • Feature configurations (SSO, 2FA, AI features)
  • Storage configuration (default, S3, MinIO)
  • OCR configuration (document text extraction)
  • Associated locations, users, and data

Multi-Tenancy Context

TGM Manager uses a two-level multi-tenancy architecture. Understanding the hierarchy is crucial:

┌─────────────────────────────────────────────────────────────────┐
│                    Platform (Master Database)                    │
│  Contains: Clients registry, platform administration             │
└─────────────────────────────────────────────────────────────────┘
                               │
        ┌──────────────────────┼──────────────────────┐
        ▼                      ▼                      ▼
┌───────────────┐      ┌───────────────┐      ┌───────────────┐
│   Client A    │      │   Client B    │      │   Client C    │
│   Database    │      │   Database    │      │   Database    │
├───────────────┤      ├───────────────┤      ├───────────────┤
│   Company 1   │      │   Company 1   │      │   Company 1   │
│   (settings)  │      │   (settings)  │      │   (settings)  │
├───────────────┤      ├───────────────┤      ├───────────────┤
│    Sandbox    │      │    Sandbox    │      │    Sandbox    │
│    (schema)   │      │    (schema)   │      │    (schema)   │
└───────────────┘      └───────────────┘      └───────────────┘

Terminology

Term Description Database Scope
Client An organization with isolated database Separate PostgreSQL database
Company Configuration entity within a client Table within client's database
Sandbox Development/testing environment Schema within client's database

API Request Headers

All company management requests require multi-tenant headers:

curl -X GET "http://localhost:1337/api/companies" \
  -H "Authorization: Bearer $JWT" \
  -H "X-Client-ID: acme-corp"
Header Required Description
Authorization Yes JWT or API token
X-Client-ID Yes* Client identifier
X-Tenant-ID No Sandbox (omit for production)

*Can be resolved via subdomain: acme-corp.tgm-expert.com


Company Entity Fields

Field Type Default Description
name String Required Company name (unique)
address String - Physical address
email String - Contact email
phone String - Contact phone
city String - City
state String - State/Province
country String - Country
isActive Boolean true Whether company is active
appLanguage Enum EN Default language (EN, FR, ES, etc.)
measurementUnitSystem Enum - METRIC or IMPERIAL
enable2FA Boolean false Enable two-factor authentication
ssoEnabled Boolean false Enable Single Sign-On
storageType String default Storage provider type
ocrEnabled Boolean false Enable OCR processing

Creating a Company

Note: Company creation happens within a client's database. Include the X-Client-ID header.

# Create a new company within a client's database
curl -X POST "http://localhost:1337/api/companies" \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -H "X-Client-ID: acme-corp" \
  -d '{
    "name": "Acme Corporation",
    "address": "123 Main Street",
    "email": "admin@acme.com",
    "phone": "+1-555-0100",
    "city": "New York",
    "state": "NY",
    "country": "USA",
    "isActive": true,
    "appLanguage": "EN",
    "measurementUnitSystem": "IMPERIAL"
  }'

Response:

{
  "data": {
    "id": 1,
    "name": "Acme Corporation",
    "address": "123 Main Street",
    "email": "admin@acme.com",
    "isActive": true,
    "storageType": "default",
    "ocrEnabled": false
  },
  "message": "Created successfully"
}

Required Permissions

  • SUPER_ADMIN: Full access to all company operations
  • ADMIN: Can create/update companies within their scope
  • Users need companies:create permission

Storage Configuration

Each company can use their own storage provider. By default, companies use the platform's global storage.

Storage Types

Type Description Use Case
default Use platform storage Most companies
minio Self-hosted MinIO On-premise deployments
s3 AWS S3 Cloud-native companies
azure Azure Blob (future) Azure-based companies

Set Default Storage

To use the platform's default storage:

curl -X POST "http://localhost:1337/api/companies/{companyId}/storage-config/reset" \
  -H "Authorization: Bearer $JWT"

Configure Custom Storage (S3)

curl -X PUT "http://localhost:1337/api/companies/{companyId}/storage-config" \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "storageType": "s3",
    "storageEndpoint": "https://s3.us-east-1.amazonaws.com",
    "storageAccessKey": "AKIAIOSFODNN7EXAMPLE",
    "storageSecretKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
    "storageBucket": "acme-tgm-files",
    "storageRegion": "us-east-1",
    "storagePublicUrl": "https://cdn.acme.com"
  }'

Configure Custom Storage (MinIO)

curl -X PUT "http://localhost:1337/api/companies/{companyId}/storage-config" \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "storageType": "minio",
    "storageEndpoint": "https://minio.internal.acme.com:9000",
    "storageAccessKey": "acmeAccessKey",
    "storageSecretKey": "acmeSecretKey",
    "storageBucket": "documents"
  }'

Test Storage Connectivity

curl -X POST "http://localhost:1337/api/companies/{companyId}/storage-config/test" \
  -H "Authorization: Bearer $JWT"

Response:

{
  "data": {
    "success": true,
    "message": "Storage connectivity test passed",
    "storageInfo": {
      "type": "s3",
      "bucket": "acme-tgm-files",
      "region": "us-east-1"
    }
  }
}


OCR Configuration

Enable OCR for automatic document text extraction.

Enable OCR

curl -X POST "http://localhost:1337/api/companies/{companyId}/ocr-config/enable" \
  -H "Authorization: Bearer $JWT"

Configure OCR Settings

curl -X PUT "http://localhost:1337/api/companies/{companyId}/ocr-config" \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "ocrEnabled": true,
    "ocrLanguage": "en",
    "ocrAutoProcess": true,
    "ocrFileTypes": "pdf,png,jpg,jpeg,tiff,docx"
  }'

OCR Settings

Setting Default Description
ocrEnabled false Enable OCR for this company
ocrLanguage en OCR language (en, fr, es, de, etc.)
ocrAutoProcess true Auto-process files on upload
ocrFileTypes pdf,png,jpg... Comma-separated file types to process

Manual Database Operations

For direct database operations (use with caution).

Create Company via SQL

-- Insert a new company
INSERT INTO companies (
    name,
    address,
    email,
    phone,
    city,
    state,
    country,
    is_active,
    app_language,
    measurement_unit_system,
    storage_type,
    ocr_enabled,
    created_at,
    updated_at
) VALUES (
    'Acme Corporation',
    '123 Main Street',
    'admin@acme.com',
    '+1-555-0100',
    'New York',
    'NY',
    'USA',
    true,
    'EN',
    'IMPERIAL',
    'default',
    false,
    NOW(),
    NOW()
);

-- Get the created company ID
SELECT id, name FROM companies WHERE name = 'Acme Corporation';

Configure Storage via SQL

-- Set company to use AWS S3
UPDATE companies SET
    storage_type = 's3',
    storage_endpoint = 'https://s3.us-east-1.amazonaws.com',
    storage_access_key = 'AKIAIOSFODNN7EXAMPLE',
    storage_secret_key = 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
    storage_bucket = 'acme-tgm-files',
    storage_region = 'us-east-1',
    storage_public_url = 'https://cdn.acme.com',
    updated_at = NOW()
WHERE id = 1;

-- Reset to default storage
UPDATE companies SET
    storage_type = 'default',
    storage_endpoint = NULL,
    storage_access_key = NULL,
    storage_secret_key = NULL,
    storage_bucket = NULL,
    storage_region = NULL,
    storage_public_url = NULL,
    updated_at = NOW()
WHERE id = 1;

Enable OCR via SQL

-- Enable OCR for a company
UPDATE companies SET
    ocr_enabled = true,
    ocr_language = 'en',
    ocr_auto_process = true,
    ocr_file_types = 'pdf,png,jpg,jpeg,tiff,docx,doc',
    updated_at = NOW()
WHERE id = 1;

View Company Configuration

-- View company with all configurations
SELECT
    id,
    name,
    is_active,
    app_language,
    -- Storage config
    storage_type,
    storage_endpoint,
    storage_bucket,
    storage_region,
    CASE WHEN storage_access_key IS NOT NULL THEN 'configured' ELSE 'not set' END as storage_credentials,
    -- OCR config
    ocr_enabled,
    ocr_language,
    ocr_auto_process,
    ocr_file_types,
    -- SSO config
    sso_enabled,
    sso_enforced,
    -- Timestamps
    created_at,
    updated_at
FROM companies
WHERE id = 1;

Create Admin User for Company

After creating a company, you typically need to create an admin user:

-- Create admin user for the company
INSERT INTO users (
    username,
    email,
    first_name,
    last_name,
    password,
    role,
    company_id,
    is_active,
    email_verified,
    created_at,
    updated_at
) VALUES (
    'admin@acme.com',
    'admin@acme.com',
    'Admin',
    'User',
    '$2a$10$...', -- bcrypt hashed password
    'ADMIN',
    1, -- company_id
    true,
    true,
    NOW(),
    NOW()
);

Note: For password, use a bcrypt hash. Generate one via:

# Using htpasswd
htpasswd -nbBC 10 "" "yourpassword" | tr -d ':\n' | sed 's/$2y/$2a/'

# Or in Java/Spring context, the password will be hashed automatically via the API


API Reference

Company CRUD Operations

Method Endpoint Description Permission
GET /api/companies List all companies companies:read
GET /api/companies/{id} Get company by ID companies:read
POST /api/companies Create company companies:create
PUT /api/companies/{id} Update company companies:update
DELETE /api/companies/{id} Delete company companies:delete

Storage Configuration

Method Endpoint Description
GET /api/companies/{id}/storage-config Get storage config
PUT /api/companies/{id}/storage-config Update storage config
POST /api/companies/{id}/storage-config/reset Reset to default
POST /api/companies/{id}/storage-config/test Test connectivity

OCR Configuration

Method Endpoint Description
GET /api/companies/{id}/ocr-config Get OCR config
PUT /api/companies/{id}/ocr-config Update OCR config
POST /api/companies/{id}/ocr-config/enable Enable OCR
POST /api/companies/{id}/ocr-config/disable Disable OCR

Troubleshooting

Company Creation Fails

Error: "Company name already exists" - Solution: Use a unique company name

Error: "Access denied" - Solution: Ensure user has companies:create permission or SUPER_ADMIN role

Storage Configuration Issues

Error: "Storage connectivity test failed" - Check endpoint URL is correct and accessible - Verify access key and secret key - Ensure bucket exists - Check network connectivity and firewall rules

Error: "Bucket does not exist" - Create the bucket in your storage provider before configuring - Verify bucket name is correct (case-sensitive)

OCR Not Processing Files

Checklist: 1. Is ocrEnabled set to true for the company? 2. Is the OCR service running? Check /api/companies/ocr-status 3. Is the file type in ocrFileTypes list? 4. Is ocrAutoProcess enabled?

Cache Issues After Configuration Change

If configuration changes don't take effect immediately:

# Clear Redis cache (if direct access)
redis-cli FLUSHDB

# Or restart the application to clear all caches


Best Practices

New Company Setup Checklist

  1. Create the company with basic information
  2. Configure storage (default or custom)
  3. Test storage connectivity
  4. Enable OCR if document processing is needed
  5. Create admin user for the company
  6. Configure SSO if using external identity provider
  7. Set up locations for the company
  8. Invite users to the company

Security Recommendations

  • Use dedicated IAM users/roles for S3 access
  • Rotate storage credentials regularly
  • Enable encryption at rest for storage buckets
  • Use TLS for all MinIO connections
  • Store credentials encrypted in database
  • Limit admin access to storage configuration

Multi-Tenant Isolation

Each company's data is isolated: - Files stored in separate buckets or prefixes - Database queries filtered by company_id - API responses scoped to user's company - Audit logs track all company actions