## Tenant Admin Control Plane Feature Proposal

## Purpose

Design the first control-plane feature for managing customer organizations and restaurant tenants in KDSAI.

This feature defines how the platform:
- registers customer organizations
- lets each customer create its own restaurant tenants
- stores tenant system names needed for provisioning
- triggers tenant warehouse bootstrap as a separate action

This aligns with `docs/ETL.md`, where tenant isolation is database-per-tenant.

## Feature Overview

This feature introduces the minimum business and operational layer needed before ETL onboarding can scale beyond manually configured tenants. It separates business registration from infrastructure provisioning so that clients and tenants can be created safely first, then bootstrapped explicitly when ready.

The feature is exposed through two API surfaces:
- `admin` for customer-organization management
- `client` for tenant creation and configuration scoped to the authenticated client

Both surfaces use the same business model. The difference is scope and responsibility.

## Core Concepts

- `client` = customer organization
- `tenant` = restaurant/store
- one client can have many tenants
- one tenant maps to exactly one Redshift database
- bootstrap is a separate action from tenant creation
- `systems` is a flexible list of tenant system names used as bootstrap input

We keep the technical word `tenant` in API and backend naming for now, even though business-wise it means restaurant. This avoids unnecessary renaming during the PoC while still allowing UI/business language to say `restaurant` later.

## Scope

In scope:
- admin create client
- admin list clients
- client create tenant under the authenticated client
- client list tenants for the authenticated client
- client get tenant by id for the authenticated client
- client bootstrap tenant for the authenticated client
- store tenant systems as bootstrap input
- normalize tenant systems case-insensitively and deduplicate them per tenant

Out of scope:
- customer roles and permissions
- detailed auth and claims design
- secrets and API key management
- bootstrap internals redesign
- full source-system taxonomy
- advanced onboarding workflow orchestration

## Main Decisions

### Data ownership

- `Clients` is the business record for customer organizations
- `Tenants` is the business record for restaurant tenants
- `TenantWarehouseMappings` remains a technical support table for warehouse resolution

### Identity and naming

- client code is generated automatically from client name and is immutable
- tenant code is generated automatically from tenant name and is immutable
- tenant code is globally unique
- tenant name is unique within a client
- database name is derived from tenant code and is immutable
- database name must satisfy Redshift naming rules

### Tenant state

PoC tenant statuses:
- `PendingBootstrap`
- `Active`
- `BootstrapFailed`

State rules:
- tenant is created as `PendingBootstrap`
- tenant starts with `IsActive = false`
- successful bootstrap sets `Status = Active` and `IsActive = true`
- failed bootstrap sets `Status = BootstrapFailed` and keeps `IsActive = false`
- tenant may be created with an empty systems list
- bootstrap is blocked when the tenant has no configured systems

### Systems model

For the PoC, tenant systems are stored as a flexible list of names such as `Brink` or `LogicControls`.

Rules:
- values are normalized case-insensitively
- duplicates are not allowed after normalization
- order is not significant
- classification such as POS/KDS/Inventory is intentionally deferred

## API Surface Summary

### Admin surface

Used by platform operators.

Characteristics:
- manages customer organizations
- does not create tenants in this PoC
- does not list tenants in this PoC

Examples:
- `POST /admin/clients`
- `GET /admin/clients`

### Client surface

Used by customer self-service users.

Characteristics:
- scoped to the authenticated client
- creates and lists tenants for the authenticated client
- reads basic details for a specific tenant owned by the authenticated client
- may only operate on tenants owned by the authenticated client

Examples:
- `POST /client/tenants`
- `GET /client/tenants`
- `GET /client/tenants/{tenantId}`
- `POST /client/tenants/{tenantId}/bootstrap`

## Key Flows

## 1. Client creation

This flow creates the customer organization record that becomes the parent for future tenants. It stays intentionally small so onboarding can start before any restaurant-specific provisioning begins.

```mermaid
flowchart LR
    A[Admin] --> B[POST /admin/clients]
    B --> C[Generate client code]
    C --> D[Save client]
    D --> E[Client ready for tenant onboarding]
```

## 2. Tenant creation

This flow creates a tenant under a client, generates its stable identifiers, stores tenant systems, and creates the inactive warehouse mapping. In the PoC, tenant creation belongs to the client surface and is always scoped to the authenticated client.

```mermaid
flowchart LR
    A[Client] --> B[Resolve authenticated client]
    B --> C[Create tenant request]
    C --> D[Generate tenant code]
    D --> E[Derive database name]
    E --> F[Save tenant and systems]
    F --> G[Create inactive warehouse mapping]
    G --> H[Tenant status: PendingBootstrap]
```

## 3. Tenant bootstrap

This flow provisions the tenant warehouse only after the tenant already exists. In the PoC, bootstrap is a client-side action on a tenant owned by the authenticated client.

```mermaid
flowchart LR
    A[Client] --> B[Bootstrap request]
    B --> C[Load tenant and systems]
    C --> D{Systems configured?}
    D -->|No| E[Reject bootstrap]
    D -->|Yes| F[Trigger existing bootstrap flow]
    F --> G{Bootstrap result}
    G -->|Success| H[Set tenant Active]
    G -->|Failure| I[Set tenant BootstrapFailed]
```

## 4. Operational reads

This flow gives platform admins visibility into clients and gives customers visibility into tenants within their own organization. A worker from a specific restaurant can use the tenant-by-id read to fetch only the basic data for the tenant they are allowed to access.

```mermaid
flowchart LR
    A[Admin UI] --> B[GET /admin/clients]
    C[Client UI] --> D[GET /client/tenants]
    C --> E[GET /client/tenants/{tenantId}]
```

## Why This Fits The ETL Architecture

From `docs/ETL.md`:
- isolation is database-per-tenant
- tenant-specific database resolution is part of the platform
- cross-tenant access is handled by platform metadata and query routing

This feature fits that direction because:
- tenant remains the unit of warehouse isolation
- each restaurant gets one database
- tenant systems are captured before bootstrap
- tenant creation and bootstrap stay with the customer that owns the tenant

## Key Rules Summary

1. `tenant` means restaurant.
2. one client can have many tenants.
3. one tenant maps to one Redshift database.
4. admin creates and lists clients in the PoC.
5. tenant creation belongs to the client surface in the PoC.
6. client surface is scoped to the authenticated client.
7. client may read a specific tenant by id only when that tenant belongs to the authenticated client.
8. client code is auto-generated and immutable.
9. tenant code is auto-generated and immutable.
10. tenant code is globally unique.
11. tenant name is unique within a client.
12. database name is derived from tenant code and is immutable.
13. create tenant and bootstrap tenant are separate operations.
14. tenant systems are stored directly on the tenant in the PoC.
15. bootstrap endpoint is only responsible for triggering the flow with parameters.
16. bootstrap endpoint must be idempotent.
17. bootstrap is blocked when a tenant has no configured systems.

## Document Links

Supporting documents in this feature area:
- `api-contract.md` - concrete endpoint contracts and request/response examples
- `data-model.md` - relational model, constraints, and migration direction
- `implementation-notes.md` - backend implementation checklist
