105 lines
15 KiB
Markdown
105 lines
15 KiB
Markdown
# Task: Implement account isolation, roles, and audit
|
||
|
||
## Identity
|
||
|
||
- Task ID: 20260901-account-system-impl-d4e7a2
|
||
- Mode: Feature
|
||
- Branch: codex/20260901-account-system-impl-d4e7a2-account-system-impl-d4e7a2
|
||
- Worktree: /Users/inmanx/Documents/lwltAPI-account-system-impl-d4e7a2
|
||
- Base commit: ffa33408997c3e822dd8293fbca0739c72ff3d01
|
||
- Owner: codex
|
||
- Status: Ready for integration
|
||
|
||
## Scope
|
||
|
||
- Implement fixed-single-organization `admin`, `team_lead`, and `user` roles without adding organization selection or tenant administration.
|
||
- Add administrator account lifecycle APIs and UI, self-service password change, session revocation, and last-administrator safety.
|
||
- Enforce administrator-or-owner authorization for manual tasks, messages, events, artifacts, SSE, and browser execution paths.
|
||
- Preserve creator and encrypted initial/supplemental input attribution, expose authorized audit history, and replace routine task deletion with archive/restore.
|
||
- Add role-aware operator UI and table-driven security/regression coverage.
|
||
- Add a team-lead/administrator-only, read-only operations dashboard for cross-user manual instruction history, work-status summaries, multi-dimensional business drill-through, and “who/instruction/result” detail.
|
||
- Add administrator-managed per-account task-type authorization for all 18 registered manual business routes, with server-side fail-closed enforcement and denial audit.
|
||
- Do not deploy, restart the existing 8786 service, access the real database/ERP, mutate real runtime tasks, or send data externally. A separately isolated local preview on port 8876 and PostgreSQL port 55432 is permitted by the user's explicit preview request.
|
||
|
||
## Intent And Constraints
|
||
|
||
- Existing `organization_id` remains an internal fixed deployment scope and compatibility boundary; it is not exposed as a product concept.
|
||
- Existing users migrate as administrators. Administrators always retain all 18 manual business routes. New ordinary users and team leads start with no manual task-type authorization and can operate only explicitly granted routes for tasks they create; AgentBus/system tasks remain administrator-only and keep their separate channel authorization boundary.
|
||
- Team leads gain cross-user visibility only through dedicated read-only dashboard APIs. That capability does not extend normal task mutation, artifact download, SSE, ERP execution, account administration, global audit, automation, parser, or AgentBus permissions.
|
||
- Authorization is enforced in server/service/database access paths, never only by navigation visibility.
|
||
- Unauthorized resource identifiers fail without revealing cross-user existence.
|
||
- Initial and supplemental input remain encrypted at rest; password material and raw business input never enter audit or operational logs.
|
||
- Organization-wide ERP execution serialization, confirmation, idempotency, uncertain-write, and requery safety gates remain unchanged.
|
||
- Routine deletion becomes reversible archive/restore. Physical purge remains unavailable until an explicit retention policy is authorized.
|
||
- Task-type authorization is re-read from PostgreSQL at every creation/continuation and before confirmation, automatic confirmation, and browser claim, so revocation takes effect without waiting for session expiry. A non-administrator instruction that cannot resolve to exactly one registered route fails closed.
|
||
- The semantics and ERP contracts of the 18 registered business routes remain unchanged; this feature changes only which signed-in accounts may invoke each route.
|
||
|
||
## Permission Contract
|
||
|
||
| Surface | Administrator | Team lead | Ordinary user |
|
||
|---|---|---|---|
|
||
| Login, logout, current user, CSRF, own password | Allowed | Allowed | Allowed |
|
||
| Account list/create/status/role/reset/session revocation | Allowed | Denied | Denied |
|
||
| Manual task-type authorization | All 18 routes, fixed | Explicit administrator grants only; default none | Explicit administrator grants only; default none |
|
||
| Automation, parser routing/review/reparse, AgentBus channels, global audit | Allowed | Denied | Denied |
|
||
| Normal task list/search/detail/events/input history | All fixed-scope tasks | Own non-AgentBus tasks only | Own non-AgentBus tasks only |
|
||
| Create task/message/confirm/claim/result/cancel/archive/restore | Any authorized task | Own task only | Own task only |
|
||
| Artifact download and SSE | All fixed-scope tasks | Own task only | Own task only |
|
||
| Operations dashboard summaries and user directory | All manual account tasks | Read-only, all manual account tasks | Denied |
|
||
| Operations dashboard instruction/attachment-name/business-result detail | Read-only, all manual account tasks | Read-only, all manual account tasks | Denied |
|
||
| Browser heartbeat/connection | Own authenticated connection | Own authenticated connection | Own authenticated connection |
|
||
| AgentBus/system tasks | Allowed | Not visible | Not visible |
|
||
| Physical task purge | Not exposed | Not exposed | Not exposed |
|
||
|
||
Unauthorized task and artifact identifiers use the existing not-found response to avoid enumeration. Administrator-only settings and account endpoints use an explicit forbidden response.
|
||
|
||
## Outcome
|
||
|
||
- Added migration `015_account_roles_and_task_audit`: existing accounts remain administrators; new `admin`/`user` roles, forced-password lifecycle fields, message/attachment actor attribution, reversible task archive fields, and account-scoped manual idempotency keys are persisted. No organization selector or tenant-management concept was added.
|
||
- Added migration `016_team_lead_operations_dashboard`: the fixed role constraint now accepts `team_lead`, and bounded manual-task indexes support time-, actor-, status-, and business-type-oriented dashboard reads.
|
||
- Added migration `017_user_business_route_authorizations`: durable fixed-scope per-user allowlists cover all 18 registered manual business routes, carry administrator attribution and optimistic authorization revisions, and enforce same-organization user/granter references. Schema readiness now requires migration 017.
|
||
- Implemented administrator account management for list/create, enable/disable, role changes, password reset, and session revocation. Passwords remain Argon2id hashes, reset accounts can be forced to change password, role/status changes revoke sessions, and self-lockout plus removal of the last active administrator are blocked transactionally.
|
||
- Enforced owner-restricted access for both ordinary users and team leads on task list/search/detail, messages, input history, artifacts, lifecycle mutations, browser claim/result, archive/restore, historical events, and live SSE. Both roles can access only their own manual tasks through normal business APIs; AgentBus/system tasks remain administrator-only. Browser connection IDs are user-bound and idempotency keys no longer collide across manual accounts.
|
||
- Added authorized creator/original-input audit: task creator, every newly attributed user turn, attachment actor, lifecycle event actor, and account/task audit events are available to the authorized operator. Input contents and file names remain encrypted at rest; passwords and plaintext business input are not copied into the global audit log.
|
||
- Replaced routine task deletion with archive/restore across the API, UI, retention job, and compatibility routes. Physical task/audit purge code is no longer exposed or retained in the task service.
|
||
- Added role-aware platform pages for account management and global audit, mandatory/self-service password change, administrator-only settings navigation, creator/input history, per-user browser connection identity, and active/archived task views. Administrators can assign the new 组长 role.
|
||
- Added an administrator-only task-permission panel in account management with all 18 business types, selected counts, select-all/clear, optimistic save protection, and effective authorization display. Administrators are permanently shown as fully authorized; new non-administrator accounts are clearly created with no task permissions until an administrator grants them.
|
||
- Enforced the allowlist in the task service before initial parsing/plugin dispatch, on supplemental messages and passenger attachments, inside creation transactions, before manual and automatic confirmation, and before browser/ERP claim. Confirmation and claim evaluate the task creator rather than the acting administrator, so a revoked creator cannot be bypassed by an administrator. Non-administrators receive `business_not_authorized` for a known denied route or `business_type_unresolved` when the route is unknown/non-unique; both paths stop execution and return a business-readable Chinese prompt. Denial audit stores actor, route/revision, phase, and an input hash only—never the plaintext instruction—and explicitly records that parsing, plugin dispatch, and ERP writes did not run.
|
||
- Added `/operations-dashboard` and leadership-gated GET APIs with a default 30-day window, a 366-day maximum, status/person/Shanghai-business-day/business-type drill-through, aggregate KPIs, per-user work summaries, bounded pagination, and on-demand business detail. Keyword query matches the creator, full initial and supplemental instructions, business type, readable business result, task record number, group number, and order number after structured filters; decrypted matching is bounded to 2,000 candidates. Dashboard queries include only manual tasks. Its dedicated list/detail contracts expose only who acted, what was instructed, what business outcome was recorded, business type, timestamps, and simplified input attachment attribution; lifecycle events, parser/executor JSON, technical stages/errors, and artifact access data are not returned. No dashboard mutation route exists.
|
||
- Updated `control-plane/README.md` to describe the three-role account model, owner isolation, read-only operations dashboard, administrator-managed task-type allowlists, fail-closed enforcement, archive semantics, migrations 015/016/017, and the latest schema readiness gate.
|
||
- Added table-driven three-role access-policy tests plus migration, authorization-path, dashboard, UI, audit, idempotency, and no-purge regression assertions. The 18 business routes and ERP serialization/write-safety contracts were not changed.
|
||
- Upgraded only the isolated local preview on `127.0.0.1:8876`: applied migration 017 to its dedicated PostgreSQL database, restarted only the preview process, assigned small demonstrative allowlists to the preview lead/Alice/Bob accounts, and verified a denied instruction did not create a task. The existing service on port 8786 remained on its original PID and was not touched.
|
||
- No deployment, real-service restart, real database migration, ERP access, real runtime task mutation, secret read, or external message occurred.
|
||
|
||
## Verification
|
||
|
||
- `node --run check:repo`: 10/10 passed.
|
||
- `node --run check`: passed.
|
||
- `node --run test:control-plane`: 153/153 passed.
|
||
- `node --run test:legacy`: 256/256 passed.
|
||
- `node --run build`: passed.
|
||
- `node --check LianSyn-platform/app.js`: passed.
|
||
- `git diff --check`: passed.
|
||
- Focused authorization regression (`node --test --import tsx control-plane/test/account-authorization.test.ts control-plane/test/control-plane.test.ts`): 60/60 passed.
|
||
- Disposable PostgreSQL API smoke: new non-administrator denied by default; one granted route accepted; another ungranted route denied; only the authorized task persisted; two denials were durably audited.
|
||
- Fresh disposable PostgreSQL migration: migrations 001–017 applied successfully, schema head was `017_user_business_route_authorizations`, and the disposable database was removed afterward.
|
||
- Isolated preview readiness: `/health/ready` reported database/schema ready with required migration 017; the account catalog returned all 18 task types; Alice, Bob, and the team lead received 2, 1, and 3 demonstrative grants respectively; Bob's ungranted “安排导游” instruction returned HTTP 403 `business_not_authorized` with the expected Chinese prompt.
|
||
- `check_project_docs.py`: passed.
|
||
- `check_doc_drift.py --task-id 20260901-account-system-impl-d4e7a2`: passed.
|
||
|
||
## Follow-ups
|
||
|
||
- Integrate this feature worktree before deployment, then apply migrations `015_account_roles_and_task_audit`, `016_team_lead_operations_dashboard`, and `017_user_business_route_authorizations` and restart the control plane only under separate authorization.
|
||
- In an authorized staging/runtime window, create one team-lead and two ordinary test accounts. Verify forced password change, default-deny task permissions, per-route grant/revoke without re-login, known-route and unresolved-route denial prompts, no parsing/plugin/ERP side effects on denial, creator-based revocation at confirmation/claim, own-task visibility, cross-user 404 behavior on normal task/artifact/SSE paths, AgentBus invisibility, dashboard denial for ordinary users, and team-lead cross-user drill-through by status/person/date/business plus keyword hits in supplemental instructions and completed business results. Also verify the dashboard response contains no lifecycle/parser/executor/artifact-access data, then cover account session revocation, creator/input audit, and archive/restore against PostgreSQL and independent browser sessions.
|
||
- Keep physical purge unavailable unless a separately approved retention design defines legal/audit retention periods and privileged irreversible-purge controls.
|
||
|
||
## Promotion Candidates
|
||
|
||
- Target canonical architecture/security/current-state memory during a later Integration task.
|
||
- Proposal: record the fixed-scope account model as `admin`, `team_lead`, and `user`, with no product-visible organization concept. Team leads retain ordinary-user ownership boundaries for business operations but receive dedicated cross-user, manual-task-only, read-only operations-dashboard access; administrators retain global settings, AgentBus/system tasks, account lifecycle, and global audit.
|
||
- Proposal: record the operations dashboard as a business-facing projection rather than a privileged task-debug surface: status/person/Shanghai-day/business drill-through and bounded plaintext matching are permitted, while lifecycle events, parser/executor payloads, technical stages/codes, and artifact access remain outside its response contract.
|
||
- Proposal: record creator/input attribution, account-scoped idempotency, user-bound browser connections, forced password change/session revocation, last-administrator protection, and archive/restore as security invariants.
|
||
- Proposal: record manual business eligibility as an administrator-managed allowlist over the 18 registered routes: administrators are always fully authorized, team leads/users default to none and require explicit grants, unknown/non-unique routes fail closed, revocation is checked at each state transition, and AgentBus keeps its independent channel boundary.
|
||
- Evidence: `control-plane/migrations/015_account_roles_and_task_audit.sql`, `control-plane/migrations/016_team_lead_operations_dashboard.sql`, `control-plane/migrations/017_user_business_route_authorizations.sql`, `control-plane/src/auth.ts`, `control-plane/src/task-service.ts`, `control-plane/src/server.ts`, `LianSyn-platform/index.html`, `LianSyn-platform/app.js`, `LianSyn-platform/styles.css`, `control-plane/README.md`, and `control-plane/test/account-authorization.test.ts` plus the full verification above.
|
||
- Human confirmation required: already received for the single-organization three-role ownership/audit/dashboard behavior; integration, database migration, deployment, restart, and live smoke testing remain separately authorized.
|