Configuration
Transactional multi-tenant account ownership migration
Upgrade one-tenant-per-user state into explicit TAuth accounts and isolated personal tenants without changing opaque tenant ids.
Operators upgrading an existing management database to the multi-tenant ownership schema.
The problem
The earlier persistence shape coupled one tenant row to one user, so one TAuth subject could not own multiple isolated tenants.
How LLM Proxy helps
LLM Proxy preflights the complete legacy dataset, then atomically creates explicit user and tenant records, preserves tenant ids and usage, and rebinds encrypted provider keys to tenant ownership.
How it works
- Drain old service instances and take an operator-owned database backup.
- Exercise the SQLite migration scenario through the repository test targets.
- Start one new instance so preflight and the bounded schema-version transaction run once.
- Verify account, tenant, secret, provider, routing, and usage isolation before adding capacity.
Feature-to-benefit table
| Feature | Why it matters here | Example |
|---|---|---|
| Fail-closed preflight | Missing tables, static owners, duplicates, malformed secrets, orphan rows, plaintext keys, corrupt ciphertext, and invalid routing data stop startup before mutation. | Invalid data never becomes a partial migration. |
| SQLite index continuity | Colliding legacy GORM index names move inside the same transaction before current tables are created. | Preserved volumes migrate without deleting tenant or usage data. |
| Tenant and usage continuity | Opaque tenant ids, secret digests, routing defaults, timestamps, and every usage event are preserved. | Existing client secrets continue to identify the same tenant. |
| Provider key re-encryption | Provider ciphertext is decrypted under the prior user binding and re-encrypted with the preserved tenant id as AES-GCM associated data. | Each key becomes tenant-bound. |
Use-case examples
SQLite verification
A disposable legacy database migrates and reopens with explicit user and tenant tables.
Configured path verification
The real startup path opens and migrates a disposable SQLite database at the supplied location.
Rollback
An injected failure at any rename, create, verify, version, or drop stage leaves the legacy schema untouched.
Objections and limitations
- Unclaimed static-config owners must be resolved before this migration.
- Plaintext or corrupt provider keys are rejected rather than repaired.
- Old and new service versions must not run concurrently against the migration database.
Repository evidence
dataset, preflightError := preflightLegacyManagedTenantSchema(database, providerKeyCipher, providers)
if preflightError != nil {
return preflightError
}
return database.Transaction(func(transaction *gorm.DB) error {
Verified 2026-08-08 by Tyemirov on GitHub against internal/proxy/management_store.go.
FAQ
What happens before the ownership migration writes data?
LLM Proxy preflights the complete legacy dataset and rejects missing, duplicate, orphaned, plaintext, corrupt, or non-canonical records before opening the mutation transaction.
Which values remain stable through the migration?
The transaction preserves opaque tenant ids, secret digests, routing defaults, timestamps, and usage events while moving ownership into explicit account and tenant records.
What makes the ownership update atomic?
Schema renames, current-table creation, record copies, verification, versioning, and legacy-table removal run in one database transaction. A failed stage rolls back and prevents startup.
Can old and new service versions run concurrently?
No. Drain old instances, take a database backup, exercise the repository migration scenario, and start one new instance before adding capacity.
What should I read next?
A closely related resource is LLM model catalog configuration in config.yml, which covers LLM model catalog configuration.
Related resources
Run the bounded ownership migration
Follow the repository runbook to back up the database, exercise the exact SQLite scenario, start one new instance, and verify tenant isolation before adding capacity.
Read the migration runbook