Tenant Settings Hardening

Tenant settings hardening

Tenant settings are resolved from generated defaults in config/mortimer.yml and optional tenant overrides in storage/tenants/:slug/config.yml.

Roles and authority

  • Tenant roles are currently member and admin.
  • Settings changes (module/capability toggles and presentation preference writes) are currently done through admin-protected routes.
  • There is currently no separate superuser role in tenant settings, and no special permission tier for team leads.

Effective config caching

  • Effective config reads are cached by tenant slug and config file signatures.
  • Cache entries are invalidated after tenant settings writes.
  • This keeps repeated reads fast while ensuring fresh values after changes.

Version migration path

  • Config resolution runs a migration pipeline before validation.
  • Overrides without a version are migrated to the current schema version.
  • Unsupported future versions fail fast with a validation error.

Audit trail

  • Each tenant settings write persists a ConfigChangeEvent.
  • Events include tenant, optional actor identity, event type, context, and before/after override payloads.
  • Export bundles include config_change_events.csv for archived tenant recovery/audit workflows.

Behavior FAQ

What happens when an admin disables a module?

  • Requests into controllers guarded by that module are blocked by ModuleGuard and return 404 Not Found.
  • This is intentional to hide disabled surfaces rather than exposing a partial page with errors.
  • Re-enabling the module restores access for users in that tenant.

What happens when an admin disables a capability inside a module?

  • Requests to guarded actions are blocked by CapabilityGuard and return 404 Not Found.
  • Example: task quick-start, reorder, and pause/resume/stop actions are individually capability-guarded.
  • Capability checks require both the module and the capability to be enabled.

Which preferences can memberships set today?

  • Current write path supports membership-level dashboard preference:
    • dashboard.compact_widgets
  • In current UI/controller flow, this is changed through admin-only membership management routes.

If a team lead sets a team preference, does it affect all team members?

  • Team preferences are resolved as team-scope overrides and are merged into membership presentation resolution for members of those teams.
  • In current permissions, team preference writes are admin-only; there is no dedicated team-lead write permission.
  • Membership-specific overrides are applied after team overrides and therefore win if both set the same key.

Who is a superuser?

  • Tenant settings currently do not define a superuser role.
  • Operationally, the highest tenant-scoped authority is admin membership for the tenant.

Can an admin hide fields on members' edit views?

  • Not as a generalized tenant-setting for all member edit forms today.
  • The config model contains task field metadata (tasks.fields) for visibility/required semantics, but broad per-view field visibility toggles for member edit pages are not currently exposed as an admin feature.
  • If needed, this should be treated as a new story with explicit scope (which views, which fields, and whether hidden vs read-only behavior is required).