create-bubbles 0.1.25 → 0.1.27

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 (622) hide show
  1. package/dist/index.js +3 -9
  2. package/package.json +1 -1
  3. package/template-nextjs-vinext-eslint/Dockerfile +4 -4
  4. package/template-nextjs-vinext-eslint/README.md +6 -2
  5. package/template-nextjs-vinext-eslint/docker-compose.yaml +4 -4
  6. package/template-nextjs-vinext-eslint/eslint.config.js +2 -0
  7. package/template-nextjs-vinext-eslint/package.json +28 -26
  8. package/template-nextjs-vinext-eslint/pnpm-workspace.yaml +13 -1
  9. package/template-nextjs-vinext-eslint/src/utils/request/core/index.ts +63 -45
  10. package/template-nextjs-vinext-eslint/src/utils/request/core/utils.ts +12 -6
  11. package/template-nextjs-vinext-eslint/vite.config.ts +1 -1
  12. package/template-react-rsbuild-biome/.agents/rules/SVG/344/275/277/347/224/250.md +8 -0
  13. package/template-react-rsbuild-biome/AGENTS.md +11 -0
  14. package/template-react-rsbuild-biome/index.html +2 -2
  15. package/template-react-rsbuild-biome/package.json +25 -24
  16. package/template-react-rsbuild-biome/pnpm-workspace.yaml +5 -0
  17. package/template-react-rsbuild-biome/rsbuild.config.ts +1 -1
  18. package/template-react-rsbuild-biome/src/assets/icon/logo.svg +1 -1
  19. package/template-react-rsbuild-biome/src/assets/svg/draft.svg +4 -0
  20. package/template-react-rsbuild-biome/src/components/Icon/svg-icon/README.md +37 -0
  21. package/template-react-rsbuild-biome/src/components/Icon/svg-icon/SvgIcon.tsx +27 -0
  22. package/template-react-rsbuild-biome/src/env.d.ts +7 -0
  23. package/template-react-rsbuild-biome/src/utils/request/index.ts +3 -4
  24. package/template-react-rsbuild-biome/tsconfig.json +1 -2
  25. package/template-taro-react-oxc/.oxlintrc.json +0 -1
  26. package/template-taro-react-oxc/package.json +53 -52
  27. package/template-taro-react-oxc/pnpm-workspace.yaml +46 -0
  28. package/template-taro-vue-eslint/package.json +56 -56
  29. package/template-vp-monorepo-react-hono/apps/web/.agents/rules/SVG/344/275/277/347/224/250.md +8 -0
  30. package/template-vp-monorepo-react-hono/apps/web/AGENTS.md +11 -0
  31. package/template-vp-monorepo-react-hono/apps/web/package.json +1 -0
  32. package/template-vp-monorepo-react-hono/apps/web/src/assets/svg/draft.svg +4 -0
  33. package/template-vp-monorepo-react-hono/apps/web/src/components/Icon/svg-icon/README.md +37 -0
  34. package/template-vp-monorepo-react-hono/apps/web/src/components/Icon/svg-icon/SvgIcon.tsx +27 -0
  35. package/template-vp-monorepo-react-hono/apps/web/tsconfig.json +1 -1
  36. package/template-vp-monorepo-react-hono/apps/web/vite.config.ts +2 -0
  37. package/template-vp-monorepo-react-hono/pnpm-workspace.yaml +1 -0
  38. package/template-vp-monorepo-react-nestjs/.agents/rules//344/273/243/347/240/201/350/256/276/350/256/241.md +4 -0
  39. package/template-vp-monorepo-react-nestjs/.agents/rules//345/205/261/344/272/253/344/273/243/347/240/201.md +4 -0
  40. 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
  41. package/template-vp-monorepo-react-nestjs/.codegraph/.gitignore +5 -0
  42. 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
  43. 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
  44. 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
  45. 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
  46. 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
  47. 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
  48. 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
  49. 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
  50. 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
  51. 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
  52. 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
  53. 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
  54. 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
  55. 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
  56. 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 +578 -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//346/265/213/350/257/225/346/212/245/345/221/212.md +137 -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//346/265/213/350/257/225/350/257/201/346/215/256/browser.json +84 -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//346/265/213/350/257/225/350/257/201/346/215/256/http.json +108 -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//346/265/213/350/257/225/350/257/201/346/215/256/legacy-http.json +18 -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//346/265/213/350/257/225/350/257/201/346/215/256/legacy.json +24 -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//350/201/224/350/260/203/350/256/260/345/275/225.md +76 -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//350/277/220/350/241/214/350/257/264/346/230/216.md +117 -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//351/234/200/346/261/202/346/226/207/346/241/243.md +275 -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//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
  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//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
  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//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
  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//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
  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//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
  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//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
  71. package/template-vp-monorepo-react-nestjs/.spaces/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 +851 -0
  72. package/template-vp-monorepo-react-nestjs/.spaces/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 +1470 -0
  73. package/template-vp-monorepo-react-nestjs/.spaces/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 +4507 -0
  74. package/template-vp-monorepo-react-nestjs/.spaces/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 +1897 -0
  75. 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
  76. 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
  77. 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
  78. 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
  79. 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
  80. 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
  81. 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
  82. 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
  83. 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
  84. 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
  85. 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
  86. 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
  87. 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
  88. 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
  89. 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
  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/register-1440.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/register-390.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/workspaces-1440.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/workspaces-390.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/workspaces-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//345/267/245/345/205/267/fixtures.mjs +132 -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//345/267/245/345/205/267/visual-check.mjs +274 -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//346/265/213/350/257/225/350/257/201/346/215/256/visual-report.json +104 -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//351/252/214/350/257/201/350/257/264/346/230/216.md +25 -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//345/233/275/351/231/205/345/214/226//344/272/244/344/273/230/350/256/260/345/275/225.md +12 -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//345/233/275/351/231/205/345/214/226//346/265/213/350/257/225/346/212/245/345/221/212.md +19 -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//345/233/275/351/231/205/345/214/226//350/256/276/350/256/241/346/226/271/346/241/210.md +18 -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//345/233/275/351/231/205/345/214/226//351/234/200/346/261/202/346/226/207/346/241/243.md +24 -0
  103. 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
  104. 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
  105. 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
  106. 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
  107. 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
  108. 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
  109. 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 +93 -0
  110. 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 +87 -0
  111. 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 +55 -0
  112. 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 +92 -0
  113. 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 +38 -0
  114. 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 +26 -0
  115. 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 +53 -0
  116. 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 +63 -0
  117. 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
  118. package/template-vp-monorepo-react-nestjs/.spaces/README.md +85 -0
  119. package/template-vp-monorepo-react-nestjs/.spaces//346/226/207/346/241/243/350/247/204/350/214/203.md +97 -0
  120. package/template-vp-monorepo-react-nestjs/AGENTS.md +18 -10
  121. package/template-vp-monorepo-react-nestjs/README.md +3 -27
  122. package/template-vp-monorepo-react-nestjs/apps/server/.agents/rules/error-handling.md +84 -0
  123. package/template-vp-monorepo-react-nestjs/apps/server/.env.development +60 -0
  124. package/template-vp-monorepo-react-nestjs/apps/server/.env.production +16 -0
  125. package/template-vp-monorepo-react-nestjs/apps/server/AGENTS.md +9 -0
  126. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/0000_military_colonel_america.sql +11 -0
  127. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/0001_loud_siren.sql +27 -0
  128. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/0002_enterprise_access.sql +182 -0
  129. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/0003_cute_killmonger.sql +357 -0
  130. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/0004_company-member-invitations.sql +25 -0
  131. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/0005_menu_svg_icons.sql +54 -0
  132. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/meta/0000_snapshot.json +97 -0
  133. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/meta/0001_snapshot.json +354 -0
  134. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/meta/0002_snapshot.json +1801 -0
  135. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/meta/0003_snapshot.json +3511 -0
  136. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/meta/0004_snapshot.json +3713 -0
  137. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/meta/_journal.json +48 -0
  138. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/rollback/0003_organization_backfill.sql +32 -0
  139. package/template-vp-monorepo-react-nestjs/apps/server/package.json +9 -3
  140. package/template-vp-monorepo-react-nestjs/apps/server/src/access-init.ts +45 -0
  141. package/template-vp-monorepo-react-nestjs/apps/server/src/app.controller.ts +3 -0
  142. package/template-vp-monorepo-react-nestjs/apps/server/src/app.module.ts +41 -6
  143. package/template-vp-monorepo-react-nestjs/apps/server/src/app.service.ts +3 -0
  144. package/template-vp-monorepo-react-nestjs/apps/server/src/common/adapters/fastify.adapter.ts +17 -0
  145. package/template-vp-monorepo-react-nestjs/apps/server/src/common/constants/session.constants.ts +9 -0
  146. package/template-vp-monorepo-react-nestjs/apps/server/src/common/decorators/access-policy.decorator.ts +18 -0
  147. package/template-vp-monorepo-react-nestjs/apps/server/src/common/decorators/current-auth.decorator.ts +4 -0
  148. package/template-vp-monorepo-react-nestjs/apps/server/src/common/decorators/public.decorator.ts +3 -0
  149. package/template-vp-monorepo-react-nestjs/apps/server/src/common/exceptions/app.exception.ts +9 -0
  150. package/template-vp-monorepo-react-nestjs/apps/server/src/common/filters/global-exception.filter.ts +38 -5
  151. package/template-vp-monorepo-react-nestjs/apps/server/src/common/security/password-security-event.ts +98 -0
  152. package/template-vp-monorepo-react-nestjs/apps/server/src/config/app.config.ts +3 -0
  153. package/template-vp-monorepo-react-nestjs/apps/server/src/config/database.config.ts +3 -0
  154. package/template-vp-monorepo-react-nestjs/apps/server/src/config/index.ts +2 -0
  155. package/template-vp-monorepo-react-nestjs/apps/server/src/config/llm.config.ts +3 -0
  156. package/template-vp-monorepo-react-nestjs/apps/server/src/config/queue.config.ts +119 -0
  157. package/template-vp-monorepo-react-nestjs/apps/server/src/config/redis.config.ts +3 -0
  158. package/template-vp-monorepo-react-nestjs/apps/server/src/config/session.config.ts +7 -0
  159. package/template-vp-monorepo-react-nestjs/apps/server/src/config/storage.config.ts +42 -0
  160. package/template-vp-monorepo-react-nestjs/apps/server/src/database/access.schema.ts +394 -0
  161. package/template-vp-monorepo-react-nestjs/apps/server/src/database/db.module.ts +3 -0
  162. package/template-vp-monorepo-react-nestjs/apps/server/src/database/organization.schema.ts +453 -0
  163. package/template-vp-monorepo-react-nestjs/apps/server/src/database/schema.ts +63 -1
  164. package/template-vp-monorepo-react-nestjs/apps/server/src/main.ts +5 -0
  165. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/access-http.ts +29 -0
  166. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/access.errors.ts +130 -0
  167. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/access.guard.ts +63 -0
  168. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/access.module.ts +27 -0
  169. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/access.service.ts +441 -0
  170. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/access.store.ts +68 -0
  171. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/access.validation.ts +44 -0
  172. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/maintenance/permissions-cleanup.controller.ts +27 -0
  173. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/maintenance/permissions-cleanup.service.ts +260 -0
  174. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/maintenance/permissions-cleanup.validation.ts +7 -0
  175. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/roles/roles.controller.ts +80 -0
  176. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/roles/roles.service.ts +249 -0
  177. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/roles/roles.validation.ts +24 -0
  178. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/seed/access-seed.service.ts +183 -0
  179. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/workspaces/workspaces.controller.ts +28 -0
  180. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/workspaces/workspaces.service.ts +94 -0
  181. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/workspaces/workspaces.validation.ts +5 -0
  182. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/audit/audit.controller.ts +26 -0
  183. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/audit/audit.module.ts +11 -0
  184. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/audit/audit.service.ts +74 -0
  185. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/audit/audit.validation.ts +11 -0
  186. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/auth.controller.ts +25 -0
  187. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/auth.errors.ts +10 -0
  188. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/auth.module.ts +1 -1
  189. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/auth.repository.ts +60 -0
  190. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/auth.service.ts +69 -13
  191. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/dto/auth-repsponse.dto.ts +2 -2
  192. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/dto/register.dto.ts +1 -1
  193. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/guards/session-auth.guard.ts +8 -0
  194. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/password/change-password.dto.ts +17 -0
  195. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/password.service.ts +6 -0
  196. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/session/session-store.service.ts +46 -0
  197. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/session/session-token.service.ts +12 -0
  198. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/session/session.script.ts +7 -1
  199. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/companies/companies.controller.ts +105 -0
  200. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/companies/companies.module.ts +12 -0
  201. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/companies/companies.service.ts +523 -0
  202. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/accounts/accounts.controller.ts +72 -0
  203. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/accounts/accounts.service.ts +154 -0
  204. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/accounts/accounts.validation.ts +8 -0
  205. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/accounts/password-reset/password-reset.service.ts +81 -0
  206. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/accounts/password-reset/reset-password.validation.ts +13 -0
  207. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/administrators/administrators.service.ts +116 -0
  208. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/administrators/administrators.validation.ts +1 -0
  209. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/invitations/company-member-invitations.controller.ts +69 -0
  210. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/invitations/member-invitation-acceptance.controller.ts +23 -0
  211. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/invitations/member-invitations.service.ts +344 -0
  212. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/invitations/member-invitations.validation.ts +23 -0
  213. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/members.controller.ts +88 -0
  214. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/members.module.ts +31 -0
  215. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/members.service.ts +573 -0
  216. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/members.validation.ts +19 -0
  217. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/menus/menus.controller.ts +56 -0
  218. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/menus/menus.module.ts +11 -0
  219. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/menus/menus.service.ts +230 -0
  220. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/menus/menus.validation.ts +30 -0
  221. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/candidates/global-account/global-account-candidates.controller.ts +35 -0
  222. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/candidates/global-account/global-account-candidates.service.ts +109 -0
  223. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/candidates/member-candidates.controller.ts +60 -0
  224. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/candidates/member-candidates.service.ts +939 -0
  225. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/initialization/project-organization-initialization.service.ts +189 -0
  226. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/organization.module.ts +34 -0
  227. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/organization.store.ts +150 -0
  228. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/organization.validation.ts +23 -0
  229. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/positions/positions.controller.ts +160 -0
  230. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/positions/positions.service.ts +636 -0
  231. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/templates/organization-templates.controller.ts +77 -0
  232. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/templates/organization-templates.service.ts +501 -0
  233. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/templates/organization-templates.store.ts +163 -0
  234. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/units/organization-units.controller.ts +187 -0
  235. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/units/organization-units.service.ts +947 -0
  236. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/projects/projects.controller.ts +94 -0
  237. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/projects/projects.module.ts +13 -0
  238. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/projects/projects.service.ts +369 -0
  239. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/queue-worker.bootstrap.ts +27 -0
  240. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/task-queue.constants.ts +24 -0
  241. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/task-queue.contracts.ts +39 -0
  242. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/task-queue.module.ts +61 -0
  243. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/task-queue.processor.ts +75 -0
  244. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/task-queue.service.ts +67 -0
  245. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/db/db.controller.ts +9 -0
  246. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/db/db.service.ts +9 -0
  247. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/error-catelog.spec.ts +34 -0
  248. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/redis/redis.controller.ts +9 -0
  249. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/redis/redis.service.ts +18 -0
  250. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/dto/initiate-mutipart-upload.dto.ts +26 -0
  251. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/dto/upload-params.dto.ts +15 -0
  252. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/storage/exact-size.transform.ts +77 -0
  253. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/storage/minio-storage.adapter.ts +276 -0
  254. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/storage/storage.port.ts +82 -0
  255. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.constants.ts +32 -0
  256. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.controller.ts +134 -0
  257. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.errors.ts +80 -0
  258. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.module.ts +20 -0
  259. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.reponsitory.ts +193 -0
  260. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.service.ts +774 -0
  261. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/utils/object-key.ts +14 -0
  262. package/template-vp-monorepo-react-nestjs/apps/server/src/utils/server-address.ts +6 -0
  263. package/template-vp-monorepo-react-nestjs/apps/server/test/access/access-policy.spec.ts +95 -0
  264. package/template-vp-monorepo-react-nestjs/apps/server/test/access/access.integration.spec.ts +2250 -0
  265. package/template-vp-monorepo-react-nestjs/apps/server/test/access/member-onboarding.validation.spec.ts +78 -0
  266. package/template-vp-monorepo-react-nestjs/apps/server/test/auth/password-operations.spec.ts +433 -0
  267. package/template-vp-monorepo-react-nestjs/apps/server/test/auth/password.integration.spec.ts +300 -0
  268. package/template-vp-monorepo-react-nestjs/apps/server/test/error-catalog.spec.ts +6 -1
  269. package/template-vp-monorepo-react-nestjs/apps/server/test/menus.validation.spec.ts +28 -0
  270. package/template-vp-monorepo-react-nestjs/apps/server/test/organization/organization-domain.spec.ts +260 -0
  271. package/template-vp-monorepo-react-nestjs/apps/server/test/task-queue.integration.spec.ts +120 -0
  272. package/template-vp-monorepo-react-nestjs/apps/server/test/task-queue.processor.spec.ts +63 -0
  273. package/template-vp-monorepo-react-nestjs/apps/server/test/task-queue.service.spec.ts +106 -0
  274. package/template-vp-monorepo-react-nestjs/apps/server/tsconfig.scripts.json +5 -0
  275. package/template-vp-monorepo-react-nestjs/apps/web/.agents/rules/SVG/344/275/277/347/224/250.md +8 -0
  276. package/template-vp-monorepo-react-nestjs/apps/web/.agents/rules//345/274/271/347/252/227/347/273/204/344/273/266.md +4 -0
  277. package/template-vp-monorepo-react-nestjs/apps/web/.agents/rules//346/226/207/344/273/266/346/213/206/345/210/206.md +4 -0
  278. package/template-vp-monorepo-react-nestjs/apps/web/.agents/rules//347/273/204/344/273/266/345/221/275/345/220/215.md +3 -0
  279. 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
  280. 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
  281. package/template-vp-monorepo-react-nestjs/apps/web/.agents/rules//350/241/250/346/240/274/351/241/265/351/235/242.md +11 -0
  282. package/template-vp-monorepo-react-nestjs/apps/web/.agents/rules//351/241/265/351/235/242/346/216/245/345/217/243.md +3 -0
  283. package/template-vp-monorepo-react-nestjs/apps/web/.env.dev +1 -1
  284. package/template-vp-monorepo-react-nestjs/apps/web/AGENTS.md +25 -0
  285. package/template-vp-monorepo-react-nestjs/apps/web/README.MD +181 -0
  286. package/template-vp-monorepo-react-nestjs/apps/web/index.html +3 -2
  287. package/template-vp-monorepo-react-nestjs/apps/web/package.json +7 -1
  288. package/template-vp-monorepo-react-nestjs/apps/web/public/favicon.svg +9 -1
  289. package/template-vp-monorepo-react-nestjs/apps/web/src/App.module.css +5 -0
  290. package/template-vp-monorepo-react-nestjs/apps/web/src/App.tsx +30 -12
  291. package/template-vp-monorepo-react-nestjs/apps/web/src/api/auth.ts +22 -0
  292. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/accounts.svg +4 -0
  293. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/audit-log.svg +4 -0
  294. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/companies.svg +5 -0
  295. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/dashboard.svg +6 -0
  296. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/draft.svg +4 -0
  297. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/home.svg +4 -0
  298. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/members.svg +4 -0
  299. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/menu-item.svg +4 -0
  300. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/menus.svg +6 -0
  301. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/organization-template.svg +4 -0
  302. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/organization.svg +6 -0
  303. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/positions.svg +4 -0
  304. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/profile.svg +5 -0
  305. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/projects.svg +4 -0
  306. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/roles.svg +4 -0
  307. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Brand/Brand.module.css +125 -0
  308. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Brand/Brand.tsx +56 -0
  309. package/template-vp-monorepo-react-nestjs/apps/web/src/components/DraftProTable/DraftProTable.module.css +78 -0
  310. package/template-vp-monorepo-react-nestjs/apps/web/src/components/DraftProTable/DraftProTable.tsx +105 -0
  311. package/template-vp-monorepo-react-nestjs/apps/web/src/components/DraftProTable/README.md +34 -0
  312. package/template-vp-monorepo-react-nestjs/apps/web/src/components/FullHeightProTable/FullHeightProTable.module.css +54 -0
  313. package/template-vp-monorepo-react-nestjs/apps/web/src/components/FullHeightProTable/FullHeightProTable.tsx +41 -0
  314. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Icon/SvgAsset/IconSelector.tsx +38 -0
  315. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Icon/SvgAsset/SvgAssetIcon.tsx +14 -0
  316. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Icon/SvgAsset/SvgAssetRegistry.ts +32 -0
  317. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Icon/SvgAsset/index.ts +10 -0
  318. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Icon/svg-icon/README.md +37 -0
  319. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Icon/svg-icon/SvgIcon.tsx +25 -0
  320. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Loading/PageLoading.module.css +7 -0
  321. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Loading/PageLoading.tsx +6 -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 +52 -0
  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/index.tsx +113 -0
  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.module.css +23 -0
  400. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/i18n/index.tsx +35 -0
  401. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/components/ProjectFormDialog.tsx +137 -0
  402. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/config/columns.tsx +126 -0
  403. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/config/index.ts +87 -0
  404. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/components/DraftProjectFormDialog.tsx +147 -0
  405. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/config/columns.tsx +134 -0
  406. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/config/index.ts +39 -0
  407. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/config/projects.ts +56 -0
  408. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/index.module.css +49 -0
  409. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/index.tsx +183 -0
  410. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/index.module.css +53 -0
  411. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/index.tsx +150 -0
  412. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/home/index.module.css +23 -0
  413. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/home/index.tsx +28 -42
  414. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/login/api.ts +14 -0
  415. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/login/index.tsx +163 -0
  416. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/login/login-form.css +199 -0
  417. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/login/login.css +186 -0
  418. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/member-invitations/accept.css +47 -0
  419. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/member-invitations/accept.tsx +143 -0
  420. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/member-invitations/api.ts +20 -0
  421. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/api.ts +91 -0
  422. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/MoveOrganizationUnitDialog.tsx +82 -0
  423. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationBrowser/OrganizationMemberColumns.tsx +87 -0
  424. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationBrowser/OrganizationMemberHeader.tsx +102 -0
  425. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationBrowser/OrganizationTreeModel.tsx +59 -0
  426. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationBrowser/OrganizationTreePanel.tsx +88 -0
  427. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationBrowser/index.ts +11 -0
  428. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationBrowser/organization-loaders.ts +47 -0
  429. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationBrowser/organization-member-filter-loaders.ts +187 -0
  430. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationMembersDialog.tsx +207 -0
  431. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationUnitDialog.tsx +110 -0
  432. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/index.tsx +258 -0
  433. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization-templates/api.ts +53 -0
  434. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization-templates/components/OrganizationTemplateDialog/TemplateDefinitionTabs.tsx +189 -0
  435. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization-templates/components/OrganizationTemplateDialog/index.tsx +135 -0
  436. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization-templates/components/OrganizationTemplateDialog/types.ts +25 -0
  437. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization-templates/index.tsx +201 -0
  438. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/positions/api.ts +81 -0
  439. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/positions/components/PositionFormDialog.tsx +86 -0
  440. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/positions/components/PositionMembersDialog.tsx +102 -0
  441. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/positions/index.tsx +198 -0
  442. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/positions/loaders.ts +35 -0
  443. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/register/api.ts +14 -0
  444. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/register/index.tsx +157 -0
  445. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/workspaces/api.ts +32 -0
  446. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/workspaces/index.tsx +146 -0
  447. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/workspaces/state.ts +24 -0
  448. package/template-vp-monorepo-react-nestjs/apps/web/src/router/AGENTS.MD +6 -0
  449. package/template-vp-monorepo-react-nestjs/apps/web/src/router/index.tsx +3 -23
  450. package/template-vp-monorepo-react-nestjs/apps/web/src/router/lazy-load/index.tsx +26 -0
  451. package/template-vp-monorepo-react-nestjs/apps/web/src/router/middleware/README.md +23 -0
  452. package/template-vp-monorepo-react-nestjs/apps/web/src/router/middleware/auth.ts +6 -0
  453. package/template-vp-monorepo-react-nestjs/apps/web/src/router/middleware/index.ts +4 -0
  454. package/template-vp-monorepo-react-nestjs/apps/web/src/router/middleware/workspace/access.ts +23 -0
  455. package/template-vp-monorepo-react-nestjs/apps/web/src/router/middleware/workspace/data.ts +55 -0
  456. package/template-vp-monorepo-react-nestjs/apps/web/src/router/middleware/workspace/entry.ts +52 -0
  457. package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/access/page.tsx +20 -0
  458. package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/auth.tsx +17 -0
  459. package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/company.tsx +30 -0
  460. package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/entry.tsx +20 -0
  461. package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/examples.tsx +23 -0
  462. package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/fallback.tsx +13 -0
  463. package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/index.tsx +32 -0
  464. package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/platform.tsx +27 -0
  465. package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/project.tsx +28 -0
  466. package/template-vp-monorepo-react-nestjs/apps/web/src/router/page-registry.tsx +94 -0
  467. package/template-vp-monorepo-react-nestjs/apps/web/src/styles/dream.css +34 -0
  468. package/template-vp-monorepo-react-nestjs/apps/web/src/styles/index.css +17 -4
  469. package/template-vp-monorepo-react-nestjs/apps/web/src/types/auto-imports.d.ts +26 -0
  470. package/template-vp-monorepo-react-nestjs/apps/web/src/utils/organization-assignment.ts +66 -0
  471. package/template-vp-monorepo-react-nestjs/apps/web/src/utils/request/core/index.ts +101 -58
  472. package/template-vp-monorepo-react-nestjs/apps/web/src/utils/request/core/utils.ts +5 -0
  473. package/template-vp-monorepo-react-nestjs/apps/web/src/utils/request/index.ts +16 -6
  474. package/template-vp-monorepo-react-nestjs/apps/web/src/utils/request/workspace.ts +82 -0
  475. package/template-vp-monorepo-react-nestjs/apps/web/src/utils/safe-next.ts +36 -0
  476. package/template-vp-monorepo-react-nestjs/apps/web/src/utils/storage/cookie.ts +51 -0
  477. package/template-vp-monorepo-react-nestjs/apps/web/src/utils/storage/session.ts +34 -0
  478. package/template-vp-monorepo-react-nestjs/apps/web/test/draft-projects.spec.ts +89 -0
  479. package/template-vp-monorepo-react-nestjs/apps/web/test/i18n-locale.spec.ts +22 -0
  480. package/template-vp-monorepo-react-nestjs/apps/web/test/icon-selector.spec.tsx +23 -0
  481. package/template-vp-monorepo-react-nestjs/apps/web/test/latest-dialog-request.spec.ts +89 -0
  482. package/template-vp-monorepo-react-nestjs/apps/web/test/member-invitation-navigation.spec.ts +34 -0
  483. package/template-vp-monorepo-react-nestjs/apps/web/test/organization-assignment.spec.ts +137 -0
  484. package/template-vp-monorepo-react-nestjs/apps/web/test/password-actions.spec.ts +40 -0
  485. package/template-vp-monorepo-react-nestjs/apps/web/test/password-reset-action.spec.ts +64 -0
  486. package/template-vp-monorepo-react-nestjs/apps/web/test/request.spec.ts +146 -0
  487. package/template-vp-monorepo-react-nestjs/apps/web/test/router/access.spec.ts +136 -0
  488. package/template-vp-monorepo-react-nestjs/apps/web/test/router/config.ts +140 -0
  489. package/template-vp-monorepo-react-nestjs/apps/web/test/router/entry.spec.ts +179 -0
  490. package/template-vp-monorepo-react-nestjs/apps/web/test/router/workspace-data.spec.ts +112 -0
  491. package/template-vp-monorepo-react-nestjs/apps/web/test/selector/global-account-select.spec.ts +311 -0
  492. package/template-vp-monorepo-react-nestjs/apps/web/test/selector/organization-member-selector.spec.ts +454 -0
  493. package/template-vp-monorepo-react-nestjs/apps/web/test/selector/selector-selection.spec.ts +132 -0
  494. package/template-vp-monorepo-react-nestjs/apps/web/test/storage.spec.ts +109 -0
  495. package/template-vp-monorepo-react-nestjs/apps/web/test/tsconfig.json +7 -0
  496. package/template-vp-monorepo-react-nestjs/apps/web/test/workspace-navigation-boundary.spec.tsx +169 -0
  497. package/template-vp-monorepo-react-nestjs/apps/web/test/workspace-navigation.spec.ts +105 -0
  498. package/template-vp-monorepo-react-nestjs/apps/web/test/workspace-requests.spec.ts +174 -0
  499. package/template-vp-monorepo-react-nestjs/apps/web/test/workspaces-password-entry.spec.tsx +71 -0
  500. package/template-vp-monorepo-react-nestjs/apps/web/tsconfig.json +1 -1
  501. package/template-vp-monorepo-react-nestjs/apps/web/vite.config.ts +85 -29
  502. package/template-vp-monorepo-react-nestjs/apps/web-vue/package.json +2 -0
  503. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/api/index.ts +1 -0
  504. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/hooks/chart/useEcharts.ts +13 -1
  505. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/layout/default/header/index.vue +1 -0
  506. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/layout/default/index.vue +6 -2
  507. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/router/guard/index.ts +1 -0
  508. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/router/guard/permissionGuard.ts +1 -0
  509. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/router/index.ts +1 -0
  510. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/store/index.ts +1 -0
  511. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/store/modules/user.ts +1 -0
  512. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/types/auto-import.d.ts +2 -0
  513. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/utils/request/core/index.ts +30 -0
  514. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/utils/request/core/utils.ts +5 -0
  515. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/utils/request/index.ts +2 -0
  516. package/template-vp-monorepo-react-nestjs/apps/web-vue/src/views/example/echart/config.ts +1 -0
  517. package/template-vp-monorepo-react-nestjs/apps/web-vue/tsconfig.tsbuildinfo +1 -0
  518. package/template-vp-monorepo-react-nestjs/docker-compose.yml +19 -0
  519. package/template-vp-monorepo-react-nestjs/mise.toml +1 -1
  520. package/template-vp-monorepo-react-nestjs/package.json +1 -13
  521. package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/command.ts +22 -2
  522. package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/config.ts +1 -0
  523. package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/files.ts +1 -0
  524. package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/load-config.ts +8 -0
  525. package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/report.ts +2 -0
  526. package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/scanner.ts +11 -0
  527. package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/sync.ts +12 -0
  528. package/template-vp-monorepo-react-nestjs/packages/i18n/cli/test/command.test.ts +1 -0
  529. package/template-vp-monorepo-react-nestjs/packages/i18n/cli/test/temporary-directory.ts +5 -0
  530. package/template-vp-monorepo-react-nestjs/packages/i18n/core/src/format.ts +1 -0
  531. package/template-vp-monorepo-react-nestjs/packages/i18n/core/src/i18n.ts +14 -0
  532. package/template-vp-monorepo-react-nestjs/packages/i18n/core/src/storage.ts +8 -0
  533. package/template-vp-monorepo-react-nestjs/packages/i18n/core/src/store.ts +9 -0
  534. package/template-vp-monorepo-react-nestjs/packages/i18n/react/src/index.tsx +5 -0
  535. package/template-vp-monorepo-react-nestjs/packages/i18n/react/src/use-store.ts +3 -0
  536. package/template-vp-monorepo-react-nestjs/packages/i18n/vue/src/index.ts +6 -0
  537. package/template-vp-monorepo-react-nestjs/packages/i18n/vue/src/use-store.ts +3 -0
  538. package/template-vp-monorepo-react-nestjs/packages/shared/package.json +5 -1
  539. package/template-vp-monorepo-react-nestjs/packages/shared/src/index.ts +2 -13
  540. package/template-vp-monorepo-react-nestjs/packages/shared/src/types/access-maintenance.ts +68 -0
  541. package/template-vp-monorepo-react-nestjs/packages/shared/src/types/access-menus.ts +94 -0
  542. package/template-vp-monorepo-react-nestjs/packages/shared/src/types/access-resources.ts +168 -0
  543. package/template-vp-monorepo-react-nestjs/packages/shared/src/types/access.ts +71 -0
  544. package/template-vp-monorepo-react-nestjs/packages/shared/src/types/auth.ts +23 -0
  545. package/template-vp-monorepo-react-nestjs/packages/shared/src/types/index.ts +9 -0
  546. package/template-vp-monorepo-react-nestjs/packages/shared/src/types/organization/models.ts +361 -0
  547. package/template-vp-monorepo-react-nestjs/packages/shared/src/utils/access-catalog.ts +304 -0
  548. package/template-vp-monorepo-react-nestjs/packages/shared/src/utils/access-scope.ts +97 -0
  549. package/template-vp-monorepo-react-nestjs/packages/shared/src/utils/account.ts +1 -0
  550. package/template-vp-monorepo-react-nestjs/packages/shared/src/utils/index.ts +65 -0
  551. package/template-vp-monorepo-react-nestjs/packages/shared/src/utils/organization/contracts.ts +237 -0
  552. package/template-vp-monorepo-react-nestjs/packages/shared/src/utils/record.ts +10 -0
  553. package/template-vp-monorepo-react-nestjs/packages/shared/src/utils/session-terminal.ts +1 -0
  554. package/template-vp-monorepo-react-nestjs/packages/shared/test/access.spec.ts +194 -0
  555. package/template-vp-monorepo-react-nestjs/packages/shared/test/organization.spec.ts +168 -0
  556. package/template-vp-monorepo-react-nestjs/pnpm-workspace.yaml +110 -68
  557. package/template-vp-monorepo-react-nestjs/scripts/enterprise-qa/browser.mjs +696 -0
  558. package/template-vp-monorepo-react-nestjs/scripts/enterprise-qa/http-support.mjs +105 -0
  559. package/template-vp-monorepo-react-nestjs/scripts/enterprise-qa/http.mjs +1091 -0
  560. package/template-vp-monorepo-react-nestjs/scripts/enterprise-qa/legacy-http.mjs +140 -0
  561. package/template-vp-monorepo-react-nestjs/scripts/enterprise-qa/legacy.mjs +196 -0
  562. package/template-vp-monorepo-react-nestjs/scripts/enterprise-qa/runtime.mjs +110 -0
  563. package/template-vp-monorepo-react-nestjs/scripts/with-enterprise-test-env.mjs +80 -0
  564. package/template-vp-monorepo-react-nestjs/src/types/auto-imports.d.ts +60 -0
  565. package/template-vp-react/.vscode/settings.json +8 -1
  566. package/template-vp-react/commitlint.config.js +0 -0
  567. package/template-vp-react/package.json +21 -26
  568. package/template-vp-react/pnpm-workspace.yaml +6 -0
  569. package/template-vp-react/src/assets/svg/draft.svg +4 -0
  570. package/template-vp-react/src/components/Icon/svg-icon/README.md +37 -0
  571. package/template-vp-react/src/components/Icon/svg-icon/SvgIcon.tsx +27 -0
  572. package/template-vp-react/src/types/auto-imports.d.ts +2 -0
  573. package/template-vp-react/src/utils/request/index.ts +18 -5
  574. package/template-vp-react/tsconfig.json +2 -3
  575. package/template-vp-react/vite.config.ts +2 -0
  576. package/template-vp-react-shadcn/.agents/rules/SVG/344/275/277/347/224/250.md +8 -0
  577. package/template-vp-react-shadcn/.vscode/settings.json +2 -2
  578. package/template-vp-react-shadcn/{agents.md → AGENTS.md} +12 -2
  579. package/template-vp-react-shadcn/README.md +41 -0
  580. package/template-vp-react-shadcn/commitlint.config.js +1 -1
  581. package/template-vp-react-shadcn/components.json +1 -1
  582. package/template-vp-react-shadcn/package.json +25 -32
  583. package/template-vp-react-shadcn/pnpm-workspace.yaml +10 -0
  584. package/template-vp-react-shadcn/src/App.tsx +10 -10
  585. package/template-vp-react-shadcn/src/assets/svg/draft.svg +4 -0
  586. package/template-vp-react-shadcn/src/components/Icon/svg-icon/README.md +37 -0
  587. package/template-vp-react-shadcn/src/components/Icon/svg-icon/SvgIcon.tsx +27 -0
  588. package/template-vp-react-shadcn/src/components/Loading/PageLoading.tsx +4 -4
  589. package/template-vp-react-shadcn/src/components/Player/VideoJS/index.tsx +94 -78
  590. package/template-vp-react-shadcn/src/components/Player/index.ts +1 -1
  591. package/template-vp-react-shadcn/src/components/ui/button.tsx +25 -32
  592. package/template-vp-react-shadcn/src/components/ui/spinner.tsx +8 -7
  593. package/template-vp-react-shadcn/src/components/ui/toast.tsx +229 -0
  594. package/template-vp-react-shadcn/src/lib/utils.ts +3 -3
  595. package/template-vp-react-shadcn/src/main.tsx +5 -4
  596. package/template-vp-react-shadcn/src/pages/home/index.tsx +43 -35
  597. package/template-vp-react-shadcn/src/router/index.tsx +15 -15
  598. package/template-vp-react-shadcn/src/styles/index.css +4 -4
  599. package/template-vp-react-shadcn/src/styles/shadcn.css +2 -2
  600. package/template-vp-react-shadcn/src/utils/env/index.tsx +2 -2
  601. package/template-vp-react-shadcn/src/utils/request/alova-core/index.ts +102 -30
  602. package/template-vp-react-shadcn/src/utils/request/alova-core/utils.ts +5 -2
  603. package/template-vp-react-shadcn/src/utils/request/index.ts +32 -19
  604. package/template-vp-react-shadcn/src/utils/request/readme.md +41 -38
  605. package/template-vp-react-shadcn/tsconfig.json +2 -3
  606. package/template-vp-react-shadcn/vite.config.ts +29 -15
  607. package/template-vp-vue-eslint-vapor/package.json +29 -36
  608. package/template-vp-vue-eslint-vapor/pnpm-workspace.yaml +29 -1
  609. package/template-vue-vp-eslint/README.md +3 -10
  610. package/template-vue-vp-eslint/package.json +27 -34
  611. package/template-vue-vp-eslint/pnpm-workspace.yaml +27 -2
  612. package/template-vue-vp-eslint/src/layout/default/index.vue +4 -3
  613. package/template-vp-monorepo-react-nestjs/.agents/auth.config.ts +0 -0
  614. package/template-vp-monorepo-react-nestjs/.spaces/server/todo.md +0 -991
  615. package/template-vp-monorepo-react-nestjs/apps/server/README.md +0 -3
  616. package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/.gitkeep +0 -0
  617. package/template-vp-react-shadcn/.oxfmtrc.jsonc +0 -8
  618. package/template-vp-react-shadcn/.oxlintrc.jsonc +0 -3
  619. package/template-vp-react-shadcn/src/components/ui/sonner.tsx +0 -43
  620. /package/template-vp-monorepo-react-nestjs/apps/web/src/assets/{hero.png → image/hero.png} +0 -0
  621. /package/template-vp-monorepo-react-nestjs/apps/web/src/assets/{react.svg → svg/react.svg} +0 -0
  622. /package/template-vp-monorepo-react-nestjs/apps/web/src/assets/{vite.svg → svg/vite.svg} +0 -0
@@ -0,0 +1,1091 @@
1
+ import { existsSync } from 'node:fs'
2
+ import { randomBytes, randomUUID } from 'node:crypto'
3
+ import { setTimeout as delay } from 'node:timers/promises'
4
+ import {
5
+ loadRuntime,
6
+ databaseConfig,
7
+ randomIdentity,
8
+ ensure,
9
+ privateStatePath,
10
+ readPrivateState,
11
+ writePrivateState,
12
+ createReporter,
13
+ serverRequire,
14
+ } from './runtime.mjs'
15
+ import {
16
+ apiClient,
17
+ registerIdentity,
18
+ loginIdentity,
19
+ runInitialization,
20
+ flattenMenus,
21
+ findMember,
22
+ } from './http-support.mjs'
23
+
24
+ const { runtime, runtimePath } = loadRuntime(process.argv[2])
25
+ ensure(runtime.database.database === 'enterprise_test', 'HTTP 验收只允许 enterprise_test')
26
+ const request = apiClient(runtime)
27
+ const statePath = privateStatePath(runtimePath, 'http')
28
+ const report = createReporter('http')
29
+ const { Client } = serverRequire('pg')
30
+ const db = new Client(databaseConfig(runtime))
31
+ const state = existsSync(statePath) ? readPrivateState(statePath) : {}
32
+ const suffix = randomBytes(4).toString('hex')
33
+ let accounts
34
+ let fixtures
35
+
36
+ function check(id, acceptance, run) {
37
+ return report.check({ id, acceptance, run })
38
+ }
39
+
40
+ async function roleList({ actor, base }) {
41
+ return (await request({ actor, path: `${base}/roles?pageSize=100` })).body.items
42
+ }
43
+
44
+ async function setStatus({ actor, path, current, status, expected = 200 }) {
45
+ return (
46
+ await request({
47
+ actor,
48
+ method: 'PATCH',
49
+ path: `${path}/status`,
50
+ body: { expectedVersion: current.version, status },
51
+ expected,
52
+ })
53
+ ).body
54
+ }
55
+
56
+ /** 由企业管理员签发一次性邀请,并由目标账号接受以建立企业成员关系。 */
57
+ async function inviteCompanyMember({ administrator, member, base }) {
58
+ const invitation = (
59
+ await request({
60
+ actor: administrator,
61
+ path: `${base}/member-invitations`,
62
+ method: 'POST',
63
+ expected: 201,
64
+ body: {},
65
+ })
66
+ ).body
67
+ ensure(invitation.token, '企业成员邀请未返回一次性 token')
68
+ await request({
69
+ actor: member,
70
+ path: '/company-member-invitations/accept',
71
+ method: 'POST',
72
+ expected: 200,
73
+ body: { token: invitation.token },
74
+ })
75
+ }
76
+
77
+ async function menuTree(scopeType) {
78
+ return (
79
+ await request({ actor: accounts.platform, path: `/platform/menus?scopeType=${scopeType}` })
80
+ ).body
81
+ }
82
+
83
+ async function updateMenu({ scopeType, id, changes, expected = 200 }) {
84
+ const tree = await menuTree(scopeType)
85
+ return (
86
+ await request({
87
+ actor: accounts.platform,
88
+ method: 'PATCH',
89
+ path: `/platform/menus/${id}`,
90
+ body: { expectedVersion: tree.version, ...changes },
91
+ expected,
92
+ })
93
+ ).body
94
+ }
95
+
96
+ async function queuedWrites({ first, second }) {
97
+ const blocker = new Client(databaseConfig(runtime))
98
+ await blocker.connect()
99
+ let firstPromise
100
+ let secondPromise
101
+ try {
102
+ await blocker.query('BEGIN')
103
+ await blocker.query('SELECT pg_advisory_xact_lock(7421, 1)')
104
+ const waitForBlocked = async (count) => {
105
+ for (let attempt = 0; attempt < 150; attempt++) {
106
+ const result = await db.query(
107
+ "SELECT count(*)::int AS count FROM pg_stat_activity WHERE datname = current_database() AND wait_event_type = 'Lock' AND wait_event = 'advisory'",
108
+ )
109
+ if (result.rows[0].count >= count) return
110
+ await delay(30)
111
+ }
112
+ throw new Error('未观察到 HTTP 管理写操作等待约定的 PostgreSQL advisory lock')
113
+ }
114
+ firstPromise = first()
115
+ await waitForBlocked(1)
116
+ secondPromise = second()
117
+ await waitForBlocked(2)
118
+ await blocker.query('COMMIT')
119
+ return await Promise.all([firstPromise, secondPromise])
120
+ } finally {
121
+ await blocker.query('ROLLBACK').catch(() => {})
122
+ await Promise.allSettled([firstPromise, secondPromise].filter(Boolean))
123
+ await blocker.end()
124
+ }
125
+ }
126
+
127
+ try {
128
+ await db.connect()
129
+ if (!state.platform) {
130
+ const bootstrapped = await db.query('SELECT count(*)::int AS count FROM access_bootstrap')
131
+ ensure(bootstrapped.rows[0].count === 0, '数据库已有未知首管理员,拒绝修改初始化或猜测测试凭据')
132
+ state.platform = await registerIdentity({ request, identity: randomIdentity('platform') })
133
+ writePrivateState(statePath, state)
134
+ }
135
+ const bootstrap = await db.query('SELECT count(*)::int AS count FROM access_bootstrap')
136
+ if (bootstrap.rows[0].count === 0)
137
+ runInitialization({ runtimePath, account: state.platform.account })
138
+ await loginIdentity({ request, identity: state.platform })
139
+ accounts = { platform: state.platform }
140
+ for (const label of ['enterprise', 'project', 'member', 'other', 'empty', 'replacement']) {
141
+ const identity = await registerIdentity({ request, identity: randomIdentity(label) })
142
+ accounts[label] = await loginIdentity({ request, identity })
143
+ }
144
+ state.accounts = accounts
145
+ writePrivateState(statePath, state)
146
+
147
+ await check('http-empty-workspaces-and-platform-entry', ['AC-01'], async () => {
148
+ const empty = (await request({ actor: accounts.empty, path: '/workspaces' })).body
149
+ ensure(empty.workspaces.length === 0, '普通新账号被自动分配工作空间')
150
+ const platform = (await request({ actor: accounts.platform, path: '/workspaces' })).body
151
+ ensure(
152
+ platform.workspaces.some((item) => item.scope.type === 'platform'),
153
+ '无企业平台管理员缺少平台入口',
154
+ )
155
+ ensure(
156
+ !platform.workspaces.some((item) => item.scope.type !== 'platform'),
157
+ '平台管理员被自动加入企业',
158
+ )
159
+ await request({ path: '/workspaces', expected: 401 })
160
+ })
161
+
162
+ const company = (
163
+ await request({
164
+ actor: accounts.platform,
165
+ path: '/platform/companies',
166
+ method: 'POST',
167
+ expected: 201,
168
+ body: {
169
+ name: `验收企业甲${suffix}`,
170
+ code: `qa_a_${suffix}`,
171
+ administratorUserId: accounts.enterprise.id,
172
+ },
173
+ })
174
+ ).body
175
+ const otherCompany = (
176
+ await request({
177
+ actor: accounts.platform,
178
+ path: '/platform/companies',
179
+ method: 'POST',
180
+ expected: 201,
181
+ body: {
182
+ name: `验收企业乙${suffix}`,
183
+ code: `qa_b_${suffix}`,
184
+ administratorUserId: accounts.other.id,
185
+ },
186
+ })
187
+ ).body
188
+ const base = `/companies/${company.id}`
189
+ const otherBase = `/companies/${otherCompany.id}`
190
+ for (const user of [accounts.project, accounts.member]) {
191
+ await inviteCompanyMember({ administrator: accounts.enterprise, member: user, base })
192
+ }
193
+ await inviteCompanyMember({
194
+ administrator: accounts.other,
195
+ member: accounts.enterprise,
196
+ base: otherBase,
197
+ })
198
+ const project = (
199
+ await request({
200
+ actor: accounts.enterprise,
201
+ path: `${base}/projects`,
202
+ method: 'POST',
203
+ expected: 201,
204
+ body: {
205
+ name: `验收项目甲${suffix}`,
206
+ code: `project_a_${suffix}`,
207
+ administratorUserId: accounts.project.id,
208
+ organizationInitialization: { mode: 'blank' },
209
+ },
210
+ })
211
+ ).body
212
+ const secondProject = (
213
+ await request({
214
+ actor: accounts.enterprise,
215
+ path: `${base}/projects`,
216
+ method: 'POST',
217
+ expected: 201,
218
+ body: {
219
+ name: `验收项目乙${suffix}`,
220
+ code: `project_b_${suffix}`,
221
+ administratorUserId: accounts.project.id,
222
+ organizationInitialization: { mode: 'blank' },
223
+ },
224
+ })
225
+ ).body
226
+ const projectBase = `${base}/projects/${project.id}`
227
+ const secondProjectBase = `${base}/projects/${secondProject.id}`
228
+ await request({
229
+ actor: accounts.project,
230
+ path: `${projectBase}/members`,
231
+ method: 'POST',
232
+ expected: 201,
233
+ body: { userId: accounts.member.id },
234
+ })
235
+ fixtures = {
236
+ company,
237
+ otherCompany,
238
+ project,
239
+ secondProject,
240
+ base,
241
+ otherBase,
242
+ projectBase,
243
+ secondProjectBase,
244
+ }
245
+ state.fixtures = fixtures
246
+ writePrivateState(statePath, state)
247
+ await check('http-create-company-project-transaction', ['AC-01'], async () => {
248
+ const rows = await db.query(
249
+ 'SELECT count(*)::int AS count FROM project_members WHERE project_id = $1 AND user_id = $2',
250
+ [project.id, accounts.project.id],
251
+ )
252
+ ensure(rows.rows[0].count === 1, '创建项目未建立首位管理员成员关系')
253
+ const failedCode = `failed_${suffix}`
254
+ await request({
255
+ actor: accounts.enterprise,
256
+ path: `${base}/projects`,
257
+ method: 'POST',
258
+ expected: 422,
259
+ body: {
260
+ name: '应当回滚的项目',
261
+ code: failedCode,
262
+ administratorUserId: accounts.empty.id,
263
+ organizationInitialization: { mode: 'blank' },
264
+ },
265
+ })
266
+ const failed = await db.query(
267
+ 'SELECT count(*)::int AS count FROM projects WHERE company_id = $1 AND code = $2',
268
+ [company.id, failedCode],
269
+ )
270
+ ensure(failed.rows[0].count === 0, '失败项目创建留下部分项目记录')
271
+ })
272
+
273
+ await check('http-scope-isolation-and-implicit-administrator', ['AC-02'], async () => {
274
+ await request({ actor: accounts.platform, path: `${base}/access`, expected: 404 })
275
+ const implicit = (await request({ actor: accounts.enterprise, path: `${projectBase}/access` }))
276
+ .body
277
+ ensure(implicit.administrator === 'company', '企业管理员未取得隐式项目管理能力')
278
+ const membership = await db.query(
279
+ 'SELECT count(*)::int AS count FROM project_members WHERE project_id = $1 AND user_id = $2',
280
+ [project.id, accounts.enterprise.id],
281
+ )
282
+ ensure(membership.rows[0].count === 0, '隐式项目管理被实现为自动创建成员')
283
+ await request({ actor: accounts.member, path: `${projectBase}/access` })
284
+ const foreign = await request({
285
+ actor: accounts.member,
286
+ path: `${otherBase}/access`,
287
+ expected: 404,
288
+ })
289
+ const missing = await request({
290
+ actor: accounts.member,
291
+ path: `/companies/${randomUUID()}/access`,
292
+ expected: 404,
293
+ })
294
+ ensure(
295
+ foreign.body.code === missing.body.code && foreign.body.message === missing.body.message,
296
+ '跨企业与不存在资源返回不一致',
297
+ )
298
+ await request({ actor: accounts.member, path: `${secondProjectBase}/access`, expected: 404 })
299
+ await request({ actor: accounts.enterprise, path: otherBase, expected: 403 })
300
+ const visible = (await request({ actor: accounts.member, path: `${base}/projects` })).body
301
+ ensure(
302
+ visible.items.length === 1 && visible.items[0].id === project.id,
303
+ '普通成员项目列表泄漏未加入项目',
304
+ )
305
+ })
306
+
307
+ await check('http-member-and-project-input-boundaries', ['AC-06', 'AC-11'], async () => {
308
+ await request({
309
+ actor: accounts.enterprise,
310
+ path: `${base}/members`,
311
+ method: 'POST',
312
+ expected: 400,
313
+ body: { account: accounts.member.account },
314
+ })
315
+ await request({
316
+ actor: accounts.project,
317
+ path: `${projectBase}/members`,
318
+ method: 'POST',
319
+ expected: 400,
320
+ body: { account: accounts.empty.account },
321
+ })
322
+ await request({
323
+ actor: accounts.member,
324
+ path: `${base}/projects`,
325
+ method: 'POST',
326
+ expected: 403,
327
+ body: {
328
+ name: '越权项目',
329
+ code: 'forbidden',
330
+ administratorUserId: accounts.member.id,
331
+ organizationInitialization: { mode: 'blank' },
332
+ },
333
+ })
334
+ await request({
335
+ actor: accounts.project,
336
+ path: `${base}/projects`,
337
+ method: 'POST',
338
+ expected: 403,
339
+ body: {
340
+ name: '越权项目',
341
+ code: 'forbidden',
342
+ administratorUserId: accounts.project.id,
343
+ organizationInitialization: { mode: 'blank' },
344
+ },
345
+ })
346
+ await request({
347
+ actor: accounts.enterprise,
348
+ path: `${base}/roles`,
349
+ method: 'POST',
350
+ expected: 400,
351
+ body: {
352
+ name: `不可下放${suffix}`,
353
+ permissionKeys: ['company.projects.read', 'company.projects.create'],
354
+ },
355
+ })
356
+ await request({
357
+ actor: accounts.enterprise,
358
+ path: `${base}/members?pageSize=101`,
359
+ expected: 400,
360
+ })
361
+ await request({
362
+ actor: accounts.enterprise,
363
+ path: `${base}/members`,
364
+ method: 'POST',
365
+ expected: 400,
366
+ body: { account: accounts.empty.account, companyId: otherCompany.id },
367
+ })
368
+ })
369
+
370
+ const companyRoles = await roleList({ actor: accounts.enterprise, base })
371
+ const builtinAdmin = companyRoles.find((role) => role.builtin === 'administrator')
372
+ const builtinMember = companyRoles.find((role) => role.builtin === 'member')
373
+ ensure(builtinAdmin && builtinMember, '缺少企业内置角色')
374
+ let editableRole = (
375
+ await request({
376
+ actor: accounts.enterprise,
377
+ path: `${base}/roles`,
378
+ method: 'POST',
379
+ expected: 201,
380
+ body: {
381
+ name: `资料编辑${suffix}`,
382
+ permissionKeys: ['company.profile.read', 'company.profile.update'],
383
+ },
384
+ })
385
+ ).body
386
+ let ordinaryMember = await findMember({
387
+ request,
388
+ actor: accounts.enterprise,
389
+ base,
390
+ userId: accounts.member.id,
391
+ })
392
+ ordinaryMember = (
393
+ await request({
394
+ actor: accounts.enterprise,
395
+ path: `${base}/members/${ordinaryMember.id}/roles`,
396
+ method: 'PUT',
397
+ body: {
398
+ expectedVersion: ordinaryMember.version,
399
+ roleIds: [builtinMember.id, editableRole.id],
400
+ },
401
+ })
402
+ ).body
403
+
404
+ await check('http-role-revoke-version-and-cross-scope', ['AC-04', 'AC-06'], async () => {
405
+ await request({ actor: accounts.member, path: base })
406
+ const oldVersion = editableRole.version
407
+ editableRole = (
408
+ await request({
409
+ actor: accounts.enterprise,
410
+ path: `${base}/roles/${editableRole.id}/permissions`,
411
+ method: 'PUT',
412
+ body: { expectedVersion: editableRole.version, permissionKeys: [] },
413
+ })
414
+ ).body
415
+ await request({ actor: accounts.member, path: base, expected: 403 })
416
+ await request({
417
+ actor: accounts.enterprise,
418
+ path: `${base}/roles/${editableRole.id}/permissions`,
419
+ method: 'PUT',
420
+ expected: 409,
421
+ body: { expectedVersion: oldVersion, permissionKeys: ['company.profile.read'] },
422
+ })
423
+ const foreignRole = (await roleList({ actor: accounts.other, base: otherBase })).find(
424
+ (role) => role.builtin === 'member',
425
+ )
426
+ ordinaryMember = await findMember({
427
+ request,
428
+ actor: accounts.enterprise,
429
+ base,
430
+ userId: accounts.member.id,
431
+ })
432
+ await request({
433
+ actor: accounts.enterprise,
434
+ path: `${base}/members/${ordinaryMember.id}/roles`,
435
+ method: 'PUT',
436
+ expected: 404,
437
+ body: { expectedVersion: ordinaryMember.version, roleIds: [foreignRole.id] },
438
+ })
439
+ editableRole = (
440
+ await request({
441
+ actor: accounts.enterprise,
442
+ path: `${base}/roles/${editableRole.id}/permissions`,
443
+ method: 'PUT',
444
+ body: {
445
+ expectedVersion: editableRole.version,
446
+ permissionKeys: ['company.profile.read', 'company.profile.update'],
447
+ },
448
+ })
449
+ ).body
450
+ })
451
+
452
+ await check('http-builtin-roles-and-last-administrator', ['AC-06', 'AC-12'], async () => {
453
+ await request({
454
+ actor: accounts.enterprise,
455
+ path: `${base}/roles/${builtinAdmin.id}`,
456
+ method: 'PATCH',
457
+ expected: 409,
458
+ body: { expectedVersion: builtinAdmin.version, name: '不可编辑' },
459
+ })
460
+ await request({
461
+ actor: accounts.enterprise,
462
+ path: `${base}/roles/${builtinMember.id}/permissions`,
463
+ method: 'PUT',
464
+ expected: 409,
465
+ body: { expectedVersion: builtinMember.version, permissionKeys: [] },
466
+ })
467
+ await request({
468
+ actor: accounts.enterprise,
469
+ path: `${base}/roles/${builtinAdmin.id}?expectedVersion=${builtinAdmin.version}`,
470
+ method: 'DELETE',
471
+ expected: 409,
472
+ })
473
+ const member = await findMember({
474
+ request,
475
+ actor: accounts.enterprise,
476
+ base,
477
+ userId: accounts.enterprise.id,
478
+ })
479
+ await setStatus({
480
+ actor: accounts.enterprise,
481
+ path: `${base}/members/${member.id}`,
482
+ current: member,
483
+ status: 'disabled',
484
+ expected: 409,
485
+ })
486
+ await request({
487
+ actor: accounts.enterprise,
488
+ path: `${base}/members/${member.id}/roles`,
489
+ method: 'PUT',
490
+ expected: 409,
491
+ body: { expectedVersion: member.version, roleIds: [builtinMember.id] },
492
+ })
493
+ await request({
494
+ actor: accounts.platform,
495
+ path: `/platform/accounts/${accounts.platform.id}/status`,
496
+ method: 'PATCH',
497
+ expected: 409,
498
+ body: { status: 'disabled' },
499
+ })
500
+ await request({ actor: accounts.platform, path: '/auth/me' })
501
+ await request({
502
+ actor: accounts.platform,
503
+ path: `/platform/accounts/${accounts.platform.id}/roles`,
504
+ method: 'PUT',
505
+ expected: 409,
506
+ body: { roleIds: [] },
507
+ })
508
+ })
509
+ await loginIdentity({ request, identity: accounts.platform })
510
+
511
+ await check('http-menu-hidden-disabled-and-protected', ['AC-03', 'AC-06'], async () => {
512
+ const tree = await menuTree('company')
513
+ const profile = flattenMenus(tree.items).find(
514
+ (item) => item.routeKey === 'company.profile' && item.type === 'page',
515
+ )
516
+ ensure(profile, '企业菜单缺少资料页面')
517
+ try {
518
+ await updateMenu({ scopeType: 'company', id: profile.id, changes: { hidden: true } })
519
+ const context = (await request({ actor: accounts.enterprise, path: `${base}/access` })).body
520
+ ensure(context.permissionKeys.includes('company.profile.read'), '隐藏菜单错误撤销权限')
521
+ ensure(
522
+ !flattenMenus(context.menus).some((item) => item.id === profile.id),
523
+ '隐藏页面仍出现在导航',
524
+ )
525
+ await request({ actor: accounts.enterprise, path: base })
526
+ await updateMenu({ scopeType: 'company', id: profile.id, changes: { status: 'disabled' } })
527
+ await request({ actor: accounts.enterprise, path: base, expected: 403 })
528
+ const platformMenus = await menuTree('platform')
529
+ const protectedPage = flattenMenus(platformMenus.items).find(
530
+ (item) => item.routeKey === 'platform.roles' && item.type === 'page',
531
+ )
532
+ await updateMenu({
533
+ scopeType: 'platform',
534
+ id: protectedPage.id,
535
+ changes: { hidden: true },
536
+ expected: 409,
537
+ })
538
+ } finally {
539
+ await updateMenu({
540
+ scopeType: 'company',
541
+ id: profile.id,
542
+ changes: { hidden: profile.hidden, status: profile.status },
543
+ })
544
+ }
545
+ })
546
+
547
+ await check('http-menu-ancestor-and-cycle-constraints', ['AC-03', 'AC-06'], async () => {
548
+ let tree = await menuTree('company')
549
+ const profile = flattenMenus(tree.items).find(
550
+ (item) => item.routeKey === 'company.profile' && item.type === 'page',
551
+ )
552
+ tree = (
553
+ await request({
554
+ actor: accounts.platform,
555
+ path: '/platform/menus?scopeType=company',
556
+ method: 'POST',
557
+ expected: 201,
558
+ body: {
559
+ expectedVersion: tree.version,
560
+ type: 'directory',
561
+ parentId: null,
562
+ name: `验收目录${suffix}`,
563
+ },
564
+ })
565
+ ).body
566
+ const directory = flattenMenus(tree.items).find((item) => item.name === `验收目录${suffix}`)
567
+ try {
568
+ await updateMenu({
569
+ scopeType: 'company',
570
+ id: profile.id,
571
+ changes: { parentId: directory.id },
572
+ })
573
+ await updateMenu({ scopeType: 'company', id: directory.id, changes: { status: 'disabled' } })
574
+ await request({ actor: accounts.enterprise, path: base, expected: 403 })
575
+ await updateMenu({
576
+ scopeType: 'company',
577
+ id: directory.id,
578
+ changes: { parentId: directory.id },
579
+ expected: 400,
580
+ })
581
+ tree = await menuTree('company')
582
+ await request({
583
+ actor: accounts.platform,
584
+ path: `/platform/menus/${directory.id}?expectedVersion=${tree.version}`,
585
+ method: 'DELETE',
586
+ expected: 409,
587
+ })
588
+ } finally {
589
+ await updateMenu({ scopeType: 'company', id: directory.id, changes: { status: 'active' } })
590
+ await updateMenu({
591
+ scopeType: 'company',
592
+ id: profile.id,
593
+ changes: { parentId: profile.parentId },
594
+ })
595
+ tree = await menuTree('company')
596
+ await request({
597
+ actor: accounts.platform,
598
+ path: `/platform/menus/${directory.id}?expectedVersion=${tree.version}`,
599
+ method: 'DELETE',
600
+ })
601
+ }
602
+ })
603
+
604
+ await check('http-status-preservation-and-member-reenable', ['AC-04', 'AC-09'], async () => {
605
+ let member = await findMember({
606
+ request,
607
+ actor: accounts.project,
608
+ base: projectBase,
609
+ userId: accounts.member.id,
610
+ })
611
+ await setStatus({
612
+ actor: accounts.project,
613
+ path: `${projectBase}/members/${member.id}`,
614
+ current: member,
615
+ status: 'disabled',
616
+ })
617
+ let companyMember = await findMember({
618
+ request,
619
+ actor: accounts.enterprise,
620
+ base,
621
+ userId: accounts.member.id,
622
+ })
623
+ companyMember = await setStatus({
624
+ actor: accounts.enterprise,
625
+ path: `${base}/members/${companyMember.id}`,
626
+ current: companyMember,
627
+ status: 'disabled',
628
+ })
629
+ await request({ actor: accounts.member, path: `${base}/access`, expected: 403 })
630
+ await setStatus({
631
+ actor: accounts.enterprise,
632
+ path: `${base}/members/${companyMember.id}`,
633
+ current: companyMember,
634
+ status: 'active',
635
+ })
636
+ await request({ actor: accounts.member, path: `${projectBase}/access`, expected: 403 })
637
+ member = await findMember({
638
+ request,
639
+ actor: accounts.project,
640
+ base: projectBase,
641
+ userId: accounts.member.id,
642
+ })
643
+ ensure(member.status === 'disabled', '企业成员恢复错误启用了原停用项目成员')
644
+ await setStatus({
645
+ actor: accounts.project,
646
+ path: `${projectBase}/members/${member.id}`,
647
+ current: member,
648
+ status: 'active',
649
+ })
650
+ const savedProject = (await request({ actor: accounts.enterprise, path: secondProjectBase }))
651
+ .body
652
+ await setStatus({
653
+ actor: accounts.enterprise,
654
+ path: secondProjectBase,
655
+ current: savedProject,
656
+ status: 'disabled',
657
+ })
658
+ let savedCompany = (
659
+ await request({ actor: accounts.platform, path: `/platform/companies/${company.id}` })
660
+ ).body
661
+ savedCompany = await setStatus({
662
+ actor: accounts.platform,
663
+ path: `/platform/companies/${company.id}`,
664
+ current: savedCompany,
665
+ status: 'disabled',
666
+ })
667
+ await request({ actor: accounts.enterprise, path: `${projectBase}/access`, expected: 403 })
668
+ await setStatus({
669
+ actor: accounts.platform,
670
+ path: `/platform/companies/${company.id}`,
671
+ current: savedCompany,
672
+ status: 'active',
673
+ })
674
+ await request({ actor: accounts.enterprise, path: `${projectBase}/access` })
675
+ await request({
676
+ actor: accounts.enterprise,
677
+ path: `${secondProjectBase}/access`,
678
+ expected: 403,
679
+ })
680
+ const items = (await request({ actor: accounts.enterprise, path: `${base}/projects` })).body
681
+ .items
682
+ const disabledProject = items.find((item) => item.id === secondProject.id)
683
+ ensure(disabledProject.status === 'disabled', '企业恢复错误启用了原停用项目')
684
+ await setStatus({
685
+ actor: accounts.enterprise,
686
+ path: secondProjectBase,
687
+ current: disabledProject,
688
+ status: 'active',
689
+ })
690
+ })
691
+
692
+ await check(
693
+ 'http-account-disable-replacement-and-session-revocation',
694
+ ['AC-04', 'AC-09', 'AC-10'],
695
+ async () => {
696
+ const oldSession = { accessToken: accounts.other.accessToken }
697
+ await request({
698
+ actor: accounts.platform,
699
+ path: `/platform/accounts/${accounts.other.id}/status`,
700
+ method: 'PATCH',
701
+ body: { status: 'disabled' },
702
+ })
703
+ await request({ actor: oldSession, path: '/auth/me', expected: 401 })
704
+ let target = (
705
+ await request({ actor: accounts.platform, path: `/platform/companies/${otherCompany.id}` })
706
+ ).body
707
+ target = await setStatus({
708
+ actor: accounts.platform,
709
+ path: `/platform/companies/${otherCompany.id}`,
710
+ current: target,
711
+ status: 'disabled',
712
+ })
713
+ await setStatus({
714
+ actor: accounts.platform,
715
+ path: `/platform/companies/${otherCompany.id}`,
716
+ current: target,
717
+ status: 'active',
718
+ expected: 409,
719
+ })
720
+ await request({
721
+ actor: accounts.platform,
722
+ path: `/platform/companies/${otherCompany.id}/administrator`,
723
+ method: 'POST',
724
+ body: {
725
+ administratorUserId: accounts.replacement.id,
726
+ replaceUserId: accounts.other.id,
727
+ },
728
+ })
729
+ target = (
730
+ await request({ actor: accounts.platform, path: `/platform/companies/${otherCompany.id}` })
731
+ ).body
732
+ ensure(target.status === 'disabled', '补任自动启用了企业')
733
+ await setStatus({
734
+ actor: accounts.platform,
735
+ path: `/platform/companies/${otherCompany.id}`,
736
+ current: target,
737
+ status: 'active',
738
+ })
739
+ const context = (await request({ actor: accounts.replacement, path: `${otherBase}/access` }))
740
+ .body
741
+ ensure(context.administrator === 'company', '补任未授予有效企业管理员身份')
742
+ await request({
743
+ actor: accounts.platform,
744
+ path: `/platform/accounts/${accounts.other.id}/status`,
745
+ method: 'PATCH',
746
+ body: { status: 'active' },
747
+ })
748
+ await request({ actor: oldSession, path: '/auth/me', expected: 401 })
749
+ await loginIdentity({ request, identity: accounts.other })
750
+ const previous = (await request({ actor: accounts.other, path: `${otherBase}/access` })).body
751
+ ensure(previous.administrator === null, '被替换旧账号启用后恢复了原管理员身份')
752
+ },
753
+ )
754
+
755
+ await check('http-audit-request-and-failure-atomicity', ['AC-07'], async () => {
756
+ const detail = (await request({ actor: accounts.enterprise, path: base })).body
757
+ const requestId = `qa-audit-${randomUUID()}`
758
+ const response = await request({
759
+ actor: accounts.enterprise,
760
+ path: base,
761
+ method: 'PATCH',
762
+ requestId,
763
+ body: { expectedVersion: detail.version, description: '独立 HTTP 审计验收' },
764
+ })
765
+ ensure(response.requestId, '成功响应缺少服务端请求ID')
766
+ const rows = await db.query(
767
+ 'SELECT scope_type, action, summary FROM audit_logs WHERE request_id = $1',
768
+ [response.requestId],
769
+ )
770
+ ensure(
771
+ rows.rowCount === 1 && rows.rows[0].scope_type === 'company',
772
+ '成功写入未产生同作用域单条审计',
773
+ )
774
+ ensure(
775
+ !/password|accessToken|sessionPepper|authorization|cookie/i.test(
776
+ JSON.stringify(rows.rows[0].summary),
777
+ ),
778
+ '审计摘要出现敏感字段',
779
+ )
780
+ const failureId = `qa-failed-${randomUUID()}`
781
+ const rejected = await request({
782
+ actor: accounts.enterprise,
783
+ path: base,
784
+ method: 'PATCH',
785
+ requestId: failureId,
786
+ expected: 409,
787
+ body: { expectedVersion: detail.version, description: '不应提交' },
788
+ })
789
+ const failed = await db.query(
790
+ 'SELECT count(*)::int AS count FROM audit_logs WHERE request_id = $1',
791
+ [rejected.requestId],
792
+ )
793
+ ensure(failed.rows[0].count === 0, '失败写操作留下成功审计')
794
+ const platformAudit = (
795
+ await request({ actor: accounts.platform, path: '/platform/audit-logs?pageSize=100' })
796
+ ).body
797
+ ensure(
798
+ platformAudit.items.every((item) => item.scope.type === 'platform'),
799
+ '平台审计包含企业内部事件',
800
+ )
801
+ const enterpriseAudit = (
802
+ await request({ actor: accounts.enterprise, path: `${base}/audit-logs?pageSize=100` })
803
+ ).body
804
+ ensure(
805
+ enterpriseAudit.items.every(
806
+ (item) => item.scope.type !== 'platform' && item.scope.companyId === company.id,
807
+ ),
808
+ '企业审计越过作用域边界',
809
+ )
810
+ })
811
+
812
+ await check('http-inflight-revocation-first', ['AC-15'], async () => {
813
+ let member = await findMember({
814
+ request,
815
+ actor: accounts.enterprise,
816
+ base,
817
+ userId: accounts.member.id,
818
+ })
819
+ const detail = (await request({ actor: accounts.enterprise, path: base })).body
820
+ const writeId = `qa-lock-denied-${randomUUID()}`
821
+ const results = await queuedWrites({
822
+ first: () =>
823
+ request({
824
+ actor: accounts.enterprise,
825
+ path: `${base}/members/${member.id}/status`,
826
+ method: 'PATCH',
827
+ expected: null,
828
+ body: { expectedVersion: member.version, status: 'disabled' },
829
+ }),
830
+ second: () =>
831
+ request({
832
+ actor: accounts.member,
833
+ path: base,
834
+ method: 'PATCH',
835
+ expected: null,
836
+ requestId: writeId,
837
+ body: { expectedVersion: detail.version, description: '撤权之后不应写入' },
838
+ }),
839
+ })
840
+ ensure(
841
+ results[0].status === 200 && results[1].status === 403,
842
+ '撤权先提交后,排队的 HTTP 写入未在锁内重新拒绝',
843
+ )
844
+ ensure(results[1].requestId, '并发拒绝响应缺少服务端请求ID')
845
+ const audit = await db.query(
846
+ 'SELECT count(*)::int AS count FROM audit_logs WHERE request_id = $1',
847
+ [results[1].requestId],
848
+ )
849
+ ensure(audit.rows[0].count === 0, '撤权后的失败写入留下成功审计')
850
+ member = await findMember({
851
+ request,
852
+ actor: accounts.enterprise,
853
+ base,
854
+ userId: accounts.member.id,
855
+ })
856
+ await setStatus({
857
+ actor: accounts.enterprise,
858
+ path: `${base}/members/${member.id}`,
859
+ current: member,
860
+ status: 'active',
861
+ })
862
+ })
863
+
864
+ await check('http-inflight-write-first', ['AC-15'], async () => {
865
+ let member = await findMember({
866
+ request,
867
+ actor: accounts.enterprise,
868
+ base,
869
+ userId: accounts.member.id,
870
+ })
871
+ if (member.status !== 'active')
872
+ member = await setStatus({
873
+ actor: accounts.enterprise,
874
+ path: `${base}/members/${member.id}`,
875
+ current: member,
876
+ status: 'active',
877
+ })
878
+ const detail = (await request({ actor: accounts.enterprise, path: base })).body
879
+ const results = await queuedWrites({
880
+ first: () =>
881
+ request({
882
+ actor: accounts.member,
883
+ path: base,
884
+ method: 'PATCH',
885
+ expected: null,
886
+ body: { expectedVersion: detail.version, description: '先取得锁的写操作提交' },
887
+ }),
888
+ second: () =>
889
+ request({
890
+ actor: accounts.enterprise,
891
+ path: `${base}/members/${member.id}/status`,
892
+ method: 'PATCH',
893
+ expected: null,
894
+ body: { expectedVersion: member.version, status: 'disabled' },
895
+ }),
896
+ })
897
+ ensure(
898
+ results.every((item) => item.status === 200),
899
+ '写操作先持锁时未按约定先完成再撤权',
900
+ )
901
+ await request({ actor: accounts.member, path: base, expected: 403 })
902
+ member = await findMember({
903
+ request,
904
+ actor: accounts.enterprise,
905
+ base,
906
+ userId: accounts.member.id,
907
+ })
908
+ await setStatus({
909
+ actor: accounts.enterprise,
910
+ path: `${base}/members/${member.id}`,
911
+ current: member,
912
+ status: 'active',
913
+ })
914
+ })
915
+
916
+ await check('http-cleanup-preview-and-rejected-candidates', ['AC-14'], async () => {
917
+ const preview = (
918
+ await request({ actor: accounts.platform, path: '/platform/permissions/cleanup-preview' })
919
+ ).body
920
+ ensure(
921
+ Array.isArray(preview.items) && preview.items.length === 0,
922
+ '首版目录出现非预期废弃演示项',
923
+ )
924
+ await request({
925
+ actor: accounts.empty,
926
+ path: '/platform/permissions/cleanup-preview',
927
+ expected: 403,
928
+ })
929
+ await request({
930
+ actor: accounts.platform,
931
+ path: '/platform/permissions/cleanup',
932
+ method: 'POST',
933
+ expected: 409,
934
+ body: { permissionKeys: ['platform.companies.read'], proofDigest: 'a'.repeat(64) },
935
+ })
936
+ await request({
937
+ actor: accounts.platform,
938
+ path: '/platform/permissions/cleanup',
939
+ method: 'POST',
940
+ expected: 400,
941
+ body: { permissionKeys: [], proofDigest: 'a'.repeat(64) },
942
+ })
943
+ return 'HTTP 空预览与非法清理拒绝;成功清理、回滚及 tombstone 另由后端受控真实 DB 测试证明'
944
+ })
945
+
946
+ await check('http-seed-repeat-preserves-configuration', ['AC-08', 'AC-12'], async () => {
947
+ const profile = flattenMenus((await menuTree('company')).items).find(
948
+ (item) => item.routeKey === 'company.profile' && item.type === 'page',
949
+ )
950
+ await updateMenu({
951
+ scopeType: 'company',
952
+ id: profile.id,
953
+ changes: { name: `资料配置保留${suffix}`, hidden: true },
954
+ })
955
+ try {
956
+ const assignmentsBefore = await db.query(
957
+ 'SELECT role_id FROM user_roles WHERE user_id = $1 ORDER BY role_id',
958
+ [accounts.member.id],
959
+ )
960
+ runInitialization({ runtimePath, account: accounts.platform.account })
961
+ const preserved = flattenMenus((await menuTree('company')).items).find(
962
+ (item) => item.id === profile.id,
963
+ )
964
+ ensure(
965
+ preserved.name === `资料配置保留${suffix}` && preserved.hidden,
966
+ '重复初始化覆盖了管理员菜单配置',
967
+ )
968
+ const assignmentsAfter = await db.query(
969
+ 'SELECT role_id FROM user_roles WHERE user_id = $1 ORDER BY role_id',
970
+ [accounts.member.id],
971
+ )
972
+ ensure(
973
+ JSON.stringify(assignmentsBefore.rows) === JSON.stringify(assignmentsAfter.rows),
974
+ '重复初始化改变用户角色分配',
975
+ )
976
+ runInitialization({ runtimePath, account: accounts.empty.account, expectedSuccess: false })
977
+ const empty = (await request({ actor: accounts.empty, path: '/workspaces' })).body
978
+ ensure(empty.workspaces.length === 0, '重复初始化向其他账号提权')
979
+ } finally {
980
+ await updateMenu({
981
+ scopeType: 'company',
982
+ id: profile.id,
983
+ changes: { name: profile.name, hidden: profile.hidden },
984
+ })
985
+ }
986
+ })
987
+
988
+ await check('http-upload-owner-regression', ['AC-08'], async () => {
989
+ const upload = (
990
+ await request({
991
+ actor: accounts.member,
992
+ path: '/uploads/multipart',
993
+ method: 'POST',
994
+ expected: 201,
995
+ body: {
996
+ clientUploadId: randomUUID(),
997
+ fileName: 'qa.txt',
998
+ fileSize: 4,
999
+ contentType: 'text/plain',
1000
+ },
1001
+ })
1002
+ ).body
1003
+ const id = upload.uploadSessionId ?? upload.id
1004
+ ensure(typeof id === 'string', '上传初始化响应缺少上传会话 ID')
1005
+ await request({ actor: accounts.empty, path: `/uploads/multipart/${id}`, expected: 404 })
1006
+ await request({
1007
+ actor: accounts.member,
1008
+ path: `/uploads/multipart/${id}/parts/1`,
1009
+ method: 'PUT',
1010
+ body: 'test',
1011
+ headers: { 'Content-Type': 'application/octet-stream', 'Content-Length': '4' },
1012
+ })
1013
+ await request({
1014
+ actor: accounts.member,
1015
+ path: `/uploads/multipart/${id}/complete`,
1016
+ method: 'POST',
1017
+ })
1018
+ const stored = await db.query('SELECT owner_id, status FROM upload_sessions WHERE id = $1', [
1019
+ id,
1020
+ ])
1021
+ ensure(
1022
+ stored.rows[0]?.owner_id === accounts.member.id && stored.rows[0]?.status === 'completed',
1023
+ '上传 ownerId 或完成状态回归失败',
1024
+ )
1025
+ })
1026
+
1027
+ await check(
1028
+ 'http-enterprise-member-removal-cleans-children',
1029
+ ['AC-04', 'AC-06', 'AC-09'],
1030
+ async () => {
1031
+ const member = await findMember({
1032
+ request,
1033
+ actor: accounts.enterprise,
1034
+ base,
1035
+ userId: accounts.member.id,
1036
+ })
1037
+ await request({
1038
+ actor: accounts.enterprise,
1039
+ path: `${base}/members/${member.id}?expectedVersion=${member.version}`,
1040
+ method: 'DELETE',
1041
+ })
1042
+ const child = await db.query(
1043
+ 'SELECT count(*)::int AS count FROM project_members WHERE company_id = $1 AND user_id = $2',
1044
+ [company.id, accounts.member.id],
1045
+ )
1046
+ ensure(child.rows[0].count === 0, '移除企业成员未清理项目关系')
1047
+ await request({ actor: accounts.member, path: `${projectBase}/access`, expected: 404 })
1048
+ await inviteCompanyMember({
1049
+ administrator: accounts.enterprise,
1050
+ member: accounts.member,
1051
+ base,
1052
+ })
1053
+ const restored = await findMember({
1054
+ request,
1055
+ actor: accounts.enterprise,
1056
+ base,
1057
+ userId: accounts.member.id,
1058
+ })
1059
+ ensure(
1060
+ restored.roleIds.length === 1 && restored.roleIds[0] === builtinMember.id,
1061
+ '重新添加恢复了已清理的旧授权',
1062
+ )
1063
+ await request({
1064
+ actor: accounts.project,
1065
+ path: `${projectBase}/members`,
1066
+ method: 'POST',
1067
+ expected: 201,
1068
+ body: { userId: accounts.member.id },
1069
+ })
1070
+ },
1071
+ )
1072
+
1073
+ state.accounts = accounts
1074
+ state.fixtures = fixtures
1075
+ writePrivateState(statePath, state)
1076
+ } catch (error) {
1077
+ report.results.push({
1078
+ id: 'http-setup-or-run',
1079
+ acceptance: ['AC-01'],
1080
+ status: 'failed',
1081
+ evidence: error instanceof Error ? error.message : 'HTTP 验收失败',
1082
+ })
1083
+ process.stdout.write('FAIL http-setup-or-run\n')
1084
+ } finally {
1085
+ if (accounts) state.accounts = accounts
1086
+ if (fixtures) state.fixtures = fixtures
1087
+ writePrivateState(statePath, state)
1088
+ await db.end().catch(() => {})
1089
+ report.save()
1090
+ if (report.results.some((item) => item.status === 'failed')) process.exitCode = 1
1091
+ }