Multi-tenancy
One Optimizely database often holds several tenants: home pages for a few countries, a developer portal, a leasing site. SeeAMess gives each tenant a database of its own, and lets you move a tenant to another instance at any time, even though editors use each other’s content freely.
Four decisions
Section titled “Four decisions”- The database is the tenant. There is no tenant column and no shard key. A tenant is one complete SeeAMess database, and the engine stays a single-database engine. Moving a tenant is copying a database and changing one directory entry.
- Place decides where content lives; use decides nothing. Content in a tenant’s tree is that tenant’s. Everything else, global assets first of all, belongs to the shared tenant, which has no sites. Content never changes database because an editor started or stopped using it.
- Use becomes a mount, automatically. A tenant that uses another tenant’s content holds a read-only mirror of it. To the engine, another tenant is one more upstream source, the same mechanism as the Optimizely overlay. Every reference resolves inside its own database. Every tenant mounts all of the shared tenant.
- The map is computed. A plan lists every tenant’s content and its mounts. A mount is not a violation to fix; it is how interwoven content keeps working.
Plan the split
Section titled “Plan the split”The only decision a person makes is which sites form which tenant. A site no tenant lists becomes a tenant of its own.
{ "shared": {"id": "shared", "roots": []}, "tenants": [{"id": "homepage", "sites": ["Home PL", "Home CZ"], "roots": []}], "includeHistory": false}-
Export the content graph from Optimizely:
seeamess-migrate graph --source "<connection string>" --out graph.json -
Plan. This needs no engine and no database, and exits
1with every problem in the input.seeamess tenants plan --graph graph.json --tenants tenants.json --out plan.jsonThe report shows contents, versions and binaries per tenant, how the shared content is used, and every mount.
-
Sync every tenant from Optimizely by the plan, during the overlay phase:
seeamess-migrate sync --source "<connection string>" --targets targets.json --tenants tenants.json --watch 30targets.jsonmaps each tenant ID to its engine’surlandtoken.
Placement rules. Content lives where the nearest anchor above it says: a root listed for a tenant, a site’s start page, the global assets root (shared), a site’s assets root, the owner of a “For This Page” folder, or else the shared tenant. A tenant mounts everything its content embeds, directly or through other content. Links to pages of another tenant need no mount; they resolve to that site’s URL.
Running tenants
Section titled “Running tenants”Each tenant runs its own processes on its own database and blob store. SEEAMESS_TENANT names the process’s tenant and SEEAMESS_TENANTS points at the directory file:
{ "shared": "shared", "tenants": { "shared": {"databaseUrl": "postgres://…/shared", "blobStore": "s3://bucket/shared", "url": "https://shared.cms.example"}, "homepage": {"databaseUrl": "postgres://…/homepage", "blobStore": "s3://bucket/homepage", "url": "https://home.cms.example"} }}The mount-sync job runs every minute and keeps each mount current from the owner’s outbox, copying the blobs it needs. Every tenant needs a blob store of its own. The directory is read again on every run, so a changed entry applies without a restart.
What editors see
Section titled “What editors see”- Mirrored content is read-only and carries a badge with its owner. “Open in <tenant>” opens the same content in the owner’s editor.
- Pickers search every tenant with “Also search other tenants”. Picking content another tenant owns mounts it at once.
- Take over copies the mirror into this tenant under the same ID; everything that refers to it then shows this tenant’s version. The owner’s later changes arrive as upstream versions, with the usual compare and accept actions. Give back returns it to a read-only mirror.
- Fork makes a separate copy with a new ID, placed anywhere, which remembers its origin and shows when the origin changes.
Move a tenant
Section titled “Move a tenant”- Stop the tenant’s processes.
- Copy its database (dump and restore, or replicate and switch).
- Start the processes with
SEEAMESS_DATABASE_URLnaming the new database. - Change the tenant’s
databaseUrlin the directory file. Other tenants pick it up on their next mount run.
No rows are picked out of a shared database, because there is none.
Several upstream CMSes in one tenant
Section titled “Several upstream CMSes in one tenant”The reverse also works: two or more Optimizely installations feeding one tenant. System content with the same fixed IDs in every Optimizely is treated as common ground, --scope lets two CMSes share one schema scope, and --namespace re-keys a cloned installation whose content IDs collide. seeamess tenants plan accepts several --graph files and plans their union.