Multi-tenancy decisions before implementation: MT-3, MT-7, MT-12, MT-19a, MT-22
Test 3 expects invalidForeignKey, as MT-3 says. A tenant admin reads its own tenant through sysTenantGet and sysTenantQuery, added to the default Tenant Administrator role for new installs only. The server adds nothing for MT-7's dashboard list. The MT-19a submission warning is deferred. MT-22's logo is the urn:inbuxa:jmap account capability's logo field (contract C-1).
This commit is contained in:
@@ -64,6 +64,10 @@ Each has an ID, and tests name the IDs they check.
|
||||
fork no longer tracks upstream;
|
||||
- `contract`: this contract's version, an integer, starting at `1`;
|
||||
- `webmailUrl` and `adminUrl`: where the front ends are, if configured.
|
||||
|
||||
In `accountCapabilities`, the signed-in principal's own account carries
|
||||
`urn:inbuxa:jmap` with `logo`: the logo that applies to it (multi-tenancy
|
||||
MT-22), a string (URL or data URL) or `null`. Added 2026-09-18.
|
||||
- **C-2.** Each front end states the contract versions it supports and checks
|
||||
`contract` after signing in. Outside its range it stops, with a message
|
||||
naming both versions. For ihasmail-inbuxa this replaces public ihasmail's
|
||||
|
||||
@@ -138,6 +138,9 @@ Each requirement has an ID, and tests name the IDs they check.
|
||||
state. Existing accounts found in it (none at INBUXA, possible elsewhere)
|
||||
are left working and listed in the admin dashboard for an operator to
|
||||
resolve.
|
||||
**Decision** (2026-09-18): the server exposes nothing new for that list.
|
||||
ihasmail finds such accounts itself by comparing each account's
|
||||
`memberTenantId` with its domain's.
|
||||
- **MT-8.** A domain can move into a tenant only from no tenant, and out of one
|
||||
only back to no tenant. It moves only when no principal on it belongs to
|
||||
anything other than the destination. **Decision**, a deliberate improvement
|
||||
@@ -165,6 +168,13 @@ Each requirement has an ID, and tests name the IDs they check.
|
||||
itself is server-level. **Decision**, a deliberate difference: upstream
|
||||
refuses the read with `forbidden` (observed 3), so a tenant admin can't see
|
||||
its own limits or usage. ihasmail needs them to warn before a limit is hit.
|
||||
**Decision** (2026-09-18) on how: the read needs `sysTenantGet` (and
|
||||
`sysTenantQuery` to list), which the default Tenant Administrator role now
|
||||
holds. Inside a tenant they reach only its own `x:Tenant`; any other comes
|
||||
back `notFound`. `x:Tenant/set` is refused inside a tenant whatever the
|
||||
permissions (MT-6). Only the defaults change: roles already stored on an
|
||||
existing server are left as they are (SPEC.md §7), and an operator adds the
|
||||
two permissions to an existing tenant-admin role by hand.
|
||||
|
||||
### The permission ceiling
|
||||
|
||||
@@ -212,7 +222,9 @@ Each requirement has an ID, and tests name the IDs they check.
|
||||
still succeeds, so the sender learns nothing until the delay notice.
|
||||
**Decision** on top: when a sender inside the server submits to a
|
||||
recipient whose tenant is over quota, say so at submission time too (a
|
||||
JMAP `EmailSubmission` warning, not a refusal).
|
||||
JMAP `EmailSubmission` warning, not a refusal). **Deferred** (2026-09-18):
|
||||
RFC 8621 has no warnings field, so the submission-time warning waits until
|
||||
the contract defines one. The `451` refusal is built.
|
||||
- **MT-20.** `usedDiskQuota` is kept current as members' usage changes: it
|
||||
moved on the delivery itself (observed 2). It is never written by a client.
|
||||
- **MT-21.** The `recalculateQuota` task recomputes one tenant's
|
||||
@@ -227,6 +239,11 @@ Each requirement has an ID, and tests name the IDs they check.
|
||||
over JMAP so ihasmail can draw it (see "Interfaces"). Branding BT-1 and BT-2
|
||||
(`branding-and-templates.md`) extend the chain past the tenant, to the
|
||||
server-wide logo and then the built-in one, and are the full rule.
|
||||
**Decision** (2026-09-18) on the shape: in the JMAP session, the
|
||||
principal's own account's `accountCapabilities` carry `urn:inbuxa:jmap`
|
||||
(contract C-1) with `logo`: a string (the URL or data URL as stored) or
|
||||
`null`. Until branding is built it follows this chain, steps 1 and 2 of
|
||||
BT-1.
|
||||
- **MT-23.** The server never fetches a logo URL itself. ihasmail draws URL
|
||||
logos through its image proxy, as it does today.
|
||||
|
||||
@@ -235,9 +252,9 @@ Each requirement has an ID, and tests name the IDs they check.
|
||||
- **Existing, unchanged:** `x:Tenant/get`, `/set`, `/query`, `/changes`; the
|
||||
`memberTenantId` field on the types listed above; the permission names; the
|
||||
task and maintenance types; the event.
|
||||
- **New:** the signed-in principal's applicable logo (MT-22). Proposed as a
|
||||
read-only property on the principal's own account object in the fork's
|
||||
namespace, with the exact shape settled in the contract spec (SPEC.md §5.2).
|
||||
- **New:** the signed-in principal's applicable logo (MT-22), as `logo` in
|
||||
the `urn:inbuxa:jmap` account capability of its own account in the JMAP
|
||||
session (contract C-1).
|
||||
- **Errors:** RFC 8620 `SetError` types, as named above. Each refusal names
|
||||
the property or limit involved, so ihasmail can say which one.
|
||||
|
||||
@@ -263,7 +280,9 @@ marked **(compat)** also run against a copy of INBUXA's data.
|
||||
1. Tenant admin in T lists accounts: sees only T's (MT-1).
|
||||
2. Tenant admin in T gets a U account by id: `notFound`, not `forbidden`.
|
||||
**Decision**: don't confirm that another tenant's object exists.
|
||||
3. Tenant admin adds a U account to a T group: `forbidden` (MT-3).
|
||||
3. Tenant admin adds a U account to a T group: `invalidForeignKey` (MT-3).
|
||||
**Decision** (2026-09-18): MT-3's error, not `forbidden` as this test
|
||||
first said.
|
||||
4. Mail from a T address to a U address is delivered (MT-4).
|
||||
5. Tenant admin sets `memberTenantId` on anything: refused (MT-6, MT-11).
|
||||
6. Account created on a T domain is in T with no `memberTenantId` sent (MT-7).
|
||||
|
||||
Reference in New Issue
Block a user