- 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)
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.
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.
- Change all permission codes from colon (`:`) to dot (`.`) separator
to match handler require_permission() calls consistently
- Add missing user.list, role.list, permission.list, organization.list,
department.list, position.list permissions (handlers check for .list
but seeds only had :read)
- Add missing message module permissions (message.list, message.send,
message.template.list, message.template.create)
- Add missing setting.delete, numbering.delete permissions
- Fix workflow handlers: workflow: → workflow.
- Fix message handlers: message: → message.
- Update viewer role READ_PERM_INDICES for new permission list
This fixes a critical runtime bug where ALL permission checks in
erp-auth and erp-config handlers would return 403 Forbidden because
the seed data used colon separators but handlers checked for dots.
- Add missing version column to all message tables (migration + entities)
- Replace N+1 mark_all_read loop with single batch UPDATE query
- Fix NotificationList infinite re-render (extract queryFilter to stable ref)
- Fix NotificationPreferences dynamic import and remove unused Dayjs type
- Add Semaphore (max 8) to event listener for backpressure control
- Add /docs/openapi.json endpoint for API documentation
- Add permission check to unread_count handler
- Add version: Set(1) to all ActiveModel inserts
Security fixes:
- Add startup warning for default JWT secret in config
- Add enum validation for priority, recipient_type, channel fields
- Add pagination size cap (max 100) via safe_page_size()
- Return generic "权限不足" instead of specific permission names
Compilation fixes:
- Fix missing standard fields in ActiveModel for tokens/process_variables
- Fix migration imports for Statement/DatabaseBackend/Uuid
- Add version_field to process_definition ActiveModel
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- CORS: replace permissive() with configurable whitelist (default.toml)
- Auth store: synchronously restore state at creation to eliminate
flash-of-login-page on refresh
- MainLayout: menu highlight now tracks current route via useLocation
- Add extractErrorMessage() utility to reduce repeated error parsing
- Fix all clippy warnings across 4 crates (erp-auth, erp-config,
erp-workflow, erp-message): remove unnecessary casts, use div_ceil,
collapse nested ifs, reduce function arguments with DTOs
- Message module subscribes to workflow events (process_instance.started)
- Auto-generates notifications when workflows start
- Added started_by to workflow instance event payload
- Event listener runs as background tokio task
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>