create-bubbles 0.1.26 → 0.1.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (575) hide show
  1. package/dist/index.js +4 -4
  2. package/package.json +10 -2
  3. package/template-pnpm-vp-monorepo/.changeset/README.md +8 -0
  4. package/template-pnpm-vp-monorepo/.changeset/config.json +11 -0
  5. package/template-pnpm-vp-monorepo/.gitattributes +5 -0
  6. package/template-pnpm-vp-monorepo/.github/workflows/ci.yml +33 -0
  7. package/template-pnpm-vp-monorepo/.github/workflows/docs.yml +55 -0
  8. package/template-pnpm-vp-monorepo/.github/workflows/release.yml +54 -0
  9. package/template-pnpm-vp-monorepo/.vite-hooks/commit-msg +1 -0
  10. package/template-pnpm-vp-monorepo/.vite-hooks/pre-commit +1 -0
  11. package/template-pnpm-vp-monorepo/.vite-hooks/run.mjs +17 -0
  12. package/template-pnpm-vp-monorepo/.vscode/settings.json +23 -0
  13. package/{LICENSE → template-pnpm-vp-monorepo/LICENSE} +2 -2
  14. package/template-pnpm-vp-monorepo/README.md +93 -0
  15. package/template-pnpm-vp-monorepo/_gitignore +43 -0
  16. package/template-pnpm-vp-monorepo/apps/docs/.vitepress/config.mts +69 -0
  17. package/template-pnpm-vp-monorepo/apps/docs/guide/getting-started.md +70 -0
  18. package/template-pnpm-vp-monorepo/apps/docs/guide/release.md +73 -0
  19. package/template-pnpm-vp-monorepo/apps/docs/guide/workspace.md +84 -0
  20. package/template-pnpm-vp-monorepo/apps/docs/index.md +22 -0
  21. package/template-pnpm-vp-monorepo/apps/docs/package.json +23 -0
  22. package/template-pnpm-vp-monorepo/apps/docs/tsconfig.json +7 -0
  23. package/template-pnpm-vp-monorepo/apps/docs/vite.config.ts +12 -0
  24. package/template-pnpm-vp-monorepo/apps/playground/index.html +14 -0
  25. package/template-pnpm-vp-monorepo/apps/playground/package.json +24 -0
  26. package/template-pnpm-vp-monorepo/apps/playground/src/App.vue +214 -0
  27. package/template-pnpm-vp-monorepo/apps/playground/src/env.d.ts +6 -0
  28. package/template-pnpm-vp-monorepo/apps/playground/src/main.ts +6 -0
  29. package/template-pnpm-vp-monorepo/apps/playground/src/style.css +728 -0
  30. package/template-pnpm-vp-monorepo/apps/playground/tsconfig.json +10 -0
  31. package/template-pnpm-vp-monorepo/apps/playground/vite.config.ts +29 -0
  32. package/template-pnpm-vp-monorepo/commitlint.config.mjs +3 -0
  33. package/template-pnpm-vp-monorepo/eslint.config.mjs +22 -0
  34. package/template-pnpm-vp-monorepo/mise.toml +3 -0
  35. package/template-pnpm-vp-monorepo/package.json +40 -0
  36. package/template-pnpm-vp-monorepo/packages/utils/LICENSE +21 -0
  37. package/template-pnpm-vp-monorepo/packages/utils/README.md +26 -0
  38. package/template-pnpm-vp-monorepo/packages/utils/_gitignore +4 -0
  39. package/template-pnpm-vp-monorepo/packages/utils/package.json +42 -0
  40. package/template-pnpm-vp-monorepo/packages/utils/scripts/verify-package.mjs +127 -0
  41. package/template-pnpm-vp-monorepo/packages/utils/src/index.ts +12 -0
  42. package/template-pnpm-vp-monorepo/packages/utils/tests/consumer/commonjs.cts +20 -0
  43. package/template-pnpm-vp-monorepo/packages/utils/tests/consumer/esm.mts +20 -0
  44. package/template-pnpm-vp-monorepo/packages/utils/tests/consumer/tsconfig.json +10 -0
  45. package/template-pnpm-vp-monorepo/packages/utils/tests/index.test.ts +30 -0
  46. package/template-pnpm-vp-monorepo/packages/utils/tsconfig.json +4 -0
  47. package/template-pnpm-vp-monorepo/packages/utils/vite.config.ts +20 -0
  48. package/template-pnpm-vp-monorepo/pnpm-workspace.yaml +27 -0
  49. package/template-pnpm-vp-monorepo/tsconfig/base.json +22 -0
  50. package/template-pnpm-vp-monorepo/tsconfig/node.json +8 -0
  51. package/template-pnpm-vp-monorepo/tsconfig/vue.json +7 -0
  52. package/template-pnpm-vp-monorepo/tsconfig.json +4 -0
  53. package/template-pnpm-vp-monorepo/vite.config.ts +38 -0
  54. package/template-vp-monorepo-react-nestjs/.agents/rules//345/205/261/344/272/253/344/273/243/347/240/201.md +2 -2
  55. package/template-vp-monorepo-react-nestjs/.agents/rules//351/234/200/346/261/202/344/270/216/350/256/276/350/256/241/346/226/207/346/241/243.md +50 -0
  56. package/template-vp-monorepo-react-nestjs/.codegraph/.gitignore +5 -0
  57. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225/PRD.md +121 -0
  58. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225/ui/cleanup-empty-preview.png +0 -0
  59. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225/ui/company-created.png +0 -0
  60. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225/ui/login-desktop.png +0 -0
  61. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225/ui/member-role-assigned.png +0 -0
  62. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225/ui/permission-revoked.png +0 -0
  63. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225/ui/platform-menu-recovery.png +0 -0
  64. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225/ui/project-created.png +0 -0
  65. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225/ui/project-member-home.png +0 -0
  66. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225/ui/replacement-administrator.png +0 -0
  67. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225/ui/workspace-empty.png +0 -0
  68. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225//345/206/263/347/255/226/350/256/260/345/275/225.md +29 -0
  69. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225//345/211/215/347/253/257/344/272/244/346/216/245.md +74 -0
  70. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225//345/220/216/347/253/257/346/265/213/350/257/225/346/212/245/345/221/212.md +115 -0
  71. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225//346/212/200/346/234/257/345/245/221/347/272/246.md +580 -0
  72. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225//346/265/213/350/257/225/346/212/245/345/221/212.md +137 -0
  73. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225//346/265/213/350/257/225/350/257/201/346/215/256/browser.json +84 -0
  74. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225//346/265/213/350/257/225/350/257/201/346/215/256/http.json +108 -0
  75. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225//346/265/213/350/257/225/350/257/201/346/215/256/legacy-http.json +18 -0
  76. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225//346/265/213/350/257/225/350/257/201/346/215/256/legacy.json +24 -0
  77. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225//350/201/224/350/260/203/350/256/260/345/275/225.md +76 -0
  78. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225//350/277/220/350/241/214/350/257/264/346/230/216.md +117 -0
  79. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225//351/234/200/346/261/202/346/226/207/346/241/243.md +275 -0
  80. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//347/273/204/347/273/207/346/236/266/346/236/204//345/206/263/347/255/226/350/256/260/345/275/225.md +35 -0
  81. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//347/273/204/347/273/207/346/236/266/346/236/204//346/212/200/346/234/257/345/245/221/347/272/246.md +744 -0
  82. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//347/273/204/347/273/207/346/236/266/346/236/204//346/265/213/350/257/225/346/212/245/345/221/212.md +174 -0
  83. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//347/273/204/347/273/207/346/236/266/346/236/204//350/201/224/350/260/203/350/256/260/345/275/225.md +137 -0
  84. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//347/273/204/347/273/207/346/236/266/346/236/204//350/256/276/350/256/241/346/226/271/346/241/210.md +215 -0
  85. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//347/273/204/347/273/207/346/236/266/346/236/204//351/234/200/346/261/202/346/226/207/346/241/243.md +421 -0
  86. package/template-vp-monorepo-react-nestjs/.spaces/{server/05./344/270/212/344/274/240/346/224/271/351/200/240/346/226/271/346/241/210/README.md → 02./344/270/212/344/274/240/344/270/216/346/226/207/344/273/266//344/270/212/344/274/240/346/224/271/351/200/240//350/256/276/350/256/241/346/226/271/346/241/210.md} +13 -20
  87. package/template-vp-monorepo-react-nestjs/.spaces/{server/06./345/205/254/345/205/261/351/230/237/345/210/227/346/216/245/345/205/245/346/226/271/346/241/210//344/270/212/344/274/240/346/270/205/347/220/206.md → 02./344/270/212/344/274/240/344/270/216/346/226/207/344/273/266//344/270/212/344/274/240/346/270/205/347/220/206//350/256/276/350/256/241/346/226/271/346/241/210.md} +13 -8
  88. package/template-vp-monorepo-react-nestjs/.spaces/{server/04.upload.md → 02./344/270/212/344/274/240/344/270/216/346/226/207/344/273/266//345/210/206/347/211/207/344/270/212/344/274/240//345/256/236/346/226/275/346/225/231/347/250/213.md} +21 -18
  89. package/template-vp-monorepo-react-nestjs/.spaces/{server/06./345/205/254/345/205/261/351/230/237/345/210/227/346/216/245/345/205/245/346/226/271/346/241/210/README.md → 03./344/273/273/345/212/241/351/230/237/345/210/227//345/205/254/345/205/261/351/230/237/345/210/227//350/256/276/350/256/241/346/226/271/346/241/210.md} +13 -6
  90. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/accounts-mobile-320.png +0 -0
  91. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/accounts-mobile-360.png +0 -0
  92. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/accounts-mobile-390.png +0 -0
  93. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/companies-desktop-data.png +0 -0
  94. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/companies-desktop-empty.png +0 -0
  95. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/companies-mobile-320.png +0 -0
  96. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/companies-mobile-360.png +0 -0
  97. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/companies-mobile-390.png +0 -0
  98. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/company-create-dialog.png +0 -0
  99. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/company-projects-1440.png +0 -0
  100. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/company-projects-390.png +0 -0
  101. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/login-1440.png +0 -0
  102. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/login-390.png +0 -0
  103. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/project-home-1440.png +0 -0
  104. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/project-home-390.png +0 -0
  105. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/register-1440.png +0 -0
  106. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/register-390.png +0 -0
  107. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/workspaces-1440.png +0 -0
  108. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/workspaces-390.png +0 -0
  109. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/workspaces-empty.png +0 -0
  110. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273//345/267/245/345/205/267/fixtures.mjs +132 -0
  111. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273//345/267/245/345/205/267/visual-check.mjs +274 -0
  112. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273//346/265/213/350/257/225/350/257/201/346/215/256/visual-report.json +104 -0
  113. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273//351/252/214/350/257/201/350/257/264/346/230/216.md +25 -0
  114. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//344/272/244/344/273/230/350/256/260/345/275/225.md +21 -0
  115. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//345/217/221/345/270/203/350/257/204/344/274/260.md +93 -0
  116. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//345/267/245/345/205/267//350/277/220/350/241/214/346/227/266/345/217/221/345/270/203/346/243/200/346/237/245.mjs +340 -0
  117. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//346/265/213/350/257/225/346/212/245/345/221/212.md +41 -0
  118. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//346/265/213/350/257/225/350/257/201/346/215/256/cli-/346/211/253/346/217/217/350/276/271/347/225/214/comment-clean/catalog/en_US.json +4 -0
  119. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//346/265/213/350/257/225/350/257/201/346/215/256/cli-/346/211/253/346/217/217/350/276/271/347/225/214/comment-clean/i18n.config.mjs +9 -0
  120. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//346/265/213/350/257/225/350/257/201/346/215/256/cli-/346/211/253/346/217/217/350/276/271/347/225/214/comment-clean/report.json +16 -0
  121. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//346/265/213/350/257/225/350/257/201/346/215/256/cli-/346/211/253/346/217/217/350/276/271/347/225/214/comment-clean/source/app.ts +2 -0
  122. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//346/265/213/350/257/225/350/257/201/346/215/256/cli-/346/211/253/346/217/217/350/276/271/347/225/214/empty-scan/catalog/en_US.json +4 -0
  123. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//346/265/213/350/257/225/350/257/201/346/215/256/cli-/346/211/253/346/217/217/350/276/271/347/225/214/empty-scan/i18n.config.mjs +9 -0
  124. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//346/265/213/350/257/225/350/257/201/346/215/256/cli-/346/211/253/346/217/217/350/276/271/347/225/214/empty-scan/report.json +19 -0
  125. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//346/265/213/350/257/225/350/257/201/346/215/256/cli-/346/211/253/346/217/217/350/276/271/347/225/214/output.json +84 -0
  126. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//346/265/213/350/257/225/350/257/201/346/215/256/cli-/346/211/253/346/217/217/350/276/271/347/225/214//345/275/223/345/211/215/345/244/215/351/252/214.json +86 -0
  127. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//346/265/213/350/257/225/350/257/201/346/215/256/cli-/346/211/253/346/217/217/350/276/271/347/225/214//346/243/200/346/237/245/347/273/223/346/236/234.json +30 -0
  128. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//346/265/213/350/257/225/350/257/201/346/215/256/cli-/346/211/253/346/217/217/350/276/271/347/225/214//346/263/250/351/207/212/345/233/236/345/275/222.json +40 -0
  129. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//346/265/213/350/257/225/350/257/201/346/215/256//345/214/205/345/217/221/345/270/203/bubblesjs-i18n-core-0.0.0.tgz +0 -0
  130. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//346/265/213/350/257/225/350/257/201/346/215/256//345/214/205/345/217/221/345/270/203/bubblesjs-i18n-react-0.0.0.tgz +0 -0
  131. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//346/265/213/350/257/225/350/257/201/346/215/256//345/214/205/345/217/221/345/270/203/bubblesjs-i18n-vue-0.0.1.tgz +0 -0
  132. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//346/265/213/350/257/225/350/257/201/346/215/256//345/214/205/345/217/221/345/270/203//344/272/247/347/211/251/345/244/215/351/252/214.json +419 -0
  133. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//346/265/213/350/257/225/350/257/201/346/215/256//345/214/205/345/217/221/345/270/203//346/243/200/346/237/245/347/273/223/346/236/234.json +339 -0
  134. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//346/265/213/350/257/225/350/257/201/346/215/256//350/277/220/350/241/214/346/227/266/345/217/221/345/270/203/346/243/200/346/237/245.json +131 -0
  135. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//350/256/276/350/256/241/346/226/271/346/241/210.md +37 -0
  136. package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//351/234/200/346/261/202/346/226/207/346/241/243.md +42 -0
  137. package/template-vp-monorepo-react-nestjs/.spaces/05./350/277/220/350/241/214/347/273/264/346/212/244//345/271/263/345/217/260/346/223/215/344/275/234/346/211/213/345/206/214.md +397 -0
  138. package/template-vp-monorepo-react-nestjs/.spaces/05./350/277/220/350/241/214/347/273/264/346/212/244//346/225/260/346/215/256/345/272/223/350/277/201/347/247/273//345/244/207/344/273/275/backup.dump +0 -0
  139. package/template-vp-monorepo-react-nestjs/.spaces/05./350/277/220/350/241/214/347/273/264/346/212/244//346/225/260/346/215/256/345/272/223/350/277/201/347/247/273//345/244/207/344/273/275/export-dump.ps1 +34 -0
  140. package/template-vp-monorepo-react-nestjs/.spaces/05./350/277/220/350/241/214/347/273/264/346/212/244//346/225/260/346/215/256/345/272/223/350/277/201/347/247/273//345/244/207/344/273/275/restore-dump.ps1 +73 -0
  141. package/template-vp-monorepo-react-nestjs/.spaces/05./350/277/220/350/241/214/347/273/264/346/212/244//346/225/260/346/215/256/345/272/223/350/277/201/347/247/273//346/223/215/344/275/234/346/214/207/345/215/227.md +227 -0
  142. package/template-vp-monorepo-react-nestjs/.spaces/05./350/277/220/350/241/214/347/273/264/346/212/244//346/225/260/346/215/256/345/272/223/350/277/201/347/247/273//351/234/200/346/261/202/346/226/207/346/241/243.md +31 -0
  143. package/template-vp-monorepo-react-nestjs/.spaces/06./350/256/244/350/257/201/344/270/216/344/274/232/350/257/235//344/274/232/350/257/235/347/256/241/347/220/206//346/212/200/346/234/257/345/245/221/347/272/246.md +96 -0
  144. package/template-vp-monorepo-react-nestjs/.spaces/06./350/256/244/350/257/201/344/270/216/344/274/232/350/257/235//344/274/232/350/257/235/347/256/241/347/220/206//351/234/200/346/261/202/346/226/207/346/241/243.md +88 -0
  145. package/template-vp-monorepo-react-nestjs/.spaces/06./350/256/244/350/257/201/344/270/216/344/274/232/350/257/235//344/277/256/346/224/271/345/257/206/347/240/201/PRD.md +56 -0
  146. package/template-vp-monorepo-react-nestjs/.spaces/06./350/256/244/350/257/201/344/270/216/344/274/232/350/257/235//344/277/256/346/224/271/345/257/206/347/240/201//346/212/200/346/234/257/345/245/221/347/272/246.md +93 -0
  147. package/template-vp-monorepo-react-nestjs/.spaces/06./350/256/244/350/257/201/344/270/216/344/274/232/350/257/235//344/277/256/346/224/271/345/257/206/347/240/201//346/265/213/350/257/225/346/212/245/345/221/212.md +41 -0
  148. package/template-vp-monorepo-react-nestjs/.spaces/06./350/256/244/350/257/201/344/270/216/344/274/232/350/257/235//344/277/256/346/224/271/345/257/206/347/240/201//350/201/224/350/260/203/350/256/260/345/275/225.md +27 -0
  149. package/template-vp-monorepo-react-nestjs/.spaces/06./350/256/244/350/257/201/344/270/216/344/274/232/350/257/235//344/277/256/346/224/271/345/257/206/347/240/201//350/256/276/350/256/241/346/226/271/346/241/210.md +54 -0
  150. package/template-vp-monorepo-react-nestjs/.spaces/06./350/256/244/350/257/201/344/270/216/344/274/232/350/257/235//344/277/256/346/224/271/345/257/206/347/240/201//351/234/200/346/261/202/346/226/207/346/241/243.md +64 -0
  151. package/template-vp-monorepo-react-nestjs/.spaces/07.API/344/270/216/351/224/231/350/257/257//346/212/200/346/234/257/345/245/221/347/272/246.md +95 -0
  152. package/template-vp-monorepo-react-nestjs/.spaces/README.md +86 -0
  153. package/template-vp-monorepo-react-nestjs/.spaces//346/226/207/346/241/243/350/247/204/350/214/203.md +97 -0
  154. package/template-vp-monorepo-react-nestjs/AGENTS.md +12 -0
  155. package/template-vp-monorepo-react-nestjs/README.md +3 -27
  156. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/0002_enterprise_access.sql +182 -0
  157. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/0003_cute_killmonger.sql +357 -0
  158. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/0004_company-member-invitations.sql +25 -0
  159. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/0005_menu_svg_icons.sql +54 -0
  160. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/meta/0002_snapshot.json +1801 -0
  161. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/meta/0003_snapshot.json +3511 -0
  162. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/meta/0004_snapshot.json +3713 -0
  163. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/meta/_journal.json +29 -1
  164. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/rollback/0003_organization_backfill.sql +32 -0
  165. package/template-vp-monorepo-react-nestjs/apps/server/package.json +6 -4
  166. package/template-vp-monorepo-react-nestjs/apps/server/src/access-init.ts +45 -0
  167. package/template-vp-monorepo-react-nestjs/apps/server/src/app.controller.ts +3 -0
  168. package/template-vp-monorepo-react-nestjs/apps/server/src/app.module.ts +28 -5
  169. package/template-vp-monorepo-react-nestjs/apps/server/src/app.service.ts +3 -0
  170. package/template-vp-monorepo-react-nestjs/apps/server/src/common/adapters/fastify.adapter.ts +11 -0
  171. package/template-vp-monorepo-react-nestjs/apps/server/src/common/constants/session.constants.ts +9 -0
  172. package/template-vp-monorepo-react-nestjs/apps/server/src/common/decorators/access-policy.decorator.ts +18 -0
  173. package/template-vp-monorepo-react-nestjs/apps/server/src/common/decorators/current-auth.decorator.ts +4 -0
  174. package/template-vp-monorepo-react-nestjs/apps/server/src/common/decorators/public.decorator.ts +3 -0
  175. package/template-vp-monorepo-react-nestjs/apps/server/src/common/exceptions/app.exception.ts +9 -0
  176. package/template-vp-monorepo-react-nestjs/apps/server/src/common/filters/global-exception.filter.ts +38 -5
  177. package/template-vp-monorepo-react-nestjs/apps/server/src/common/security/password-security-event.ts +98 -0
  178. package/template-vp-monorepo-react-nestjs/apps/server/src/config/app.config.ts +3 -0
  179. package/template-vp-monorepo-react-nestjs/apps/server/src/config/database.config.ts +3 -0
  180. package/template-vp-monorepo-react-nestjs/apps/server/src/config/llm.config.ts +3 -0
  181. package/template-vp-monorepo-react-nestjs/apps/server/src/config/queue.config.ts +14 -0
  182. package/template-vp-monorepo-react-nestjs/apps/server/src/config/redis.config.ts +3 -0
  183. package/template-vp-monorepo-react-nestjs/apps/server/src/config/session.config.ts +7 -0
  184. package/template-vp-monorepo-react-nestjs/apps/server/src/config/storage.config.ts +9 -0
  185. package/template-vp-monorepo-react-nestjs/apps/server/src/database/access.schema.ts +394 -0
  186. package/template-vp-monorepo-react-nestjs/apps/server/src/database/db.module.ts +3 -0
  187. package/template-vp-monorepo-react-nestjs/apps/server/src/database/organization.schema.ts +453 -0
  188. package/template-vp-monorepo-react-nestjs/apps/server/src/database/schema.ts +6 -0
  189. package/template-vp-monorepo-react-nestjs/apps/server/src/main.ts +4 -0
  190. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/access-http.ts +29 -0
  191. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/access.errors.ts +130 -0
  192. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/access.guard.ts +63 -0
  193. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/access.module.ts +27 -0
  194. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/access.service.ts +441 -0
  195. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/access.store.ts +68 -0
  196. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/access.validation.ts +44 -0
  197. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/maintenance/permissions-cleanup.controller.ts +27 -0
  198. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/maintenance/permissions-cleanup.service.ts +260 -0
  199. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/maintenance/permissions-cleanup.validation.ts +7 -0
  200. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/roles/roles.controller.ts +80 -0
  201. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/roles/roles.service.ts +249 -0
  202. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/roles/roles.validation.ts +24 -0
  203. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/seed/access-seed.service.ts +183 -0
  204. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/workspaces/workspaces.controller.ts +28 -0
  205. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/workspaces/workspaces.service.ts +94 -0
  206. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/workspaces/workspaces.validation.ts +5 -0
  207. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/audit/audit.controller.ts +26 -0
  208. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/audit/audit.module.ts +11 -0
  209. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/audit/audit.service.ts +74 -0
  210. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/audit/audit.validation.ts +11 -0
  211. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/auth.controller.ts +25 -0
  212. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/auth.errors.ts +10 -0
  213. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/auth.module.ts +1 -1
  214. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/auth.repository.ts +60 -0
  215. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/auth.service.ts +69 -11
  216. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/dto/register.dto.ts +1 -1
  217. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/guards/session-auth.guard.ts +8 -0
  218. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/password/change-password.dto.ts +17 -0
  219. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/password.service.ts +6 -0
  220. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/session/session-store.service.ts +46 -0
  221. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/session/session-token.service.ts +12 -0
  222. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/session/session.script.ts +7 -1
  223. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/companies/companies.controller.ts +105 -0
  224. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/companies/companies.module.ts +12 -0
  225. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/companies/companies.service.ts +523 -0
  226. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/accounts/accounts.controller.ts +72 -0
  227. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/accounts/accounts.service.ts +154 -0
  228. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/accounts/accounts.validation.ts +8 -0
  229. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/accounts/password-reset/password-reset.service.ts +81 -0
  230. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/accounts/password-reset/reset-password.validation.ts +13 -0
  231. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/administrators/administrators.service.ts +116 -0
  232. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/administrators/administrators.validation.ts +1 -0
  233. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/invitations/company-member-invitations.controller.ts +69 -0
  234. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/invitations/member-invitation-acceptance.controller.ts +23 -0
  235. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/invitations/member-invitations.service.ts +344 -0
  236. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/invitations/member-invitations.validation.ts +23 -0
  237. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/members.controller.ts +88 -0
  238. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/members.module.ts +31 -0
  239. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/members.service.ts +573 -0
  240. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/members.validation.ts +19 -0
  241. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/menus/menus.controller.ts +56 -0
  242. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/menus/menus.module.ts +11 -0
  243. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/menus/menus.service.ts +230 -0
  244. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/menus/menus.validation.ts +30 -0
  245. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/candidates/global-account/global-account-candidates.controller.ts +35 -0
  246. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/candidates/global-account/global-account-candidates.service.ts +109 -0
  247. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/candidates/member-candidates.controller.ts +60 -0
  248. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/candidates/member-candidates.service.ts +939 -0
  249. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/initialization/project-organization-initialization.service.ts +189 -0
  250. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/organization.module.ts +34 -0
  251. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/organization.store.ts +150 -0
  252. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/organization.validation.ts +23 -0
  253. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/positions/positions.controller.ts +160 -0
  254. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/positions/positions.service.ts +636 -0
  255. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/templates/organization-templates.controller.ts +77 -0
  256. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/templates/organization-templates.service.ts +501 -0
  257. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/templates/organization-templates.store.ts +163 -0
  258. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/units/organization-units.controller.ts +187 -0
  259. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/units/organization-units.service.ts +947 -0
  260. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/projects/projects.controller.ts +94 -0
  261. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/projects/projects.module.ts +13 -0
  262. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/projects/projects.service.ts +369 -0
  263. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/queue-worker.bootstrap.ts +3 -0
  264. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/task-queue.contracts.ts +4 -0
  265. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/task-queue.module.ts +5 -0
  266. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/task-queue.processor.ts +13 -0
  267. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/task-queue.service.ts +9 -0
  268. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/db/db.controller.ts +9 -0
  269. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/db/db.service.ts +9 -0
  270. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/redis/redis.controller.ts +9 -0
  271. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/redis/redis.service.ts +18 -0
  272. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/dto/upload-params.dto.ts +1 -1
  273. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/storage/exact-size.transform.ts +14 -3
  274. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/storage/minio-storage.adapter.ts +37 -0
  275. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/storage/storage.port.ts +21 -0
  276. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.constants.ts +9 -0
  277. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.controller.ts +25 -0
  278. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.reponsitory.ts +27 -0
  279. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.service.ts +78 -0
  280. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/utils/object-key.ts +4 -0
  281. package/template-vp-monorepo-react-nestjs/apps/server/src/utils/server-address.ts +6 -0
  282. package/template-vp-monorepo-react-nestjs/apps/server/test/access/access-policy.spec.ts +95 -0
  283. package/template-vp-monorepo-react-nestjs/apps/server/test/access/access.integration.spec.ts +2250 -0
  284. package/template-vp-monorepo-react-nestjs/apps/server/test/access/member-onboarding.validation.spec.ts +78 -0
  285. package/template-vp-monorepo-react-nestjs/apps/server/test/auth/password/password-operations.spec.ts +433 -0
  286. package/template-vp-monorepo-react-nestjs/apps/server/test/auth/password/password.integration.spec.ts +300 -0
  287. package/template-vp-monorepo-react-nestjs/apps/server/test/error-catalog.spec.ts +6 -1
  288. package/template-vp-monorepo-react-nestjs/apps/server/test/menus.validation.spec.ts +28 -0
  289. package/template-vp-monorepo-react-nestjs/apps/server/test/organization/organization-domain.spec.ts +260 -0
  290. package/template-vp-monorepo-react-nestjs/apps/server/tsconfig.scripts.json +5 -0
  291. package/template-vp-monorepo-react-nestjs/apps/web/.agents/rules//347/273/204/344/273/266/345/244/215/347/224/250.md +7 -0
  292. package/template-vp-monorepo-react-nestjs/apps/web/.agents/rules//350/241/250/345/215/225/345/233/236/345/241/253.md +4 -0
  293. package/template-vp-monorepo-react-nestjs/apps/web/AGENTS.md +17 -8
  294. package/template-vp-monorepo-react-nestjs/apps/web/README.MD +36 -8
  295. package/template-vp-monorepo-react-nestjs/apps/web/index.html +2 -2
  296. package/template-vp-monorepo-react-nestjs/apps/web/package.json +1 -0
  297. package/template-vp-monorepo-react-nestjs/apps/web/src/App.tsx +19 -8
  298. package/template-vp-monorepo-react-nestjs/apps/web/src/api/auth.ts +14 -1
  299. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/accounts.svg +4 -0
  300. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/audit-log.svg +4 -0
  301. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/companies.svg +5 -0
  302. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/dashboard.svg +6 -0
  303. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/home.svg +4 -0
  304. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/members.svg +4 -0
  305. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/menu-item.svg +4 -0
  306. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/menus.svg +6 -0
  307. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/organization-template.svg +4 -0
  308. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/organization.svg +6 -0
  309. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/positions.svg +4 -0
  310. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/profile.svg +5 -0
  311. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/projects.svg +4 -0
  312. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/roles.svg +4 -0
  313. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Brand/Brand.module.css +125 -0
  314. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Brand/Brand.tsx +56 -0
  315. package/template-vp-monorepo-react-nestjs/apps/web/src/components/DraftProTable/DraftProTable.tsx +11 -5
  316. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Icon/SvgAsset/IconSelector.tsx +38 -0
  317. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Icon/SvgAsset/SvgAssetIcon.tsx +14 -0
  318. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Icon/SvgAsset/SvgAssetRegistry.ts +32 -0
  319. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Icon/SvgAsset/index.ts +10 -0
  320. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Icon/svg-icon/SvgIcon.tsx +0 -2
  321. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Loading/PageLoading.tsx +5 -1
  322. package/template-vp-monorepo-react-nestjs/apps/web/src/components/LocaleSwitch/LocaleSwitch.tsx +52 -0
  323. package/template-vp-monorepo-react-nestjs/apps/web/src/components/PasswordActions/ChangePasswordDialog.tsx +90 -0
  324. package/template-vp-monorepo-react-nestjs/apps/web/src/components/PasswordActions/PasswordFields.module.css +12 -0
  325. package/template-vp-monorepo-react-nestjs/apps/web/src/components/PasswordActions/PasswordFields.tsx +54 -0
  326. package/template-vp-monorepo-react-nestjs/apps/web/src/components/PasswordActions/ResetAccountPasswordDialog.tsx +100 -0
  327. package/template-vp-monorepo-react-nestjs/apps/web/src/components/PasswordActions/change-password-session.ts +13 -0
  328. package/template-vp-monorepo-react-nestjs/apps/web/src/components/RouteTransition/RouteTransition.css +60 -0
  329. package/template-vp-monorepo-react-nestjs/apps/web/src/components/RouteTransition/RouteTransition.tsx +44 -0
  330. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/BasicTableSelector/BasicTableSelector.tsx +218 -0
  331. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/BasicTableSelector/BasicTableSelectorSelection.ts +91 -0
  332. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/BasicTableSelector/BasicTableSelectorTypes.ts +60 -0
  333. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/BasicTableSelector/README.md +110 -0
  334. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/BasicTableSelector/index.ts +7 -0
  335. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/GlobalAccountSelect/GlobalAccountSelect.tsx +211 -0
  336. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/GlobalAccountSelect/GlobalAccountSelectTypes.ts +75 -0
  337. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/GlobalAccountSelect/README.md +35 -0
  338. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/GlobalAccountSelect/index.ts +9 -0
  339. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/OrganizationMemberSelector/OrganizationMemberBrowser.tsx +146 -0
  340. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/OrganizationMemberSelector/OrganizationMemberCandidateColumns.tsx +137 -0
  341. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/OrganizationMemberSelector/OrganizationMemberFilterPanel.tsx +209 -0
  342. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/OrganizationMemberSelector/OrganizationMemberSelector.tsx +196 -0
  343. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/OrganizationMemberSelector/OrganizationMemberSelectorTypes.ts +103 -0
  344. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/OrganizationMemberSelector/README.md +8 -0
  345. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/OrganizationMemberSelector/index.ts +13 -0
  346. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/README.md +13 -0
  347. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/index.ts +30 -0
  348. package/template-vp-monorepo-react-nestjs/apps/web/src/config/theme.ts +41 -9
  349. package/template-vp-monorepo-react-nestjs/apps/web/src/hooks/useLatestDialogRequest.ts +71 -0
  350. package/template-vp-monorepo-react-nestjs/apps/web/src/i18n/config.ts +40 -0
  351. package/template-vp-monorepo-react-nestjs/apps/web/src/i18n/index.ts +10 -0
  352. package/template-vp-monorepo-react-nestjs/apps/web/src/i18n/instance.ts +36 -0
  353. package/template-vp-monorepo-react-nestjs/apps/web/src/i18n/ui-locale.ts +30 -0
  354. package/template-vp-monorepo-react-nestjs/apps/web/src/layouts/{BasicLayout.tsx → BasicLayout/index.tsx} +42 -35
  355. package/template-vp-monorepo-react-nestjs/apps/web/src/layouts/WorkspaceLayout/components/WorkspaceNavigationBoundary.tsx +50 -0
  356. package/template-vp-monorepo-react-nestjs/apps/web/src/layouts/WorkspaceLayout/index.tsx +196 -0
  357. package/template-vp-monorepo-react-nestjs/apps/web/src/layouts/WorkspaceLayout/workspace-landing.css +119 -0
  358. package/template-vp-monorepo-react-nestjs/apps/web/src/layouts/WorkspaceLayout/workspace-surfaces.css +110 -0
  359. package/template-vp-monorepo-react-nestjs/apps/web/src/layouts/WorkspaceLayout/workspace.css +223 -0
  360. package/template-vp-monorepo-react-nestjs/apps/web/src/locales/en_US.json +639 -1
  361. package/template-vp-monorepo-react-nestjs/apps/web/src/locales/zh_CN.json +621 -1
  362. package/template-vp-monorepo-react-nestjs/apps/web/src/main.tsx +8 -2
  363. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/api.ts +226 -0
  364. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/audit.tsx +169 -0
  365. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/AdministratorDialog.tsx +128 -0
  366. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/CleanupDialog.tsx +140 -0
  367. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/CompanyHierarchyDialog.tsx +244 -0
  368. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/EntityFormDialog.tsx +285 -0
  369. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/EntitySelectors/index.ts +6 -0
  370. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/EntitySelectors/selector-requests.ts +59 -0
  371. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberAffiliations/MemberOrganizationsDialog.tsx +188 -0
  372. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberAffiliations/MemberPositionsDialog.tsx +116 -0
  373. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberAffiliations/affiliation-loaders.ts +18 -0
  374. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberAffiliations/index.ts +5 -0
  375. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberOnboarding/AddProjectMemberDialog.tsx +75 -0
  376. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberOnboarding/CompanyMemberInvitation/CompanyMemberInvitationDialog.tsx +246 -0
  377. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberOnboarding/CompanyMemberInvitation/InvitationRecordsTable.tsx +152 -0
  378. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberOnboarding/CompanyMemberInvitation/invitation-link.ts +9 -0
  379. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberOnboarding/MemberOnboardingActions.tsx +79 -0
  380. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberOnboarding/RegisterCompanyMember/RegisterCompanyMemberDialog.module.css +12 -0
  381. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberOnboarding/RegisterCompanyMember/RegisterCompanyMemberDialog.tsx +122 -0
  382. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberRolesDialog.tsx +80 -0
  383. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberTable/MemberTableColumns.tsx +234 -0
  384. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberTable/index.ts +2 -0
  385. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberTable/member-candidate-cache.ts +12 -0
  386. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MenuFormDialog.tsx +251 -0
  387. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/RoleFormDialog.tsx +73 -0
  388. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/RolePermissionsDialog.tsx +185 -0
  389. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/entities.tsx +268 -0
  390. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/home.tsx +67 -0
  391. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/members.tsx +310 -0
  392. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/menus/api.ts +74 -0
  393. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/menus/index.tsx +325 -0
  394. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/profile.tsx +160 -0
  395. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/roles.tsx +173 -0
  396. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/use-access.ts +35 -0
  397. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/error/404.tsx +20 -0
  398. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/error/error.tsx +42 -0
  399. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/i18n/index.tsx +20 -38
  400. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/components/ProjectFormDialog.tsx +46 -41
  401. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/config/columns.tsx +20 -15
  402. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/config/index.ts +32 -22
  403. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/components/DraftProjectFormDialog.tsx +41 -34
  404. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/config/columns.tsx +27 -20
  405. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/config/projects.ts +21 -13
  406. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/index.tsx +47 -27
  407. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/index.tsx +51 -36
  408. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/home/index.tsx +9 -6
  409. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/login/api.ts +3 -0
  410. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/login/index.tsx +62 -82
  411. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/login/login-form.css +199 -0
  412. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/login/login.css +146 -124
  413. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/member-invitations/accept.css +47 -0
  414. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/member-invitations/accept.tsx +143 -0
  415. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/member-invitations/api.ts +20 -0
  416. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/api.ts +91 -0
  417. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/MoveOrganizationUnitDialog.tsx +82 -0
  418. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationBrowser/OrganizationMemberColumns.tsx +87 -0
  419. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationBrowser/OrganizationMemberHeader.tsx +102 -0
  420. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationBrowser/OrganizationTreeModel.tsx +59 -0
  421. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationBrowser/OrganizationTreePanel.tsx +88 -0
  422. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationBrowser/index.ts +11 -0
  423. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationBrowser/organization-loaders.ts +47 -0
  424. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationBrowser/organization-member-filter-loaders.ts +187 -0
  425. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationMembersDialog.tsx +207 -0
  426. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationUnitDialog.tsx +110 -0
  427. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/index.tsx +258 -0
  428. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization-templates/api.ts +53 -0
  429. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization-templates/components/OrganizationTemplateDialog/TemplateDefinitionTabs.tsx +189 -0
  430. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization-templates/components/OrganizationTemplateDialog/index.tsx +135 -0
  431. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization-templates/components/OrganizationTemplateDialog/types.ts +25 -0
  432. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization-templates/index.tsx +201 -0
  433. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/positions/api.ts +81 -0
  434. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/positions/components/PositionFormDialog.tsx +86 -0
  435. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/positions/components/PositionMembersDialog.tsx +102 -0
  436. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/positions/index.tsx +198 -0
  437. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/positions/loaders.ts +35 -0
  438. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/register/api.ts +14 -0
  439. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/register/index.tsx +157 -0
  440. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/workspaces/api.ts +32 -0
  441. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/workspaces/index.tsx +146 -0
  442. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/workspaces/state.ts +24 -0
  443. package/template-vp-monorepo-react-nestjs/apps/web/src/router/AGENTS.MD +6 -0
  444. package/template-vp-monorepo-react-nestjs/apps/web/src/router/index.tsx +2 -46
  445. package/template-vp-monorepo-react-nestjs/apps/web/src/router/lazy-load/index.tsx +26 -0
  446. package/template-vp-monorepo-react-nestjs/apps/web/src/router/middleware/README.md +23 -0
  447. package/template-vp-monorepo-react-nestjs/apps/web/src/router/middleware/auth.ts +6 -0
  448. package/template-vp-monorepo-react-nestjs/apps/web/src/router/middleware/index.ts +4 -0
  449. package/template-vp-monorepo-react-nestjs/apps/web/src/router/middleware/workspace/access.ts +23 -0
  450. package/template-vp-monorepo-react-nestjs/apps/web/src/router/middleware/workspace/data.ts +55 -0
  451. package/template-vp-monorepo-react-nestjs/apps/web/src/router/middleware/workspace/entry.ts +52 -0
  452. package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/access/page.tsx +20 -0
  453. package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/auth.tsx +17 -0
  454. package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/company.tsx +30 -0
  455. package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/entry.tsx +20 -0
  456. package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/examples.tsx +23 -0
  457. package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/fallback.tsx +13 -0
  458. package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/index.tsx +32 -0
  459. package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/platform.tsx +27 -0
  460. package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/project.tsx +28 -0
  461. package/template-vp-monorepo-react-nestjs/apps/web/src/router/page-registry.tsx +94 -0
  462. package/template-vp-monorepo-react-nestjs/apps/web/src/styles/dream.css +34 -0
  463. package/template-vp-monorepo-react-nestjs/apps/web/src/styles/index.css +6 -0
  464. package/template-vp-monorepo-react-nestjs/apps/web/src/types/auto-imports.d.ts +26 -0
  465. package/template-vp-monorepo-react-nestjs/apps/web/src/utils/organization-assignment.ts +66 -0
  466. package/template-vp-monorepo-react-nestjs/apps/web/src/utils/request/core/index.ts +48 -13
  467. package/template-vp-monorepo-react-nestjs/apps/web/src/utils/request/core/utils.ts +5 -0
  468. package/template-vp-monorepo-react-nestjs/apps/web/src/utils/request/index.ts +7 -2
  469. package/template-vp-monorepo-react-nestjs/apps/web/src/utils/request/workspace.ts +82 -0
  470. package/template-vp-monorepo-react-nestjs/apps/web/src/utils/safe-next.ts +36 -0
  471. package/template-vp-monorepo-react-nestjs/apps/web/src/utils/storage/cookie.ts +1 -0
  472. package/template-vp-monorepo-react-nestjs/apps/web/src/utils/storage/session.ts +1 -0
  473. package/template-vp-monorepo-react-nestjs/apps/web/test/i18n-locale.spec.ts +22 -0
  474. package/template-vp-monorepo-react-nestjs/apps/web/test/icon-selector.spec.tsx +23 -0
  475. package/template-vp-monorepo-react-nestjs/apps/web/test/latest-dialog-request.spec.ts +89 -0
  476. package/template-vp-monorepo-react-nestjs/apps/web/test/member-invitation-navigation.spec.ts +34 -0
  477. package/template-vp-monorepo-react-nestjs/apps/web/test/organization-assignment.spec.ts +137 -0
  478. package/template-vp-monorepo-react-nestjs/apps/web/test/password/password-actions.spec.ts +40 -0
  479. package/template-vp-monorepo-react-nestjs/apps/web/test/password/password-reset-action.spec.ts +66 -0
  480. package/template-vp-monorepo-react-nestjs/apps/web/test/password/workspaces-password-entry.spec.tsx +71 -0
  481. package/template-vp-monorepo-react-nestjs/apps/web/test/request.spec.ts +1 -0
  482. package/template-vp-monorepo-react-nestjs/apps/web/test/router/access.spec.ts +136 -0
  483. package/template-vp-monorepo-react-nestjs/apps/web/test/router/config.ts +140 -0
  484. package/template-vp-monorepo-react-nestjs/apps/web/test/router/entry.spec.ts +179 -0
  485. package/template-vp-monorepo-react-nestjs/apps/web/test/router/workspace-data.spec.ts +112 -0
  486. package/template-vp-monorepo-react-nestjs/apps/web/test/selector/global-account-select.spec.ts +311 -0
  487. package/template-vp-monorepo-react-nestjs/apps/web/test/selector/organization-member-selector.spec.ts +454 -0
  488. package/template-vp-monorepo-react-nestjs/apps/web/test/selector/selector-selection.spec.ts +132 -0
  489. package/template-vp-monorepo-react-nestjs/apps/web/test/storage.spec.ts +1 -0
  490. package/template-vp-monorepo-react-nestjs/apps/web/test/tsconfig.json +2 -2
  491. package/template-vp-monorepo-react-nestjs/apps/web/test/workspace-navigation-boundary.spec.tsx +169 -0
  492. package/template-vp-monorepo-react-nestjs/apps/web/test/workspace-navigation.spec.ts +105 -0
  493. package/template-vp-monorepo-react-nestjs/apps/web/test/workspace-requests.spec.ts +174 -0
  494. package/template-vp-monorepo-react-nestjs/apps/web/vite.config.ts +84 -35
  495. package/template-vp-monorepo-react-nestjs/apps/web-vue/package.json +2 -0
  496. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/api/index.ts +1 -0
  497. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/hooks/chart/useEcharts.ts +13 -1
  498. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/layout/default/header/index.vue +1 -0
  499. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/layout/default/index.vue +6 -2
  500. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/router/guard/index.ts +1 -0
  501. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/router/guard/permissionGuard.ts +1 -0
  502. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/router/index.ts +1 -0
  503. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/store/index.ts +1 -0
  504. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/store/modules/user.ts +1 -0
  505. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/types/auto-import.d.ts +2 -0
  506. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/utils/request/core/index.ts +30 -0
  507. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/utils/request/core/utils.ts +5 -0
  508. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/utils/request/index.ts +2 -0
  509. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/views/example/echart/config.ts +1 -0
  510. package/template-vp-monorepo-react-nestjs/apps/web-vue/tsconfig.tsbuildinfo +1 -1
  511. package/template-vp-monorepo-react-nestjs/package.json +1 -8
  512. package/template-vp-monorepo-react-nestjs/packages/i18n/cli/README.md +2 -0
  513. package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/command.ts +22 -2
  514. package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/config.ts +1 -0
  515. package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/files.ts +1 -0
  516. package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/load-config.ts +8 -0
  517. package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/report.ts +2 -0
  518. package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/scanner.test.ts +88 -0
  519. package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/scanner.ts +42 -8
  520. package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/sync.ts +12 -0
  521. package/template-vp-monorepo-react-nestjs/packages/i18n/cli/test/command.test.ts +37 -0
  522. package/template-vp-monorepo-react-nestjs/packages/i18n/cli/test/temporary-directory.ts +5 -0
  523. package/template-vp-monorepo-react-nestjs/packages/i18n/core/src/format.ts +1 -0
  524. package/template-vp-monorepo-react-nestjs/packages/i18n/core/src/i18n.ts +14 -0
  525. package/template-vp-monorepo-react-nestjs/packages/i18n/core/src/storage.ts +8 -0
  526. package/template-vp-monorepo-react-nestjs/packages/i18n/core/src/store.ts +9 -0
  527. package/template-vp-monorepo-react-nestjs/packages/i18n/react/src/index.tsx +5 -0
  528. package/template-vp-monorepo-react-nestjs/packages/i18n/react/src/use-store.ts +18 -5
  529. package/template-vp-monorepo-react-nestjs/packages/i18n/vue/src/index.ts +6 -0
  530. package/template-vp-monorepo-react-nestjs/packages/i18n/vue/src/use-store.ts +3 -0
  531. package/template-vp-monorepo-react-nestjs/packages/shared/package.json +5 -1
  532. package/template-vp-monorepo-react-nestjs/packages/shared/src/index.ts +2 -13
  533. package/template-vp-monorepo-react-nestjs/packages/shared/src/types/access-maintenance.ts +68 -0
  534. package/template-vp-monorepo-react-nestjs/packages/shared/src/types/access-menus.ts +94 -0
  535. package/template-vp-monorepo-react-nestjs/packages/shared/src/types/access-resources.ts +168 -0
  536. package/template-vp-monorepo-react-nestjs/packages/shared/src/types/access.ts +71 -0
  537. package/template-vp-monorepo-react-nestjs/packages/shared/src/types/auth.ts +23 -0
  538. package/template-vp-monorepo-react-nestjs/packages/shared/src/types/index.ts +9 -0
  539. package/template-vp-monorepo-react-nestjs/packages/shared/src/types/organization/models.ts +361 -0
  540. package/template-vp-monorepo-react-nestjs/packages/shared/src/utils/access-catalog.ts +304 -0
  541. package/template-vp-monorepo-react-nestjs/packages/shared/src/utils/access-scope.ts +97 -0
  542. package/template-vp-monorepo-react-nestjs/packages/shared/src/utils/account.ts +1 -0
  543. package/template-vp-monorepo-react-nestjs/packages/shared/src/utils/index.ts +65 -0
  544. package/template-vp-monorepo-react-nestjs/packages/shared/src/utils/organization/contracts.ts +237 -0
  545. package/template-vp-monorepo-react-nestjs/packages/shared/src/utils/record.ts +10 -0
  546. package/template-vp-monorepo-react-nestjs/packages/shared/src/utils/session-terminal.ts +1 -0
  547. package/template-vp-monorepo-react-nestjs/packages/shared/test/access.spec.ts +194 -0
  548. package/template-vp-monorepo-react-nestjs/packages/shared/test/organization.spec.ts +168 -0
  549. package/template-vp-monorepo-react-nestjs/pnpm-workspace.yaml +103 -69
  550. package/template-vp-monorepo-react-nestjs/scripts/enterprise-qa/browser.mjs +696 -0
  551. package/template-vp-monorepo-react-nestjs/scripts/enterprise-qa/http-support.mjs +105 -0
  552. package/template-vp-monorepo-react-nestjs/scripts/enterprise-qa/http.mjs +1091 -0
  553. package/template-vp-monorepo-react-nestjs/scripts/enterprise-qa/legacy-http.mjs +140 -0
  554. package/template-vp-monorepo-react-nestjs/scripts/enterprise-qa/legacy.mjs +196 -0
  555. package/template-vp-monorepo-react-nestjs/scripts/enterprise-qa/runtime.mjs +110 -0
  556. package/template-vp-monorepo-react-nestjs/scripts/with-enterprise-test-env.mjs +80 -0
  557. package/template-vp-monorepo-react-nestjs/src/types/auto-imports.d.ts +60 -0
  558. package/template-vp-monorepo-react-nestjs/tsconfig.lib.json +1 -1
  559. package/template-vp-react/package.json +12 -12
  560. package/template-vp-react/src/types/auto-imports.d.ts +2 -0
  561. package/template-vp-vue-eslint-vapor/.vscode/settings.json +53 -0
  562. package/template-vp-vue-eslint-vapor/package.json +21 -20
  563. package/template-vp-vue-eslint-vapor/pnpm-workspace.yaml +0 -24
  564. package/template-vp-vue-eslint-vapor/src/main.ts +2 -3
  565. package/template-vp-vue-eslint-vapor/vite.config.ts +26 -31
  566. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//351/234/200/346/261/202/346/226/207/346/241/243.md +0 -177
  567. package/template-vp-monorepo-react-nestjs/apps/web/src/layouts/BasicLayout.module.css +0 -17
  568. package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/.gitkeep +0 -0
  569. package/template-vp-react/.agents/rules/SVG/344/275/277/347/224/250.md +0 -8
  570. package/template-vp-react/.vscode/settings.json +0 -11
  571. package/template-vp-react/AGENTS.md +0 -11
  572. /package/{template-vp-vue-eslint-vapor → template-pnpm-vp-monorepo}/.vscode/extensions.json +0 -0
  573. /package/template-vp-monorepo-react-nestjs/apps/web/src/assets/{hero.png → image/hero.png} +0 -0
  574. /package/template-vp-monorepo-react-nestjs/apps/web/src/assets/{react.svg → svg/react.svg} +0 -0
  575. /package/template-vp-monorepo-react-nestjs/apps/web/src/assets/{vite.svg → svg/vite.svg} +0 -0
@@ -0,0 +1,744 @@
1
+ # 企业/项目组织架构、岗位与成员选择器实施契约
2
+
3
+ 契约状态:独立企业与组织架构主体已确认,进入实施同步阶段;企业邀请只确认产品入口,具体协议不属于现行契约。PRD 状态:部分确认。日期:2026-09-18。
4
+
5
+ 本文件是 [PRD](./需求文档.md) 已确认部分的前后端、共享类型、数据库和迁移单一真相源。用户于 2026-09-16 确认初版契约,并于 2026-09-17 明确平台下企业彼此独立及新的成员入口边界;最新决定覆盖初版中的企业间父子关系和完整账号添加成员设计。企业邀请当前只确认入口存在,任何业务或技术细节均须产品确认后才能写入本契约。实现发现会改变已确认业务语义的缺口时,必须先更新本契约并重新确认;前后端不得各自发明字段、端点或权限 key。
6
+
7
+ ## 1. 工程基线与实施边界
8
+
9
+ - 继续使用现有 `platform | company | project` 三种 `AccessScope`。平台下企业彼此独立,不新增企业类型或企业间父子关系;集团、事业群、分公司、部门等层级名称由单个企业内部的组织单元表达,不新增 group、organization 或 department 作用域。
10
+ - 共享 DTO、返回类型、枚举、权限目录和纯规范化方法统一放在 `packages/shared/src/types`、`packages/shared/src/utils` 并从既有入口导出;前端和后端不得复制第二份传输类型。
11
+ - 成功响应直接返回约定 JSON,不增加 `{ code, data }` 包装。失败沿用 `ApiFailure = { code, message, details? }`,并使用服务端 `request.id`/`x-request-id` 关联审计。
12
+ - GET 成功为 200,创建资源的 POST 成功为 201,其余写操作成功为 200。稳定资源没有 DELETE 端点;批量替换关系直接返回替换后的关系集合。
13
+ - Controller 接收 `unknown`,使用 Zod `strictObject` 拒绝未知字段;URL UUID 使用现有路由校验;作用域只从 URL 和登录上下文推导,不能相信请求体自报的 companyId、projectId 或 scope。
14
+ - 所有新增 Controller 显式声明 `@AccessPolicy`,未声明策略继续默认拒绝。鉴权顺序固定为登录与账号状态 → 作用域与成员资格 → 页面及操作权限 → 资源归属。
15
+ - 跨企业、跨项目、跨组织树 ID 与不存在 ID 统一返回 404;已确认处于当前作用域但缺少权限返回 403。
16
+ - 前端继续使用现有 alova 实例、页面旁 `api.ts`、React Router middleware、工作空间取消控制和 `cacheFor: 0, shareRequest: false` 的管理请求约定。
17
+ - 本期实现范围只包含 React Web、NestJS Server 和 shared;不改 `apps/web-vue`,不实现完整工作流。
18
+
19
+ ## 2. 共享类型与字段规范
20
+
21
+ ### 2.1 基础枚举与引用
22
+
23
+ ```ts
24
+ type OrganizationScope = Extract<AccessScope, { type: 'company' | 'project' }>
25
+ type OrganizationDuty = 'member' | 'leader' | 'deputy'
26
+ type ProjectOrganizationInitialization =
27
+ { mode: 'blank' } | { mode: 'template'; templateId: string; templateVersion: number }
28
+
29
+ interface OrganizationRelationInput {
30
+ organizationUnitId: string
31
+ duty: OrganizationDuty
32
+ }
33
+ ```
34
+
35
+ - 所有实体 ID 和 userId 均为 UUID 字符串;日期输出 ISO 8601 UTC 字符串。
36
+ - `sort` 是 `0~999999999` 的单个整数,不拆分主排序/细分排序,不接受小数。
37
+ - 所有稳定可编辑资源的 `version` 从 1 开始;写请求携带 `expectedVersion`,成功后版本加一。
38
+ - 名称等展示文本保存前只 `trim` 并保留大小写;需要唯一校验的名称和编码统一使用 `lower(NFKC(trim(value)))` 作为规范值,内部空白不折叠。所有公开 code DTO 先 trim 并按 ASCII 大小写字母/数字/下划线/短横线校验,再执行 `toLowerCase` 保存;因此新建或更新写入的 code 及其响应固定为小写,未被编辑的存量记录仍按原值展示,迁移不静默重写。新增表的 key 列由共享纯方法计算并写入,数据库再以 `lower(normalize(btrim(value), NFKC))` CHECK 校验原值与 key 一致;没有 key 列的既有 code 使用同一表达式函数索引,不能假设 PostgreSQL `lower()` 自动完成 NFKC。
39
+ - 公共规范化方法、树深度计算、作用域 URL 构造等非显然方法必须写 JSDoc;超过 3 个参数的方法使用对象参数。
40
+
41
+ ### 2.2 字段长度、格式与分页基线
42
+
43
+ | 字段 | 共享 DTO 规则 | 新表数据库规则 |
44
+ | ------------- | --------------------------------------------------------- | ------------------------------------------- |
45
+ | `name` | `trim` 后 2~100 个字符 | `varchar(100)`,并以 CHECK 保证长度下限 |
46
+ | `code` | trim 后 2~32 个字符,先接受 `^[A-Za-z0-9_-]+$`,再转小写 | `varchar(32)`,CHECK 保证长度、字符集和小写 |
47
+ | `description` | 可省略;`trim` 后 0~500 个字符,省略时保存为空字符串 | `varchar(500)`,默认空字符串 |
48
+ | `query` | 可省略;`trim` 后最多 100 个字符 | 不持久化 |
49
+ | `page` | 正整数,默认 1 | 不持久化 |
50
+ | `pageSize` | 1~100 的整数,默认 20 | 不持久化 |
51
+
52
+ - 上表的 `name`、`code`、`description` 统一适用于企业、项目、组织单元、岗位、组织模板及模板子项;shared 导出唯一一套基础 schema,各 Controller 组合复用,不得在前后端或模块内复制不同上限。
53
+ - 新增业务表的物理列宽与公开 DTO 上限一致。既有 `companies.name varchar(100)` 保持不变;既有 `companies.description/projects.description` 可继续使用 `text`,但公开写接口仍严格执行 500 字上限。
54
+ - 既有 `companies.code` 与 `projects.code` 当前为 `varchar(64)`,本期不缩短物理列,避免无意义重写和失败回滚;所有新旧公开写接口仍统一执行 32 字上限,不得因物理容量为 64 而放宽 API。
55
+ - migration 在任何 DDL 前预检存量企业和项目 code。只要 trim 后长度不在 2~32、字符不符合大小写 ASCII 字母/数字/下划线/短横线规则,或新规范键产生冲突,就立即停止迁移并输出记录 ID 供人工修复;禁止自动截断、改名、拼接后缀或静默转小写。存量 code 保留原展示值但参与不区分大小写的规范唯一校验;后续公开写入统一保存小写。企业 code 继续保持既有全局唯一,项目 code 继续保持企业内唯一。
56
+ - 所有数组筛选字段和 resolve 的 `userIds` 每类最多 100 个 UUID;字段一旦出现就必须至少 1 个且去重,空数组和重复项按请求校验失败处理。
57
+
58
+ ### 2.3 独立企业边界与企业创建
59
+
60
+ ```ts
61
+ interface CreateCompanyRequest {
62
+ name: string
63
+ code: string
64
+ description?: string
65
+ administratorUserId: string
66
+ }
67
+ ```
68
+
69
+ - 既有 `CompanyRecord`、`CompanyDetail`、`ProjectRecord extends CompanyRecord` 以及企业列表/详情/资料/状态响应保持原契约;本期不向企业模型新增父级、类型、排序或企业名称规范键字段。
70
+ - 平台继续使用既有企业列表管理彼此独立的企业,不新增企业树查询、父级选择、企业移动或层级摘要端点。
71
+ - 项目始终直接保存一个 `companyId`;组织树、岗位、成员、模板及权限校验均以该直接所属企业为边界,不产生跨企业继承或隐式归属。
72
+ - 创建企业仍以 `CompanyDetail` 返回;请求只把管理员标识从 `administratorAccount` 破坏性切换为 `administratorUserId`,不接受任何企业层级字段。
73
+
74
+ ### 2.4 组织树与组织单元
75
+
76
+ ```ts
77
+ interface OrganizationTreeRecord {
78
+ id: string
79
+ scope: OrganizationScope
80
+ parentId: string | null
81
+ units: OrganizationUnitNode[]
82
+ }
83
+
84
+ interface OrganizationTreeQuery {
85
+ parentId?: string
86
+ }
87
+
88
+ interface OrganizationUnitRecord {
89
+ id: string
90
+ treeId: string
91
+ parentId: string | null
92
+ name: string
93
+ code: string
94
+ description: string
95
+ sort: number
96
+ status: EntityStatus
97
+ version: number
98
+ depth: number
99
+ fullPath: string
100
+ createdAt: string
101
+ updatedAt: string
102
+ }
103
+
104
+ interface OrganizationUnitNode extends OrganizationUnitRecord {
105
+ effective: boolean
106
+ hasChildren: boolean
107
+ }
108
+
109
+ interface CreateOrganizationUnitRequest {
110
+ parentId?: string | null
111
+ name: string
112
+ code: string
113
+ description?: string
114
+ sort?: number
115
+ }
116
+
117
+ interface UpdateOrganizationUnitRequest extends VersionRequest {
118
+ name?: string
119
+ code?: string
120
+ description?: string
121
+ sort?: number
122
+ }
123
+
124
+ interface MoveOrganizationUnitRequest extends VersionRequest {
125
+ parentId: string | null
126
+ sort?: number
127
+ }
128
+ ```
129
+
130
+ - 企业/项目本身只作为 UI 虚拟根,不持久化根节点;真实顶级节点 `parentId = null` 且深度为 1。
131
+ - 树接口按父节点懒加载:查询省略 `parentId` 时返回顶级节点并在响应中写 `parentId = null`;传入 `parentId` 时只返回其直接子节点。每个节点以 `hasChildren` 表示是否还有可见直接子节点,不递归返回 `children`。
132
+ - 每棵树最多 10 层。创建、移动和模板复制都在事务锁内校验目标节点及完整子树深度。
133
+ - `code` 在单棵树内规范化唯一;`name` 在同一父级下规范化唯一,不同分支允许同名。
134
+ - `fullPath`、`depth`、`effective` 是查询派生字段,不落库。`effective` 仅在自身及全部祖先都 active 时为 true。
135
+ - 停用节点不改写后代状态,也不删除成员关系;停用父节点下不能新建节点,有无效祖先的节点不能成为有效节点的移动目标。
136
+ - 移动保持组织单元 ID 不变,禁止移动到自身或后代。未传 sort 时取目标同级下一个可用整数。
137
+
138
+ ### 2.5 组织成员关系
139
+
140
+ ```ts
141
+ interface OrganizationMembershipRecord {
142
+ id: string
143
+ organizationUnit: Pick<OrganizationUnitRecord, 'id' | 'name' | 'code' | 'fullPath' | 'status'>
144
+ duty: OrganizationDuty
145
+ createdAt: string
146
+ updatedAt: string
147
+ }
148
+
149
+ interface ReplaceMemberOrganizationUnitsRequest {
150
+ relations: OrganizationRelationInput[]
151
+ }
152
+
153
+ interface ReplaceMemberOrganizationUnitsResult {
154
+ userId: string
155
+ relations: OrganizationMembershipRecord[]
156
+ }
157
+
158
+ interface OrganizationUnitMemberInput {
159
+ userId: string
160
+ duty: OrganizationDuty
161
+ }
162
+
163
+ interface OrganizationUnitMemberRecord {
164
+ membershipId: string
165
+ member: Pick<MemberRecord, 'id' | 'userId' | 'account' | 'name' | 'status' | 'accountStatus'>
166
+ duty: OrganizationDuty
167
+ createdAt: string
168
+ updatedAt: string
169
+ }
170
+
171
+ interface ReplaceOrganizationUnitMembersRequest {
172
+ members: OrganizationUnitMemberInput[]
173
+ }
174
+
175
+ interface ReplaceOrganizationUnitMembersResult {
176
+ organizationUnitId: string
177
+ members: OrganizationUnitMemberRecord[]
178
+ }
179
+ ```
180
+
181
+ - 企业关系绑定既有 company member,项目关系绑定既有 project member。一次请求中的 `userId` 与所有组织单元必须属于 URL 指定的同一作用域。
182
+ - 同一成员可加入多个组织单元;`(成员, 组织单元)` 唯一。全部关系同等,不存在主归属、默认组织或数组第一项的特殊语义。
183
+ - 每条关系只有一个 duty;每个组织单元最多一个 leader、可有多个 deputy。同一个人可以领导多个组织单元。
184
+ - 按成员替换时,`relations` 是该成员在当前 URL 作用域内的完整组织关系集合;按组织单元替换时,`members` 是该单元的完整成员集合,只替换该单元关系并保留每名成员在其他组织单元的关系。两种方向都在锁内原子完成,重复组织单元/userId、跨作用域、非法新增/升级或负责人冲突使整批失败,不能留下部分写入。
185
+ - 两种替换请求的空数组都允许:按成员空数组解除该成员全部组织关系,按组织单元空数组清空该单元全部成员。按组织单元提交时同样比较该单元的持久化旧集合与新集合;停用成员或停用/无效组织单元的旧关系只可原样保留、移除或降级,不可新增或升级,且最终最多一名 leader。
186
+ - 关系返回固定按 leader、deputy、member,再按关系 ID 升序。不存在成员排序字段。
187
+ - “未归属组织”由候选查询的 `unassigned = true` 派生,数据库不创建对应节点。
188
+ - active 成员只可向 effective 组织单元新增关系或升级职责。停用成员以及指向停用/无效组织单元的既有关系可原样保留、移除,或按 `leader → deputy → member` 的方向降级;不得新增关系或反向升级职责。服务端比较持久化旧集合与请求新集合后判定,而不是把含停用 ID 的请求一律拒绝。
189
+
190
+ ### 2.6 岗位与任职
191
+
192
+ ```ts
193
+ interface PositionRecord {
194
+ id: string
195
+ scope: OrganizationScope
196
+ name: string
197
+ code: string
198
+ description: string
199
+ status: EntityStatus
200
+ version: number
201
+ memberCount: number
202
+ createdAt: string
203
+ updatedAt: string
204
+ }
205
+
206
+ interface CreatePositionRequest {
207
+ name: string
208
+ code: string
209
+ description?: string
210
+ }
211
+
212
+ interface UpdatePositionRequest extends VersionRequest {
213
+ name?: string
214
+ code?: string
215
+ description?: string
216
+ }
217
+
218
+ interface ReplaceMemberPositionsRequest {
219
+ positionIds: string[]
220
+ }
221
+
222
+ interface ReplaceMemberPositionsResult {
223
+ userId: string
224
+ positions: PositionRecord[]
225
+ }
226
+
227
+ interface PositionMemberRecord {
228
+ assignmentId: string
229
+ member: Pick<MemberRecord, 'id' | 'userId' | 'account' | 'name' | 'status' | 'accountStatus'>
230
+ createdAt: string
231
+ }
232
+
233
+ interface ReplacePositionMembersRequest {
234
+ userIds: string[]
235
+ }
236
+
237
+ interface ReplacePositionMembersResult {
238
+ positionId: string
239
+ members: PositionMemberRecord[]
240
+ }
241
+ ```
242
+
243
+ - 岗位是企业或项目作用域内的平面列表,不是树,不属于组织单元。
244
+ - 岗位、岗位任职和模板岗位的请求、响应、表结构均不包含 organizationUnitId、treeId 或 templateUnitId;Zod strict DTO 会拒绝这些未知字段。
245
+ - 同一作用域的岗位 name 和 code 分别按规范键唯一;一人可多岗,一岗可多人,成员与岗位组合唯一。
246
+ - 组织关系、岗位任职和 RBAC 角色分别维护、分别审计,任一方变化不得联动另外两方。
247
+ - 按成员替换时,`positionIds` 是该成员在当前 URL 作用域内的完整岗位集合;按岗位替换时,`userIds` 是该岗位的完整成员集合,只替换该岗位任职并保留每名成员的其他岗位。两种方向均在锁内原子完成,重复 ID、跨作用域或非法新增使整批失败。
248
+ - 两种岗位替换请求的空数组都允许,分别表示解除该成员全部任职或清空该岗位全部任职。停用成员或停用岗位的既有任职可原样保留或移除,但不得新增;服务端必须比较旧集合和新集合,不能因目标停用而阻止清理,也不能借全量替换新增停用关系。
249
+
250
+ ### 2.7 项目组织模板与项目创建
251
+
252
+ ```ts
253
+ interface OrganizationTemplateUnitInput {
254
+ clientKey: string
255
+ parentClientKey: string | null
256
+ name: string
257
+ code: string
258
+ description?: string
259
+ sort: number
260
+ }
261
+
262
+ interface OrganizationTemplatePositionInput {
263
+ name: string
264
+ code: string
265
+ description?: string
266
+ status: EntityStatus
267
+ }
268
+
269
+ interface OrganizationTemplateUnitRecord extends Omit<
270
+ OrganizationTemplateUnitInput,
271
+ 'clientKey' | 'parentClientKey'
272
+ > {
273
+ id: string
274
+ parentId: string | null
275
+ templateVersion: number
276
+ }
277
+
278
+ interface OrganizationTemplatePositionRecord extends OrganizationTemplatePositionInput {
279
+ id: string
280
+ templateVersion: number
281
+ }
282
+
283
+ interface OrganizationTemplateRecord {
284
+ id: string
285
+ companyId: string
286
+ name: string
287
+ description: string
288
+ status: EntityStatus
289
+ isDefault: boolean
290
+ version: number
291
+ units: OrganizationTemplateUnitRecord[]
292
+ positions: OrganizationTemplatePositionRecord[]
293
+ createdAt: string
294
+ updatedAt: string
295
+ }
296
+
297
+ interface OrganizationTemplateSummary extends Omit<
298
+ OrganizationTemplateRecord,
299
+ 'units' | 'positions'
300
+ > {
301
+ unitCount: number
302
+ positionCount: number
303
+ }
304
+
305
+ interface CreateOrganizationTemplateRequest {
306
+ name: string
307
+ description?: string
308
+ isDefault?: boolean
309
+ units: OrganizationTemplateUnitInput[]
310
+ positions: OrganizationTemplatePositionInput[]
311
+ }
312
+
313
+ interface ReplaceOrganizationTemplateRequest extends VersionRequest {
314
+ name: string
315
+ description?: string
316
+ isDefault: boolean
317
+ units: OrganizationTemplateUnitInput[]
318
+ positions: OrganizationTemplatePositionInput[]
319
+ }
320
+
321
+ interface UpdateOrganizationTemplateStatusRequest extends VersionRequest {
322
+ status?: EntityStatus
323
+ isDefault?: boolean
324
+ }
325
+
326
+ interface CreateProjectRequest {
327
+ name: string
328
+ code: string
329
+ description?: string
330
+ administratorUserId: string
331
+ organizationInitialization: ProjectOrganizationInitialization
332
+ }
333
+ ```
334
+
335
+ - `clientKey` 只用于一次请求内表达模板树父子关系,不持久化,不作为跨请求稳定 ID;同一请求内唯一且 `parentClientKey` 必须引用本请求节点。缺失父节点、自引用或任意环按 400 `COMMON.VALIDATION_FAILED` 拒绝;形成的森林超过 10 层按 409 `ACCESS.ORGANIZATION_DEPTH_EXCEEDED` 拒绝。
336
+ - 模板 `version` 同时是乐观锁版本和当前组织单元/岗位子项快照版本,不代表可重建整个模板聚合的历史。创建时 `isDefault` 省略即为 false;模板 PUT 必须显式提交 `isDefault` 与完整定义,更新模板主表当前值并生成下一份完整子项版本快照;状态 PATCH 的 `status/isDefault` 至少提交一项,省略的字段保持原值,也必须生成下一版本,并把上一版本的全部组织单元和岗位原样复制到新版本后再变更状态/默认标记,不能产生没有子项的当前版本。旧版本子项永久保留供来源追踪和审计,不作为新项目可选版本;旧的 name、description、status、isDefault 只由审计记录表达,不承诺从模板表重建历史主表状态。
337
+ - 每个企业最多一个 active 且 `isDefault = true` 的模板。设为默认时目标最终状态必须为 active;同一事务锁定目标和旧默认模板。若存在另一旧默认模板,旧模板也递增 version、把自身当前完整子项复制到下一版本、仅把 `isDefault` 改为 false,并写独立审计;不能旁路 UPDATE 绕过乐观锁或生成空版本。停用默认模板时目标新版本强制 `isDefault = false`,不自动挑选替代默认模板。
338
+ - 项目创建必须显式提交 `organizationInitialization`。blank 不允许模板字段;template 必须提交 templateId 和 templateVersion,且模板属于项目直接企业、active、版本等于当前版本。
339
+ - 模板查询先以项目直接 `companyId + templateId` 约束资源归属;跨企业或不存在统一 404。只有已经确认属于当前企业后,停用、不能作为默认或其他当前作用域内不可用状态才返回 422 `ACCESS.TEMPLATE_UNAVAILABLE`,版本不等于当前版本返回 409 `ACCESS.TEMPLATE_VERSION_CONFLICT`。
340
+ - template 初始化在写锁内先比较 `organization_templates.version`,再只读取 `organization_template_units/positions` 中该 `template_id + template_version` 的完整子项版本快照;不能读取“最新子项”或跨版本拼接。状态变更生成的新版本因已复制完整子项,可被后续项目正常初始化。
341
+ - 模板组织单元输入和表有意不含 status:模板中存在的结构节点都可用,初始化后的项目组织单元统一为 active,避免在模板树中再引入无效祖先语义。模板岗位是平面定义,保留显式 status;初始化时按原状态复制,disabled 岗位在项目中仍为 disabled,项目可随后独立启用。因此 97 个新增字段统计不变,此差异不是漏字段。
342
+ - 模板复制只生成项目组织单元和项目岗位,保留各自来源模板子项 ID;不复制成员、负责人、组织关系、岗位任职或 RBAC 角色。
343
+ - 项目创建后组织和岗位完全独立;模板修改、停用、恢复均不自动同步既有项目。
344
+
345
+ ### 2.8 账号与组织成员候选
346
+
347
+ ```ts
348
+ type GlobalAccountCandidatePurpose = 'createCompanyAdministrator' | 'setCompanyAdministrator'
349
+ type OrganizationMemberCandidatePurpose =
350
+ | 'browseOrganization'
351
+ | 'assignPositionMembers'
352
+ | 'createProjectAdministrator'
353
+ | 'setProjectAdministrator'
354
+ | 'addProjectMember'
355
+ type CandidateDisabledReason =
356
+ | 'accountInactive'
357
+ | 'memberInactive'
358
+ | 'scopeInactive'
359
+ | 'organizationInactive'
360
+ | 'positionInactive'
361
+ | null
362
+
363
+ interface GlobalAccountCandidateQuery extends PageQuery {
364
+ purpose: GlobalAccountCandidatePurpose
365
+ }
366
+
367
+ interface GlobalAccountCandidate {
368
+ userId: string
369
+ account: string
370
+ name: string
371
+ status: AccountStatus
372
+ disabled: boolean
373
+ disabledReason: CandidateDisabledReason
374
+ }
375
+
376
+ interface OrganizationMemberCandidateQuery extends PageQuery {
377
+ purpose?: OrganizationMemberCandidatePurpose
378
+ organizationUnitIds?: string[]
379
+ positionIds?: string[]
380
+ roleIds?: string[]
381
+ projectIds?: string[]
382
+ unassigned?: boolean
383
+ includeDisabled?: boolean
384
+ }
385
+
386
+ interface OrganizationUnitCandidateTag {
387
+ id: string
388
+ membershipId: string
389
+ name: string
390
+ fullPath: string
391
+ status: EntityStatus
392
+ effective: boolean
393
+ duty: OrganizationDuty
394
+ }
395
+
396
+ interface PositionCandidateTag {
397
+ id: string
398
+ name: string
399
+ status: EntityStatus
400
+ }
401
+
402
+ interface OrganizationMemberIdentity {
403
+ scope: OrganizationScope
404
+ scopeName: string
405
+ memberId: string
406
+ memberStatus: EntityStatus
407
+ scopeStatus: EntityStatus
408
+ organizationUnits: OrganizationUnitCandidateTag[]
409
+ positions: PositionCandidateTag[]
410
+ roles: Array<{ id: string; name: string }>
411
+ }
412
+
413
+ interface OrganizationMemberCandidate {
414
+ userId: string
415
+ account: string
416
+ name: string
417
+ accountStatus: AccountStatus
418
+ identities: OrganizationMemberIdentity[]
419
+ disabled: boolean
420
+ disabledReason: CandidateDisabledReason
421
+ }
422
+
423
+ interface ResolveCandidatesRequest {
424
+ userIds: string[]
425
+ }
426
+
427
+ interface ResolveGlobalAccountCandidatesRequest extends ResolveCandidatesRequest {
428
+ purpose: GlobalAccountCandidatePurpose
429
+ }
430
+
431
+ interface ResolveOrganizationMemberCandidatesRequest extends ResolveCandidatesRequest {
432
+ purpose?: OrganizationMemberCandidatePurpose
433
+ }
434
+
435
+ interface SetAdministratorRequest {
436
+ administratorUserId: string
437
+ replaceUserId?: string
438
+ }
439
+ ```
440
+
441
+ - 候选查询和回显均按 userId 去重。搜索支持姓名或完整账号,服务端分页,默认按规范化姓名、完整账号、userId 升序;返回完整账号、`scopeName`、组织完整路径、组织/岗位状态、必要角色及身份状态。
442
+ - `OrganizationMemberSelector` 的稳定选择值固定为 `userId`。当前企业/项目由调用候选及保存动作的 URL `AccessScope` 解释;候选中的项目 identity 只用于权限裁剪后的展示、筛选与辨识,不进入持久化选择值。需要修改某个项目的关系时,业务必须在该项目 URL 下提交,不能让客户端在请求体中自报 scope。
443
+ - `organizationUnits` 中每个标签对应一条真实成员关系,必须返回稳定的 `membershipId` 与 `duty`。`browseOrganization` 的 `organizationUnitIds` 恰好包含一个 ID 时,改按该匹配关系的 duty 优先级 `leader → deputy → member`、`membershipId ASC`、`userId ASC` 排序,使组织成员表可直接分页编辑;其他候选查询仍按规范化姓名、完整账号、userId 排序。
444
+ - `purpose` 省略时固定为 `browseOrganization`。`includeDisabled` 省略时固定为 `true`,停用候选仍返回并带禁选原因;显式为 `false` 时只返回当前 purpose 下可提交的候选。resolve 不丢弃已选的停用候选,以便稳定回显,但仍标记禁选。
445
+ - 普通浏览时,企业端点聚合当前企业身份及调用者在该企业内获准查看的项目身份;项目端点只返回当前项目身份。企业端只有具备 `company.projects.read` 时才可读取任何项目 identity,并继续按现有项目可见性逐项目裁剪;仅有 `company.projects.read` 不代表可以读取项目组织、岗位或角色标签。企业端未传 `projectIds` 时,身份筛选域是当前企业身份;传入时筛选域是所列可见项目身份,`projectIds` 内部为 OR,且当前企业身份不参与本次筛选。项目端不接受 `projectIds`。
446
+ - 企业端返回的每个项目 identity 都按该项目实际权限裁剪:组织标签要求该项目的 `project.organization.read`,岗位标签要求 `project.positions.read`,角色标签要求既有 `project.roles.read`;缺少某类权限时不返回该类标签,不能用其他项目或企业权限替代。`organizationUnitIds`、`positionIds`、`roleIds` 用于项目身份筛选时,也必须对每个目标项目分别具备上述对应权限;可见项目内权限不足返回 403,不可见、跨企业或不存在的项目/资源返回 404。
447
+ - `organizationUnitIds`、`positionIds`、`roleIds` 各自数组内部为 OR,不同类别之间与 `query`、`unassigned` 之间为 AND;必须由同一个筛选域 identity 同时满足全部身份类条件,不能用企业身份的角色与项目身份的组织标签拼成一次命中。候选只要存在一个这样的 identity 即命中。
448
+ - `unassigned` 省略或为 `false` 时不参与过滤;为 `true` 时要求上述同一个 identity 没有任何持久化组织关系,包含指向停用组织单元的关系也仍算“已归属”。因此企业端无 `projectIds` 时判断企业组织关系,有 `projectIds` 时分别在所选项目身份中判断;项目端只判断当前项目。
449
+ - 所有筛选 ID 必须属于本次筛选域且对调用者可见;跨域或不存在返回 404,筛选能力所需权限不足返回 403。响应中的 identities 及各类标签仍按当前企业或逐项目权限返回,不能借筛选参数扩张可见范围。
450
+ - 同一候选存在多个命中 identity 时,只要至少一个 identity 在当前 purpose 下可提交,候选整体 `disabled=false`;全部不可提交时,才按 `accountInactive → scopeInactive → memberInactive → organizationInactive → positionInactive` 取第一个禁选原因。后两项只在本次命中依赖对应无效标签时生效;某人存在其他无效组织或岗位标签,不会使其有效身份无条件禁选。提交业务动作时服务端按该动作重新校验,不能信任查询时状态。
451
+ - `assignPositionMembers` 只返回 URL 当前企业或项目的成员身份,要求对应 `*.positions.read` 与 `*.positions.assign`,不要求 `*.organization.read`。该 purpose 只接受 `page/pageSize/query/positionIds/includeDisabled`;响应保留当前身份的岗位标签,并清空组织与角色标签,既满足岗位成员回显和筛选,也不借岗位维护权限暴露组织信息。
452
+ - `createProjectAdministrator` 与 `setProjectAdministrator` 只允许调用企业端候选接口,分别要求既有 `company.projects.create` 与 `company.projects.administrator`,不额外要求 `company.organization.read` 或 `company.members.read`。这两个 purpose 只允许 `page/pageSize/query/includeDisabled`,其他身份筛选字段出现即 400;只搜索当前企业成员,并把 identities 裁成一个企业身份且清空组织、岗位、角色标签,避免为选管理员扩大信息暴露。
453
+ - `addProjectMember` 只允许调用项目端候选接口,要求 `project.members.add`,不额外要求企业成员列表、组织、岗位或角色读取权限。该 purpose 只接受 `page/pageSize/query/includeDisabled`;只返回项目所属企业中账号和企业成员关系均有效、且尚无当前项目成员关系的用户,identity 只保留所属企业成员摘要并清空组织、岗位、角色标签。resolve 对已经加入项目或状态失效的既有选择仍返回禁选原因,保存接口仍须二次校验。
454
+ - 除 `addProjectMember` 这一明确业务动作外,`OrganizationMemberSelector` 只负责选择既有成员,不创建成员、组织关系、岗位任职或角色。
455
+ - 企业新增成员只确认直接注册新账号并加入企业、发起邀请两个产品入口;不能通过候选接口枚举平台账号,也不能继续用旧 `{ account }` 精确匹配方式直接拉入既有账号。邀请对象、是否绑定账号、载体、有效期、状态、接受/拒绝、撤销/重发、发送渠道、DTO、端点、Token、安全、事务、审计和验收标准均待确认,其他专项或现有实现中的邀请细节不得被本契约引用为默认规则。
456
+ - 项目普通成员新增提交 `{ userId }`。后端在写事务中重新验证账号 active、目标是当前项目所属企业的 active company member、当前项目不存在该成员关系;不满足时返回 `ACCESS.INVALID_MEMBER_RELATION`,重复关系按 `ACCESS.DUPLICATE_RESOURCE` 处理。候选结果不构成写入授权。
457
+ - 平台创建企业、设置企业管理员统一改用 `administratorUserId`;项目创建、设置项目管理员也统一提交 `administratorUserId`,目标必须是有效企业成员。新旧 account/userId 字段不同时接受,Web 与 Server 同版本发布。
458
+ - 创建企业或由平台设置企业管理员时,目标可为尚未加入该企业的 active 全局账号;事务内按既有规则创建或恢复 company member 并授予管理员角色。项目管理员只能从项目直接企业的 active company member 中选择,事务内创建或恢复 project member 后授予管理员角色;直接提交未通过候选查询的 userId 仍执行相同资格校验并以 `ACCESS.INVALID_MEMBER_RELATION` 拒绝。
459
+
460
+ ## 3. 数据模型与数据库约束
461
+
462
+ ### 3.1 表与字段清单
463
+
464
+ 本期新增 10 张表,共 **97 个新增字段**;不向 `companies` 或其他既有表新增企业间父子关系专属字段。既有 `companies.code`、`projects.code` 的规范唯一索引调整不计入字段数;索引、外键、CHECK 和 enum 同样不计入字段数。
465
+
466
+ | 表 | 字段 | 核心约束 |
467
+ | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
468
+ | `organization_trees` | `id`, `scope_type`, `company_id`, `project_id`, `backfill_batch_key`, `created_at` | company 行要求 company_id 非空、project_id 为空;project 行两者非空并组合 FK 到 projects;分别保留企业/项目组合引用键 |
469
+ | `organization_units` | `id`, `tree_id`, `parent_id`, `name`, `name_key`, `code`, `code_key`, `description`, `sort`, `status`, `version`, `source_template_unit_id`, `created_at`, `updated_at` | `(tree_id,id)` 唯一;组合自 FK `(tree_id,parent_id)`;单树 code_key 唯一;根/非根分别做同父 name_key 唯一;sort/version CHECK |
470
+ | `company_organization_unit_members` | `id`, `scope_type`, `company_id`, `tree_id`, `organization_unit_id`, `user_id`, `duty`, `created_at`, `updated_at` | scope_type 固定 company;组合 FK 同时约束企业树、单元和 company member;成员-单元唯一;leader 部分唯一 |
471
+ | `project_organization_unit_members` | `id`, `scope_type`, `company_id`, `project_id`, `tree_id`, `organization_unit_id`, `user_id`, `duty`, `created_at`, `updated_at` | scope_type 固定 project;组合 FK 同时约束项目树、单元和 project member;成员-单元唯一;leader 部分唯一 |
472
+ | `positions` | `id`, `scope_type`, `company_id`, `project_id`, `name`, `name_key`, `code`, `code_key`, `description`, `status`, `version`, `source_template_position_id`, `created_at`, `updated_at` | scope CHECK;保留 `(id,scope_type,company_id)` 与 `(id,scope_type,company_id,project_id)` 唯一键;分 scope 唯一索引;不含组织字段 |
473
+ | `company_position_members` | `id`, `scope_type`, `company_id`, `position_id`, `user_id`, `created_at` | scope_type 固定 company;组合 FK 约束岗位和 company member;成员-岗位唯一 |
474
+ | `project_position_members` | `id`, `scope_type`, `company_id`, `project_id`, `position_id`, `user_id`, `created_at` | scope_type 固定 project;组合 FK 约束岗位和 project member;成员-岗位唯一 |
475
+ | `organization_templates` | `id`, `company_id`, `name`, `name_key`, `description`, `status`, `is_default`, `version`, `created_at`, `updated_at` | 企业内 name_key 唯一;active 默认模板部分唯一;version CHECK |
476
+ | `organization_template_units` | `id`, `template_id`, `template_version`, `parent_id`, `name`, `name_key`, `code`, `code_key`, `description`, `sort`, `created_at` | 同版本组合父 FK、code_key 唯一;根节点与非根节点分别建立 name_key 唯一索引;sort CHECK;服务层限制 10 层 |
477
+ | `organization_template_positions` | `id`, `template_id`, `template_version`, `name`, `name_key`, `code`, `code_key`, `description`, `status`, `created_at` | 同模板版本 name_key、code_key 分别唯一;不含模板组织节点字段 |
478
+
479
+ ### 3.2 关系完整性与生命周期
480
+
481
+ - `organization_trees`、`organization_units`、`positions`、`organization_templates` 及模板版本子项使用 RESTRICT,不通过级联物理删除稳定资源。
482
+ - 成员关系表对现有 company/project member 使用 `ON DELETE CASCADE` 仅作数据库兜底;正式成员移除必须先在同一业务事务显式删除组织关系、负责人关系和岗位任职并写审计,再删除成员,不能依赖静默级联代替审计。
483
+ - 每张关系表复制必要 scope 键并使用组合 FK。禁止只分别 FK `memberId` 与 `unitId/positionId`,否则数据库会允许跨企业或跨项目组合。
484
+ - `organization_trees` 的 CHECK 精确固定两种行形状:company 行为 `scope_type='company' AND company_id IS NOT NULL AND project_id IS NULL`;project 行为 `scope_type='project' AND company_id IS NOT NULL AND project_id IS NOT NULL`。project 行另以 `(company_id,project_id)` 引用既有 `projects(company_id,id)`。
485
+ - `organization_trees` 同时建立 `UNIQUE(id,scope_type,company_id)` 与 `UNIQUE(id,scope_type,company_id,project_id)`;前者只供企业关系引用,后者只供 project_id 非空的项目关系引用。每企业一棵树使用 company 条件唯一索引,每项目一棵树使用 project 条件唯一索引。
486
+ - 企业组织关系表不包含 nullable `project_id`,且 `scope_type/company_id/tree_id/organization_unit_id/user_id` 全部 NOT NULL;分别以 `(tree_id,scope_type,company_id)`、`(tree_id,organization_unit_id)`、`(company_id,user_id)` 引用企业树、组织单元和 company member。
487
+ - 项目组织关系表的 `scope_type/company_id/project_id/tree_id/organization_unit_id/user_id` 全部 NOT NULL;分别以 `(tree_id,scope_type,company_id,project_id)`、`(tree_id,organization_unit_id)`、`(project_id,user_id)` 引用项目树、组织单元和 project member。
488
+ - `positions` 使用与树相同的 company/project 行形状 CHECK,company_id 始终 NOT NULL;project 行以 `(company_id,project_id)` 引用 `projects(company_id,id)`,并明确建立 `UNIQUE(id,scope_type,company_id)` 与 `UNIQUE(id,scope_type,company_id,project_id)`。
489
+ - 企业岗位任职表不携带 `project_id`,所有 scope 键 NOT NULL,以 `(position_id,scope_type,company_id)` 和 `(company_id,user_id)` 组合 FK;项目岗位任职表的 project_id NOT NULL,以 `(position_id,scope_type,company_id,project_id)` 和 `(project_id,user_id)` 组合 FK。关系表拆分及非空约束用于避免 PostgreSQL `MATCH SIMPLE` 因任一列为 NULL 而跳过组合 FK。
490
+ - `organization_units` 的同父名称唯一使用两个索引:根节点 `UNIQUE(tree_id,name_key) WHERE parent_id IS NULL`,非根节点 `UNIQUE(tree_id,parent_id,name_key) WHERE parent_id IS NOT NULL`。模板节点同理,根节点使用 `UNIQUE(template_id,template_version,name_key) WHERE parent_id IS NULL`,非根节点增加 parent_id;普通含 NULL 的 UNIQUE 不能代替这两个约束。
491
+ - 所有新增表中的 `name_key/code_key` 均以 CHECK 校验其等于 `lower(normalize(btrim(原值), NFKC))`;迁移使用同一 PostgreSQL 表达式写入,shared 规范化方法必须用包含全角、组合字符和大小写的固定语料验证与数据库结果一致。`companies` 不新增 `name_key`。
492
+ - 既有 `companies.code` 不新增字段,改用上述规范表达式的全局唯一函数索引;既有 `projects.code` 使用 `company_id + 规范表达式` 的企业内唯一函数索引。新索引建立前必须先通过第 2.2 节预检,建立后才能移除被其覆盖的旧大小写敏感唯一约束。
493
+ - leader 唯一使用 `WHERE duty = 'leader'` 的部分唯一索引;deputy 和 member 不受人数限制。
494
+ - `organization_units.source_template_unit_id` 与 `positions.source_template_position_id` 可空且 RESTRICT,只有项目模板复制生成的数据填写;它们只表示来源,不建立同步关系。
495
+ - 组织、岗位、模板均无 DELETE Controller。关系替换可以删除不再存在的关系行,历史由审计保留。
496
+
497
+ ### 3.3 迁移与回滚
498
+
499
+ 1. 数据库 `0003` 尚未应用;当前 Schema、Shared、Server、Web、测试及 `0003_cute_killmonger.sql` 仍残留企业间父子关系实现。直接同步修正该 Drizzle migration、journal、snapshot 和各实现层,删除企业间父子关系专属内容,不再追加一个先创建错误结构再回滚的修复迁移,并继续由 `apps/server/src/database/schema.ts` 导出最终 Schema。
500
+ 2. migration 的第一条事务性检查执行第 2.2 节企业/项目 code 长度、字符和规范键冲突预检;任一失败时在 DDL 与数据写入前终止,不截断、不改名、不静默转小写。
501
+ 3. 预检通过后只创建组织、岗位和模板领域所需 enum、表、规范键、约束及索引,并调整既有企业/项目 code 规范唯一索引;不得向 `companies` 添加企业父级、类型、排序或名称规范键字段。
502
+ 4. 为每个缺少树的企业和项目插入一条空 `organization_trees`,写同一迁移批次 `backfill_batch_key`。依赖作用域唯一索引使重复执行不产生第二棵树。
503
+ 5. 不推断存量成员组织关系、负责人、岗位或模板,不创建虚拟“未归属”节点。
504
+ 6. 回滚只删除当前批次创建、仍为空且没有任何引用的树;一旦出现组织单元或业务引用就拒绝自动回滚并要求人工审阅。已经存在或后续业务创建的树绝不删除。
505
+ 7. `0004_company-member-invitations.sql` 及其对应邀请代码、页面和测试是未获产品确认的实现偏差;邀请协议确认并正式写入契约前,不得把该迁移纳入组织专项迁移链、执行或作为验收证据。
506
+
507
+ ## 4. REST 端点
508
+
509
+ 第 4.1~4.5 节固定 26 个方法/路径行,其中 11 行为固定 URL,带 `{scopeBase}` 的 15 行各展开为企业和项目两条实际 URL,因此契约表共有 **41 个实际端点**:37 个新增端点、4 个修改请求 DTO 的现有端点。第 4.6 节另列 4 个不新增路由但行为随本期变化的既有端点;合计 **45 个实际受影响端点**。企业邀请端点尚未获得产品确认,不进入本组织专项或其他现行端点统计;代码中已经存在的邀请端点仅记为实现偏差。
510
+
511
+ `{scopeBase}` 仅是本文简写,实际 Controller 必须显式注册:
512
+
513
+ - 企业:`/companies/:companyId`
514
+ - 项目:`/companies/:companyId/projects/:projectId`
515
+
516
+ ### 4.1 账号与既有创建端点
517
+
518
+ | 方法与路径 | 请求/返回 | 权限与规则 |
519
+ | -------------------------------------------------------------- | -------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
520
+ | GET `/platform/account-candidates` | `GlobalAccountCandidateQuery` → `PageResult<GlobalAccountCandidate>` | purpose 只允许两种固定值;服务端据 purpose 分别要求 create 或 administrator 权限,不信任客户端自报权限 key |
521
+ | POST `/platform/account-candidates/resolve` | `ResolveGlobalAccountCandidatesRequest` → `GlobalAccountCandidate[]` | 与搜索相同鉴权;最多 100 个去重 userId,按请求顺序回显 |
522
+ | POST `/platform/companies` | `CreateCompanyRequest` → `CompanyDetail` | 修改既有请求;不再接受 `administratorAccount` 或企业层级字段;创建企业、树、成员、管理员角色与审计同事务 |
523
+ | POST `/platform/companies/:companyId/administrator` | `SetAdministratorRequest` → `SetAdministratorResult` | 修改既有请求;不再接受 account |
524
+ | POST `/companies/:companyId/projects` | `CreateProjectRequest` → `ProjectDetail` | 修改既有请求;不再接受 `administratorAccount`;显式 blank/template 初始化同事务 |
525
+ | POST `/companies/:companyId/projects/:projectId/administrator` | `SetAdministratorRequest` → `SetAdministratorResult` | 修改既有请求;目标必须是当前企业有效成员,不再接受 account |
526
+
527
+ ### 4.2 组织单元与成员关系
528
+
529
+ | 方法与路径 | 请求/返回 | 权限与规则 |
530
+ | ----------------------------------------------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
531
+ | GET `{scopeBase}/organization/tree` | `OrganizationTreeQuery` → `OrganizationTreeRecord` | 对应 `*.organization.read`;按 parentId 懒加载一层,含停用节点、fullPath、effective、hasChildren,按同父 `sort ASC,id ASC` |
532
+ | POST `{scopeBase}/organization/units` | `CreateOrganizationUnitRequest` → `OrganizationUnitRecord` | `*.organization.create`;父级省略/null 表示顶级 |
533
+ | PATCH `{scopeBase}/organization/units/:unitId` | `UpdateOrganizationUnitRequest` → `OrganizationUnitRecord` | `*.organization.update`;至少一个业务字段,sort 也走此端点 |
534
+ | POST `{scopeBase}/organization/units/:unitId/move` | `MoveOrganizationUnitRequest` → `OrganizationUnitRecord` | `*.organization.move`;同树移动,完整子树深度校验 |
535
+ | PATCH `{scopeBase}/organization/units/:unitId/status` | `StatusRequest` → `OrganizationUnitRecord` | `*.organization.update`;停用保留关系,恢复不改后代自身状态 |
536
+ | PUT `{scopeBase}/organization/members/:userId/units` | `ReplaceMemberOrganizationUnitsRequest` → `ReplaceMemberOrganizationUnitsResult` | `*.organization.assign`;按成员全量原子替换,空数组解除该成员全部组织关系 |
537
+ | PUT `{scopeBase}/organization/units/:unitId/members` | `ReplaceOrganizationUnitMembersRequest` → `ReplaceOrganizationUnitMembersResult` | `*.organization.assign`;按单元全量原子替换,只影响该单元,空数组清空该单元全部成员 |
538
+
539
+ ### 4.3 岗位与任职
540
+
541
+ | 方法与路径 | 请求/返回 | 权限与规则 |
542
+ | -------------------------------------------------------- | ---------------------------------------------------------------- | -------------------------------------------------------------------------------- |
543
+ | GET `{scopeBase}/positions` | `PageQuery & { status? }` → `PageResult<PositionRecord>` | 对应 `*.positions.read`;支持名称/编码搜索,稳定按 `createdAt DESC,id DESC` |
544
+ | POST `{scopeBase}/positions` | `CreatePositionRequest` → `PositionRecord` | `*.positions.create` |
545
+ | PATCH `{scopeBase}/positions/:positionId` | `UpdatePositionRequest` → `PositionRecord` | `*.positions.update`;至少一个业务字段 |
546
+ | PATCH `{scopeBase}/positions/:positionId/status` | `StatusRequest` → `PositionRecord` | `*.positions.update`;停用保留任职关系 |
547
+ | PUT `{scopeBase}/organization/members/:userId/positions` | `ReplaceMemberPositionsRequest` → `ReplaceMemberPositionsResult` | `*.positions.assign`;按成员全量原子替换,空数组解除该成员全部任职 |
548
+ | PUT `{scopeBase}/positions/:positionId/members` | `ReplacePositionMembersRequest` → `ReplacePositionMembersResult` | `*.positions.assign`;按岗位全量原子替换,只影响该岗位,空数组清空该岗位全部任职 |
549
+
550
+ ### 4.4 组织成员候选
551
+
552
+ | 方法与路径 | 请求/返回 | 权限与规则 |
553
+ | --------------------------------------------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------- |
554
+ | GET `{scopeBase}/organization/member-candidates` | `OrganizationMemberCandidateQuery` → `PageResult<OrganizationMemberCandidate>` | 按 purpose 鉴权并裁剪身份;组织、岗位和项目管理员 purpose 分别使用对应最小权限 |
555
+ | POST `{scopeBase}/organization/member-candidates/resolve` | `ResolveOrganizationMemberCandidatesRequest` → `OrganizationMemberCandidate[]` | 与相同 purpose 的搜索使用同一鉴权和字段裁剪;最多 100 个去重 userId;未知或越权 ID 不返回占位数据 |
556
+
557
+ 候选端点通过 `organizationUnitIds`、`positionIds`、`roleIds`、`projectIds` 和 `unassigned` 覆盖按组织、岗位、角色、项目及未归属筛选。单组织查询通过 membershipId、duty 和固定关系排序形成可编辑成员视图;岗位 purpose 形成岗位成员视图,因此不再增加重复的只读“组织成员列表”“岗位成员列表”“未归属列表”端点。保存则分别使用第 4.2、4.3 节按成员或按资源全量替换的写端点。
558
+
559
+ - `purpose=browseOrganization` 要求对应 `*.organization.read`;`positionIds` 及岗位标签另要求 `*.positions.read`,`roleIds` 及角色标签另要求既有 `*.roles.read`。
560
+ - `purpose=assignPositionMembers` 要求对应 `*.positions.read` 与 `*.positions.assign`,不要求 `*.organization.read`;身份字段和允许筛选按第 2.8 节最小化。
561
+ - 企业 browse 的 `projectIds` 及任何项目 identity 首先要求既有 `company.projects.read`,并继续按调用者实际可见项目裁剪;每个项目的组织、岗位、角色标签及相应筛选再分别要求该项目的 `project.organization.read`、`project.positions.read`、`project.roles.read`。项目端不接受 `projectIds`。
562
+ - 两个项目管理员 purpose 与 `addProjectMember` 的搜索、resolve 均直接复用本端点,不新增通用“企业成员枚举”接口;其最小权限、允许字段和脱敏响应固定按第 2.8 节执行。
563
+
564
+ 企业直接注册与项目成员写入端点沿用既有成员接口,不计入本组织专项契约表;候选端点仍只增加本契约已统计的两条路由。企业邀请协议及端点待产品确认,现有邀请端点不得计入组织专项或其他现行契约统计。
565
+
566
+ ### 4.5 企业项目组织模板
567
+
568
+ | 方法与路径 | 请求/返回 | 权限与规则 |
569
+ | ----------------------------------------------------------------------- | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------- |
570
+ | GET `/companies/:companyId/organization/templates` | `PageQuery & { status? }` → `PageResult<OrganizationTemplateSummary>` | `company.organization.templates.read`;列表只返回 unitCount/positionCount,不返回完整定义 |
571
+ | GET `/companies/:companyId/organization/templates/:templateId` | → `OrganizationTemplateRecord` | 同上;返回当前版本完整定义 |
572
+ | POST `/companies/:companyId/organization/templates` | `CreateOrganizationTemplateRequest` → `OrganizationTemplateRecord` | `company.organization.templates.create`;整个模板聚合创建 |
573
+ | PUT `/companies/:companyId/organization/templates/:templateId` | `ReplaceOrganizationTemplateRequest` → `OrganizationTemplateRecord` | `company.organization.templates.update`;显式 isDefault、完整替换并新增不可变子项版本快照 |
574
+ | PATCH `/companies/:companyId/organization/templates/:templateId/status` | `UpdateOrganizationTemplateStatusRequest` → `OrganizationTemplateRecord` | `company.organization.templates.update`;复制完整子项快照到下一版本,再变更状态/默认标记 |
575
+
576
+ ### 4.6 既有行为变更端点
577
+
578
+ 以下 4 个端点不新增路由,也不计入第 4.1~4.5 节的 26 个方法/路径行,但实现与测试必须纳入本期总计 45 个实际受影响端点:
579
+
580
+ - `POST /companies/:companyId/members`:请求只允许直接注册新账号,不接受既有 `userId` 或旧 `{ account }` 精确挂接;账号、企业成员、默认角色与审计同事务。
581
+ - `POST /companies/:companyId/projects/:projectId/members`:请求固定为 `{ userId }`;目标必须是直属企业有效成员且尚未加入当前项目,写事务内重新校验。
582
+ - `DELETE /companies/:companyId/members/:memberId`:沿用现有请求 DTO,增加第 9 节企业成员关联清理及审计数量。
583
+ - `DELETE /companies/:companyId/projects/:projectId/members/:memberId`:沿用现有请求 DTO,增加第 9 节项目成员关联清理及审计数量。
584
+
585
+ ## 5. 权限目录与页面
586
+
587
+ 本期新增 **21 个权限 key**。页面 `.read` 及其操作必须同时进入 `ACCESS_PAGE_CATALOG`、`ACCESS_PERMISSION_CATALOG`、菜单种子、Web page registry 和路由模块,并提升 `ACCESS_CATALOG_VERSION`。操作权限仍依赖所属页面 `.read`。
588
+
589
+ | scope | routeKey/既有页面 | Web 路径 | 新增权限 key |
590
+ | ------- | -------------------------------- | -------------------------------------------------------- | ------------------------------------------------- |
591
+ | company | `company.organization` | `/companies/:companyId/organization` | `.read`, `.create`, `.update`, `.move`, `.assign` |
592
+ | company | `company.positions` | `/companies/:companyId/positions` | `.read`, `.create`, `.update`, `.assign` |
593
+ | company | `company.organization.templates` | `/companies/:companyId/organization/templates` | `.read`, `.create`, `.update` |
594
+ | project | `project.organization` | `/companies/:companyId/projects/:projectId/organization` | `.read`, `.create`, `.update`, `.move`, `.assign` |
595
+ | project | `project.positions` | `/companies/:companyId/projects/:projectId/positions` | `.read`, `.create`, `.update`, `.assign` |
596
+
597
+ 表中以点开头的后缀须与 routeKey 拼接,例如 `company.organization.assign`。新增数量为 5 + 4 + 3 + 5 + 4 = 21。平台企业管理沿用既有权限,不新增企业层级权限。
598
+
599
+ - 平台账号候选不新增通用“搜索所有账号”权限。`purpose=createCompanyAdministrator` 要求 `platform.companies.create` 且为平台内置管理员;`purpose=setCompanyAdministrator` 要求 `platform.companies.administrator` 且为平台内置管理员。
600
+ - 项目管理员候选不新增权限 key。`purpose=createProjectAdministrator` 只复用 `company.projects.create`,`purpose=setProjectAdministrator` 只复用 `company.projects.administrator`;两者沿用既有 adminOnly 规则,但均不隐式要求组织或成员页面 read。
601
+ - 项目模板初始化同时要求既有 `company.projects.create` 与 `company.organization.templates.read`;blank 创建不要求模板读取权限。
602
+ - 候选接口不能因为用户有页面 read 就泄露所有角色或项目标签;只返回其在当前端点策略下可见的身份摘要。
603
+ - 组织负责人、组织归属和岗位不会自动生成任何权限 key,也不会授予 RBAC 角色。
604
+ - 不新增 `company.organization.publish`、`project.workflow.*`、企业目标或任务级授权权限。
605
+
606
+ ## 6. 事务、并发、查询与审计
607
+
608
+ ### 6.1 写事务
609
+
610
+ - 所有本期管理写操作继续使用 PostgreSQL `pg_advisory_xact_lock(7421, 1)`。取得锁后必须重新执行登录状态、作用域成员资格、管理员身份、页面+操作权限、资源归属和 expectedVersion 校验。
611
+ - 写事务沿用现有 READ COMMITTED;组织默认 sort、组织循环/深度、leader 唯一、模板版本与默认模板唯一都在锁内基于最新已提交状态计算。
612
+ - 企业创建、项目创建/模板复制、按成员或按组织单元/岗位的批量关系替换、成员移除清理、模板定义/状态快照和对应成功审计必须在同一事务提交。任何步骤失败全部回滚,且没有成功审计。
613
+ - 数据库唯一索引是并发兜底,服务层应把已知约束映射为约定业务错误;未知数据库或程序异常交全局过滤器,不做大范围 catch 后伪装成 503。
614
+
615
+ ### 6.2 只读查询
616
+
617
+ - 组织树、模板详情和候选聚合等多查询读取继续使用 REPEATABLE READ + READ ONLY,确保树、路径、成员标签和分页总数来自同一快照。
618
+ - Repository 查询必须在 SQL 条件中同时约束 companyId/projectId/treeId;禁止先按裸 ID 读取其他租户资源再在 Controller 过滤。
619
+ - 候选搜索 trim 后最多 100 字,分页沿用默认 20、最大 100;数组筛选每类最多 100 个去重 UUID。
620
+
621
+ ### 6.3 审计动作
622
+
623
+ 新增固定 action:
624
+
625
+ ```text
626
+ organization.unit.create
627
+ organization.unit.update
628
+ organization.unit.move
629
+ organization.unit.status
630
+ organization.members.replace
631
+ position.create
632
+ position.update
633
+ position.status
634
+ position.members.replace
635
+ organization_template.create
636
+ organization_template.replace
637
+ organization_template.status
638
+ project.organization.initialize
639
+ ```
640
+
641
+ - action 的企业/项目范围由 `AuditRecord.scope` 区分,不复制两套 action 名。
642
+ - 摘要只保存对象 ID、changedFields、from/to、数量、目标 userId、模板 ID/版本等白名单;不得记录密码、token、完整请求体或不必要的成员信息。
643
+ - `organization.members.replace` 与 `position.members.replace` 同时复用于按成员和按资源替换;摘要必须记录替换方向、目标 userId/organizationUnitId/positionId、变更前后数量及新增/移除/职责变化数量,不能只记录入口名称。
644
+ - 设置新默认模板时,目标模板按入口写 `organization_template.create`、`organization_template.replace` 或 `organization_template.status`;被自动取消默认的旧模板另写一条 `organization_template.status`,摘要记录旧/新 version 与 `isDefault: true → false`。相关审计与完整子项版本快照在同一事务提交。
645
+ - 企业/项目成员移除的既有审计摘要增加 `removedOrganizationRelationCount`、`removedPositionAssignmentCount`,但仍保持原 action。
646
+
647
+ ## 7. 错误码与状态语义
648
+
649
+ 本期复用既有通用错误目录,并新增 **7 个领域错误码**。
650
+
651
+ | HTTP | code | 场景 |
652
+ | ---- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
653
+ | 400 | `COMMON.VALIDATION_FAILED` | strict DTO、UUID、未知字段、非法枚举、请求内重复、筛选/resolve 等明确要求非空的数组为空、分页和 sort 范围;关系替换空数组合法 |
654
+ | 401 | 既有 `AUTH.*` | 会话或账号失效 |
655
+ | 403 | `ACCESS.FORBIDDEN` | 当前作用域已识别但缺少页面/操作权限或内置管理员资格 |
656
+ | 404 | `ACCESS.NOT_FOUND` | 目标账号、成员或资源不存在,或其属于其他企业、项目、组织树时统一返回;不得用该响应暴露跨作用域存在性 |
657
+ | 409 | `ACCESS.VERSION_CONFLICT` | 组织、岗位、模板 PUT/状态 PATCH 等 expectedVersion 过期 |
658
+ | 409 | `ACCESS.DUPLICATE_RESOURCE` | 已持久化的组织名称/编码、岗位名称/编码、模板名称或企业/项目 code 规范唯一冲突 |
659
+ | 409 | `ACCESS.RESOURCE_IN_USE` | 数据库 RESTRICT 保护的稳定引用仍被使用 |
660
+ | 409 | `ACCESS.ORGANIZATION_CYCLE` | 组织单元移动形成自身/后代循环 |
661
+ | 409 | `ACCESS.ORGANIZATION_DEPTH_EXCEEDED` | 创建、移动或模板复制后超过 10 层 |
662
+ | 409 | `ACCESS.ORGANIZATION_LEADER_CONFLICT` | 同一组织单元出现第二名 leader |
663
+ | 409 | `ACCESS.ORGANIZATION_SORT_EXHAUSTED` | 省略 sort 时同级最大值已经达到上限 |
664
+ | 422 | `ACCESS.INVALID_MEMBER_RELATION` | 已确认属于当前作用域,但账号/成员状态无效、负责人资格无效或候选状态不可用于新增、升级关系 |
665
+ | 409 | `ACCESS.TEMPLATE_VERSION_CONFLICT` | 项目 template 初始化提交的 templateVersion 不是模板当前版本 |
666
+ | 422 | `ACCESS.TEMPLATE_UNAVAILABLE` | 已确认属于项目直接企业,但模板已停用、目标默认状态非法或不能用于新项目 |
667
+ | 500 | `COMMON.INTERNAL_SERVER_ERROR` | 未知错误,底层信息不公开 |
668
+
669
+ 新增 7 个错误码为:`ORGANIZATION_CYCLE`、`ORGANIZATION_DEPTH_EXCEEDED`、`ORGANIZATION_LEADER_CONFLICT`、`ORGANIZATION_SORT_EXHAUSTED`、`INVALID_MEMBER_RELATION`、`TEMPLATE_VERSION_CONFLICT`、`TEMPLATE_UNAVAILABLE`。
670
+
671
+ ## 8. 前端组件与状态契约
672
+
673
+ - `Selector/src/Selector.tsx` 继续只做出口归类;`BasicTableSelector`、`GlobalAccountSelect`、`OrganizationMemberSelector` 分别作为独立功能目录,不增加一个庞大 mode 组件。
674
+ - `GlobalAccountSelect` 是平台账号远程搜索单选,稳定值为 userId,由业务注入 search/resolve request;编辑回显使用候选快照,不从名称反查。
675
+ - `OrganizationMemberSelector` 是 Select 风格表单字段 + 弹窗组织浏览器。左侧为当前可见作用域/组织/岗位/角色筛选,右侧为分页人员和已选区;组织节点只做筛选值,已选值统一为 userId,不持久化候选 identity 的 scope。
676
+ - 组织树按层懒加载,节点缓存键必须包含完整 AccessScope 与 parentId;`hasChildren=false` 时不得继续请求子节点。由于节点缓存包含 fullPath、depth、effective,重命名、移动或状态变更必须失效受影响节点及所有后代,同时失效会改变 `hasChildren` 的原/新父级列表;如果前端没有可靠的后代依赖索引,必须直接清空当前 AccessScope 的整棵树缓存,不能只失效父级或祖先。
677
+ - 企业页面和项目页面各自从现有 workspace 路由进入,页面内部不再提供第二套企业/项目切换器。请求、树、筛选、分页、已选缓存键必须包含完整 AccessScope;切换工作空间时取消旧请求并清空旧状态。
678
+ - 同名人员显示姓名、完整账号和来源作用域;同名组织显示企业/项目名称及 fullPath;组织标签与岗位标签分栏,不暗示关联。
679
+ - 401 清登录状态,403 刷新一次 access context,404 显示统一不可见,409 保留表单并提示刷新,422 展示可修正业务原因。前端禁用只是体验,服务端始终二次校验 userId 与作用域。
680
+
681
+ ## 9. 成员移除与状态清理
682
+
683
+ - 移除项目成员:锁内删除该项目的组织关系(包含 leader/deputy)、岗位任职和项目 user_roles,再删除 project member,写一条既有成员移除审计及清理数量。
684
+ - 移除企业成员:锁内先按现有规则处理该企业直接项目中的项目成员及其组织/岗位/角色关系,再清本企业组织关系、岗位任职和 company user_roles,最后删除 company member。
685
+ - 停用成员不删除组织或岗位关系,但不再作为新增关系的有效候选;恢复后按当前保存关系重新可见。停用期间允许全量替换请求原样保留或移除既有关系,并允许组织职责降级;禁止新增关系或职责升级。停用组织单元/岗位遵循同一“可保留、可解除、不可新增”规则。
686
+ - 任何企业清理不得触碰该 userId 在其他企业中的独立成员、组织、岗位或角色关系。
687
+
688
+ ## 10. 验收追踪矩阵
689
+
690
+ | PRD 验收项 | 契约保障 | 必测证据 |
691
+ | ------------------------- | -------------------------------------------------------------- | ----------------------------------------------------- |
692
+ | AC-01~AC-02 身份与作用域 | userId 稳定值;AccessScope 不扩枚举 | 同名账号、三作用域回归 |
693
+ | AC-03~AC-06 独立企业边界 | companies 模型保持不变;无企业树端点/权限;项目直接 companyId | 禁止字段/端点全仓扫描、跨企业隔离、项目直接归属 |
694
+ | AC-07~AC-12 组织树与排序 | 独立 tree、组合 FK、10 层、单整数 sort、移动端点 | 跨树 404、深度、默认和显式排序、移动保持 ID |
695
+ | AC-13~AC-18 组织成员 | 两类关系表、集合替换、duty、leader 唯一、未归属查询 | 多组织、无主归属、冲突整批回滚、默认顺序 |
696
+ | AC-19~AC-21 岗位 | 平面 positions、两类任职表、strict DTO、无组织字段 | 多岗多人、规范唯一、组织/角色无联动 |
697
+ | AC-22~AC-25 模板与迁移 | 显式 union、子项版本快照、来源 ID、创建事务、backfill 批次 | blank/template 非法组合、复制边界、独立演进、幂等回滚 |
698
+ | AC-26~AC-31 页面与选择器 | workspace 路由隔离、两类选择器、候选与保存契约 | 快切无旧数据、分页去重、同名展示、禁选、账号边界 |
699
+ | AC-32~AC-35 权限与安全 | 21 key、SQL 作用域、稳定资源仅状态、同事务审计 | 前后端权限一致、跨域 404、清理范围、失败无成功审计 |
700
+ | AC-36 排除范围 | 第 11 节禁止清单 | schema/types/routes 全仓扫描无禁用概念 |
701
+
702
+ 后续 QA 必须逐条回填 AC-01~AC-36 的自动化或人工证据;上表归组不表示可以省略任一条验收标准。
703
+
704
+ ## 11. 明确排除与禁止字段
705
+
706
+ 本期不得新增以下表、字段、DTO、端点、权限或 UI:
707
+
708
+ - 项目小组或第四种组织/访问作用域。
709
+ - 企业间父子关系,以及企业级父级、企业类型、企业名称规范键、企业排序同义字段、企业树查询/移动端点、企业层级权限或审计动作。
710
+ - 主归属、默认组织、primaryOrganization、isPrimary 等同义字段。
711
+ - 任何成员手工排序字段或双框排序交互。
712
+ - 岗位到组织单元、组织树、模板组织节点的持久关联。
713
+ - 企业目标发布、WorkflowTargetSelector、运行时接收人解析、任务参与者、任务级资源/附件授权、流程转交机制或可执行工作流引擎。
714
+
715
+ “项目 → 直接所属企业”仅是后续工作流专项的首个推荐方向,本期不建表、不加接口、不加权限、不计入验收完成。
716
+
717
+ ## 12. 前后端并行边界与确认门
718
+
719
+ 契约确认后的实施顺序固定为:
720
+
721
+ 1. 契约/架构负责人先独占 `packages/shared`、数据库 schema 与 migration,完成共享导出、权限/错误目录、空库和存量库迁移验证。
722
+ 2. 共享契约稳定后,后端负责 `apps/server` 的 Controller、Service、Repository、事务、审计与集成测试;前端负责 `apps/web` 的路由、页面、选择器和组件测试,两边并行但只消费 shared 类型。
723
+ 3. 集成阶段验证全部 45 个实际受影响端点(41 个契约表端点及 4 个既有行为变更端点)、21 个权限 key、7 个组织领域新增错误码、成员移除清理和 AC-01~AC-36;企业邀请细节确认后另行进入成员接入契约和验证范围,现有邀请实现不得提前计入。
724
+ 4. QA 默认使用真实 PostgreSQL 集成测试和 Playwright 覆盖关键 Web 流程;环境无法验证必须明确标记,不能算通过。
725
+
726
+ ### 变更与确认记录
727
+
728
+ 用户于 2026-09-16 明确回复“确认,继续”,并于 2026-09-17 明确取消企业间父子关系;2026-09-18 进一步澄清企业邀请只确认入口,具体协议尚未确认。企业独立决定覆盖初版契约中所有企业层级字段、端点、权限、审计与验收语义;当前实施基线为:
729
+
730
+ 1. 账号管理员接口按同版本破坏性迁移,从 `administratorAccount` 一次切换到 `administratorUserId`,不提供双字段兼容期。
731
+ 2. 数据层按 10 张新表、97 个新增字段落地;不向 `companies` 增加企业父级、类型、排序或名称规范键字段;模板定义采用保留历史子项的版本快照。
732
+ 3. 接口和授权按 41 个契约表实际端点(37 个新增、4 个修改请求 DTO)及另 4 个既有行为变更端点实施,总计 45 个实际受影响端点;同时固定 21 个新增权限 key、7 个组织领域新增错误码,不由实现阶段删并端点或改名。企业邀请端点尚未确认,不计入任何现行契约统计。
733
+ 4. 写事务使用 READ COMMITTED + 全局管理锁,聚合只读使用 REPEATABLE READ + READ ONLY;业务变更和成功审计保持同事务。
734
+ 5. 平台企业继续按独立列表管理;企业与企业之间不存在父子关系,每个企业和每个项目只维护各自的一棵组织树。
735
+ 6. 企业普通成员新增只确认直接注册和邀请两个产品入口;邀请入口之后的对象、流程、状态与技术协议全部待确认。项目普通成员从所属企业有效成员中按 `userId` 选择,候选排除已加入者,写入时由服务端重新校验。
736
+
737
+ 除明确列为待确认的企业邀请协议外,本契约不把架构空白留给前端或后端自行决定。现有邀请代码、页面、自动化测试及 `0004` 不能代替产品确认;后续形成完整邀请规则时,须先更新需求、设计和契约并重新确认。
738
+
739
+ | 日期 | 变更摘要 | 原因 | 影响范围 |
740
+ | ---------- | ------------------------------------------------------------------------------------------------------ | ---------------------------- | -------------------------------------------- |
741
+ | 2026-09-18 | 邀请口径纠偏为“只确认入口,具体协议待确认”;撤回既有端点数量、固定有效期、Token 和接受流程等未确认契约 | 现有实现不能反向定义产品协议 | 成员边界、迁移、端点统计、确认门、联调与测试 |
742
+ | 2026-09-18 | 明确 Schema、Shared、Server、Web、测试及 `0003` 当前仍残留企业层级 | 区分目标契约和实际实现状态 | 迁移、发布阻断与复验 |
743
+ | 2026-09-17 | 取消企业之间的父子层级 | 最新企业边界确认 | 字段、表、端点、权限、审计、迁移与验收 |
744
+ | 2026-09-17 | 企业成员改为直接注册/邀请;项目成员改为企业有效成员候选 `userId` 选择 | 最新成员边界确认 | 候选 purpose、成员写接口约束、错误与测试 |