Backend:
- Add ChangePasswordReq DTO with validation (current + new password)
- Add AuthService::change_password() method with credential verification,
password rehash, and token revocation
- Add POST /api/v1/auth/change-password endpoint with utoipa annotation
Frontend:
- Add changePassword() API function in auth.ts
- Add ChangePassword.tsx page with form validation and confirmation
- Add "修改密码" tab in Settings page
After password change, all refresh tokens are revoked and the user
is redirected to the login page.
- ErpModule trait hooks now accept db and event_bus parameters
- AuthModule.on_tenant_created: seeds default roles, permissions,
and admin user for new tenants using existing seed_tenant_auth()
- AuthModule.on_tenant_deleted: soft-deletes all users for the tenant
- Updated all other modules (config, workflow, message) to match
the new trait signature
- Add #[utoipa::path] annotations to all 70+ handler functions across
auth, config, workflow, and message modules
- Add IntoParams/ToSchema derives to Pagination, PaginatedResponse, ApiResponse
in erp-core, and MessageQuery/TemplateQuery in erp-message
- Collect all module paths into OpenAPI spec via AuthApiDoc, ConfigApiDoc,
WorkflowApiDoc, MessageApiDoc structs in erp-server main.rs
- Update openapi_spec handler to merge all module specs
- The /docs/openapi.json endpoint now returns complete API documentation
with all endpoints, request/response schemas, and security requirements
- Run cargo fmt on all Rust crates for consistent formatting
- Update CLAUDE.md with WASM plugin commands and dev.ps1 instructions
- Update wiki: add WASM plugin architecture, rewrite dev environment docs
- Minor frontend cleanup (unused imports)
- Replace non-existent PaletteOutlined with BgColorsOutlined
- Apply user's refined light/dark theme configuration with proper
color tokens, component overrides, and design system consistency
Phase A (P1 production blockers):
- A1: Apply IP rate limiting to public routes (login/refresh)
- A2: Publish domain events for workflow instance state transitions
(completed/suspended/resumed/terminated) via outbox pattern
- A3: Replace hardcoded nil UUID default tenant with dynamic DB lookup
- A4: Add GET /api/v1/audit-logs query endpoint with pagination
- A5: Enhance CORS wildcard warning for production environments
Phase B (P2 functional gaps):
- B1: Remove dead erp-common crate (zero references in codebase)
- B2: Refactor 5 settings pages to use typed API modules instead of
direct client calls; create api/themes.ts; delete dead errors.ts
- B3: Add resume/suspend buttons to InstanceMonitor page
- B4: Remove unused EventHandler trait from erp-core
- B5: Handle task.completed events in message module (send notifications)
- B6: Wire TimeoutChecker as 60s background task
- B7: Auto-skip ServiceTask nodes instead of crashing the process
- B8: Remove empty register_routes() from ErpModule trait and modules
Add domain_events migration and SeaORM entity. Modify EventBus::publish
to persist events before broadcasting (best-effort: DB failure logs
warning but still broadcasts in-memory). Update all 19 publish call
sites across 4 crates to pass db reference.
Add outbox relay background task that polls pending events every 5s
and re-broadcasts them, ensuring no events are lost on server restart.
Store Redis client in AppState instead of discarding it. Create
rate_limit middleware using Redis INCR + EXPIRE for fixed-window
counting. Apply user-based rate limiting (100 req/min) to all
protected routes. Graceful degradation when Redis is unavailable.
Add VersionMismatch error variant and check_version() helper to erp-core.
All 13 mutable entities now enforce version checking on update/delete:
- erp-auth: user, role, organization, department, position
- erp-config: dictionary, dictionary_item, menu, setting, numbering_rule
- erp-workflow: process_definition, process_instance, task
- erp-message: message, message_subscription
Update DTOs to expose version in responses and require version in update
requests. HTTP 409 Conflict returned on version mismatch.
- InstanceMonitor: add '流程图' button that opens ProcessViewer modal
with active node highlighting, loading flow definition via API
- PendingTasks: add '委派' button with delegate modal (UUID input),
wired to the existing delegateTask API function
- Both ProcessViewer component and delegateTask API were previously
dead code (never imported/called)
ServiceTask was accepted by the parser but fell through to the
wildcard branch in the executor, creating an active token that
never progresses. Now returns a clear error so users know the
feature is not yet implemented rather than debugging a stuck flow.
Add doc comments to distinguish the business version field (key-based
revision counter, currently fixed at 1) from the optimistic lock field
(version_field). Renaming requires a DB migration so deferred to later.
The delegate method was accepting any UUID as delegate_to without
verifying the target user belongs to the same tenant. This allowed
cross-tenant task delegation. Added raw SQL check against users table
to avoid cross-module dependency on erp-auth.
Replace hardcoded placeholder values with live data fetched from
/users, /roles, /workflow/instances, and message store unread count.
Uses Promise.allSettled for resilient parallel loading.
- Add POST /config/menus (create single menu)
- Add PUT /config/menus/{id} (update single menu)
- Add DELETE /config/menus/{id} (soft delete single menu)
- Frontend MenuConfig was calling individual CRUD routes that didn't exist,
causing 404 errors on all create/update/delete operations
- Fix frontend to correctly handle nested tree response from backend