3.4 KiB
EDU-017 — Tenant appearance, public settings, and theme lifecycle
- Status: done — bounded appearance/theme slice implemented and verified
- Type: tenant administration / public presentation configuration
- Phase: 4 / tenant operations
- Blockers: EDU-003, System Tenant authority, Vben admin foundation
Decision
System Tenant remains authoritative for tenant identity, display name, lifecycle, and bound websites. Education owns only presentation-specific configuration: branding extensions, student/admin feature flags, public runtime configuration, and draft/published theme state. The public tenant locator response remains the minimal EDU-003 contract; appearance is exposed separately under the normal request tenant context.
Platform theme templates are global trusted configuration and are explicitly excluded from MyBatis tenant injection. Tenant appearance rows extend TenantBaseDO, retain one live row per tenant, and use optimistic versions for every update. RuoYi System RBAC, tenant validation, admin projection, API access/operation logging, and the normal tenant-id security filter remain authoritative.
Delivered contract
- Admin read, branding write, settings write, theme preview, and theme publish endpoints with independent permissions.
GET /education/tenant-appearance/publicis anonymous but not tenant-ignored; it requires the normal validated tenant header/context and returns no admin flags or draft data.- System tenant name is the lazy-row default and fallback; no duplicate Education tenant identity or domain authority is created.
- Three legacy-compatible templates are seeded:
classic,focus, andhigh-contrast. - Theme preview is a shallow template/override merge. Publication revalidates the persisted draft and clears it atomically.
- Recursively rejects secret/password/token/private-key/API-key-like public keys except
secretRef; theme tokens, CSS variables, icons, assets, colors, radii, modes, and density are allowlisted and unsafe renderable strings fail closed. - Vben page
education/tenant-appearance/indexmanages branding, JSON settings, templates, draft preview, and explicit publication with client-side preflight checks.
Verification
- Policy unit tests cover recursive secret rejection, closed theme/asset key sets, colors/radii/CSS, URLs, and shallow merge.
- Service unit tests cover System-name fallback, optimistic conflict, sanitized draft persistence, and public projection.
- Method-security contract tests prove query, branding, settings, and theme permissions are independent.
- Real PostgreSQL service tests prove lazy defaults, shared templates, settings, draft/publish, public projection, stale-version rejection, and cross-tenant isolation through the production MyBatis interceptor.
- Flyway tests prove the V4290 schema, exact template seeds, menu shape, unique tenant row, and draft/publish database state.
Explicitly open
- Domains stay in System Tenant
websites; no Education domain CRUD authority is planned. - Payment-account configuration must compose Pay rather than copy the legacy table.
- Authentication-provider configuration must reuse System/Member authentication seams.
- Tenant secret storage/rotation needs a dedicated encrypted private-storage decision and must never be added to the public appearance table.
- Activation codes and coupons need a Mall Promotion/Member entitlement ownership and idempotent redemption decision.