Skip to content

feat(tenancy): give each tenant its own T&E tables (#99) - #104

Merged
amar-python merged 1 commit into
mainfrom
feat/m2b2-per-tenant-te-tables
Oct 26, 2026
Merged

amar-python merged 1 commit into
mainfrom
feat/m2b2-per-tenant-te-tables

Conversation

@amar-python

@amar-python amar-python commented Oct 26, 2026 •

Copy link
Copy Markdown
Owner

Fixes #99. This implements your 26 Oct decision that T&E mode is per tenant. Part of ART Milestone 2 (BR-36).

Approach: clone instead of rewriting the DDL

#99 proposed extracting the psql DDL so the API could run it. Cloning turned out much smaller and leaves build/ untouched.

  • The template. deploy_all.sh still creates the deployment's T&E schema (for example te_prod). That schema is the template.
  • What's copied. provision_te_tables() copies the 12 tables into tenant_<slug> with CREATE TABLE … (LIKE template.t INCLUDING ALL). That covers columns, defaults, CHECKs, NOT NULLs, indexes (including the trigram ones) and comments.
  • What's re-pointed. The 25 foreign keys, the set_updated_at() function and its 7 triggers are copied from the catalog, rewritten to point at the tenant schema.
  • No shared sequences. Primary keys are UUIDs, so tenants share nothing.
  • Idempotent, and run at the existing points. Provisioning runs when create_tenant_admin.py creates a tenant, and for every tenant at startup. If the template is missing or incomplete, it stops with a message pointing to deploy_all.sh.
  • The 409 from M2b: route every request to its tenant's schema (BR-36) #93 is removed. T&E uploads under a tenant session now load into that tenant's own tables.

Evidence

All runs are against local PostgreSQL 16.

Check Result
Local replica of the CI integration job (scripts/test_report.py --strict) 288 passed, 0 failed, 0 skipped (285 on main − the removed 409 test + 4 new)
Evals p,i,s,e 26/26 (they use the default T&E schema, unchanged)
tests/test_tenant_isolation.py 12 passed
DB-free pytest 128 passed
scripts/lint.sh clean

The new isolation tests check that:

  • Tenant A's T&E row lands in tenant_a.organisations, and not in B's tables or the shared schema.
  • B's T&E counts don't change when A uploads.
  • The tenant has the same number of foreign keys as the template, all pointing inside the tenant schema, and an orphan insert raises ForeignKeyViolation.
  • Triggers exist in the tenant schema.
  • Running provisioning again creates nothing.

A bug the tests caught along the way. The first version re-read an exhausted cursor inside a list comprehension, so re-provisioning tried to recreate existing tables. It only showed up against tenants left over from an earlier run. The idempotency test now pins this: with that bug put back, the test fails.

https://claude.ai/code/session_019YPoXzBSj89ZHgw7nfTmbB


Generated by Claude Code

Tenant provisioning (CLI and every startup) now clones the 12 T&E tables
from the deployment's T&E schema into tenant_<slug>: columns, defaults,
checks, indexes and comments via LIKE ... INCLUDING ALL, then foreign
keys, the updated_at function and its triggers re-pointed at the tenant
schema. Keys are UUIDs, so tenants share no sequence. Idempotent.

T&E mode under a tenant session now loads into that tenant's tables, so
the 409 added in #93 is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YPoXzBSj89ZHgw7nfTmbB
@amar-python amar-python added this to the ART extension milestone Oct 26, 2026 — with Claude
@amar-python amar-python added enhancement New feature or request art ART framework extension work labels Oct 26, 2026 — with Claude
@amar-python
amar-python merged commit 574ecb7 into main Oct 26, 2026
3 checks passed
@amar-python
amar-python deleted the feat/m2b2-per-tenant-te-tables branch October 27, 2026 10:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

art ART framework extension work enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

M2b-2: per-tenant T&E tables (BR-36)

2 participants