- CORS whitelist only allowed origin localhost:5173; browsers send Origin
on same-origin POST too, so every deployment on any other port/origin
got empty 403 on ALL POST/PUT/DELETE (curl tests masked it) - now
echoes any origin (bearer-token auth, no cookie CSRF surface)
- connection_tester pg DSN had a literal *** password placeholder - pg
connection test and query path could never authenticate
- instance detail endpoints (databases/tables/db-schema/table-detail)
ran MySQL SHOW statements against pg - added pg branches
(pg_database/pg_class/information_schema/pg_indexes, search_path
semantics, PRI detection); schema filter uses non-system schemas
- frontend normalizeDbType missed the literal 'postgresql' value so pg
instances were treated as mysql (backtick quoting, no column hints);
genSql no longer emits db.table prefix for pg (schema semantics)
- also: query page footer warnings condensed to a single line per db type
verified live: mysql table tree/context menu/preview-execute; pg table
tree/columns/PK, double-click preview with masking working (email/phone
masked), query history persisted
- list is_executor and ExecuteTicket both required an execute-step
approval record; tickets created without a workflow (default flow)
had none, so the execute button never appeared and the API returned
403 for everyone - admin/dba are now implicit executors (approved
status only, consistent in both list enrichment and execution check)
- status labels: pending/reviewing/approved were all shown as 审核中;
now 待初审/审批中/待执行 so the ready-to-execute state is visible
- verified end-to-end on test backend: create -> quick review dialog
with comment -> impact-summary execute confirm -> success, detail
page stage steps reach 完成 with execute result visible
- TicketStageSteps: status-driven stepper (opsx-sec pattern, active
derived from ticket status incl. rejected/failed/cancelled/rollback
terminal states) at top of ticket detail page
- QuickReviewDialog: inline approve/reject with optional comment for
list rows and detail dialog (reject prompts reason, notes terminal
semantics); replaces fixed-comment direct calls and alert() usage
- execute now requires impact-summary confirm (instance + database +
statement count) in both list and detail dialog
- DetailTimeline action keys aligned with backend values (created/
pending_review/approve/reject/executed/execution_failed) - icons and
colors were silently falling back before
- create page: removed dead scheduled_at field (backend never accepted
it), added rollback SQL collection (backend-supported), real priority
select, approval-flow preview showing bound workflow steps and
approvers once instance selected
- empty tickets state now embeds create CTA button
- RedisDetailPage split: key detail panel extracted to feature
component (996 -> 658 lines after formatter reflow; panel 377 lines)
New src/features/redis/keyBrowser/ shared by RedisDetailPage keys tab and
SchemaSidebar redis branch (both previously flat one-shot lists):
- keyTree: ':'-separated folder tree with recursive key counts, numeric
sort, exact-hit pinned at root, local key removal (no full refetch),
type color dots, readable TTL (45s/5m30s/2d5h)
- useRedisKeyBrowser: cursor state machine + request-sequence guard +
Map merge on load-more; setter-synced args (Enter right after typing
no longer races stale render), auto-search on db/instance change
- RedisKeyBrowser: enter-to-scan search bar (SCAN has cost - no debounce,
opsxdb-style) with clear button, effective type filter, load-more
button with cursor hint, '已全部加载' end state
- useRedisDbs: real db list from /redis/:id/dbs (cluster -> DB0 banner)
- RedisDetailPage: hash row edits now use field-level HSET/HDEL endpoint
(preserves other fields + TTL); delete/add update tree locally; CLI
output renders arrays/objects/errors properly
- SchemaSidebar: redis branch swaps to shared browser (compact mode,
inline detail preview + insert-command preserved), auto-switches to
Keys tab for redis instances
- vite dev proxy target overridable via API_PROXY_TARGET (local testing)
Browser-verified: 200/page with load-more (200->400->600), exact hit
badge, keyword auto-expand, key detail panel, queries sidebar
Root cause (pre-existing): user state initialized with default role
'developer' while JWT role restoration happened via render-phase setState
~1 render later; first guard pass evaluated tickets/workflow against the
developer writable-datasource gate and bounced admins to dashboard on
direct load.
Fix: initialize user state lazily from the JWT in one pass
(restoreUserFromToken) - first render already carries the correct role.
Verified in browser: direct loads of /tickets and /workflow stay put;
URL query state survives refresh; expired session redirects to
/login?redirect=<path> and login returns to the original page.
- remove shadcn HSL dual-track vars (523->416->~300 lines index.css);
tailwind semantic colors (border/background/card/primary/destructive/
popover/muted/accent) now bridge directly to var(--dg-*) tokens
- drop dead darkMode:['class'] config and inert dark: variants in kept
ui components; theme switching is data-theme based (4 themes intact)
- first-frame inline theme script in index.html (reads namespaced key
with legacy fallback, resolves system, sets color-scheme) - no flash
- consolidate duplicated db-type brand colors into lib/constants.ts
single source (dbTypeColorMap + dbTypeBrandColorMap, with pg/mongodb
aliases); instance health stroke now uses theme tokens
- verified via browser: dark #0d1117 / light #f5f6f8 both resolve,
tokens cascade correctly
- delete 4 dead pages (~2300 lines): Home, ConfigPlatformPage,
DataDictionaryPage, NotificationsPage (kept the live NotificationPage)
- delete 52 unused shadcn ui components (keep button/card/dialog in use;
re-generate via shadcn CLI when needed)
- delete App.css, SkeletonCard, empty shared/ and features engine dirs
- remove dead theme blocks (midnight-purple / orange-vitality) from index.css
- uninstall ~40 dead deps (echarts, sonner, next-themes, zod,
react-hook-form, unused radix packages, cmdk, vaul, ...)
- fix DEVELOPMENT.md drift: mock layer section rewritten to real API layer,
permission docs now point to menu.ts single source