docs: design housekeeping modernization
This commit is contained in:
1 parent
3a76dbdb97
commit
601a3e746f
1 file changed
+438
@@ -0,0 +1,438 @@
|
||||
# Housekeeping modernization design
|
||||
|
||||
Date: 2026-08-24
|
||||
Status: approved in design review; awaiting review of this written specification
|
||||
|
||||
## Purpose
|
||||
|
||||
Replace the current administration experience with one coherent, role-adaptive Housekeeping (HK) at `/admin`.
|
||||
|
||||
The new HK is a modular part of the existing Next.js application. It is built in parallel, validated against the current system, and exposed with one atomic cutover. It unifies the current `/admin` and `/mod` surfaces, removes duplicated workflows, and preserves reliable domain services without automatically preserving their current pages.
|
||||
|
||||
This document is the master architecture for the program. It is deliberately not one giant implementation plan. Delivery is split into independently specified and verified subprojects, beginning with **Inventory & Foundation**.
|
||||
|
||||
## Current-state findings
|
||||
|
||||
- The repository currently contains 124 `page.tsx` files below `src/app/admin` and 13 below `src/app/mod`: 137 administration pages in total.
|
||||
- `src/lib/admin-nav.ts` currently exposes nine navigation groups and seven hub definitions.
|
||||
- `/admin` and `/mod` provide overlapping moderation, ticket, ban, team, and user workflows with separate shells.
|
||||
- `/admin/housekeeping` is a legacy permission archive/comparison/export surface, while `/admin/permissions` is the live permission-management surface.
|
||||
- The current dashboard reports useful counts but is not an operational work queue.
|
||||
- Page composition, localization, ACL checks, filtering, error handling, and action feedback are not yet uniform across the administration surface.
|
||||
|
||||
The migration must therefore classify every current page. A visual refresh without workflow and boundary changes is insufficient.
|
||||
|
||||
## Approved decisions
|
||||
|
||||
| Area | Decision |
|
||||
| --- | --- |
|
||||
| Audience | One role-adaptive HK. Effective capabilities, not rank names alone, determine what an operator sees and can do. |
|
||||
| Entry point | `/admin` is the only administration entry point after cutover. `/mod` is removed. |
|
||||
| Layout | Command Deck: compact domain rail, contextual navigation, global command palette, operational workspace. |
|
||||
| Personalization | Hybrid: the system supplies mandatory capability-derived content; the operator may pin and reorder allowed shortcuts and optional widgets. |
|
||||
| Compatibility | Clean break. Old subroute compatibility and legacy UX are not preserved through redirects. |
|
||||
| Build strategy | Build the new HK in parallel, keep it unavailable to normal production operators, then switch atomically. |
|
||||
| Work queue | “Da fare ora” is derived from existing sources. It is not a second task database and never owns workflow state. |
|
||||
| Command palette | It navigates, searches entities, and executes only safe commands. Sensitive actions open a dedicated contextual flow. |
|
||||
| Architecture | Modular hybrid replacement inside the current application: reuse sound services, rebuild weak UI/workflows, merge duplicates, and remove obsolete surfaces. |
|
||||
|
||||
## Goals
|
||||
|
||||
1. Give each operator one clear, capability-appropriate place to work.
|
||||
2. Replace feature sprawl with six stable domains and consistent page contracts.
|
||||
3. Make urgent work visible without copying or diverging from source workflow state.
|
||||
4. Enforce authorization, validation, transaction boundaries, error semantics, and audit behavior server-side.
|
||||
5. Remove `/mod`, the legacy HK archive page, duplicate hubs, and manual navigation concepts that the new foundation owns.
|
||||
6. Reach explicit functional, authorization, audit, localization, accessibility, and data-parity gates before cutover.
|
||||
7. Keep rollback practical without exposing a mixed legacy/new experience.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Creating a separate HK application, microservice, or deployment.
|
||||
- Creating a new assignment/task system for the operational inbox.
|
||||
- Preserving every current page, route, component, or interaction.
|
||||
- Adding backward-compatible redirects for removed administration subroutes.
|
||||
- Providing full sensitive-workflow parity on phones. The target is desktop-first with usable tablet layouts.
|
||||
- Redesigning public CMS or game-client experiences as part of this program.
|
||||
- Replacing sound domain logic solely for architectural uniformity.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Modular monolith
|
||||
|
||||
The HK remains inside EpicNext CMS and uses the application's existing authentication, database, service, localization, and deployment infrastructure.
|
||||
|
||||
The target source organization separates composition from behavior:
|
||||
|
||||
```text
|
||||
src/app/admin/ route composition only
|
||||
src/features/housekeeping/
|
||||
foundation/ shell, registry, ACL context, preferences
|
||||
domains/
|
||||
operations/ derived inbox, global search, recent work
|
||||
people/
|
||||
content/
|
||||
economy/
|
||||
hotel/
|
||||
system/
|
||||
src/lib/services/ existing and extracted domain services
|
||||
```
|
||||
|
||||
The exact filenames are an implementation-plan concern, but the boundaries are mandatory:
|
||||
|
||||
- App Router files compose pages and bind route parameters; they do not own business rules.
|
||||
- The foundation owns cross-cutting HK behavior and does not mutate domain data.
|
||||
- Each domain owns its queries, commands, search providers, inbox providers, widgets, and page composition.
|
||||
- Domains do not import another domain's UI internals. Cross-domain interaction uses registered contracts or links to the owning route.
|
||||
- Existing reliable services are adapted behind domain contracts rather than copied into the new UI.
|
||||
|
||||
### Module manifest and registry
|
||||
|
||||
Every domain exports a manifest with stable identifiers for:
|
||||
|
||||
- domain metadata and localized labels;
|
||||
- routes and contextual navigation;
|
||||
- required capabilities;
|
||||
- command-palette entries;
|
||||
- entity-search providers;
|
||||
- derived-inbox sources;
|
||||
- mandatory and optional dashboard widgets.
|
||||
|
||||
The foundation composes these manifests into the rail, contextual navigation, palette, dashboard, and route metadata. Contract tests reject duplicate IDs, duplicate routes, missing localization keys, unknown capability slugs, and commands without an owner.
|
||||
|
||||
The manifest registry replaces hand-maintained duplication between the sidebar, hubs, search, and dashboards. It is code-owned and reviewable. Operator preferences can alter presentation only within what the registry and capability context permit.
|
||||
|
||||
### Capability context
|
||||
|
||||
The server creates one request-scoped capability context from the authenticated operator and the existing ACL source.
|
||||
|
||||
- Capability checks are based on effective permission slugs.
|
||||
- Super-administrator behavior remains explicit and testable.
|
||||
- Rank may help choose default presentation, but never grants access by itself.
|
||||
- Navigation filtering is a usability feature, not an authorization boundary.
|
||||
- Every query and command rechecks its capability on the server and defaults to deny.
|
||||
|
||||
## Functional domains
|
||||
|
||||
| Domain | Owns | Representative current areas |
|
||||
| --- | --- | --- |
|
||||
| Da fare & operations | Derived inbox, global search, recent work, favorites, operational summaries | Dashboard, selected alerts and cross-domain counts; projections only |
|
||||
| People & community | Users, online state, accounts, guilds, applications, staff directory, moderation, support | Users, multi-accounts, guilds, applications, CFH, moderation actions, bans, IP/VPN, word filter, tickets, help tickets, `/mod/*` |
|
||||
| Content & engagement | Public/editorial content and engagement workflows | Articles, photos, media, banners, ads, events, polls, help content, tags, prefixes, writable boxes, email content, branding/localization surfaces |
|
||||
| Economy & catalog | Products, value, commercial assets, and economic history | Catalog, items, import/maintenance, shop, marketplace, transactions, vouchers, subscriptions, rare values, badges, achievements, sounds |
|
||||
| Hotel & world | Live hotel surfaces and world-management tools | Rooms, navigator, radio, studio/runtime asset tools, contextual hotel actions |
|
||||
| System, access & observability | Configuration, authorization, diagnostics, and privileged operations | Permissions, access audit, settings, maintenance, emulator, command center, logs, analytics, alerts, DevOps |
|
||||
|
||||
Where an existing feature spans two domains, responsibility follows the action rather than the old route. For example, the staff directory belongs to People, while the policy granting staff capabilities belongs to System and Access.
|
||||
|
||||
Domain landing pages summarize their own workflows. They do not recreate the global dashboard or become a second source of state.
|
||||
|
||||
## Operator experience
|
||||
|
||||
### Command Deck shell
|
||||
|
||||
The shared shell contains:
|
||||
|
||||
1. A compact rail for the six domains.
|
||||
2. Contextual navigation generated from the active domain manifest.
|
||||
3. A global command/search field available by keyboard.
|
||||
4. A main workspace using consistent title, context, primary action, filters, content, and feedback regions.
|
||||
5. Operator identity, effective-capability context, notifications, and session controls.
|
||||
|
||||
The shell is desktop-first, fully keyboard operable, and responsive for tablets. Phone layouts may support inspection and low-risk triage, but sensitive multi-step operations are not optimized for phone use.
|
||||
|
||||
### Adaptive dashboard
|
||||
|
||||
ACL and capability data determine:
|
||||
|
||||
- visible domains and routes;
|
||||
- mandatory queues and warnings;
|
||||
- permitted metrics and widgets;
|
||||
- available commands and search providers.
|
||||
|
||||
The operator may:
|
||||
|
||||
- pin allowed routes and safe commands;
|
||||
- reorder shortcuts and optional widgets;
|
||||
- add or remove optional allowed widgets;
|
||||
- persist preferred filters and presentation density where supported.
|
||||
|
||||
The operator may not hide mandatory warnings, reveal unauthorized data, or preserve a shortcut after its required capability is lost.
|
||||
|
||||
Preferences are server-persisted, user-scoped, schema-versioned, and non-authoritative. If no suitable existing preference store exists, the foundation adds one additive `housekeeping_user_preferences` store containing presentation state only. It never stores task status or authorization decisions. Every preference is reconciled with the current manifest and capability context when read.
|
||||
|
||||
### Standard page contract
|
||||
|
||||
Every target page follows the same structural contract:
|
||||
|
||||
- localized title, description, breadcrumb/context, and one clear primary action;
|
||||
- capability-derived actions with server authorization;
|
||||
- shared filtering, pagination, empty, loading, partial, and error states;
|
||||
- explicit unsaved-change behavior for editable forms;
|
||||
- consistent confirmation and outcome feedback;
|
||||
- stable deep links to owned entities and workflows;
|
||||
- responsive table-to-detail behavior without hiding critical fields;
|
||||
- audit context for mutations.
|
||||
|
||||
## Operational inbox
|
||||
|
||||
The inbox is a read model over domain-owned sources such as tickets, CFH reports, alerts, emulator errors, and detected anomalies.
|
||||
|
||||
Each source emits normalized work items containing at least:
|
||||
|
||||
- stable source and item IDs;
|
||||
- domain and required capability;
|
||||
- severity and source timestamp;
|
||||
- localized summary and optional context;
|
||||
- stable destination route and entity target;
|
||||
- deduplication key;
|
||||
- freshness/availability metadata.
|
||||
|
||||
The aggregator:
|
||||
|
||||
1. Requests sources independently with bounded timeouts.
|
||||
2. Filters every result against the operator's capability context.
|
||||
3. Deduplicates by stable source identity.
|
||||
4. Orders by severity, age, and domain policy.
|
||||
5. Returns both items and per-source availability.
|
||||
|
||||
The aggregator never creates, assigns, dismisses, or completes work. Selecting an item opens the owning workflow. If that workflow supports assignment or resolution, those state changes occur there.
|
||||
|
||||
A failed or timed-out source does not erase successful sources. The UI labels the missing source and the freshness of remaining data instead of presenting the whole system as healthy.
|
||||
|
||||
## Global search and command palette
|
||||
|
||||
The palette has three provider types:
|
||||
|
||||
1. **Navigation providers** for permitted routes and favorites.
|
||||
2. **Entity providers** for capability-filtered entities such as users, rooms, tickets, articles, or catalog entries.
|
||||
3. **Safe command providers** for narrowly scoped, validated, idempotent or reversible actions.
|
||||
|
||||
A mutation may run directly from the palette only when it is single-target, low impact, reviewable in the palette, protected by a specific capability, and safe against duplicate submission. It still uses the normal server command and audit path.
|
||||
|
||||
Destructive, economic, moderation, permission, bulk, or otherwise sensitive actions return a navigation intent. The target page receives validated context and shows impact, current state, required reason, confirmation, and final outcome.
|
||||
|
||||
## Data and command flow
|
||||
|
||||
### Queries
|
||||
|
||||
```text
|
||||
page or shell
|
||||
-> request-scoped capability context
|
||||
-> typed domain query
|
||||
-> existing API/repository through an adapter
|
||||
-> sanitized response
|
||||
```
|
||||
|
||||
The UI does not query arbitrary tables or reproduce sensitive filter rules. Authorization-sensitive results are filtered at the query boundary. Short-lived caching may be used for operational counts, but authorization is applied after cache lookup and sensitive per-user results are not shared across capability contexts.
|
||||
|
||||
### Commands
|
||||
|
||||
```text
|
||||
intent
|
||||
-> server capability check
|
||||
-> schema validation
|
||||
-> current-state/concurrency check
|
||||
-> domain transaction or controlled external call
|
||||
-> audit outcome
|
||||
-> typed result and cache invalidation
|
||||
```
|
||||
|
||||
Every command receives a server-issued action ID used as an idempotency key. Duplicate submissions return the original known outcome rather than repeating the mutation.
|
||||
|
||||
For records with a revision or update timestamp, edits use optimistic concurrency. A stale edit returns a conflict result and current-state reference; it is not silently overwritten. Where a source cannot expose a revision, the command performs the strongest available transactional re-read before mutation.
|
||||
|
||||
## Security and audit
|
||||
|
||||
- Default-deny server checks protect every query and command.
|
||||
- Sensitive actions require a dedicated flow, an explicit target, an impact summary, confirmation, and a non-empty operator reason.
|
||||
- Domain validation occurs after authorization and before mutation.
|
||||
- Audit is append-only from the HK application: no HK route can edit or delete audit events.
|
||||
- Audit records include actor, target, command, reason, sanitized before/after details where appropriate, outcome, timestamp, action ID, and correlation ID.
|
||||
- Secrets, credentials, tokens, and unnecessary personal data are excluded from audit payloads.
|
||||
- When data and audit share a transactional store, a privileged mutation and its audit record commit together.
|
||||
- For external operations, an intent/pending audit record is written before dispatch and completed with success or failure afterward.
|
||||
- A privileged mutation fails closed if its required audit trail cannot be established.
|
||||
|
||||
## Error model
|
||||
|
||||
Domain boundaries return typed outcomes rather than leaking raw infrastructure errors:
|
||||
|
||||
- validation failure;
|
||||
- authentication required;
|
||||
- capability denied;
|
||||
- not found;
|
||||
- stale/conflicting state;
|
||||
- dependency unavailable;
|
||||
- partial aggregate result;
|
||||
- unexpected internal failure.
|
||||
|
||||
Expected outcomes have localized, actionable messages. Unexpected failures expose a correlation ID to the operator and retain technical detail only in server logs. Forms preserve safe input after recoverable failures. Lists and the operational dashboard distinguish empty results from unavailable data.
|
||||
|
||||
## Migration inventory
|
||||
|
||||
The first subproject creates a committed migration matrix covering all 137 current pages. Each row contains:
|
||||
|
||||
- legacy path and source surface (`admin` or `mod`);
|
||||
- target domain and owning workflow;
|
||||
- target path;
|
||||
- decision: `REHOST`, `REBUILD`, `MERGE`, or `REMOVE`;
|
||||
- required read and mutation capabilities;
|
||||
- source queries and mutations;
|
||||
- audit requirement;
|
||||
- localization and accessibility status;
|
||||
- required unit, integration, and E2E coverage;
|
||||
- parity evidence and migration status.
|
||||
|
||||
Decision meanings:
|
||||
|
||||
- **REHOST**: the current UI and service are sound enough to enter the new shell after contract and ACL adaptation.
|
||||
- **REBUILD**: preserve the workflow and sound service logic, but reconstruct its interaction and page composition.
|
||||
- **MERGE**: combine duplicated routes or variants into one owning workflow with contextual views.
|
||||
- **REMOVE**: eliminate obsolete or foundation-owned behavior at cutover.
|
||||
|
||||
Mandatory consolidations:
|
||||
|
||||
- All 13 `/mod` pages merge into People and Community workflows. `/mod` does not redirect after cutover.
|
||||
- `/admin/housekeeping` ceases to exist as a named feature. Useful comparison/export history moves into System, Access, and Audit.
|
||||
- `/admin/permissions` remains the live policy editor under System and Access.
|
||||
- Legacy dashboard, hub, and manual HK-navigation concepts are removed when their responsibilities are supplied by the registry and Command Deck.
|
||||
|
||||
No page is considered migrated merely because it renders in the new shell. Its matrix row closes only after data, actions, capability behavior, audit, localization, accessibility, and required tests pass.
|
||||
|
||||
## Delivery decomposition
|
||||
|
||||
This master design controls the program. For delivery purposes it is also the approved design specification for subproject 01. Subprojects 02 through 06 require their own scoped design specifications before their implementation plans. Subprojects are delivered in this order:
|
||||
|
||||
### 01. Inventory & Foundation
|
||||
|
||||
This is the first and only scope of the initial implementation plan.
|
||||
|
||||
Deliverables:
|
||||
|
||||
- the complete 137-page migration matrix;
|
||||
- HK manifest contracts and registry validation;
|
||||
- request-scoped capability context and server guard interfaces;
|
||||
- domain query, command, search, inbox, and widget contracts;
|
||||
- the Command Deck shell primitives and standard page-state contract;
|
||||
- six domain manifests with no migrated business workflow yet;
|
||||
- a non-production/test-only entry mechanism that cannot expose a mixed HK to normal production operators;
|
||||
- contract, capability, localization-key, accessibility-smoke, and shell tests.
|
||||
|
||||
Explicit exclusions:
|
||||
|
||||
- no current `/admin` or `/mod` route changes;
|
||||
- no production operator exposure;
|
||||
- no operational inbox aggregation;
|
||||
- no entity search implementation;
|
||||
- no domain mutation migration;
|
||||
- no legacy deletion.
|
||||
|
||||
### 02. Access, audit & system core
|
||||
|
||||
Implement the capability enforcement adapters, audit command path, error taxonomy, correlation IDs, and core observability used by every later vertical.
|
||||
|
||||
### 03. People, moderation & support
|
||||
|
||||
Deliver the first complete vertical and unify user, ticket, CFH, moderation-action, and ban workflows. This vertical proves the future removal of `/mod` without exposing a partial cutover.
|
||||
|
||||
### 04. Command Deck operations
|
||||
|
||||
Implement global search, safe commands, favorites, preferences, and the derived inbox against the sources available from completed verticals.
|
||||
|
||||
### 05. Remaining domain verticals
|
||||
|
||||
Deliver separate scoped specifications and plans for:
|
||||
|
||||
1. Content and Engagement;
|
||||
2. Hotel and World;
|
||||
3. Economy and Catalog;
|
||||
4. remaining System, Access, and Observability pages.
|
||||
|
||||
Economy and permission-affecting mutations receive the strictest confirmation, concurrency, and audit coverage.
|
||||
|
||||
### 06. Parity, cutover & cleanup
|
||||
|
||||
Close the migration matrix, run cross-role journeys and data comparisons, switch `/admin`, make `/mod` unreachable, observe the release, then delete unreachable legacy code and later remove obsolete schema safely.
|
||||
|
||||
Subproject 01 uses this specification; every later subproject has its own spec, implementation plan, tests, review, and completion gate. A later subproject may not silently expand an earlier approved scope.
|
||||
|
||||
## Verification strategy
|
||||
|
||||
Every subproject runs proportionate checks from these layers:
|
||||
|
||||
1. **Unit tests** for manifest parsing, normalizers, policy functions, reducers, and domain services.
|
||||
2. **Contract tests** for unique IDs/routes, capability declarations, localization keys, command ownership, and provider behavior.
|
||||
3. **Integration tests** against representative repository/API implementations, including transactions, external failures, idempotency, and conflicts.
|
||||
4. **ACL matrix tests** covering permitted, denied, capability-revoked, and super-administrator cases at both render and server boundaries.
|
||||
5. **E2E journeys** for moderation, support, editorial, economy, hotel operations, and administration roles defined by capabilities rather than rank labels.
|
||||
6. **Audit assertions** after every tested mutation.
|
||||
7. **Accessibility checks** for keyboard use, focus order, names, contrast, live feedback, dialogs, and table/detail transitions.
|
||||
8. **Localization checks** rejecting new hard-coded operator copy and missing translation keys.
|
||||
9. **Visual regression checks** for the shared shell and high-risk standard states.
|
||||
10. **Performance comparison** against a recorded legacy baseline using the same environment and dataset. Comparable new flows may not regress median or p95 response time by more than 10% without an explicit reviewed exception. Performance improvements are reported only from measurements.
|
||||
|
||||
## Cutover gate
|
||||
|
||||
The atomic switch is permitted only when all of the following are true:
|
||||
|
||||
- all 137 migration rows are closed with evidence;
|
||||
- every exposed query and command has a declared and tested capability;
|
||||
- every mutation has validation and required audit coverage;
|
||||
- no blocking or critical defect remains open;
|
||||
- equivalent legacy/new counts and records have been compared for migrated read workflows;
|
||||
- role journeys for moderator, support operator, editor, economy operator, hotel operator, and administrator pass;
|
||||
- localization, accessibility, build, type, lint, test, and visual checks pass;
|
||||
- production-like smoke tests, backup verification, rollback procedure, and health checks have been rehearsed;
|
||||
- the new HK is not dependent on legacy UI routes;
|
||||
- communication and operator runbooks are ready for the clean break.
|
||||
|
||||
## Cutover and rollback
|
||||
|
||||
Before cutover, the new HK is exercised through test/staging or an explicit non-production mechanism. Read-only shadow comparisons may run against representative data. There is no production dual-write.
|
||||
|
||||
At cutover:
|
||||
|
||||
1. `/admin` changes to the new route composition in one release/flag transition.
|
||||
2. `/mod` and removed legacy subroutes become unreachable without compatibility redirects.
|
||||
3. Smoke tests verify authentication, capability filtering, representative reads, one controlled mutation per risk class, audit, and health signals.
|
||||
|
||||
Database changes required before cutover are additive and backward-compatible for the emergency rollback window. A flag or previous release can temporarily restore the legacy application if the cutover fails. During normal operation, only one HK is exposed.
|
||||
|
||||
After the agreed stability window, unreachable legacy code and flags are removed. Destructive schema cleanup is a later migration and is not coupled to the cutover release.
|
||||
|
||||
## Success criteria
|
||||
|
||||
The program is complete when:
|
||||
|
||||
- `/admin` is the single role-adaptive administration surface;
|
||||
- `/mod` and the legacy Housekeeping archive surface are gone;
|
||||
- all 137 legacy pages have an evidenced migration decision;
|
||||
- all exposed data, navigation, commands, widgets, and inbox items are capability-correct;
|
||||
- the operational inbox derives live work without owning duplicate workflow state;
|
||||
- all mutations use the domain command, validation, concurrency, idempotency, and audit path appropriate to their risk;
|
||||
- no mixed legacy/new production experience exists;
|
||||
- measured performance meets the approved comparison gate;
|
||||
- rollback and eventual legacy cleanup are complete.
|
||||
|
||||
## Rejected alternatives
|
||||
|
||||
### Full greenfield rewrite
|
||||
|
||||
Rejected because it would discard reliable existing services and maximize parity, timing, and regression risk across 137 pages.
|
||||
|
||||
### Cosmetic refactor of the existing HK
|
||||
|
||||
Rejected because it would preserve duplicated `/admin` and `/mod` workflows, inconsistent page boundaries, and manual navigation debt.
|
||||
|
||||
### Separate HK service/application
|
||||
|
||||
Rejected because the current requirement does not justify another deployment, authentication boundary, or distributed consistency problem.
|
||||
|
||||
### Persistent cross-domain task database
|
||||
|
||||
Rejected because it would duplicate ticket, moderation, alert, and anomaly state and create reconciliation failure modes.
|
||||
|
||||
## Final design invariant
|
||||
|
||||
The migration may be incremental internally, but the operator-facing product is not. Until the cutover gate passes, the current HK remains the only normal production surface. After cutover, the new HK is the only surface.
|
||||
Reference in new issue
Block a user