diff --git a/docs/superpowers/plans/2026-07-01-stage-1-6-enterprise-governance.md b/docs/superpowers/plans/2026-07-01-stage-1-6-enterprise-governance.md new file mode 100644 index 0000000..22f704b --- /dev/null +++ b/docs/superpowers/plans/2026-07-01-stage-1-6-enterprise-governance.md @@ -0,0 +1,628 @@ +# Stage 1.6 Enterprise Governance Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Add a usable enterprise governance baseline with login, current user, users, user groups, roles, menus, API permission enforcement, permission-driven frontend navigation, and deployment bootstrap. + +**Architecture:** Backend keeps Django's built-in `User`, `Group`, and `Permission` as the core auth model, adds `UserGroup` and `MenuItem` for product governance, exposes session-authenticated Django Ninja APIs, and enforces permissions in ticket/solution/audit/governance routers. Frontend wraps the Vite SPA in an auth provider, renders a shadcn-based Chinese login page for anonymous users, consumes backend menu data in `AppSidebar`, and adds shadcn-based system governance pages. + +**Tech Stack:** Python 3.12, Django, Django Ninja, pytest, ruff, React, Vite, TypeScript, Tailwind CSS v3, shadcn/ui, Radix UI, npm. + +--- + +## Source Spec + +- `docs/superpowers/specs/2026-07-01-stage-1-6-enterprise-governance-design.md` + +## File Structure + +Backend: + +- Modify: `backend/config/settings/base.py` +- Modify: `backend/config/urls.py` +- Modify: `backend/apps/accounts/models.py` +- Modify: `backend/apps/accounts/permissions.py` +- Modify: `backend/apps/accounts/schemas.py` +- Modify: `backend/apps/accounts/api.py` +- Create: `backend/apps/accounts/auth.py` +- Create: `backend/apps/accounts/menus.py` +- Create: `backend/apps/accounts/bootstrap.py` +- Create: `backend/apps/accounts/management/commands/bootstrap_governance.py` +- Create: `backend/apps/accounts/migrations/0001_initial.py` +- Modify: `backend/apps/tickets/api.py` +- Modify: `backend/apps/solutions/api.py` +- Modify: `backend/apps/audit/api.py` +- Create: `backend/apps/accounts/tests/test_auth_api.py` +- Create: `backend/apps/accounts/tests/test_governance_api.py` +- Create: `backend/apps/accounts/tests/test_permission_enforcement.py` +- Create: `backend/apps/accounts/tests/test_bootstrap_governance.py` +- Modify: existing ticket/solution/audit tests to authenticate where protected endpoints are exercised. + +Frontend: + +- Modify: `frontend/src/lib/api.ts` +- Create: `frontend/src/features/auth/types.ts` +- Create: `frontend/src/features/auth/api.ts` +- Create: `frontend/src/features/auth/AuthProvider.tsx` +- Create: `frontend/src/features/auth/LoginPage.tsx` +- Modify: `frontend/src/app/App.tsx` +- Modify: `frontend/src/app/router.tsx` +- Modify: `frontend/src/app/layout/AppShell.tsx` +- Modify: `frontend/src/components/app/AppSidebar.tsx` +- Modify: `frontend/src/components/app/AppTopbar.tsx` +- Create: `frontend/src/features/system/api.ts` +- Create: `frontend/src/features/system/types.ts` +- Create: `frontend/src/features/system/SystemUsersPage.tsx` +- Create: `frontend/src/features/system/SystemUserGroupsPage.tsx` +- Create: `frontend/src/features/system/SystemRolesPage.tsx` +- Create: `frontend/src/features/system/SystemMenusPage.tsx` +- Create: `frontend/src/features/audit/AuditLogPage.tsx` +- Add shadcn components if missing: `checkbox`, `switch`, `alert`, `pagination`. + +Deployment/docs: + +- Modify: `.env.example` +- Create: `infra/backend-entrypoint.sh` +- Modify: `infra/backend.Dockerfile` +- Modify: `infra/docker-compose.yml` +- Modify: `docs/development/local-setup.md` + +## Task 1: Backend Governance Models And Bootstrap + +**Files:** +- Modify: `backend/apps/accounts/models.py` +- Modify: `backend/apps/accounts/permissions.py` +- Create: `backend/apps/accounts/menus.py` +- Create: `backend/apps/accounts/bootstrap.py` +- Create: `backend/apps/accounts/management/commands/bootstrap_governance.py` +- Create: `backend/apps/accounts/tests/test_bootstrap_governance.py` + +- [ ] **Step 1: Write failing bootstrap test** + +Create `backend/apps/accounts/tests/test_bootstrap_governance.py` with tests proving: + +```python +from django.contrib.auth import get_user_model +from django.contrib.auth.models import Group, Permission +from django.core.management import call_command + +from apps.accounts.models import MenuItem, UserGroup + + +def test_bootstrap_governance_seeds_admin_roles_groups_permissions_and_menus(db, settings): + settings.DJANGO_SUPERUSER_USERNAME = "admin" + settings.DJANGO_SUPERUSER_PASSWORD = "admin12345" + settings.DJANGO_SUPERUSER_EMAIL = "admin@example.com" + + call_command("bootstrap_governance") + call_command("bootstrap_governance") + + user = get_user_model().objects.get(username="admin") + assert user.is_superuser is True + assert user.check_password("admin12345") + assert Group.objects.filter(name="系统管理员").exists() + assert Permission.objects.filter(codename="system.user.manage").exists() + assert UserGroup.objects.filter(code="default").exists() + assert MenuItem.objects.filter(code="system.users", title="用户管理").exists() + assert MenuItem.objects.filter(code="system.roles", permission_code="system.role.view").exists() +``` + +- [ ] **Step 2: Run the test to verify RED** + +Run: + +```bash +cd backend +python -m pytest apps/accounts/tests/test_bootstrap_governance.py -v +``` + +Expected: fails because `MenuItem`, `UserGroup`, and `bootstrap_governance` do not exist. + +- [ ] **Step 3: Implement models, catalog, menus, bootstrap command** + +Implement: + +- `UserGroup` with `name`, `code`, `description`, `users`, `is_active`, timestamps. +- `MenuItem` with `code`, `title`, `path`, `icon`, `parent`, `sort_order`, `permission_code`, `is_visible`, `is_enabled`, timestamps. +- Chinese permission names and governance permission codes in `permissions.py`. +- Default role names in Chinese. +- Default menu catalog in `menus.py`. +- `bootstrap_governance()` service function and `bootstrap_governance` management command. + +- [ ] **Step 4: Make migrations and verify GREEN** + +Run: + +```bash +cd backend +python manage.py makemigrations accounts +python -m pytest apps/accounts/tests/test_bootstrap_governance.py -v +``` + +Expected: test passes. + +- [ ] **Step 5: Commit** + +```bash +git add backend/apps/accounts +git commit -m "feat: add governance bootstrap models" +``` + +## Task 2: Backend Auth And Current User APIs + +**Files:** +- Modify: `backend/config/settings/base.py` +- Modify: `backend/config/urls.py` +- Create: `backend/apps/accounts/auth.py` +- Modify: `backend/apps/accounts/schemas.py` +- Modify: `backend/apps/accounts/api.py` +- Create: `backend/apps/accounts/tests/test_auth_api.py` + +- [ ] **Step 1: Write failing auth API tests** + +Create `backend/apps/accounts/tests/test_auth_api.py` with tests for: + +```python +from django.contrib.auth import get_user_model +from django.contrib.auth.models import Group +from django.core.management import call_command + + +def test_login_me_and_logout_flow(client, db): + call_command("bootstrap_governance") + + login = client.post( + "/api/accounts/auth/login", + data={"username": "admin", "password": "admin12345"}, + content_type="application/json", + ) + assert login.status_code == 200 + assert login.json()["username"] == "admin" + + me = client.get("/api/accounts/auth/me") + assert me.status_code == 200 + payload = me.json() + assert payload["username"] == "admin" + assert "system.user.manage" in payload["permissions"] + assert any(menu["code"] == "system" for menu in payload["menus"]) + + logout = client.post("/api/accounts/auth/logout") + assert logout.status_code == 200 + assert client.get("/api/accounts/auth/me").status_code == 401 + + +def test_login_rejects_invalid_password(client, db): + get_user_model().objects.create_user(username="u", password="right") + + response = client.post( + "/api/accounts/auth/login", + data={"username": "u", "password": "wrong"}, + content_type="application/json", + ) + + assert response.status_code == 401 +``` + +- [ ] **Step 2: Run tests to verify RED** + +Run: + +```bash +cd backend +python -m pytest apps/accounts/tests/test_auth_api.py -v +``` + +Expected: fails because auth endpoints do not exist. + +- [ ] **Step 3: Implement session auth endpoints** + +Implement: + +- `GET /api/accounts/auth/csrf` +- `POST /api/accounts/auth/login` +- `POST /api/accounts/auth/logout` +- `GET /api/accounts/auth/me` +- `CORS_ALLOW_CREDENTIALS = True` +- `CSRF_TRUSTED_ORIGINS` env parsing + +- [ ] **Step 4: Verify GREEN** + +Run: + +```bash +cd backend +python -m pytest apps/accounts/tests/test_auth_api.py -v +``` + +Expected: tests pass. + +- [ ] **Step 5: Commit** + +```bash +git add backend/config backend/apps/accounts +git commit -m "feat: add session auth api" +``` + +## Task 3: Backend Governance CRUD APIs + +**Files:** +- Modify: `backend/apps/accounts/schemas.py` +- Modify: `backend/apps/accounts/api.py` +- Create: `backend/apps/accounts/tests/test_governance_api.py` + +- [ ] **Step 1: Write failing governance API tests** + +Tests must cover: + +- Admin lists users. +- Admin creates a user. +- Admin creates a user group and assigns members. +- Admin creates a role and assigns permissions. +- Admin lists menus and updates one menu permission. +- Anonymous calls to governance endpoints return 401. + +- [ ] **Step 2: Run tests to verify RED** + +Run: + +```bash +cd backend +python -m pytest apps/accounts/tests/test_governance_api.py -v +``` + +Expected: fails because CRUD endpoints do not exist. + +- [ ] **Step 3: Implement schemas and APIs** + +Implement `/api/accounts` endpoints: + +- `/users` +- `/users/{id}` +- `/users/{id}/reset-password` +- `/users/{id}/roles` +- `/users/{id}/user-groups` +- `/user-groups` +- `/user-groups/{id}` +- `/user-groups/{id}/members` +- `/roles` +- `/roles/{id}` +- `/roles/{id}/permissions` +- `/permissions` +- `/menus` +- `/menus/{id}` +- `/menus/reorder` + +- [ ] **Step 4: Verify GREEN** + +Run: + +```bash +cd backend +python -m pytest apps/accounts/tests/test_governance_api.py -v +``` + +Expected: tests pass. + +- [ ] **Step 5: Commit** + +```bash +git add backend/apps/accounts +git commit -m "feat: add governance management api" +``` + +## Task 4: Backend Permission Enforcement + +**Files:** +- Create: `backend/apps/accounts/auth.py` if not already created. +- Modify: `backend/apps/tickets/api.py` +- Modify: `backend/apps/solutions/api.py` +- Modify: `backend/apps/audit/api.py` +- Modify: existing ticket/solution/audit tests. +- Create: `backend/apps/accounts/tests/test_permission_enforcement.py` + +- [ ] **Step 1: Write failing permission enforcement tests** + +Tests must prove: + +- Anonymous ticket list is denied. +- User with `ticket.view` can list tickets. +- User without `ticket.create` cannot create tickets. +- User with `solution.view` can list solutions. +- User without `system.audit.view` cannot list audit logs. + +- [ ] **Step 2: Run tests to verify RED** + +Run: + +```bash +cd backend +python -m pytest apps/accounts/tests/test_permission_enforcement.py -v +``` + +Expected: fails because current APIs are public. + +- [ ] **Step 3: Implement helpers and protect APIs** + +Implement helpers: + +```python +require_login(request) +require_permission(request, "ticket.view") +``` + +Update routers: + +- `/api/system/health` remains public. +- tickets require ticket permissions. +- solutions require solution permissions. +- audit requires `system.audit.view`. +- governance endpoints use governance permissions. + +- [ ] **Step 4: Update existing tests to authenticate** + +Existing ticket/solution/audit API tests should create a superuser or assign required permissions before calling protected endpoints. + +- [ ] **Step 5: Verify backend API tests** + +Run: + +```bash +cd backend +python -m pytest apps/accounts/tests apps/tickets/tests apps/solutions/tests apps/audit/tests -v +``` + +Expected: tests pass. + +- [ ] **Step 6: Commit** + +```bash +git add backend/apps/accounts backend/apps/tickets backend/apps/solutions backend/apps/audit +git commit -m "feat: enforce api permissions" +``` + +## Task 5: Frontend Auth Shell And Permission Menus + +**Files:** +- Modify: `frontend/src/lib/api.ts` +- Create: `frontend/src/features/auth/types.ts` +- Create: `frontend/src/features/auth/api.ts` +- Create: `frontend/src/features/auth/AuthProvider.tsx` +- Create: `frontend/src/features/auth/LoginPage.tsx` +- Modify: `frontend/src/app/App.tsx` +- Modify: `frontend/src/app/layout/AppShell.tsx` +- Modify: `frontend/src/components/app/AppSidebar.tsx` +- Modify: `frontend/src/components/app/AppTopbar.tsx` + +- [ ] **Step 1: Add missing shadcn components** + +Run: + +```bash +cd frontend +npx shadcn@latest add alert checkbox switch pagination --yes +``` + +Then review generated files for Tailwind v3 compatibility. + +- [ ] **Step 2: Implement auth API client and provider** + +Implement: + +- CSRF fetch. +- login/logout/me calls. +- `AuthProvider`. +- `useAuth`. +- `apiRequest` sends `credentials: "include"` and CSRF token on unsafe methods. + +- [ ] **Step 3: Implement Chinese login page** + +`LoginPage` uses shadcn `Card`, `Input`, `Label`, `Button`, and `Alert`. + +Visible text must include: + +```text +AI 工单平台 +企业技术支持工作台 +账号 +密码 +登录 +``` + +- [ ] **Step 4: Gate app by auth state** + +Anonymous users see `LoginPage`. Authenticated users see `AppShell` and `Router`. + +- [ ] **Step 5: Make sidebar backend-driven** + +`AppSidebar` receives menu data from auth context. Keep local icon mapping with lucide icons. + +- [ ] **Step 6: Run frontend verification** + +Run: + +```bash +cd frontend +npm run typecheck +npm run build +``` + +Expected: both pass. + +- [ ] **Step 7: Commit** + +```bash +git add frontend/src frontend/components.json frontend/package.json frontend/package-lock.json +git commit -m "feat: add frontend auth shell" +``` + +## Task 6: Frontend System Governance Pages + +**Files:** +- Create: `frontend/src/features/system/types.ts` +- Create: `frontend/src/features/system/api.ts` +- Create: `frontend/src/features/system/SystemUsersPage.tsx` +- Create: `frontend/src/features/system/SystemUserGroupsPage.tsx` +- Create: `frontend/src/features/system/SystemRolesPage.tsx` +- Create: `frontend/src/features/system/SystemMenusPage.tsx` +- Create: `frontend/src/features/audit/AuditLogPage.tsx` +- Modify: `frontend/src/app/router.tsx` + +- [ ] **Step 1: Add system API client** + +Create typed API functions for users, user groups, roles, permissions, menus, and audit logs. + +- [ ] **Step 2: Add users page** + +`#/system/users` shows table columns: + +```text +用户名 +显示名称 +邮箱 +状态 +角色 +用户组 +操作 +``` + +Use Dialog or Sheet for create/edit. + +- [ ] **Step 3: Add user groups page** + +`#/system/user-groups` shows Chinese table and create/edit dialog. + +- [ ] **Step 4: Add roles page** + +`#/system/roles` shows role list and permission matrix grouped by module. + +- [ ] **Step 5: Add menus page** + +`#/system/menus` shows menu rows, required permission, visibility/enabled status, and edit dialog. + +- [ ] **Step 6: Add audit page** + +`#/audit` shows existing operation logs in a Chinese table. + +- [ ] **Step 7: Run frontend verification** + +Run: + +```bash +cd frontend +npm run typecheck +npm run build +``` + +Expected: both pass. + +- [ ] **Step 8: Commit** + +```bash +git add frontend/src/features/system frontend/src/features/audit frontend/src/app/router.tsx +git commit -m "feat: add system governance pages" +``` + +## Task 7: Deployment Bootstrap And Final Verification + +**Files:** +- Modify: `.env.example` +- Create: `infra/backend-entrypoint.sh` +- Modify: `infra/backend.Dockerfile` +- Modify: `infra/docker-compose.yml` +- Modify: `docs/development/local-setup.md` + +- [ ] **Step 1: Add environment defaults** + +Add admin bootstrap env vars to `.env.example`: + +```dotenv +DJANGO_SUPERUSER_USERNAME=admin +DJANGO_SUPERUSER_PASSWORD=admin12345 +DJANGO_SUPERUSER_EMAIL=admin@example.com +CSRF_TRUSTED_ORIGINS=http://localhost:5173,http://127.0.0.1:5173 +``` + +- [ ] **Step 2: Add backend entrypoint** + +Create `infra/backend-entrypoint.sh`: + +```sh +#!/bin/sh +set -e + +python manage.py migrate +python manage.py bootstrap_governance +exec "$@" +``` + +- [ ] **Step 3: Wire backend Dockerfile and compose** + +Backend service uses the entrypoint before running `runserver`. Worker can still start Celery after migrations are handled by backend. + +- [ ] **Step 4: Update setup docs** + +Document: + +- fresh Docker startup +- default login account +- production warning to override password + +- [ ] **Step 5: Run full verification** + +Run: + +```bash +cd backend +python -m pytest -v +python -m ruff check . + +cd ../frontend +npm run typecheck +npm run build +npx shadcn@latest info +``` + +Expected: all commands pass. + +- [ ] **Step 6: Verify compose config** + +Run: + +```bash +cd infra +docker compose --env-file ../.env.example config +``` + +Expected: config prints without errors. On this Windows host, use Docker Desktop's full docker executable path if `docker` is unavailable in shell PATH. + +- [ ] **Step 7: Browser smoke test** + +Start backend and frontend locally if feasible, then verify: + +- anonymous user sees login page +- admin can log in +- sidebar shows system governance menus +- `#/system/users`, `#/system/roles`, `#/system/menus`, `#/audit` render Chinese UI +- logout returns to login + +- [ ] **Step 8: Commit** + +```bash +git add .env.example infra docs/development +git commit -m "feat: add governance deployment bootstrap" +``` + +## Final Review Checklist + +- [ ] `bootstrap_governance` is idempotent. +- [ ] Login/logout/me APIs work. +- [ ] Frontend anonymous state shows login only. +- [ ] Sidebar menus are backend-driven. +- [ ] User/user-group/role/menu pages use shadcn/App components. +- [ ] Ticket/solution/audit/governance APIs enforce permissions. +- [ ] Docker startup can migrate and seed governance. +- [ ] Backend tests pass. +- [ ] Backend ruff passes. +- [ ] Frontend typecheck passes. +- [ ] Frontend build passes. +- [ ] shadcn info still reports Vite/Tailwind v3 and installed components.