Skip to content

Stamp org_id on tenant writes; scope public reads to the site org#8

Merged
WebTigers merged 1 commit into
mainfrom
feat/org-id-tenant-stamp
Jul 17, 2026
Merged

Stamp org_id on tenant writes; scope public reads to the site org#8
WebTigers merged 1 commit into
mainfrom
feat/org-id-tenant-stamp

Conversation

@WebTigers

Copy link
Copy Markdown
Owner

Content was never attributed to a tenant — CMS pages and blog articles saved with org_id='', while everything else set it. That blocks a clean multi-site story and isn't honest attribution. Fixed in the base model so it can't be forgotten per-module.

Write side

  • Tiger_Model_Table: setOrg()/$_org + auto-stamp org_id on insert (mirrors the created_by actor stamp) for any table with the column. Explicit org_id wins; no org set (system/global) keeps ''. The Authorization plugin wires setOrg() from the authenticated org, right next to setActor().

Read side

  • Tiger_Model_Org::siteOrgId()/setSiteOrgId() — the org that owns the public site: configured tiger.site.org_id, else the founding (oldest) org. (NB parent_org_id is future — all orgs are root today — so it's not a distinguishing query.)
  • PageDispatch + blog article resolve pass siteOrgId(); _orgScope('') resolves to it too, so blog lists / CMS datatable / redirects scope to the site without touching each caller. Scope stays [org, '']nothing 404s mid-transition. This is the exact seam a multi-site module overrides by host.

Data

  • Migration 0033 backfills legacy page.org_id='' → the site org (callable migration; empty DBs no-op).

Verification

  • Smoke now seeds an org-stamped published page and asserts its body dispatches at its public URL — the guard for the write-stamp ↔ read-scope path (a mismatch 404s there). This exercises base-model stamping + public dispatch end-to-end on a fresh install, which nothing did before.
  • Migration 0032's transform was unit-tested previously; 0033 uses the same callable-migrator path.

Single-site behavior is unchanged (founding org = the one site); this is the groundwork the future multi-site module drops onto.

🤖 Generated with Claude Code

Content was never attributed to a tenant: CMS pages and blog articles saved with
org_id='' (the column default), while everything else set org_id explicitly. That
blocks a clean multi-site story and isn't honest attribution. Fix it in the base
model so it can't be forgotten per-module.

- Tiger_Model_Table: setOrg()/$_org + auto-stamp org_id on insert (mirrors the
  created_by actor stamp) for any table with the column. Explicit org_id wins;
  no org set (system/global) keeps the '' default. Authorization plugin wires
  setOrg() from the authenticated org, next to setActor().
- Tiger_Model_Org::siteOrgId()/setSiteOrgId(): the org owning the public site —
  configured tiger.site.org_id, else the founding (oldest) org. NB parent_org_id
  is future (all orgs are root today), so it's not a distinguishing query.
- Reads: PageDispatch + blog article resolve pass siteOrgId(); _orgScope('')
  resolves to it too, so blog lists / CMS datatable / redirects all scope to the
  site without touching each caller. Scope stays [org, ''] → nothing 404s mid-
  transition. This is the seam a multi-site module overrides by host.
- Migration 0033: backfill legacy page.org_id='' -> the site org.

Smoke now seeds an ORG-STAMPED published page and asserts its body dispatches at
its public URL — the guard for the write-stamp <-> read-scope path (a mismatch
404s there). Verifies base-model stamping end to end on a fresh install.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@WebTigers
WebTigers merged commit e7db31f into main Jul 17, 2026
5 checks passed
@WebTigers
WebTigers deleted the feat/org-id-tenant-stamp branch July 17, 2026 13:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant