Skip to main content

Site-Wide Control Matrix (Single Source of Truth)

Serves P2b "site-wide control closure". Update this table at the end of each wave.
Status: ✅ E2E/automation coverage exists · 🚧 open, pending closure · 🗑 trimmed/pending removal · 📋 deferred
Collection: run manually frontend/tests/e2e/control-inventory.spec.ts (skipped by default, not in CI).

Wave Index​

WaveScoperoadmap
W0HomeLayout / GroupLayout child route shells✅
W1Acquisition & session (login/register/logout/avatar)✅
W2Project surfaces (home / person / group / recent / new)✅
W3Designer core (model tree / relation diagram / project menu)✅
W4Version time machine (versions / work orders / approvals)✅
W5Import/export + data sources✅
W6Perimeter trim (dataDomain/query/ChatSQL/account/placeholders)✅

W0 — Layout Shell​

SurfaceControlExpected closureRelated flowStatusVerification
HomeLayoutChild route content areaRenders props.children; main content visible (not slogan only)Home routes such as /home✅layout-outlet.spec /home
HomeLayoutTop bar actionshomeRightContent (WeChat official account/GitHub); no SaveStatus / presence / read-only share/home✅layout-outlet.spec /home
GroupLayoutChild route content areaSame as above/project/group/setting/*✅layout-outlet.spec basic
DesignLayoutprops.childrenDesigner main area rendersCorrectly wired✅smoke / relation / loading

W1 — Acquisition & Session​

SurfaceControlExpected closureRelated flowStatusVerification
/loginSign-in buttonSuccess navigates to /home; invalid credentials show one clear messageJWT session✅smoke "invalid credentials" / "login→create"
/loginRegister linkNavigates to /registerConversion funnel✅session.spec "go to register"
/login AuthBrandShellSkip + Tab order + EnterFirst Skip "Skip to sign-in form" → form; username→password→sign in→footer; Enter submits; focus-visible; no trapADR-0016 keyboard facade✅session "login shell keyboard"
/login AuthBrandShellSecondary densityBrand/form pad ≤20×16; gap ∈[8,12]; header mb ∈[8,12]; form Title mt≤8; item mb∈[8,16]; controls ∈[24,32]; title ≥24; hero ≤180; ~40% panelADR-0016 density✅smoke "login page render"
/register AuthBrandShellSkip + Tab order + EnterFirst Skip "Skip to registration form" → form; field chain (tip out of order)→register→footer; Enter validates; focus-visible; no trapADR-0016 keyboard facade✅session "register shell keyboard"
/register AuthBrandShellSecondary densitySame as login: pad 20×16 + gap12 + header mb12 + form body 12/28; "go to register" + register keyboard densifyADR-0016 density✅session "go to register" + "register shell keyboard"
/s/* invalid gateSecondary densityBrand/form pad same as above; header mb ≤20; keyboard cases unchangedADR-0016 density✅share "invalid token"
/ LandingChromeSkip + Tab orderFirst Skip "Skip to main action" → #landing-main-cta; try demo→register→login; focus-visible surface; no trapADR-0016 keyboard facade✅landing "landing page keyboard"
/ LandingChromeSecondary densityBelow-fold section pad ≤52; comparison row ≤12; nav ≤20; footer ≤36; hero brand text ≥36 + full widthADR-0016 density✅landing "load visible brand"
/compare LandingChromeSkip + Tab orderSame shell Skip→ #landing-main-cta; open demo→self-host→back to home; surface focus-visible; no trapADR-0016 keyboard facade✅compare "compare page keyboard"
/compare LandingChromeSecondary densitycompare hero ≤36; section ≤52; comparison row ≤12; eyebrow ≥22; nav ≤20ADR-0016 density✅compare "load comparison table"
/s/* success meta/table listSecondary densitymeta ≤60 / gap≤2 / stage≤6; table list pad≤6·title≤12·row∈20–26; collapsed by defaultADR-0016 density✅demo "guest /demo"
Read-only share ModalSecondary density.erd-io-modal body≤8; hint mb≤8; link row mb≤10; input ~28; keyboard no regressionADR-0016 density✅share-project-keyboard
HomeLayout /homeSkip + Tab orderFirst Skip "Skip to main content" → #home-main-content; continue modeling→create→example→secondary entries→project cards; brand focus-visible; no trapADR-0016 keyboard facade✅home-keyboard "Home keyboard"
/home hero CTASecondary densityactions gap ≤8; secondary button pad ≤4×10; hero gap ≤24 / mb·pb ≤16; primary CTA ≥40; greeting text ≥28ADR-0016 density✅home-keyboard densify
/home empty state/announcementsSecondary densityempty state pad ≤24×12; secondary entry mb ≤16; project area mb ≤20; announcement pt ≤4 / row pad ≤4·gap ≤10 / title ≤13; CTA preservedADR-0016 density✅home-keyboard empty/announce densify
HomeLayout / GroupLayout outer wellSecondary densityshell/content pad ≤12×16; body ≤12×16; list empty state ≤12×8; forbid 24/20; Skip/top bar not weakenedADR-0016 density✅layout-outlet shell densify
/account/settings BaseViewSecondary densityform/avatar column gap ≤16 (narrow ≤12); forbid 24; form items/controls 28 unchanged; Skip/save not weakenedADR-0016 density✅account-settings densify
Three-shell top bar erd-chrome-actionsSecondary densityHome/Group/share gap ≤12; Design ≤8; forbid 16; top bar 64 / Skip·user menu not weakenedADR-0016 density✅layout-outlet densify
Three-shell top bar erd-chrome-headerSecondary densitypadX ≤16; brand–nav gap ≤12 (Design ≤8); forbid 20/16; top bar 64 / Skip not weakenedADR-0016 density✅layout-outlet densify
Home horizontal nav MenuSecondary densityitem padX ∈[8,12]; item height 64; hit width ≥44; forbid padX16; Skip/keyboard not weakenedADR-0016 density✅layout-outlet + home-keyboard
Group sidebar nav MenuSecondary densityitem height ∈[28,32]; padX ∈[8,12]; marginY ≤4; forbid height40/pad24; Skip/keyboard not weakenedADR-0016 density✅layout-outlet + group-keyboard
DesignLayout sidebar nav MenuSecondary densityitem height ∈[28,32]; padX ∈[8,12]; marginY ≤4; forbid height40/pad24; version/import/export/settings same source; menuitem keyboard not weakenedADR-0016 density✅layout-outlet densify + sidebar keyboard
Project list toolbarFragment densitySpace gap ∈[8,12]; search/button height ≤28; toolbar height ≤32; forbid Search default 32; keyboard not weakenedADR-0016 density✅project-surface densify + project-list-keyboard
/project/notice announcement rowFragment density.project-list-page__notice-row gap ∈[8,12] (target 8); row pad ≤4×8; forbid gap12; toolbar not weakenedADR-0016 density✅project-notice densify
Canvas empty-state CTA .erd-empty-ctaFragment densitypad ∈[8,12] (target 10×12); primary CTA hit ∈[26,28]; forbid 14×18; Auth logo / welcome pad not weakenedADR-0016 density✅relation "empty state layout"
Canvas empty-state silhouette ErdEmptyDiagram compactFragment densitywidth 112 (was 132); ∈[96,120]; forbid ≥132; hero 176 / Auth logo / welcome pad not weakenedADR-0016 density✅relation "empty state layout"
Canvas empty-state panel .erd-empty-panelFragment densitymt ≈ min(8vh,64) and ∈[32,64]; forbid min(10vh,88); CTA pad / Auth logo / welcome pad not weakenedADR-0016 density✅relation "empty state layout"
Canvas empty-state vertical rhythm title/descFragment densitytitle mt ≈8∈[6,10]; desc mb ≈12∈[8,12]; desc mt≤8; forbid legacy 16/18; Auth logo / welcome pad / CTA pad / panel top spacing not weakenedADR-0016 density✅relation "empty state layout"
Canvas empty-state secondary links .erd-empty-linksFragment densitymt ≈10∈[8,12]; Controls 22/pad0 already dense, unchanged; forbid links mt>12; Auth logo / welcome / CTA / panel / title·desc not weakenedADR-0016 density✅relation "empty state layout" + "Controls"
Team member toolbarFragment densitymb≤8; Space gap ∈[8,12]; search/button height ≤28; toolbar height ≤32; button padX∈[8,12]; forbid Search default 32 / mb16ADR-0016 density✅group-layout-nav densify + group-keyboard / add-user-keyboard
Group user-group page header/left role tabsFragment densitytitle ≤14·lh≤24·mb≤8·mt≤4; title→tab ≤12; left tab padX∈[8,12]·height∈[28,32]·text≤13; forbid Title level4 / Space large / padX24ADR-0016 density✅group-layout-nav densify + group-keyboard / add-user-keyboard
Group basic settings page headerFragment densitytitle ≤14·lh≤24·mb≤8·mt≤4; title→form ≤12; forbid Title level4ADR-0016 density✅group-basic-setting densify + group-layout-nav / group-keyboard
Group basic settings FormFragment densityitem mb∈[8,16] (target 12); Input/Select/button height∈[24,32] (target 28); label≤13; forbid antd default 24/32ADR-0016 density✅group-basic-setting densify + group-layout-nav / group-keyboard
Group basic settings delete zoneFragment densityDivider mt/mb∈[8,16] (target 12); body gap∈[4,12] (target 8); secondary text≤13/lh≤20; title mb≤2; forbid Divider24 + Space stacked mbADR-0016 density✅group-basic-setting densify + group-project-delete-keyboard
DesignLayout secondary paneFragment density.erd-secondary-pane pad ≤8×12; Steps mt/mb ≤10/12; settings hint mb ≤8; SyncConfig→.erd-io-modal; forbid 16/24 StepsADR-0016 density✅designer-secondary-pane densify
Import/export Modal StepsSecondary density alignment.erd-io-modal__steps mt/mb ≤10/12; title ≤13; same tier as secondary pane; keyboard no regressionADR-0016 density✅reverse-database-keyboard + export-ddl-keyboard densify
Import/export Modal header/body/footerFragment density.erd-io-modal header/body/footer pad ≤8×12 (forbid header 10×14×8 / footer 8×14 / body 12×14); title ≤14·lh≥20; footer buttons ≥28; keyboard no regressionADR-0016 density✅dbml-import + dbml-export densify
EntityModal header/body/footerFragment density.erd-entity-modal header/body/footer pad ≤8×12; width≤420; title ≤14·lh≥20; input/OK ≥28; keyboard no regressionADR-0016 density✅relation "entity create modal density"
GroupLayout /project/group/setting/*Skip + Tab orderFirst Skip "Skip to main content" → #group-main-content; bypass top bar + sidebar; basic settings fields enter order; brand focus-visible; no trapADR-0016 keyboard facade✅group-keyboard "Group keyboard"
Project list /project/{person,recent,group}Row Enter / Tab actionsstretched link removes dead card; Enter opens designer; Tab row actions reversible; row :has inset brand focus-visible; no trapADR-0016 keyboard list✅project-list-keyboard
Project action modals create/edit/deleteOpen focus / Esc / Tab trapcreate→type; edit→project name; delete→"Yes"; Esc returns to trigger; focus cannot escape dialogADR-0016 keyboard modal✅project-action-modals-keyboard
Import/export modal DBMLOpen focus / Esc / Tab trapimport→DBML text; export→export model; Esc returns to empty-state CTA / project menu; focus cannot escape dialogADR-0016 keyboard modal✅import-export-keyboard
Import skip validation Modal.warningOpen focus / Esc·OK / Tab trapsecond import all skipped→focus "Got it"; Esc/OK returns to "Parse and import"ADR-0016 keyboard modal✅import-skip-warning-keyboard
Version action modals create/edit/delete/revertOpen focus / Esc / Tab trapcreate/edit latest→version number; edit non-latest→description; delete/revert→"Yes"; Esc returns to trigger; focus cannot escape dialogADR-0016 keyboard modal✅version-action-modals-keyboard
Version compare/detail diff ModalOpen focus / Esc / Tab trapcompare→"Initial version"; detail→"Export change list"; Esc returns to trigger; focus cannot escape dialogADR-0016 keyboard modal✅version-diff-keyboard
Sync config/rebuild version ModalOpen focus / Esc / Tab trapsync config→"Field increment"; rebuild version→"Version number"; Esc returns to trigger; focus cannot escape dialogADR-0016 keyboard modal✅version-sync-rebuild-keyboard
Rebuild baseline second confirmationOpen focus / Esc / Tab trapfocus "Rebuild"; Esc cancels without persisting, returns to "Rebuild version" button; focus cannot escape dialogADR-0016 keyboard modal✅version-rebuild-confirm-keyboard
Initialize baseline ModalOpen focus / Esc / Tab trapfocus "Version number"; Esc returns to trigger; focus cannot escape dialogADR-0016 keyboard modal✅version-init-keyboard
Duplicate ModalOpen focus / Esc / Tab trapfocus "Project name"; Esc returns to trigger; focus cannot escape dialogADR-0016 keyboard modal✅project-copy-keyboard
Data source settings ModalOpen focus / Esc / Tab trapfocus "Add data source"; Esc returns to "Project menu"; focus cannot escape dialogADR-0016 keyboard modal✅database-setup-keyboard
Default items settings ModalOpen focus / Esc / Tab trapfocus "Default fields" Tab; Esc returns to "Project menu"; focus cannot escape dialogADR-0016 keyboard modal✅default-setup-keyboard
Data source reverse parse ModalOpen focus / Esc / Tab trapfocus "Data source" Select; Esc returns to "Project menu"; focus cannot escape dialogADR-0016 keyboard modal✅reverse-database-keyboard
Export DDL ModalOpen focus / Esc / Tab trapfocus "Data source" Select; Esc returns to "Project menu"; focus cannot escape dialogADR-0016 keyboard modal✅export-ddl-keyboard
Parse ERD file ModalOpen focus / Esc / Tab trapfocus upload area "Select ERD file"; Esc returns to "Project menu"; focus cannot escape dialogADR-0016 keyboard modal✅reverse-erd-keyboard
Parse PdMan file ModalOpen focus / Esc / Tab trapfocus upload area "Select PdMan file"; Esc returns to "Project menu"; focus cannot escape dialogADR-0016 keyboard modal✅reverse-pdman-keyboard
Change password ModalOpen focus / Esc / Tab trapfocus "Password"; Esc returns to trigger; focus cannot escape dialogADR-0016 keyboard modal✅reset-password-keyboard
Change password failureBusiness code failure / retryreadable toast; failure keeps modal open; retry success closes modal; no stacked modalszero silent failure✅reset-password-failure
Sync config failureBusiness code failure / retryonly code===200 writes store + "Settings saved" closes modal; failure toast readable; modal stays open, retryablezero silent failure✅sync-config-failure
Default items settings failureBusiness code failure / retryonly code===200 writes store + "Settings saved" closes modal; failure toast readable; modal stays open, retryablezero silent failure✅default-setup-failure
Data source settings confirm failureBusiness code failure / retryonly PUT success "Saved successfully!" closes modal; failure toast readable; modal stays open, retryablezero silent failure✅database-setup-failure
EntityModal persist failureBusiness code failure / retryonly save code===200 writes store+toast+closes modal; failure toast readable; modal stays open, retryablezero silent failure✅entity-modal-failure
Canvas relation diagram modal persist failureBusiness code failure / retryonly save code===200 writes store+toast+closes modal; failure toast readable; modal stays open, retryablezero silent failure✅diagram-modal-failure
Canvas table header rename persist failureBusiness code failure / retryonly save code===200 writes store+exits edit; failure toast readable; draft/node id preserved, retryablezero silent failure✅table-rename-failure
Canvas create table/inline add field persist failureBusiness code failure / retryonly save code===200 adds to canvas/closes create edit; failure toast; no node or draft retryable; empty name toast/empty field CTA preservedzero silent failure✅canvas-create-field-failure
Canvas field rename/delete field persist failureBusiness code failure / retryonly save code===200 exits edit/removes row; failure toast; rename draft preserved; delete confirm modal keep (reject) can delete againzero silent failure✅canvas-field-rename-delete-failure
Canvas delete table persist failureBusiness code failure / retryonly save code===200 removes+"Table deleted successfully"; failure toast; node preserved; delete confirm modal keep (reject) can delete againzero silent failure✅canvas-delete-table-failure
Left tree delete model/relation diagram persist failureBusiness code failure / retryonly save code===200 removes+success toast; failure toast; tree/table preserved; delete confirm modal keep (reject) can delete againzero silent failure✅tree-delete-module-diagram-failure
Left tree cut/paste table persist failureBusiness code failure / retryonly save code===200 writes clipboard and remove/write+success toast; failure toast; no duplicate or table preserved; retryable; copy does not persistzero silent failure✅tree-cut-paste-failure
Canvas drag table coordinates persist failureBusiness code failure / retrycommitDiagramGeometry only save code===200 writes layout; failure toast; RF transform rolls back, can drag againzero silent failure✅canvas-drag-reposition-failure
Canvas align/auto-layout persist failureBusiness code failure / retryalignSelected/autoLayout→commitDiagramGeometry; failure toast; RF rolls back, can click againzero silent failure✅canvas-align-layout-failure
Frame rename/fit members persist failureBusiness code failure / retryrenameFrame/commitDiagramGeometry persist; failure toast; rename draft preserved; fit members RF+store rollback; retryablezero silent failure✅canvas-frame-rename-bounds-failure
Frame create/member add/remove persist failureBusiness code failure / retrycreateFrame/addFrameMembers/removeFrameMembers persist; failure toast; not added to canvas/members unchanged; add rejects close modal; retryablezero silent failure✅canvas-frame-members-failure
Canvas connect edge create association persist failureBusiness code failure / retryaddAssociation persist; failure toast; no edge added; can drag again to retryzero silent failure✅canvas-connect-edge-failure
Canvas change edge cardinality persist failureBusiness code failure / retryupdateAssociationRelation persist; failure toast; chip keeps original cardinality; can select again to retryzero silent failure✅canvas-cardinality-failure
Canvas edge FK metadataConstraint name / rules / failure retryupdateAssociationFkMeta persist; same old constraintName split edge sync rename; erd-edge-constraint-namezero silent failure✅canvas-fk-meta-edit
Canvas field meta persist failureBusiness code failure / retrytype/PK/NN/AI/hidden/browse PK: only save code===200 writes store; failure toast; edit draft rolls back; hidden does not exitzero silent failure✅canvas-field-meta-failure
Table design JExcel field meta persist failureBusiness code failure / retryfield tab PK/hidden etc.: only save code===200 writes store; failure toast + re-mount grid rolls back checkbox; retryable; canvas alignedzero silent failure✅jexcel-field-meta-failure
Table design index tab persist failureBusiness code failure / retryadd/unique checkbox etc.: only save code===200 writes store + success toast; failure toast + empty state/re-mount rollback; delete confirm failure rejects close; retryable; canvas UKzero silent failure✅jexcel-index-failure
Table design index tab fields/expressionText persist / failure rollback"Fields/expression*" semicolon mix → fields[]; business code failure re-mount rollback; success shows id;LOWER(…)zero silent failure✅index-expression-edit
Initiate SQL approval ModalOpen focus / Esc / Tab trapfocus "Approver"; Esc returns to trigger (parent detail still open); focus cannot escape dialogADR-0016 keyboard modal✅sql-approval-keyboard
Add member ModalOpen focus / Esc / Tab trapfocus "Select user"; Esc returns to trigger; focus cannot escape dialogADR-0016 keyboard modal✅add-user-keyboard
Add member invite failureBusiness code failure / retryreadable toast; failure keeps modal open; retry success closes modal; no stacked modalszero silent failure✅add-user-invite-failure
Version init/rebuild save failureBusiness code failure / retryinit failure keeps modal open, retryable; rebuild failure no fake success, no rebaselinezero silent failure✅version-save-failure
Read-only share create failureBusiness code failure / retryreadable toast; modal stays open; "Regenerate" retryable; no stacked modals; forbid disabled dead affordancezero silent failure✅share-create-failure
Read-only share ModalOpen focus / Esc / Tab trapfocus "Share link"; Esc returns to trigger; focus cannot escape dialogADR-0016 keyboard modal✅share-project-keyboard
Read-only share revoke confirmationOpen focus / Esc / Tab trapfocus "Revoke"; Esc cancels without revoking; outer share modal still open; focus returns to revoke button; focus cannot escape dialogADR-0016 keyboard modal✅share-revoke-keyboard
Team project delete confirmationOpen focus / Esc / Tab trapfocus "Delete"; Esc cancels without deleting; focus returns to "Delete team project"; focus cannot escape dialogADR-0016 keyboard modal✅group-project-delete-keyboard
Team member remove confirmationOpen focus / Esc / Tab trapfocus "Remove"; Esc cancels without removing; focus returns to "Remove member {username}"; focus cannot escape dialogADR-0016 keyboard modal✅group-user-remove-keyboard
Approval action confirmation (approve/reject/revoke/re-approve)Open focus / Esc / Tab trapfocus semantic OK; Esc cancels without persisting; focus returns to trigger; focus cannot escape dialogADR-0016 keyboard modal✅approval-action-keyboard
Approval/work order SQL detail Modal.infoOpen focus / Esc·OK / Tab trapfocus "Got it"; Esc/OK returns to "View SQL"; focus cannot escape dialogADR-0016 keyboard modal✅sql-detail-keyboard
Import skip validation Modal.warningOpen focus / Esc·OK / Tab trapfocus "Got it"; Esc/OK returns to "Parse and import"; focus cannot escape dialogADR-0016 keyboard modal✅import-skip-warning-keyboard
EntityModal create model/table/relation diagramOpen focus / Esc / Tab trapcreate model focus "Name"; create table focus "Parent model"; Esc returns to trigger; focus cannot escape dialogADR-0016 keyboard modal✅entity-modal-keyboard
Canvas create/rename relation diagram ModalOpen focus / Esc / Tab trapfocus "Relation diagram name"; Esc returns to trigger; focus cannot escape dialog; Esc disabled while submittingADR-0016 keyboard modal✅diagram-modal-keyboard
Canvas add to group ModalOpen focus / Esc / Tab trapfocus "Select group"; Esc returns to trigger; focus cannot escape dialogADR-0016 keyboard modal✅diagram-modal-keyboard (same product source)
Canvas delete table confirmationOpen focus / Esc / Tab trapfocus "Delete"; Esc cancels without deleting; focus returns to trigger; focus cannot escape dialogADR-0016 keyboard modal✅canvas-delete-table-keyboard
Canvas delete edge/delete group confirmationOpen focus / Esc / Tab trapfocus "Delete"; Esc cancels without deleting; focus returns to trigger; focus cannot escape dialogADR-0016 keyboard modal✅canvas-delete-edge-frame-keyboard
Canvas delete field confirmationOpen focus / Esc / Tab trapfocus "Delete"; Esc cancels without deleting; focus returns to trigger; focus cannot escape dialogADR-0016 keyboard modal✅canvas-delete-field-keyboard
Table design delete index confirmationOpen focus / Esc / Tab trapfocus "Delete"; Esc cancels without deleting; focus returns to trigger; focus cannot escape dialogADR-0016 keyboard modal✅table-index-delete-keyboard
JExcel toolbar delete row confirmationOpen focus / Esc / Tab trapfocus "Delete"; Esc cancels without deleting; focus returns to trigger; focus cannot escape dialogADR-0016 keyboard modal✅jexcel-toolbar-delete-keyboard
JExcel quick actions Modal.infoOpen focus / Esc / Tab trapfocus "Got it"; Esc/OK returns to "Quick actions"; focus cannot escape dialogADR-0016 keyboard modal✅jexcel-grid-keyboard
JExcel Escape backspaceEdit mode Esc / focus returnEsc discards cell draft; focus returns to jexcel-grid; tab stays open; forbid persist hidden textareaADR-0016 keyboard grid✅jexcel-grid-keyboard
Left tree delete model/table/relation diagram confirmationOpen focus / Esc / Tab trapfocus "Delete"; Esc cancels without deleting; focus returns to row "…actions"; focus cannot escape dialogADR-0016 keyboard modal✅tree-delete-keyboard
Data source settings delete confirmationOpen focus / Esc / Tab trapfocus "Delete"; Esc cancels without deleting; focus returns to row delete button; outer config modal still open; focus cannot escape confirm dialogADR-0016 keyboard modal✅database-setup-delete-keyboard
Workbench databaseConfig delete/batch delete confirmationOpen focus / Esc / Tab trapfocus "Delete"; Esc cancels without deleting; focus returns to row delete button/batch delete button; focus cannot escape dialogADR-0016 keyboard modal✅database-config-delete-keyboard
Version sync result Modal.success/warnOpen focus / Esc·OK / Tab trap; row bindingfocus "Got it"; Esc/OK returns to "Sync"; clicking row "Sync" does not depend on hover; focus cannot escape dialogADR-0016 keyboard modal✅version-sync-result-keyboard
Workbench databaseConfig DrawerOpen focus / Esc / Tab trapfocus "Connection name"; Esc returns to "New connection"/"Edit"; focus cannot escape dialogADR-0016 keyboard modal✅database-config-drawer-keyboard
/404 AuthBrandShell gateSkip + Tab orderFirst Skip "Skip to main action" → #exception-main-cta; open example→back to home; focus-visible brand; no trapADR-0016 keyboard facade✅not-found "404 shell keyboard"
/403 AuthBrandShell gateSkip + Tab orderSame as 404; deep link /403 reachableADR-0016 keyboard facade✅not-found "403 shell keyboard"
/s/:token invalid gateSkip + Tab orderFirst Skip "Skip to main action" → #exception-main-cta (share-invalid-gate); open example→back to home; focus-visible brand; no trapADR-0016 keyboard facade✅share "share invalid gate keyboard"
/registerRegister submitSuccess navigates to /home; may carry redirectshare autofork✅session.spec "register success"; share redirect
/demoRedirect→ /s/public-demo read-only diagram + copy CTAADR-0007✅demo.spec
/s/:tokenCopy to my projectNot logged in→register redirect; logged in→forkshare fork✅share.spec
Avatar menuAccount center→ /account/settings?selectKey=baseaccount✅session.spec
Avatar menuLicense info→ selectKey=identificationlicence✅session.spec
Avatar menuSign outcache.clear() returns to /loginlogout()✅session.spec
DesignLayout top barGitHub stars linkExternal link erdonline/erdonlinecommunity✅copy/link merged
DesignLayout top barShare buttonGenerates read-only linkADR-0007✅share.spec
DesignLayout top barCollaboration presenceVisible online listADR-0009✅presence.spec

W2 — Project Surfaces (HomeLayout menu + /project/*)​

HomeLayout main navigation​

SurfaceControlExpected closureRelated flowStatusVerification
HomeLayout menuHome→ /home main contentW0✅layout-outlet / project-surface
HomeLayout menuData models→ /dataModelsProject list alias surface✅project-surface
HomeLayout menuData query_defaultProps removed; route kept for experimental deep linksexec ignores selected DS✅home-data-query.spec
HomeLayout menuData sources→ /databaseConfigADR-0008 / W5✅project-surface / adr0008
HomeLayout menuCommunityExternal link GitHub Issuescommunity✅external link not tested

/home shortcuts​

SurfaceControlExpected closureRelated flowStatusVerification
/homeCreate model home-link-new-project→ /project/personEmpty-state create✅activation / project-activation
/homeExample project home-link-exampleCreates example and opens designer with tables30s activation✅activation.spec
/homeImport model→ /project/person (guided)Import in designer✅project-surface navigation same as person
/homeRecent projects→ /project/recent✅project-surface
/homePersonal projects→ /project/person✅project-surface / smoke
/homeTeam projects→ /project/group✅project-surface
/homeVIP/license badge→ account identification📋Avatar menu already covers identification

Project list routes​

SurfaceControlExpected closureRelated flowStatusVerification
/project/personEmpty state "Create"Modal→create→visible in listVIP/open-source unlimited count✅project-activation "create"
/project/personOne-click exampleExample opens designer✅project-activation / activation
/project/personProject card openOpens /design/table/model?projectId=Dead link fixed✅smoke "login→create→designer"
/project/personDelete projectAfter confirm, disappears from list; can create againcache✅smoke cleanup path
/project/recentList/openOpens recent project in designer✅project-surface
/project/groupTeam project list/openOpens designer or settingspermissions✅project-surface reachable; empty-projectjson
/project/groupEnter team settings→ /project/group/setting/basicGroupLayout✅layout-outlet
/project/noticeNotification listHome "More announcements"→readable list; failure toast; notice-row gap ≤8✅project-notice.spec
/project/new(whole page)redirect→/project/person; placeholder page removedW2 create goes through person✅project-surface
/dataModelsModel list entryEquivalent to project list, usable✅project-surface

W3 — Designer Core​

SurfaceControlExpected closureRelated flowStatusVerification
DesignLayout menuModel→ /design/table/modelRelation diagram✅relation / smoke
/design/table/modelTree "Relation diagram" tree-open-relationOpens canvas tabRF✅relation.spec
/design/table/modelEmpty-state create table CTATable node appears✅relation full journey
/design/table/modelInline fields/connect/guardsPersists after refresh; chnname/defaultValue inline; delete field second confirmation (× / selected Delete·Backspace)✅relation
/design/table/modelTable node "Index" canvas-open-indexDirect to table design index tab (aria-selected); can switch to fields then re-enter via canvas✅relation "canvas open index tab"
/design/table/modelIndex tab empty-state CTA index-empty-add"Add first index"→ seed row + grid; no blank screen✅relation "index tab empty-state CTA"
/design/table/modelFields tab empty-state CTA field-empty-add"Add first field"→ seed first defaultField / id + grid; no blank screen✅table-field-empty
/design/table/modelCanvas empty table fields CTA canvas-fields-empty"Add first field"→ inline create; after fields exist returns to "Add field"✅table-field-empty
/design/table/modelIndex tab add another row index-add-rowAfter index exists "+ Add another index"→ append seed row; no dead affordance✅relation "index tab add another row CTA"
/design/table/modelIndex tab delete index-delete-N"Delete index {name}"→ Modal confirm before delete; cancel preserves; delete all returns to empty-state CTA; keyboard initial focus/Esc/Tab trap✅relation "index tab delete second confirmation"+table-index-delete-keyboard
/design/table/modelJExcel toolbar delete jexcel-toolbar-remove"Delete selected rows"→ Modal confirm before deleteRow; cancel preserves; unselected toast; keyboard initial focus/Esc/Tab trap✅relation "JExcel toolbar delete second confirmation"+jexcel-toolbar-delete-keyboard
/design/table/modelJExcel toolbar/grid Tab order7 toolbar buttons Tab+Enter; jexcel-grid focusable; Shift+Tab no trap✅relation "toolbar Tab reachable"
/design/table/modelJExcel Escape backspace / quick actions ModalEdit mode Esc discards→focus back to jexcel-grid; quick actions focus "Got it"; Esc returns; Tab trapADR-0016 keyboard✅jexcel-grid-keyboard
/design/table/modelTable design fields tab draft write-backMissing name/typeName → toast + abort write-back; all-empty draft discardable; Esc stops grid✅relation "draft row not silently dropped"
/design/table/modelTable design index tab draft write-backMissing name/fields (incl. []/";" empty) → toast + abort write-back; Esc stops grid; re-enter index still there✅relation "index tab: draft row not silently dropped"
/design/table/modelTable node "Fields" canvas-open-fieldDirect to table design fields tab (aria-selected + table-field-edit); can switch to index then re-enter via canvas✅relation "canvas open fields tab"
/design/table/modelTable node "Metadata" canvas-open-codeDirect to table design metadata application tab (aria-selected + table-code-edit); can switch to fields then re-enter via canvas✅relation "canvas open metadata application tab"
/design/table/modelTable node "Triggers" canvas-open-triggerDirect to table design triggers tab (aria-selected + table-trigger-edit); can switch to fields then re-enter via canvas✅relation "canvas open triggers tab"
/design/table/modelTriggers tab edit existing rowRow "Edit" modal; structural change rebuilds DDL; persist-on-200; failure keeps modal open, retryable; focus namezero silent failure✅table-triggers edit / edit persist failure
/design/table/modelTable header ✎ renameName updates; chnname dual-column inline✅relation "rename" / "table header Chinese name"
/design/table/modelPK badge toggleCancel/restore✅relation "PK"
/design/table/modelTree delete tableSecond confirmation; confirm removeEntity persist:true (only save success removes); failure modal keep✅smoke cancel/confirm + canvas-delete-table-failure
/design/table/modelTree delete model/relation diagramSecond confirmation; confirm removeModule/removeDiagram persist:true; failure modal keep; cancel preserves✅multi-diagram "left tree delete relation diagram/model second confirmation"+tree-delete-module-diagram-failure
/design/table/modelTree cut/paste table·modelcut*/past* persist:true (only save success writes clipboard and remove/write); failure preserved; copy does not persist✅tree-cut-paste-failure
/design/table/modelCanvas drag table/drag frame coordinatescommitDiagramGeometry persist:true; only save success writes layout/bounds; failure RF rollback✅canvas-drag-reposition-failure
/design/table/modelCanvas align/auto-layoutcommitDiagramGeometry persist:true; only save success writes layout; failure RF rollback; fitView only on success✅canvas-align-layout-failure
/design/table/modelFrame rename/fit membersrenameFrame/commitDiagramGeometry persist; failure draft/RF rollback; "Members fitted" only on success✅canvas-frame-rename-bounds-failure
/design/table/modelFrame create/member add/removecreateFrame/add*Members/remove*Members persist; failure not added to canvas/members unchanged✅canvas-frame-members-failure
/design/table/modelDrag connect create associationaddAssociation persist; failure no edge, retryable✅canvas-connect-edge-failure + relation PK/FK
/design/table/modelChange edge cardinalityupdateAssociationRelation persist; failure keeps original cardinality, retryable✅canvas-cardinality-failure + relation PK/FK
/design/table/modelundo/redoCan undo canvas operationscanvasHistory✅relation full journey Meta+z
/design/table/modelDelete edgeDelete → Modal confirm then removeAssociation persist:true (only save success removes); failure modal keep; cancel preserves✅relation "canvas delete table/delete edge" "after delete edge refresh"+canvas-delete-edge-frame-failure
/design/table/modelCanvas delete tableDelete → Modal confirm then removeEntity persist:true (only save success removes); failure modal keep; cancel preserves; keyboard initial focus/Esc/Tab trap✅relation "canvas delete table/delete edge second confirmation"+canvas-delete-table-keyboard+canvas-delete-table-failure
/design/table/modelCanvas delete groupDelete → Modal confirm then removeFrame persist:true (only save success removes); failure modal keep; deletes frame only, not tables✅diagram-frame "delete group second confirmation"+canvas-delete-edge-frame-keyboard+canvas-delete-edge-frame-failure
DesignLayoutProject menu buttonDropdown opens✅project-menu.spec
Project menuAll projects→ /project/recent✅project-menu "all projects"
Project menuRecent projectsMax 5 items; current ✓; click other item switches designer✅project-menu "recent projects switchable"
Project menuVersion (moved to top bar)Top bar "Version"→ version management; no "Version" in menu✅project-menu "all projects…top bar version"
Project menuImport→three itemsModal opens; closing dropdown does not block✅project-menu "import"
Project menuExport→five itemsVisible; DDL opens✅project-menu "export"
Project menuSettings→data source settingsModal opensADR-0008✅project-menu "data source settings"
Project menuSettings→default items settingsOpens + save success message✅project-menu "default items"
DesignLayoutAutosave statusTop bar shows saving/saved; failure shows clickable "Save failed, click to retry" + single toast (offline no stacked modals)P1✅relation.spec "Saving…→Saved" + save-failure
DesignLayoutCommonTabs / table design tab barBar height ~24; tab padX≤8/gap≤4; inner tab gutter≤2; label/close button not clipped; Tab focus-visible; Cmd+1/2/3ADR-0016 density✅model-design-ux "table design three tabs" "table design inner tabs"
DesignLayoutCommonTabs tab bar keyboard←/→ roving + Enter activate; close aria-label=Close {table name}; close tab focus returns; focus-visible; inner tabs same patternADR-0016 keyboard facade✅common-tabs-keyboard
RF TableNodeFooter / empty table well chromeHeader pad≤6 / field minH20 already dense; add margin≤6 + minH≥22; open table design margin≤6×4 + btn minH≥22; empty table well pad≤6/gap≤4; NODE_FOOTER_H 28; persist no regressionADR-0016 density✅relation "PK/FK" + table-field-empty "canvas empty table"
DesignLayoutCommand palette/shortcutsCmd/Ctrl+K/F toggle; search table locate+highlight; ↑↓/aria-activedescendant; empty state "No matches" pad≤8×8 / list≤2; footer pad≤4×8; Esc returns; Tab trapRF CommandPalette✅relation.spec "command palette" + "search table locate"
DesignLayoutShortcut cheat sheet? / toolbar "?"→ aria dialog "Shortcuts"; includes Cmd+1/2/3 table design tabs; density maxH≤360 / list 2×4 / row padY≤6; Esc + close button focusable; mutually exclusive with command paletteRF ShortcutHelp✅relation.spec "shortcut cheat sheet"
DesignLayoutSkip navigationFirst Tab "Skip to model tree/main workspace"→ landmark focus; no trapfocus ring audit✅relation "designer Skip"
DesignLayoutLeft tree toolbar densityToolbar ≤32 / controls ∈24–28; icons not clipped; sider secondary density; create focus-visibleQueryTree toolbar + sider-inner✅model-design-ux "model tree"
DesignLayoutVersion list secondary densityToolbar controls ∈24–28; icons not clipped; token colors; create button focus-visible; keyboard modals no regressionversion-page toolbar/list✅version.spec "version list row density" + version-action-modals-keyboard
DesignLayoutVersion list empty well secondary densityEmpty state pad ≤12×8; forbid 16×12; preserve "Save first version" CTAversion-empty / list empty-text✅version.spec "can add version without data source"
DesignLayoutWork order/approval list densityTitle bar ~24; row pad 4×8; action buttons ∈22–28; icons not clipped; focus-visible; confirm keyboard no regressionapproval-workorder-page✅approval.spec "work order/approval list row density" + approval-action-keyboard
DesignLayoutSecondary pane table density (JExcel / version diff)JExcel toolbar ~24; header/row pad 4×8; icons not clipped; focus-visible; diff group header/row ~24 token colors; toolbar Tab / visual diff no regressionjexcel-root / version-diff-panel✅model-design-ux "table design JExcel row density" + relation "toolbar Tab" + version.spec diff
DesignLayoutMetadata application sub-tab densityCodeTab/DbTab bar ~24; labels not clipped; sub-tab Tab focus-visible; Cmd+1/2/3 no regressionerd-code-tab / erd-db-tab✅model-design-ux "metadata application sub-tabs" + relation "table design Cmd/Ctrl+1/2/3"
DesignLayoutTable design inner tab densityFields/index/metadata bar ~24; labels not clipped; inner tab Tab focus-visible; Cmd+1/2/3 no regressionerd-table-design__tabs / #tableNav✅model-design-ux "table design inner tabs" + relation "table design Cmd/Ctrl+1/2/3"
DesignLayoutTable design tab body content secondary densitySide/bottom pad 6/4; hint ~24; JExcel not clipped; metadata tip dense; empty field CTA / empty name toast preservederd-tab-body-pad / erd-meta-ddl-hint✅model-design-ux "table design tab body secondary density" + table-field-empty
DesignLayoutDesigner empty state secondary densityFallback forbid marginTop:100; fields/index Empty margin-block 0 + pad flush tab-body; preserve CTAerd-pane-empty / erd-table-*-empty✅model-design-ux "designer empty state secondary density" + table-field-empty
DesignLayoutWelcome empty state secondary densitypad 20×16; title 18/mt12·lh22; hero 176; reverse links + left tree create modelerd-welcome-empty / designer-welcome-empty(-inner)✅model-design-ux "welcome empty state secondary density"
DesignLayoutContext menu/tree action menu densityItem height ~28 (∈26–30); border-box + padY≤2; icons/copy not clipped; role=menuitem; arrow keys/Esc.erd-dense-menu✅model-design-ux "context menu/tree action menu density"
DesignLayoutLeft tree keyboard rovingSkip→↓ enter tree; arrow keys+Enter locate table/open relation; active brand ring; Tab into search no trapQueryTree.focusKeyboard + handleSelect✅relation "left tree keyboard roving"
RF TableNodeField browser Tab loopOnly selected table fields/add/open table design in order; inline micro button -1; no trap + focus-visiblekeyboard modeling✅relation "field browser Tab loop"
RF canvas chromeControls / toolbar Tab; MiniMap out of orderControls→toolbar; MiniMap tabindex=-1; Controls focus-visiblekeyboard chrome✅relation "canvas chrome Tab order"
RF MiniMapPanel chrome fragment spacing128×96 overview; margin ≈8∈[8,12]; sunken background; forbid RF margin15; Controls buttons/version toolbar unchangedADR-0016 density✅relation "MiniMap" + demo
RF Controls / toolbar PanelPanel chrome fragment spacingmargin ≈8∈[8,12] (forbid RF default 15); buttons≤22; aligned with MiniMap; version toolbar/edge labels unchangedADR-0016 density✅relation "Controls" + demo
Edge cardinality Select / Entity FormControl density lockSelect height≤28; item mb≤12; input/OK≤28; forbid revert to 32/24ADR-0016 density✅relation "PK/FK" + "entity create modal density"
RF node-level TabSelection gate; RF wrapper out of ordernodesFocusable/edgesFocusable=false; selected table/edge chip/Frame in orderkeyboard modeling✅relation "canvas node-level Tab"
/s/:token share shellSkip + Controls TabFirst Skip "Skip to relation diagram"→ stage; zoom in/out/fit reachable; MiniMap out of order; focus-visible; no trapADR-0016 keyboard facade✅share "share shell keyboard"
TableTabCmd/Ctrl+1/2/3Table design: fields / index / metadata application; does not intercept while typing; mounted only on table design tabTableTab activatePane✅relation "table design Cmd/Ctrl+1/2/3"
DesignLayoutLeft tree click table locateClick table → switch relation diagram + select + fitView + flash; does not open table designDataTable → pendingLocate + focusTable✅relation.spec "left tree click table"
ProjectSortMenuCreated time/last modifiedRemoved from Menu exportdead code🗑Code no longer exists (grep zero hits)
ProjectFilterMenuFilter1/Filter2Removed from Menu exportdead code🗑Code no longer exists (grep zero hits)
NavigationMenu(empty horizontal menu)Removed from Menu export🗑Code no longer exists (grep zero hits)

W4 — Version Time Machine​

SurfaceControlExpected closureRelated flowStatusVerification
DesignLayout menuVersion management→ /design/table/version/all✅project-menu / version / loading
/design/table/version/allAdd version (no data source)New version visible in listNorth Star✅version.spec "add"
/design/table/version/allBack to model→ /design/table/model?projectId=✅version.spec "back to model"
/design/table/version/allVersion detail diffAdd/delete/modify color-coded✅version.spec "diff"
/design/table/version/allRename/delete versionList updates+toast; latest version number change succeeds; duplicate number toast and modal stays openVersionHandle✅version.spec "rename and delete"
/design/table/version/allCompare versionsCompare result visible✅version.spec "visual diff" two-version compare (version-compare-btn→compare any version)
/design/table/version/allRevertPersists; model still reverted after refresh✅revert persists; version/approval green
DesignLayout menuMy work orders→ /design/table/version/order empty-state guide✅approval.spec
DesignLayout menuMy approvals→ .../approval empty-state guide✅approval.spec
/design/table/version/allTop bar "My work orders/My approvals"Direct to order/approval pageW3 slice 3✅approval.spec "submit work order entry"
/design/table/version/allVersion row "Submit work order"Team not synced row → detail "SQL approval" visibleW3 slice 3✅approval.spec "submit work order entry"
Work orders/approvalsSubmit→approve/reject full flowStatus change visiblerequires data✅approval.spec: API seed→UI reject toast→work order re-approve (approve=JDBC too heavy, not covered)
Work orders/approvalsApprove/reject/revoke/re-approve confirm keyboardFocus primary action; Esc does not persist; Tab trapADR-0016 keyboard modal✅approval-action-keyboard
Work orders/approvalsSQL detail Modal.info keyboardFocus "Got it"; Esc/OK returns to "View SQL"; Tab trapADR-0016 keyboard modal✅sql-detail-keyboard

W5 — Import/Export + Data Sources​

SurfaceControlExpected closureRelated flowStatusVerification
/design/table/import/reverseReverse parse submitTables enter modelADR-0006✅import-reverse.spec (MySQL reverse_demo)
/design/table/import/reverseParse failure readable + retrytoast/page copy; "Re-parse" restoresADR-0016 zero silent✅reverse-parse-failure (mock API)
/design/table/import/pdmanUpload PdManModel visible✅import-pdman.spec
/design/table/import/erdUpload ERDModel visible✅import-erd.spec
ReverseERWinParse ERWin fileComponent removed; menu not wiredstub🗑Code no longer exists (grep zero hits)
/design/table/export/commonExport MarkdownFile downloadno G6✅export.spec
/design/table/export/commonExport HTML/Word/ERDDownload or explicit failure✅export.spec HTML+ERD
/design/table/export/moreAdvanced export DDLWith source+tables can enter step 2ADR-0008✅project-menu "DDL step 2"
/design/table/export/moreDDL final step downloadProduces SQL file✅project-menu "DDL download"

/databaseConfig​

SurfaceControlExpected closureRelated flowStatusVerification
/databaseConfigCreate/save data sourcePOST dataSources; profile no passwordADR-0008✅adr0008-datasource.spec
/databaseConfigTest connectionSuccess/failure toast✅adr0008-datasource.spec "test connection"
/databaseConfigEdit/delete/batch deleteList updates+confirm; row inline aria✅adr0008-datasource "edit save + delete confirm"
/databaseConfigDelete/batch delete confirm keyboardFocus "Delete"; Esc cancels without deleting; Tab trapADR-0016 keyboard modal✅database-config-delete-keyboard
/databaseConfigCreate/edit Drawer keyboardFocus "Connection name"; Esc returns to trigger; Tab trapADR-0016 keyboard modal✅database-config-drawer-keyboard
/databaseConfigSync status buttonping + toast + badge update✅adr0008-datasource "sync status"
/databaseConfig top bar"Statistics" buttonRemoved (originally no onClick)dead affordance🗑Top bar has no such button (only form "Need help?" copy)
/databaseConfig top bar"Help" buttonRemoved (originally no onClick)dead affordance🗑Top bar has no such button (only form "Need help?" copy)

W6 — Perimeter & Account​

SurfaceControlExpected closureRelated flowStatusVerification
DesignLayout menuData domain_defaultProps removed; route kept for experimental pageweak North Star✅data-domain.spec; deep link see "experimental features"
DesignLayout menuQuery_defaultProps removed; route kept for experimental deep linksexec ignores selected DS✅design-query.spec
DesignLayout menuChat SQLSidebar hidden; route kept for experimental pageAI deferred✅W6 trim navigation
/design/dataDomainIn-page type domain treeExperimental; do not expand main journey closure📋Do not expand E2E editing
/design/table/queryIn-page run/scheduleExperimental; failure has toast; do not expand real DS SELECT📋Do not expand JDBC query console
/design/table/chatsqlIn-page send etc.Experimental; not North Star closure📋Do not expand model
/design/table/setting/defaultFieldDefault fields savetoast + new tables get default fields; only code===200; failure rollback retryable✅default-field.spec "edit save has toast"; default-field-failure
/design/table/setting/dataTypeLogical type dictionary CRUDadd/update/remove persist:true; only save code===200; failure modal keep✅datatype-domains-failure
/design/table/setting/dataTypeLogical type apply dialect mappingModal "Database dialect mapping" edits apply[code].type; enum buildEnumApply✅datatype-apply-ux
/design/table/setting/dataTypeCreate/edit type Modal keyboardFocus "Type name"; Esc returns to trigger; Tab trap; Esc disabled while submittingADR-0016 keyboard modal✅datatype-domains-keyboard
Project menu / import secondary paneERD·PdMan·DBML / data source reverse submitsetProjectJson/importReverseTable persist; only save code===200; failure does not write store✅import-erd-failure (file); import-reverse (happy)
Project menu→data source settingsSwitch default data source RadiosetDefaultDb only save code===200; failure toast+list rollback✅default-db-failure
Version row→revertConfirm revertOnly save code===200 writes store+"Revert successful" closes modal; failure toast; modal stays open retryable; forbid setModules first✅version-revert-failure
Default items settings→download templatedownloadWordTemplateOnly non-empty ZIP(PK) blob saves; empty/JSON error body toast, no fake .docx✅word-template-download-failure
Export file→export WordPOST /doc/gendocxSame docxBlobGate; empty/JSON/non-ZIP toast, no fake download✅word-gendocx-download-failure
/design/table/setting/defaultSystem default itemsSame as project menu default items✅project-menu "default items settings"
/dataQueryIn-page run/CRUDExperimental; failure has toast; do not expand real DS SELECT📋Do not expand JDBC query console
/account/settingsBasic profile savetoast✅account-settings.spec
/account/settingsShell keyboard Skip/TabSkip→main form; fields→save; focus-visible; no trapHomeLayout✅account-settings-keyboard.spec
/account/settings"Change avatar" UploadChanged to "Avatar upload not yet available" copy✅W6 remove fake upload
/account/settingsOther selectKey tabsSwitchable with content✅account-settings.spec avatar→security/identification
/project/group/setting/basicSave basic settingstoastGroupLayout/W0✅group-basic-setting.spec
/project/group/setting/permissionPermission group maintenanceMembers visibleaccess✅group-layout-nav "permission groups"
GroupLayout menuBack to project list→ /dataModels✅group-layout-nav "back/open"
GroupLayout menuOpen model→ designerprojectId✅group-layout-nav "back/open"
/*404 pageUnknown path friendly message✅not-found.spec

Other Covered Cross-Cutting Concerns​

SurfaceControlExpected closureRelated flowStatusVerification
Removed auth paths/login/success etc.No frontend page; backend unavailabledead code cleanup✅dead-auth-routes.spec
Canvas large projectViewport cullingOff-screen nodes not renderedperformance budget✅canvas-scale.spec
Collaboration syncRemote change toastinfo / warning + "Save version"→ version/all persist (≤1/min)ADR-0009✅sync-toast.spec (full path + throttle)
Loading skeletonList/designer/versionaria-busy + accessible name✅loading.spec
UX invariantsDead affordance/credentialsFull journey screenshots + assertions✅ux-audit.spec
Empty projectJSONTeam project add modelCan add model✅empty-projectjson.spec

Statistics (v1 initial)​

StatusRow count
✅93
🚧0
🗑6
📋6
Total105

📋 Deferred (not in this phase): forum external link, VIP badge, dataDomain / query / chatsql / dataQuery.
Vision loop: when matrix 🚧=0, prioritize actionable matrix 📋 or roadmap next 📋 (Issue seed / AI), see scripts/agent-loop-vision.prompt.md.