@qlover/create-app 0.7.14 → 0.8.0

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 (361) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/configs/_common/.gitignore.template +6 -0
  3. package/dist/configs/_common/.prettierignore +17 -5
  4. package/dist/configs/_common/.vscode/settings.json +6 -1
  5. package/dist/index.cjs +1 -1
  6. package/dist/index.js +1 -1
  7. package/dist/templates/next-app/.env.template +1 -1
  8. package/dist/templates/next-app/README.en.md +130 -0
  9. package/dist/templates/next-app/README.md +114 -20
  10. package/dist/templates/next-app/config/Identifier/api.ts +5 -5
  11. package/dist/templates/next-app/config/Identifier/common/admint.table.ts +69 -0
  12. package/dist/templates/next-app/config/Identifier/common/common.ts +76 -0
  13. package/dist/templates/next-app/config/Identifier/common/index.ts +3 -0
  14. package/dist/templates/next-app/config/Identifier/{validator.ts → common/validators.ts} +5 -5
  15. package/dist/templates/next-app/config/Identifier/index.ts +2 -12
  16. package/dist/templates/next-app/config/Identifier/pages/index.ts +6 -0
  17. package/dist/templates/next-app/config/Identifier/pages/page.admin.home.ts +27 -0
  18. package/dist/templates/next-app/config/Identifier/pages/page.admin.locales.ts +266 -0
  19. package/dist/templates/next-app/config/Identifier/pages/page.admin.user.ts +293 -0
  20. package/dist/templates/{react-app/config/Identifier → next-app/config/Identifier/pages}/page.home.ts +15 -22
  21. package/dist/templates/next-app/config/Identifier/{page.login.ts → pages/page.login.ts} +28 -34
  22. package/dist/templates/next-app/config/Identifier/{page.register.ts → pages/page.register.ts} +30 -29
  23. package/dist/templates/next-app/config/adminNavs.ts +19 -0
  24. package/dist/templates/next-app/config/common.ts +22 -13
  25. package/dist/templates/next-app/config/i18n/HomeI18n.ts +5 -5
  26. package/dist/templates/next-app/config/i18n/admin18n.ts +61 -19
  27. package/dist/templates/next-app/config/i18n/i18nConfig.ts +2 -0
  28. package/dist/templates/next-app/config/i18n/i18nKeyScheam.ts +36 -0
  29. package/dist/templates/next-app/config/i18n/loginI18n.ts +22 -22
  30. package/dist/templates/next-app/config/i18n/register18n.ts +23 -24
  31. package/dist/templates/next-app/docs/en/api.md +387 -0
  32. package/dist/templates/next-app/docs/en/component.md +544 -0
  33. package/dist/templates/next-app/docs/en/database.md +496 -0
  34. package/dist/templates/next-app/docs/en/development-guide.md +727 -0
  35. package/dist/templates/next-app/docs/en/env.md +563 -0
  36. package/dist/templates/next-app/docs/en/i18n.md +287 -0
  37. package/dist/templates/next-app/docs/en/index.md +165 -0
  38. package/dist/templates/next-app/docs/en/page.md +457 -0
  39. package/dist/templates/next-app/docs/en/project-structure.md +176 -0
  40. package/dist/templates/next-app/docs/en/router.md +427 -0
  41. package/dist/templates/next-app/docs/en/theme.md +532 -0
  42. package/dist/templates/next-app/docs/en/validator.md +478 -0
  43. package/dist/templates/next-app/docs/zh/api.md +387 -0
  44. package/dist/templates/next-app/docs/zh/component.md +544 -0
  45. package/dist/templates/next-app/docs/zh/database.md +496 -0
  46. package/dist/templates/next-app/docs/zh/development-guide.md +727 -0
  47. package/dist/templates/next-app/docs/zh/env.md +563 -0
  48. package/dist/templates/next-app/docs/zh/i18n.md +287 -0
  49. package/dist/templates/next-app/docs/zh/index.md +165 -0
  50. package/dist/templates/next-app/docs/zh/page.md +457 -0
  51. package/dist/templates/next-app/docs/zh/project-structure.md +176 -0
  52. package/dist/templates/next-app/docs/zh/router.md +427 -0
  53. package/dist/templates/next-app/docs/zh/theme.md +532 -0
  54. package/dist/templates/next-app/docs/zh/validator.md +476 -0
  55. package/dist/templates/next-app/make/generateLocales.ts +19 -12
  56. package/dist/templates/next-app/migrations/schema/LocalesSchema.ts +15 -0
  57. package/dist/templates/next-app/migrations/sql/1694244000000.sql +11 -0
  58. package/dist/templates/next-app/package.json +7 -3
  59. package/dist/templates/next-app/public/locales/en.json +172 -207
  60. package/dist/templates/next-app/public/locales/zh.json +172 -207
  61. package/dist/templates/next-app/src/app/[locale]/admin/locales/page.tsx +153 -0
  62. package/dist/templates/next-app/src/app/[locale]/admin/users/page.tsx +48 -50
  63. package/dist/templates/next-app/src/app/[locale]/login/LoginForm.tsx +2 -2
  64. package/dist/templates/next-app/src/app/api/admin/locales/create/route.ts +34 -0
  65. package/dist/templates/next-app/src/app/api/admin/locales/import/route.ts +40 -0
  66. package/dist/templates/next-app/src/app/api/admin/locales/route.ts +42 -0
  67. package/dist/templates/next-app/src/app/api/admin/locales/update/route.ts +32 -0
  68. package/dist/templates/next-app/src/app/api/locales/json/route.ts +44 -0
  69. package/dist/templates/next-app/src/base/cases/AdminPageManager.ts +1 -13
  70. package/dist/templates/next-app/src/base/cases/Datetime.ts +18 -0
  71. package/dist/templates/next-app/src/base/cases/DialogErrorPlugin.ts +12 -6
  72. package/dist/templates/next-app/src/base/cases/ResourceState.ts +17 -0
  73. package/dist/templates/next-app/src/base/cases/TranslateI18nInterface.ts +25 -0
  74. package/dist/templates/next-app/src/base/cases/ZodColumnBuilder.ts +200 -0
  75. package/dist/templates/next-app/src/base/port/ZodBuilderInterface.ts +8 -0
  76. package/dist/templates/next-app/src/base/services/AdminLocalesService.ts +20 -0
  77. package/dist/templates/next-app/src/base/services/AdminPageEvent.ts +26 -0
  78. package/dist/templates/next-app/src/base/services/AdminPageScheduler.ts +42 -0
  79. package/dist/templates/next-app/src/base/services/ResourceService.ts +122 -0
  80. package/dist/templates/next-app/src/base/services/adminApi/AdminLocalesApi.ts +104 -0
  81. package/dist/templates/next-app/src/base/services/adminApi/AdminUserApi.ts +38 -5
  82. package/dist/templates/next-app/src/base/services/appApi/AppApiPlugin.ts +1 -1
  83. package/dist/templates/next-app/src/i18n/request.ts +30 -1
  84. package/dist/templates/next-app/src/server/PageParams.ts +2 -10
  85. package/dist/templates/next-app/src/server/port/DBBridgeInterface.ts +5 -0
  86. package/dist/templates/next-app/src/server/port/DBTableInterface.ts +2 -0
  87. package/dist/templates/next-app/src/server/port/LocalesRepositoryInterface.ts +43 -0
  88. package/dist/templates/next-app/src/server/repositorys/LocalesRepository.ts +197 -0
  89. package/dist/templates/next-app/src/server/services/ApiLocaleService.ts +122 -0
  90. package/dist/templates/next-app/src/server/sqlBridges/SupabaseBridge.ts +60 -11
  91. package/dist/templates/next-app/src/server/validators/ExtendedExecutorError.ts +6 -0
  92. package/dist/templates/next-app/src/server/validators/LocalesValidator.ts +131 -0
  93. package/dist/templates/next-app/src/server/validators/LoginValidator.ts +2 -5
  94. package/dist/templates/next-app/src/server/validators/PaginationValidator.ts +32 -16
  95. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/_default.css +2 -1
  96. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/dark.css +28 -29
  97. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/pink.css +2 -1
  98. package/dist/templates/next-app/src/uikit/components/AdminLayout.tsx +17 -3
  99. package/dist/templates/next-app/src/uikit/components/BaseHeader.tsx +5 -4
  100. package/dist/templates/next-app/src/uikit/components/BaseLayout.tsx +5 -4
  101. package/dist/templates/next-app/src/uikit/components/BootstrapsProvider.tsx +3 -2
  102. package/dist/templates/next-app/src/uikit/components/ComboProvider.tsx +1 -1
  103. package/dist/templates/next-app/src/uikit/components/EditableCell.tsx +118 -0
  104. package/dist/templates/next-app/src/uikit/components/LogoutButton.tsx +5 -6
  105. package/dist/templates/next-app/src/uikit/components/ThemeSwitcher.tsx +1 -1
  106. package/dist/templates/next-app/src/uikit/components/With.tsx +2 -2
  107. package/dist/templates/next-app/src/uikit/components/localesImportButton/LocalesImportButton.tsx +62 -0
  108. package/dist/templates/next-app/src/uikit/components/localesImportButton/LocalesImportEvent.ts +28 -0
  109. package/dist/templates/next-app/src/uikit/components/localesImportButton/import.module.css +6 -0
  110. package/dist/templates/next-app/src/uikit/hook/useI18nInterface.ts +8 -14
  111. package/dist/templates/next-app/src/uikit/hook/useWarnTranslations.ts +25 -0
  112. package/dist/templates/react-app/.prettierignore +17 -0
  113. package/dist/templates/react-app/README.en.md +71 -54
  114. package/dist/templates/react-app/README.md +35 -18
  115. package/dist/templates/react-app/__tests__/__mocks__/BootstrapTest.ts +14 -0
  116. package/dist/templates/react-app/__tests__/__mocks__/MockAppConfit.ts +1 -1
  117. package/dist/templates/react-app/__tests__/__mocks__/MockDialogHandler.ts +2 -2
  118. package/dist/templates/react-app/__tests__/__mocks__/MockLogger.ts +1 -1
  119. package/dist/templates/react-app/__tests__/__mocks__/components/TestApp.tsx +45 -0
  120. package/dist/templates/react-app/__tests__/__mocks__/components/TestBootstrapsProvider.tsx +34 -0
  121. package/dist/templates/react-app/__tests__/__mocks__/components/TestRouter.tsx +46 -0
  122. package/dist/templates/react-app/__tests__/__mocks__/components/index.ts +12 -0
  123. package/dist/templates/react-app/__tests__/__mocks__/createMockGlobals.ts +1 -2
  124. package/dist/templates/react-app/__tests__/__mocks__/testIOC/TestIOC.ts +51 -0
  125. package/dist/templates/react-app/__tests__/__mocks__/testIOC/TestIOCRegister.ts +69 -0
  126. package/dist/templates/react-app/__tests__/setup/index.ts +1 -51
  127. package/dist/templates/react-app/__tests__/setup/setupGlobal.ts +51 -0
  128. package/dist/templates/react-app/__tests__/src/App.structure.test.tsx +115 -0
  129. package/dist/templates/react-app/__tests__/src/base/cases/AppConfig.test.ts +2 -2
  130. package/dist/templates/react-app/__tests__/src/base/cases/AppError.test.ts +1 -1
  131. package/dist/templates/react-app/__tests__/src/base/cases/DialogHandler.test.ts +3 -5
  132. package/dist/templates/react-app/__tests__/src/base/cases/I18nKeyErrorPlugin.test.ts +13 -2
  133. package/dist/templates/react-app/__tests__/src/base/cases/InversifyContainer.test.ts +1 -1
  134. package/dist/templates/react-app/__tests__/src/base/cases/PublicAssetsPath.test.ts +1 -1
  135. package/dist/templates/react-app/__tests__/src/base/cases/RequestLogger.test.ts +5 -5
  136. package/dist/templates/react-app/__tests__/src/base/cases/RequestStatusCatcher.test.ts +1 -2
  137. package/dist/templates/react-app/__tests__/src/base/cases/RouterLoader.test.ts +25 -15
  138. package/dist/templates/react-app/__tests__/src/base/services/I18nService.test.ts +29 -15
  139. package/dist/templates/react-app/__tests__/src/core/IOC.test.ts +19 -9
  140. package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapClient.test.ts +153 -0
  141. package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapsApp.test.ts +9 -7
  142. package/dist/templates/react-app/__tests__/src/main.integration.test.tsx +4 -5
  143. package/dist/templates/react-app/__tests__/src/main.test.tsx +4 -4
  144. package/dist/templates/react-app/__tests__/src/uikit/components/BaseHeader.test.tsx +68 -59
  145. package/dist/templates/react-app/config/IOCIdentifier.ts +8 -8
  146. package/dist/templates/react-app/config/Identifier/{common.error.ts → common/common.error.ts} +5 -5
  147. package/dist/templates/react-app/config/Identifier/{common.ts → common/common.ts} +9 -9
  148. package/dist/templates/react-app/config/Identifier/common/index.ts +2 -0
  149. package/dist/templates/react-app/config/Identifier/index.ts +1 -9
  150. package/dist/templates/react-app/config/Identifier/pages/index.ts +8 -0
  151. package/dist/templates/react-app/config/Identifier/{page.about.ts → pages/page.about.ts} +34 -26
  152. package/dist/templates/react-app/config/Identifier/{page.executor.ts → pages/page.executor.ts} +47 -39
  153. package/dist/templates/{next-app/config/Identifier → react-app/config/Identifier/pages}/page.home.ts +24 -23
  154. package/dist/templates/react-app/config/Identifier/pages/page.identifiter.ts +102 -0
  155. package/dist/templates/react-app/config/Identifier/{page.jsonStorage.ts → pages/page.jsonStorage.ts} +18 -11
  156. package/dist/templates/react-app/config/Identifier/{page.login.ts → pages/page.login.ts} +37 -27
  157. package/dist/templates/react-app/config/Identifier/{page.register.ts → pages/page.register.ts} +37 -25
  158. package/dist/templates/react-app/config/Identifier/{page.request.ts → pages/page.request.ts} +34 -44
  159. package/dist/templates/react-app/config/app.router.ts +66 -69
  160. package/dist/templates/react-app/config/i18n/PageI18nInterface.ts +51 -0
  161. package/dist/templates/react-app/config/i18n/aboutI18n.ts +42 -0
  162. package/dist/templates/react-app/config/i18n/executorI18n.ts +51 -0
  163. package/dist/templates/react-app/config/i18n/homeI18n.ts +24 -0
  164. package/dist/templates/react-app/config/i18n/i18nConfig.ts +30 -0
  165. package/dist/templates/react-app/config/i18n/identifiter18n.ts +30 -0
  166. package/dist/templates/react-app/config/i18n/jsonStorage18n.ts +27 -0
  167. package/dist/templates/react-app/config/i18n/login18n.ts +42 -0
  168. package/dist/templates/react-app/config/i18n/notFoundI18n.ts +34 -0
  169. package/dist/templates/react-app/config/i18n/register18n.ts +40 -0
  170. package/dist/templates/react-app/config/i18n/request18n.ts +41 -0
  171. package/dist/templates/react-app/config/theme.ts +14 -4
  172. package/dist/templates/react-app/docs/en/bootstrap.md +1670 -341
  173. package/dist/templates/react-app/docs/en/development-guide.md +1021 -345
  174. package/dist/templates/react-app/docs/en/env.md +1132 -278
  175. package/dist/templates/react-app/docs/en/i18n.md +858 -147
  176. package/dist/templates/react-app/docs/en/index.md +733 -104
  177. package/dist/templates/react-app/docs/en/ioc.md +1228 -287
  178. package/dist/templates/react-app/docs/en/playwright/e2e-tests.md +321 -0
  179. package/dist/templates/react-app/docs/en/playwright/index.md +19 -0
  180. package/dist/templates/react-app/docs/en/playwright/installation-summary.md +332 -0
  181. package/dist/templates/react-app/docs/en/playwright/overview.md +222 -0
  182. package/dist/templates/react-app/docs/en/playwright/quickstart.md +325 -0
  183. package/dist/templates/react-app/docs/en/playwright/reorganization-notes.md +340 -0
  184. package/dist/templates/react-app/docs/en/playwright/setup-complete.md +290 -0
  185. package/dist/templates/react-app/docs/en/playwright/testing-guide.md +565 -0
  186. package/dist/templates/react-app/docs/en/store.md +1194 -184
  187. package/dist/templates/react-app/docs/en/why-no-globals.md +797 -0
  188. package/dist/templates/react-app/docs/zh/bootstrap.md +1670 -341
  189. package/dist/templates/react-app/docs/zh/development-guide.md +1021 -345
  190. package/dist/templates/react-app/docs/zh/env.md +1132 -275
  191. package/dist/templates/react-app/docs/zh/i18n.md +858 -147
  192. package/dist/templates/react-app/docs/zh/index.md +717 -104
  193. package/dist/templates/react-app/docs/zh/ioc.md +1229 -287
  194. package/dist/templates/react-app/docs/zh/playwright/e2e-tests.md +321 -0
  195. package/dist/templates/react-app/docs/zh/playwright/index.md +19 -0
  196. package/dist/templates/react-app/docs/zh/playwright/installation-summary.md +332 -0
  197. package/dist/templates/react-app/docs/zh/playwright/overview.md +222 -0
  198. package/dist/templates/react-app/docs/zh/playwright/quickstart.md +325 -0
  199. package/dist/templates/react-app/docs/zh/playwright/reorganization-notes.md +340 -0
  200. package/dist/templates/react-app/docs/zh/playwright/setup-complete.md +290 -0
  201. package/dist/templates/react-app/docs/zh/playwright/testing-guide.md +565 -0
  202. package/dist/templates/react-app/docs/zh/store.md +1192 -184
  203. package/dist/templates/react-app/docs/zh/why-no-globals.md +797 -0
  204. package/dist/templates/react-app/e2e/App.spec.ts +319 -0
  205. package/dist/templates/react-app/e2e/fixtures/base.fixture.ts +40 -0
  206. package/dist/templates/react-app/e2e/main.spec.ts +20 -0
  207. package/dist/templates/react-app/e2e/utils/test-helpers.ts +19 -0
  208. package/dist/templates/react-app/eslint.config.mjs +247 -0
  209. package/dist/templates/react-app/makes/eslint-utils.mjs +195 -0
  210. package/dist/templates/react-app/makes/generateTs2LocalesOptions.ts +26 -0
  211. package/dist/templates/react-app/package.json +31 -3
  212. package/dist/templates/react-app/playwright.config.ts +79 -0
  213. package/dist/templates/react-app/public/locales/en/common.json +190 -179
  214. package/dist/templates/react-app/public/locales/zh/common.json +190 -179
  215. package/dist/templates/react-app/src/App.tsx +15 -42
  216. package/dist/templates/react-app/src/base/apis/AiApi.ts +5 -5
  217. package/dist/templates/react-app/src/base/apis/feApi/FeApi.ts +1 -1
  218. package/dist/templates/react-app/src/base/apis/feApi/FeApiAdapter.ts +1 -1
  219. package/dist/templates/react-app/src/base/apis/feApi/FeApiBootstarp.ts +8 -8
  220. package/dist/templates/react-app/src/base/apis/feApi/FeApiType.ts +1 -1
  221. package/dist/templates/react-app/src/base/apis/userApi/UserApi.ts +6 -6
  222. package/dist/templates/react-app/src/base/apis/userApi/UserApiAdapter.ts +1 -1
  223. package/dist/templates/react-app/src/base/apis/userApi/UserApiBootstarp.ts +12 -14
  224. package/dist/templates/react-app/src/base/apis/userApi/UserApiType.ts +1 -1
  225. package/dist/templates/react-app/src/base/cases/DialogHandler.ts +5 -2
  226. package/dist/templates/react-app/src/base/cases/I18nKeyErrorPlugin.ts +3 -3
  227. package/dist/templates/react-app/src/base/cases/InversifyContainer.ts +3 -3
  228. package/dist/templates/react-app/src/base/cases/RequestLanguages.ts +2 -2
  229. package/dist/templates/react-app/src/base/cases/RequestLogger.ts +4 -4
  230. package/dist/templates/react-app/src/base/cases/RequestStatusCatcher.ts +1 -1
  231. package/dist/templates/react-app/src/base/cases/ResourceState.ts +23 -0
  232. package/dist/templates/react-app/src/base/cases/RouterLoader.ts +4 -4
  233. package/dist/templates/react-app/src/base/cases/TranslateI18nInterface.ts +26 -0
  234. package/dist/templates/react-app/src/base/port/ExecutorPageBridgeInterface.ts +2 -3
  235. package/dist/templates/react-app/src/base/port/I18nServiceInterface.ts +1 -1
  236. package/dist/templates/react-app/src/base/port/IOCInterface.ts +36 -0
  237. package/dist/templates/react-app/src/base/port/JSONStoragePageBridgeInterface.ts +2 -1
  238. package/dist/templates/react-app/src/base/port/ProcesserExecutorInterface.ts +1 -1
  239. package/dist/templates/react-app/src/base/port/RequestPageBridgeInterface.ts +2 -2
  240. package/dist/templates/react-app/src/base/port/RouteServiceInterface.ts +9 -5
  241. package/dist/templates/react-app/src/base/port/UserServiceInterface.ts +1 -1
  242. package/dist/templates/react-app/src/base/services/I18nService.ts +29 -29
  243. package/dist/templates/react-app/src/base/services/IdentifierService.ts +143 -0
  244. package/dist/templates/react-app/src/base/services/ProcesserExecutor.ts +3 -3
  245. package/dist/templates/react-app/src/base/services/RouteService.ts +27 -8
  246. package/dist/templates/react-app/src/base/services/UserService.ts +8 -8
  247. package/dist/templates/react-app/src/base/types/Page.ts +14 -2
  248. package/dist/templates/react-app/src/base/types/global.d.ts +1 -1
  249. package/dist/templates/react-app/src/core/IOC.ts +5 -46
  250. package/dist/templates/react-app/src/core/bootstraps/{BootstrapApp.ts → BootstrapClient.ts} +44 -17
  251. package/dist/templates/react-app/src/core/bootstraps/BootstrapsRegistry.ts +14 -7
  252. package/dist/templates/react-app/src/core/bootstraps/IocIdentifierTest.ts +1 -1
  253. package/dist/templates/react-app/src/core/bootstraps/PrintBootstrap.ts +1 -1
  254. package/dist/templates/react-app/src/core/clientIoc/ClientIOC.ts +40 -0
  255. package/dist/templates/react-app/src/core/{IocRegisterImpl.ts → clientIoc/ClientIOCRegister.ts} +35 -24
  256. package/dist/templates/react-app/src/core/globals.ts +9 -9
  257. package/dist/templates/react-app/src/main.tsx +4 -4
  258. package/dist/templates/react-app/src/pages/404.tsx +6 -3
  259. package/dist/templates/react-app/src/pages/500.tsx +5 -2
  260. package/dist/templates/react-app/src/pages/NoRouteFound.tsx +5 -0
  261. package/dist/templates/react-app/src/pages/auth/Layout.tsx +9 -6
  262. package/dist/templates/react-app/src/pages/auth/LoginPage.tsx +46 -56
  263. package/dist/templates/react-app/src/pages/auth/RegisterPage.tsx +46 -58
  264. package/dist/templates/react-app/src/pages/base/AboutPage.tsx +35 -40
  265. package/dist/templates/react-app/src/pages/base/ExecutorPage.tsx +51 -51
  266. package/dist/templates/react-app/src/pages/base/HomePage.tsx +14 -15
  267. package/dist/templates/react-app/src/pages/base/IdentifierPage.tsx +70 -11
  268. package/dist/templates/react-app/src/pages/base/JSONStoragePage.tsx +24 -25
  269. package/dist/templates/react-app/src/pages/base/Layout.tsx +2 -2
  270. package/dist/templates/react-app/src/pages/base/RedirectPathname.tsx +3 -2
  271. package/dist/templates/react-app/src/pages/base/RequestPage.tsx +41 -59
  272. package/dist/templates/react-app/src/styles/css/antd-themes/{_default.css → _common/_default.css} +85 -0
  273. package/dist/templates/react-app/src/styles/css/antd-themes/{dark.css → _common/dark.css} +99 -0
  274. package/dist/templates/react-app/src/styles/css/antd-themes/_common/index.css +3 -0
  275. package/dist/templates/react-app/src/styles/css/antd-themes/{pink.css → _common/pink.css} +86 -0
  276. package/dist/templates/react-app/src/styles/css/antd-themes/index.css +4 -3
  277. package/dist/templates/react-app/src/styles/css/antd-themes/menu/_default.css +108 -0
  278. package/dist/templates/react-app/src/styles/css/antd-themes/menu/dark.css +67 -0
  279. package/dist/templates/react-app/src/styles/css/antd-themes/menu/index.css +3 -0
  280. package/dist/templates/react-app/src/styles/css/antd-themes/menu/pink.css +67 -0
  281. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/_default.css +34 -0
  282. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/dark.css +31 -0
  283. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/index.css +3 -0
  284. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/pink.css +36 -0
  285. package/dist/templates/react-app/src/styles/css/antd-themes/table/_default.css +44 -0
  286. package/dist/templates/react-app/src/styles/css/antd-themes/table/dark.css +43 -0
  287. package/dist/templates/react-app/src/styles/css/antd-themes/table/index.css +3 -0
  288. package/dist/templates/react-app/src/styles/css/antd-themes/table/pink.css +43 -0
  289. package/dist/templates/react-app/src/styles/css/page.css +4 -3
  290. package/dist/templates/react-app/src/styles/css/themes/_default.css +1 -0
  291. package/dist/templates/react-app/src/styles/css/themes/dark.css +1 -0
  292. package/dist/templates/react-app/src/styles/css/themes/pink.css +1 -0
  293. package/dist/templates/react-app/src/styles/css/zIndex.css +1 -1
  294. package/dist/templates/react-app/src/uikit/bridges/ExecutorPageBridge.ts +3 -3
  295. package/dist/templates/react-app/src/uikit/bridges/JSONStoragePageBridge.ts +2 -2
  296. package/dist/templates/react-app/src/uikit/bridges/NavigateBridge.ts +1 -1
  297. package/dist/templates/react-app/src/uikit/bridges/RequestPageBridge.ts +3 -3
  298. package/dist/templates/react-app/src/uikit/components/AppRouterProvider.tsx +35 -0
  299. package/dist/templates/react-app/src/uikit/components/BaseHeader.tsx +15 -11
  300. package/dist/templates/react-app/src/uikit/components/BaseRouteProvider.tsx +14 -11
  301. package/dist/templates/react-app/src/uikit/components/BaseRouteSeo.tsx +18 -0
  302. package/dist/templates/react-app/src/uikit/components/BootstrapsProvider.tsx +13 -0
  303. package/dist/templates/react-app/src/uikit/components/ClientSeo.tsx +62 -0
  304. package/dist/templates/react-app/src/uikit/components/ComboProvider.tsx +38 -0
  305. package/dist/templates/react-app/src/uikit/components/LanguageSwitcher.tsx +48 -27
  306. package/dist/templates/react-app/src/uikit/components/Loading.tsx +4 -2
  307. package/dist/templates/react-app/src/uikit/components/LocaleLink.tsx +4 -5
  308. package/dist/templates/react-app/src/uikit/components/LogoutButton.tsx +34 -11
  309. package/dist/templates/react-app/src/uikit/components/ProcessExecutorProvider.tsx +9 -5
  310. package/dist/templates/react-app/src/uikit/components/RouterRenderComponent.tsx +6 -3
  311. package/dist/templates/react-app/src/uikit/components/ThemeSwitcher.tsx +97 -40
  312. package/dist/templates/react-app/src/uikit/components/UserAuthProvider.tsx +5 -5
  313. package/dist/templates/react-app/src/uikit/components/With.tsx +17 -0
  314. package/dist/templates/react-app/src/uikit/contexts/BaseRouteContext.ts +17 -11
  315. package/dist/templates/react-app/src/uikit/contexts/IOCContext.ts +13 -0
  316. package/dist/templates/react-app/src/uikit/hooks/useAppTranslation.ts +26 -0
  317. package/dist/templates/react-app/src/uikit/hooks/useI18nGuard.ts +8 -11
  318. package/dist/templates/react-app/src/uikit/hooks/useI18nInterface.ts +25 -0
  319. package/dist/templates/react-app/src/uikit/hooks/useIOC.ts +35 -0
  320. package/dist/templates/react-app/src/uikit/hooks/useNavigateBridge.ts +3 -3
  321. package/dist/templates/react-app/src/uikit/hooks/useStrictEffect.ts +0 -1
  322. package/dist/templates/react-app/tsconfig.e2e.json +21 -0
  323. package/dist/templates/react-app/tsconfig.json +8 -1
  324. package/dist/templates/react-app/tsconfig.node.json +1 -1
  325. package/dist/templates/react-app/tsconfig.test.json +3 -1
  326. package/dist/templates/react-app/vite.config.ts +50 -34
  327. package/package.json +2 -1
  328. package/dist/configs/react-app/eslint.config.js +0 -94
  329. package/dist/templates/next-app/config/Identifier/common.error.ts +0 -41
  330. package/dist/templates/next-app/config/Identifier/common.ts +0 -69
  331. package/dist/templates/next-app/config/Identifier/page.about.ts +0 -181
  332. package/dist/templates/next-app/config/Identifier/page.admin.ts +0 -48
  333. package/dist/templates/next-app/config/Identifier/page.executor.ts +0 -272
  334. package/dist/templates/next-app/config/Identifier/page.identifiter.ts +0 -39
  335. package/dist/templates/next-app/config/Identifier/page.jsonStorage.ts +0 -72
  336. package/dist/templates/next-app/config/Identifier/page.request.ts +0 -182
  337. package/dist/templates/next-app/docs/env.md +0 -94
  338. package/dist/templates/next-app/src/base/cases/ChatAction.ts +0 -21
  339. package/dist/templates/next-app/src/base/cases/FocusBarAction.ts +0 -36
  340. package/dist/templates/next-app/src/base/cases/RequestState.ts +0 -20
  341. package/dist/templates/next-app/src/base/port/AdminPageInterface.ts +0 -85
  342. package/dist/templates/next-app/src/base/port/AsyncStateInterface.ts +0 -7
  343. package/dist/templates/next-app/src/base/services/AdminUserService.ts +0 -45
  344. package/dist/templates/next-app/src/uikit/components/ChatRoot.tsx +0 -17
  345. package/dist/templates/next-app/src/uikit/components/chat/ChatActionInterface.ts +0 -30
  346. package/dist/templates/next-app/src/uikit/components/chat/ChatFocusBar.tsx +0 -65
  347. package/dist/templates/next-app/src/uikit/components/chat/ChatMessages.tsx +0 -59
  348. package/dist/templates/next-app/src/uikit/components/chat/ChatWrap.tsx +0 -28
  349. package/dist/templates/next-app/src/uikit/components/chat/FocusBarActionInterface.ts +0 -19
  350. package/dist/templates/next-app/src/uikit/hook/useMountedClient.ts +0 -17
  351. package/dist/templates/next-app/src/uikit/hook/useStore.ts +0 -15
  352. package/dist/templates/react-app/__tests__/__mocks__/I18nService.ts +0 -13
  353. package/dist/templates/react-app/__tests__/src/App.test.tsx +0 -139
  354. package/dist/templates/react-app/config/Identifier/page.identifiter.ts +0 -39
  355. package/dist/templates/react-app/config/i18n.ts +0 -15
  356. package/dist/templates/react-app/docs/en/project-structure.md +0 -434
  357. package/dist/templates/react-app/docs/zh/project-structure.md +0 -434
  358. package/dist/templates/react-app/src/base/cases/RequestState.ts +0 -20
  359. package/dist/templates/react-app/src/base/port/AsyncStateInterface.ts +0 -7
  360. package/dist/templates/react-app/src/uikit/hooks/useDocumentTitle.ts +0 -15
  361. package/dist/templates/react-app/src/uikit/hooks/useStore.ts +0 -15
@@ -1,120 +1,328 @@
1
- # Environment Variables Injection
1
+ # Environment Variable Management
2
2
 
3
- ## What is Environment Variables Injection?
3
+ ## 📋 Table of Contents
4
4
 
5
- Environment variables injection is a crucial feature of Bootstrap that allows us to automatically inject environment variables into application configuration, enabling centralized configuration management and environment isolation.
5
+ - [What is Environment Variable Management](#-what-is-environment-variable-management)
6
+ - [Why Environment Variables are Needed](#-why-environment-variables-are-needed)
7
+ - [How It Works](#-how-it-works)
8
+ - [Implementation in the Project](#-implementation-in-the-project)
9
+ - [Multi-Environment Configuration](#-multi-environment-configuration)
10
+ - [Environment Variable Injection](#-environment-variable-injection)
11
+ - [AppConfig Usage](#-appconfig-usage)
12
+ - [Advanced Usage](#-advanced-usage)
13
+ - [Testing Configuration](#-testing-configuration)
14
+ - [Best Practices](#-best-practices)
15
+ - [FAQ](#-faq)
6
16
 
7
- **In simple terms**: Just like dressing your application in different clothes, based on different environments (development, testing, production), the application will use different configurations.
17
+ ---
8
18
 
9
- ## How It Works
19
+ ## 🎯 What is Environment Variable Management
10
20
 
11
- ### 1. Environment Variables Loading Process
21
+ Environment variable management is a core component of the Bootstrap architecture, responsible for using different configurations in different environments (development, testing, production) and passing configurations to the application through **automatic injection**.
22
+
23
+ ### Core Workflow
12
24
 
13
25
  ```
14
- App Start Bootstrap Initialization InjectEnv Plugin Load Environment Variables → Inject into AppConfig → App Uses Config
26
+ Start App → Vite loads .env filesBootstrap initializes → Inject env vars to AppConfig → IOC container → App uses them
15
27
  ```
16
28
 
17
- ### 2. Core Technology Stack
29
+ ### Key Concepts
30
+
31
+ ```
32
+ ┌─────────────────────────────────────────────────┐
33
+ │ Environment Variable Management System │
34
+ │ ┌───────────────────────────────────────────┐ │
35
+ │ │ 1. Vite --mode selects environment │ │
36
+ │ │ 2. Load corresponding .env file │ │
37
+ │ │ 3. envConfig plugin preprocessing │ │
38
+ │ │ 4. Bootstrap injects to AppConfig │ │
39
+ │ │ 5. Register to IOC container │ │
40
+ │ │ 6. App gets config through IOC │ │
41
+ │ └───────────────────────────────────────────┘ │
42
+ └─────────────────────────────────────────────────┘
43
+ ```
18
44
 
19
- - **@qlover/env-loader**: Environment variables loader
20
- - **@qlover/corekit-bridge/vite-env-config**: Vite environment variables configuration plugin
21
- - **dotenv**: .env file parser
22
- - **Vite**: Frontend build tool
45
+ ---
23
46
 
24
- ### 3. File Structure
47
+ ## 🤔 Why Environment Variables are Needed
25
48
 
49
+ ### Problem: Pain Points of Hard-coded Configuration
50
+
51
+ #### ❌ Traditional Approach: Configuration Scattered Everywhere
52
+
53
+ ```typescript
54
+ // ❌ Problem 1: API address hard-coded in code
55
+ function fetchUserInfo() {
56
+ // 😰 Dev and prod API addresses are different, need to change code every time
57
+ return fetch('http://localhost:3000/api/user');
58
+ }
59
+
60
+ // ❌ Problem 2: Configuration scattered across files
61
+ function saveToken(token: string) {
62
+ // 😰 Storage key hard-coded, difficult to manage uniformly
63
+ localStorage.setItem('user_token', token);
64
+ }
65
+
66
+ // ❌ Problem 3: Sensitive information directly in code
67
+ function callAI(prompt: string) {
68
+ // 😰 API Key directly exposed in code, security risk
69
+ return fetch('https://api.openai.com/v1/chat', {
70
+ headers: {
71
+ Authorization: 'Bearer sk-xxxxxxxxxxxx' // 😰 Dangerous!
72
+ }
73
+ });
74
+ }
75
+
76
+ // ❌ Problem 4: Difficult to switch environments
77
+ if (window.location.host === 'localhost:3000') {
78
+ // 😰 Need to manually determine environment
79
+ apiUrl = 'http://localhost:3000/api';
80
+ } else if (window.location.host === 'staging.example.com') {
81
+ apiUrl = 'https://api.staging.example.com';
82
+ } else {
83
+ apiUrl = 'https://api.production.com';
84
+ }
26
85
  ```
27
- Project Root/
28
- ├── .env # Default environment variables
29
- ├── .env.local # Local environment variables (git ignored)
30
- ├── .env.development # Development environment variables
31
- ├── .env.production # Production environment variables
32
- ├── .env.staging # Testing environment variables
33
- ├── vite.config.ts # Vite configuration
34
- └── src/
35
- └── base/
36
- └── cases/
37
- └── AppConfig.ts # Application configuration class
86
+
87
+ **Problem Summary:**
88
+
89
+ - 😰 **Scattered configuration** - Config spread across multiple files, hard to manage
90
+ - 😰 **Difficult to switch environments** - Need to manually modify code or use complex conditions
91
+ - 😰 **Security risks** - Sensitive info may be committed to code repository
92
+ - 😰 **Hard to test** - Need to mock many hard-coded values when testing
93
+ - 😰 **Team collaboration difficulties** - Each developer may have different local configs
94
+
95
+ #### ✅ Solution: Environment Variables + AppConfig
96
+
97
+ ```typescript
98
+ // ✅ 1. Environment variable files (different config for different environments)
99
+ // .env.localhost
100
+ VITE_API_BASE_URL=http://localhost:3000/api
101
+ VITE_AI_API_TOKEN=sk-dev-xxxxx
102
+
103
+ // .env.staging
104
+ VITE_API_BASE_URL=https://api.staging.example.com
105
+ VITE_AI_API_TOKEN=sk-staging-xxxxx
106
+
107
+ // .env.production
108
+ VITE_API_BASE_URL=https://api.production.com
109
+ VITE_AI_API_TOKEN=sk-prod-xxxxx
110
+
111
+ // ✅ 2. AppConfig manages configuration uniformly
112
+ export class AppConfig {
113
+ readonly feApiBaseUrl = ''; // ← Auto-injected
114
+ readonly aiApiToken = ''; // ← Auto-injected
115
+ readonly userTokenStorageKey = '__fe_user_token__';
116
+ }
117
+
118
+ // ✅ 3. Get config through IOC container
119
+ @injectable()
120
+ export class UserService {
121
+ constructor(
122
+ @inject(IOCIdentifier.AppConfig) private config: AppConfig
123
+ ) {}
124
+
125
+ async fetchUserInfo() {
126
+ // ✅ Get API address from config, automatically adapts to environment
127
+ return fetch(`${this.config.feApiBaseUrl}/user`);
128
+ }
129
+ }
130
+
131
+ // ✅ 4. Switch environments at runtime (no code changes needed)
132
+ npm run dev # localhost environment
133
+ npm run dev:staging # staging environment
134
+ npm run build:production # production environment
38
135
  ```
39
136
 
40
- ## Environment Variable Files
137
+ **Advantages:**
138
+
139
+ - ✅ **Centralized management** - All config managed uniformly in AppConfig
140
+ - ✅ **Easy environment switching** - Just switch run command
141
+ - ✅ **Secure** - Sensitive info managed through `.env.local`, not committed to repo
142
+ - ✅ **Easy to test** - Can easily mock AppConfig when testing
143
+ - ✅ **Team-friendly** - Each developer can have their own `.env.local`
144
+
145
+ ---
41
146
 
42
- ### 1. File Loading Priority
147
+ ## ⚙️ How It Works
43
148
 
44
- Vite loads environment variable files in the following priority:
149
+ ### Environment Variable Loading Flow
45
150
 
46
151
  ```
47
- .env.local > .env.[mode] > .env
152
+ ┌────────────────────────────────────────────────────────────┐
153
+ │ 1. package.json: Define startup commands │
154
+ │ npm run dev → vite --mode localhost │
155
+ │ npm run dev:staging → vite --mode staging │
156
+ │ npm run build:production → vite build --mode production │
157
+ └──────────────────┬─────────────────────────────────────────┘
158
+
159
+ ┌────────────────────────────────────────────────────────────┐
160
+ │ 2. Vite: Load corresponding .env file based on --mode │
161
+ │ --mode localhost → .env.localhost │
162
+ │ --mode staging → .env.staging │
163
+ │ --mode production → .env.production │
164
+ │ │
165
+ │ Loading priority: .env.local > .env.[mode] > .env │
166
+ └──────────────────┬─────────────────────────────────────────┘
167
+
168
+ ┌────────────────────────────────────────────────────────────┐
169
+ │ 3. vite.config.ts: envConfig plugin preprocessing │
170
+ │ - Inject APP_NAME, APP_VERSION, etc. │
171
+ │ - Set environment variable prefix (VITE_) │
172
+ └──────────────────┬─────────────────────────────────────────┘
173
+
174
+ ┌────────────────────────────────────────────────────────────┐
175
+ │ 4. BootstrapClient: Initialize Bootstrap │
176
+ │ envOptions: { │
177
+ │ target: appConfig, // Injection target │
178
+ │ source: import.meta.env, // Env var source │
179
+ │ prefix: 'VITE_', // Prefix │
180
+ │ blackList: ['env', 'userNodeEnv'] // Blacklist │
181
+ │ } │
182
+ └──────────────────┬─────────────────────────────────────────┘
183
+
184
+ ┌────────────────────────────────────────────────────────────┐
185
+ │ 5. InjectEnv plugin: Auto-inject env vars to AppConfig │
186
+ │ - VITE_APP_NAME → appConfig.appName │
187
+ │ - VITE_FE_API_BASE_URL → appConfig.feApiBaseUrl │
188
+ │ - VITE_AI_API_TOKEN → appConfig.aiApiToken │
189
+ └──────────────────┬─────────────────────────────────────────┘
190
+
191
+ ┌────────────────────────────────────────────────────────────┐
192
+ │ 6. IOC container: Register AppConfig │
193
+ │ container.bind(IOCIdentifier.AppConfig).toConstantValue │
194
+ └──────────────────┬─────────────────────────────────────────┘
195
+
196
+ ┌────────────────────────────────────────────────────────────┐
197
+ │ 7. App usage: Get config through IOC │
198
+ │ const config = useIOC('AppConfig'); │
199
+ │ console.log(config.feApiBaseUrl); │
200
+ └────────────────────────────────────────────────────────────┘
48
201
  ```
49
202
 
50
- **Examples**:
51
-
52
- ```bash
53
- # Development mode
54
- vite dev --mode development
55
- # Loading order: .env.local > .env.development > .env
203
+ ### Naming Conversion Rules
56
204
 
57
- # Production mode
58
- vite build --mode production
59
- # Loading order: .env.local > .env.production > .env
205
+ Environment variable names are automatically converted to AppConfig property names:
60
206
 
61
- # Custom mode
62
- vite dev --mode staging
63
- # Loading order: .env.local > .env.staging > .env
207
+ ```
208
+ VITE_APP_NAME → appName
209
+ VITE_FE_API_BASE_URL → feApiBaseUrl
210
+ VITE_AI_API_TOKEN → aiApiToken
211
+ VITE_USER_TOKEN_STORAGE_KEY → userTokenStorageKey
64
212
  ```
65
213
 
66
- ### 2. Environment Variable File Examples
214
+ **Conversion Rules:**
67
215
 
68
- ```bash
69
- # .env (default configuration)
70
- VITE_APP_NAME=MyApp
71
- VITE_API_BASE_URL=http://api.example.com
72
- VITE_USER_TOKEN_KEY=user_token
216
+ 1. Remove prefix (`VITE_`)
217
+ 2. Convert underscore-separated to camelCase
218
+ 3. Match property name in AppConfig
73
219
 
74
- # .env.development (development environment)
75
- VITE_API_BASE_URL=http://localhost:3000/api
76
- VITE_DEBUG=true
220
+ ---
77
221
 
78
- # .env.production (production environment)
79
- VITE_API_BASE_URL=https://api.production.com
80
- VITE_DEBUG=false
222
+ ## 🛠️ Implementation in the Project
223
+
224
+ ### 1. Define Startup Commands
81
225
 
82
- # .env.local (local override, not committed to git)
83
- VITE_API_KEY=your_secret_key
84
- VITE_LOCAL_DEBUG=true
226
+ ```json
227
+ // package.json
228
+ {
229
+ "scripts": {
230
+ "dev": "vite --mode localhost",
231
+ "dev:staging": "vite --mode staging",
232
+ "dev:prod": "vite --mode production",
233
+ "build": "npm run lint && vite build",
234
+ "build:staging": "npm run lint && vite build --mode staging",
235
+ "build:production": "npm run lint && vite build --mode production"
236
+ }
237
+ }
85
238
  ```
86
239
 
87
- ## Implementation in Project
240
+ **Explanation:**
241
+
242
+ - `--mode` parameter determines which `.env` file to load
243
+ - Development environment: use `localhost` mode
244
+ - Staging environment: use `staging` mode
245
+ - Production environment: use `production` mode
88
246
 
89
- ### 1. Vite Configuration
247
+ ### 2. Configure Vite
90
248
 
91
- ```tsx
249
+ ```typescript
92
250
  // vite.config.ts
93
- import envConfig from '@qlover/corekit-bridge/vite-env-config';
251
+ import { defineConfig } from 'vitest/config';
252
+ import { envPrefix } from './config/common';
253
+ import { name, version } from './package.json';
254
+ import envConfig from '@qlover/corekit-bridge/build/vite-env-config';
94
255
 
95
256
  export default defineConfig({
96
257
  plugins: [
258
+ // ✅ envConfig plugin: preprocess environment variables
97
259
  envConfig({
98
- envPops: true, // Enable environment variables loading
99
- envPrefix: 'VITE_', // Environment variables prefix
260
+ envPops: true, // Enable env var processing
261
+ envPrefix, // Env var prefix: 'VITE_'
100
262
  records: [
101
- ['APP_NAME', name], // Inject application name
102
- ['APP_VERSION', version] // Inject application version
263
+ ['APP_NAME', name], // Inject app name
264
+ ['APP_VERSION', version] // Inject app version
103
265
  ]
104
266
  })
267
+ // ... other plugins
105
268
  ],
106
- envPrefix: 'VITE_', // Vite environment variables prefix
269
+ envPrefix: envPrefix, // Vite env var prefix
107
270
  server: {
108
271
  port: Number(process.env.VITE_SERVER_PORT || 3200)
109
272
  }
110
273
  });
111
274
  ```
112
275
 
113
- ### 2. Application Configuration Class
276
+ **Key Configuration:**
277
+
278
+ - `envConfig` plugin handles preprocessing of environment variables
279
+ - `records` can inject additional variables (like info from package.json)
280
+ - `envPrefix` set to `'VITE_'`, only variables with this prefix are exposed to client
281
+
282
+ ### 3. Define Common Configuration
283
+
284
+ ```typescript
285
+ // config/common.ts
286
+ export const envPrefix = 'VITE_';
287
+
288
+ /**
289
+ * Bootstrap env var injection blacklist
290
+ * These properties won't be injected from env vars
291
+ */
292
+ export const envBlackList = ['env', 'userNodeEnv'];
293
+
294
+ export const browserGlobalsName = 'feGlobals';
295
+ ```
296
+
297
+ ### 4. Define AppConfig
114
298
 
115
- ```tsx
299
+ ```typescript
116
300
  // src/base/cases/AppConfig.ts
301
+ import type { EnvConfigInterface } from '@qlover/corekit-bridge';
302
+
303
+ /**
304
+ * Application configuration class
305
+ *
306
+ * All properties will be automatically injected with corresponding env var values during Bootstrap initialization
307
+ *
308
+ * Environment variable naming rules:
309
+ * - Property names are converted to UPPER_SNAKE_CASE
310
+ * - Add VITE_ prefix
311
+ *
312
+ * Examples:
313
+ * - appName → VITE_APP_NAME
314
+ * - feApiBaseUrl → VITE_FE_API_BASE_URL
315
+ * - aiApiToken → VITE_AI_API_TOKEN
316
+ */
117
317
  export class AppConfig implements EnvConfigInterface {
318
+ constructor(
319
+ /**
320
+ * Current environment mode
321
+ * @description Automatically set from Vite's MODE
322
+ */
323
+ readonly env: string = import.meta.env.VITE_USER_NODE_ENV
324
+ ) {}
325
+
118
326
  /**
119
327
  * Application name
120
328
  * @description Injected from VITE_APP_NAME environment variable
@@ -127,18 +335,30 @@ export class AppConfig implements EnvConfigInterface {
127
335
  */
128
336
  readonly appVersion = '';
129
337
 
130
- /**
131
- * Current environment mode
132
- * @description Retrieved from Vite's mode
133
- */
134
- readonly env: string = import.meta.env.MODE;
135
-
136
338
  /**
137
339
  * User token storage key
138
340
  * @description Injected from VITE_USER_TOKEN_STORAGE_KEY environment variable
139
341
  */
140
342
  readonly userTokenStorageKey = '__fe_user_token__';
141
343
 
344
+ /**
345
+ * User info storage key
346
+ * @description Injected from VITE_USER_INFO_STORAGE_KEY environment variable
347
+ */
348
+ readonly userInfoStorageKey = '__fe_user_info__';
349
+
350
+ /**
351
+ * Frontend API base URL
352
+ * @description Injected from VITE_FE_API_BASE_URL environment variable
353
+ */
354
+ readonly feApiBaseUrl = '';
355
+
356
+ /**
357
+ * User API base URL
358
+ * @description Injected from VITE_USER_API_BASE_URL environment variable
359
+ */
360
+ readonly userApiBaseUrl = '';
361
+
142
362
  /**
143
363
  * AI API base URL
144
364
  * @description Injected from VITE_AI_API_BASE_URL environment variable
@@ -151,332 +371,966 @@ export class AppConfig implements EnvConfigInterface {
151
371
  */
152
372
  readonly aiApiToken = '';
153
373
 
154
- // ... more configuration items
374
+ /**
375
+ * AI API token prefix
376
+ * @description Injected from VITE_AI_API_TOKEN_PREFIX environment variable
377
+ */
378
+ readonly aiApiTokenPrefix = 'Bearer';
379
+
380
+ /**
381
+ * Whether AI API token is required
382
+ * @description Injected from VITE_AI_API_REQUIRE_TOKEN environment variable
383
+ */
384
+ readonly aiApiRequireToken = true;
385
+
386
+ /**
387
+ * Default login username
388
+ * @description Injected from VITE_LOGIN_USER environment variable
389
+ */
390
+ readonly loginUser = '';
391
+
392
+ /**
393
+ * Default login password
394
+ * @description Injected from VITE_LOGIN_PASSWORD environment variable
395
+ */
396
+ readonly loginPassword = '';
397
+
398
+ /**
399
+ * OpenAI available models list
400
+ */
401
+ readonly openAiModels = [
402
+ 'gpt-4o-mini',
403
+ 'gpt-3.5-turbo',
404
+ 'gpt-3.5-turbo-2',
405
+ 'gpt-4',
406
+ 'gpt-4-32k'
407
+ ];
408
+
409
+ /**
410
+ * OpenAI API base URL
411
+ * @description Injected from VITE_OPEN_AI_BASE_URL environment variable
412
+ */
413
+ readonly openAiBaseUrl = '';
414
+
415
+ /**
416
+ * OpenAI API token
417
+ * @description Injected from VITE_OPEN_AI_TOKEN environment variable
418
+ */
419
+ readonly openAiToken = '';
420
+
421
+ /**
422
+ * OpenAI API token prefix
423
+ * @description Injected from VITE_OPEN_AI_TOKEN_PREFIX environment variable
424
+ */
425
+ readonly openAiTokenPrefix = '';
426
+
427
+ /**
428
+ * Whether OpenAI API token is required
429
+ * @description Injected from VITE_OPEN_AI_REQUIRE_TOKEN environment variable
430
+ */
431
+ readonly openAiRequireToken = true;
432
+
433
+ /**
434
+ * Project startup URL
435
+ * @description Injected from Bootstrap's BOOT_HREF
436
+ */
437
+ readonly bootHref = '';
438
+
439
+ /**
440
+ * Whether is production environment
441
+ */
442
+ get isProduction(): boolean {
443
+ return this.env === 'production';
444
+ }
155
445
  }
156
446
  ```
157
447
 
158
- ### 3. Injection in Bootstrap
448
+ ### 5. Bootstrap Configuration
159
449
 
160
- ```tsx
161
- // src/core/bootstraps/BootstrapApp.ts
162
- const bootstrap = new Bootstrap({
163
- root: window,
164
- logger,
165
- ioc: {
166
- manager: IOC,
167
- register: new IocRegisterImpl({ pathname, appConfig })
168
- },
169
- envOptions: {
170
- target: appConfig, // Injection target
171
- source: {
172
- ...import.meta.env, // Environment variables source
173
- [envPrefix + 'BOOT_HREF']: root.location.href
174
- },
175
- prefix: envPrefix, // Environment variables prefix
176
- blackList: envBlackList // Blacklist (variables not to inject)
450
+ ```typescript
451
+ // src/core/bootstraps/BootstrapClient.ts
452
+ import { envBlackList, envPrefix, browserGlobalsName } from '@config/common';
453
+ import { Bootstrap } from '@qlover/corekit-bridge';
454
+ import * as globals from '../globals';
455
+
456
+ export class BootstrapClient {
457
+ static async main(args: BootstrapClientArgs) {
458
+ const { root, bootHref, ioc, iocRegister } = args;
459
+ const { logger, appConfig } = globals;
460
+
461
+ // Create IOC container
462
+ const IOC = ioc.create({
463
+ pathname: bootHref,
464
+ appConfig: appConfig
465
+ });
466
+
467
+ // Create Bootstrap instance
468
+ const bootstrap = new Bootstrap({
469
+ root,
470
+ logger,
471
+ ioc: {
472
+ manager: IOC,
473
+ register: iocRegister
474
+ },
475
+ // ✅ Environment variable injection configuration
476
+ envOptions: {
477
+ target: appConfig, // Injection target: AppConfig instance
478
+ source: Object.assign({}, import.meta.env, {
479
+ [envPrefix + 'BOOT_HREF']: bootHref // Additionally inject startup URL
480
+ }),
481
+ prefix: envPrefix, // Env var prefix: 'VITE_'
482
+ blackList: envBlackList // Blacklist: ['env', 'userNodeEnv']
483
+ },
484
+ // Global variable encapsulation configuration
485
+ globalOptions: {
486
+ sources: globals,
487
+ target: browserGlobalsName
488
+ }
489
+ });
490
+
491
+ try {
492
+ logger.info('bootstrap start...');
493
+
494
+ // ✅ Initialize Bootstrap (env var injection executes here)
495
+ await bootstrap.initialize();
496
+
497
+ // Register business plugins
498
+ const bootstrapsRegistry = new BootstrapsRegistry(IOC);
499
+ await bootstrap.use(bootstrapsRegistry.register()).start();
500
+
501
+ logger.info('bootstrap completed successfully');
502
+ } catch (error) {
503
+ logger.error(`${appConfig.appName} startup error:`, error);
504
+ }
505
+
506
+ return args;
177
507
  }
178
- });
508
+ }
179
509
  ```
180
510
 
181
- ## Multi-Environment Configuration
511
+ **Key Flow:**
182
512
 
183
- ### 1. Development Environment Configuration
513
+ 1. `appConfig` is an AppConfig instance with default values for all properties
514
+ 2. `bootstrap.initialize()` executes the `InjectEnv` plugin
515
+ 3. `InjectEnv` plugin iterates through `appConfig` properties, looking for corresponding env vars in `import.meta.env`
516
+ 4. If an env var is found and value is not empty, it overwrites the default value
517
+ 5. Finally `appConfig` is registered to the IOC container
518
+
519
+ ---
520
+
521
+ ## 🌍 Multi-Environment Configuration
522
+
523
+ ### Environment File Structure
524
+
525
+ ```
526
+ Project root/
527
+ ├── .env # Default config (shared across all environments)
528
+ ├── .env.localhost # Local development environment
529
+ ├── .env.staging # Staging environment
530
+ ├── .env.production # Production environment
531
+ ├── .env.local # Local override config (not committed to git)
532
+ └── .env.template # Env var template (committed to git)
533
+ ```
534
+
535
+ ### Loading Priority
536
+
537
+ ```
538
+ .env.local > .env.[mode] > .env
539
+ ```
540
+
541
+ **Example:**
184
542
 
185
543
  ```bash
186
- # package.json
187
- {
188
- "scripts": {
189
- "dev": "vite --mode localhost",
190
- "dev:staging": "vite --mode staging",
191
- "dev:prod": "vite --mode production"
192
- }
193
- }
544
+ # Run: npm run dev (vite --mode localhost)
545
+ # Loading order:
546
+ # 1. .env.local # Highest priority
547
+ # 2. .env.localhost # Second
548
+ # 3. .env # Last
549
+
550
+ # Run: npm run build:production (vite build --mode production)
551
+ # Loading order:
552
+ # 1. .env.local
553
+ # 2. .env.production
554
+ # 3. .env
194
555
  ```
195
556
 
557
+ ### Example 1: Default Configuration
558
+
196
559
  ```bash
197
- # .env.development
198
- VITE_APP_NAME=MyApp Dev
199
- VITE_API_BASE_URL=http://localhost:3000/api
200
- VITE_DEBUG=true
560
+ # .env
561
+ # Configuration shared across all environments
562
+
563
+ VITE_APP_NAME=MyApp
564
+ VITE_USER_TOKEN_STORAGE_KEY=__fe_user_token__
565
+ VITE_USER_INFO_STORAGE_KEY=__fe_user_info__
566
+ VITE_AI_API_TOKEN_PREFIX=Bearer
567
+ VITE_AI_API_REQUIRE_TOKEN=true
568
+ ```
569
+
570
+ ### Example 2: Local Development Environment
571
+
572
+ ```bash
573
+ # .env.localhost
574
+ # Local development environment config
575
+
576
+ # API configuration
577
+ VITE_FE_API_BASE_URL=http://localhost:3000/api
578
+ VITE_USER_API_BASE_URL=http://localhost:3000/api/user
579
+ VITE_AI_API_BASE_URL=http://localhost:3001/v1
580
+
581
+ # AI configuration (dev environment may use local Mock)
582
+ VITE_AI_API_TOKEN=sk-dev-xxxxx
583
+ VITE_AI_API_REQUIRE_TOKEN=false
584
+
585
+ # Debug configuration
201
586
  VITE_LOG_LEVEL=debug
587
+ VITE_DEBUG=true
588
+
589
+ # Default login info (convenient for development)
590
+ VITE_LOGIN_USER=admin
591
+ VITE_LOGIN_PASSWORD=admin123
202
592
  ```
203
593
 
204
- ### 2. Testing Environment Configuration
594
+ ### Example 3: Staging Environment
205
595
 
206
596
  ```bash
207
597
  # .env.staging
208
- VITE_APP_NAME=MyApp Staging
209
- VITE_API_BASE_URL=https://api.staging.com
210
- VITE_DEBUG=true
598
+ # Staging environment config
599
+
600
+ # API configuration
601
+ VITE_FE_API_BASE_URL=https://api.staging.example.com
602
+ VITE_USER_API_BASE_URL=https://api.staging.example.com/user
603
+ VITE_AI_API_BASE_URL=https://api.staging.example.com/ai
604
+
605
+ # AI configuration
606
+ VITE_AI_API_TOKEN=sk-staging-xxxxx
607
+ VITE_AI_API_REQUIRE_TOKEN=true
608
+
609
+ # Debug configuration
211
610
  VITE_LOG_LEVEL=info
611
+ VITE_DEBUG=true
212
612
  ```
213
613
 
214
- ### 3. Production Environment Configuration
614
+ ### Example 4: Production Environment
215
615
 
216
616
  ```bash
217
617
  # .env.production
218
- VITE_APP_NAME=MyApp
219
- VITE_API_BASE_URL=https://api.production.com
618
+ # Production environment config
619
+
620
+ # API configuration
621
+ VITE_FE_API_BASE_URL=https://api.example.com
622
+ VITE_USER_API_BASE_URL=https://api.example.com/user
623
+ VITE_AI_API_BASE_URL=https://api.openai.com/v1
624
+
625
+ # AI configuration
626
+ VITE_AI_API_TOKEN=sk-prod-xxxxx
627
+ VITE_AI_API_REQUIRE_TOKEN=true
628
+
629
+ # Debug configuration
630
+ VITE_LOG_LEVEL=error
220
631
  VITE_DEBUG=false
221
- VITE_LOG_LEVEL=warn
222
632
  ```
223
633
 
224
- ### 4. Local Override Configuration
634
+ ### Example 5: Local Override Configuration
225
635
 
226
636
  ```bash
227
- # .env.local (not committed to git)
228
- VITE_API_KEY=your_secret_key
229
- VITE_LOCAL_DEBUG=true
230
- VITE_CUSTOM_FEATURE=true
637
+ # .env.local
638
+ # Local personal config, not committed to git
639
+
640
+ # Override AI API Token (use your own key)
641
+ VITE_AI_API_TOKEN=sk-my-personal-key
642
+
643
+ # Override API address (connect to your local service)
644
+ VITE_FE_API_BASE_URL=http://192.168.1.100:3000/api
645
+
646
+ # Enable specific features
647
+ VITE_ENABLE_EXPERIMENTAL_FEATURES=true
648
+ ```
649
+
650
+ ### Example 6: Environment Variable Template
651
+
652
+ ```bash
653
+ # .env.template
654
+ # Env var template, committed to git for team reference
655
+
656
+ # ===== Required Configuration =====
657
+ VITE_FE_API_BASE_URL=https://your-api-url.com
658
+ VITE_AI_API_TOKEN=your-ai-api-token-here
659
+
660
+ # ===== Optional Configuration =====
661
+ VITE_LOGIN_USER=your-default-username
662
+ VITE_LOGIN_PASSWORD=your-default-password
663
+
664
+ # ===== Instructions =====
665
+ # 1. Copy this file as .env.local
666
+ # 2. Fill in actual configuration values
667
+ # 3. .env.local won't be committed to git
668
+ ```
669
+
670
+ ---
671
+
672
+ ## 🔄 Environment Variable Injection
673
+
674
+ ### InjectEnv Plugin Working Principle
675
+
676
+ ```typescript
677
+ // @qlover/corekit-bridge/src/core/bootstrap/plugins/InjectEnv.ts (simplified)
678
+ export class InjectEnv implements BootstrapExecutorPlugin {
679
+ readonly pluginName = 'InjectEnv';
680
+
681
+ constructor(protected options: InjectEnvConfig) {}
682
+
683
+ /**
684
+ * Execute before Bootstrap initialization
685
+ */
686
+ onBefore(): void {
687
+ const { target, source, prefix, blackList } = this.options;
688
+
689
+ // Iterate through all properties of target object
690
+ for (const key in target) {
691
+ // Skip properties in blacklist
692
+ if (blackList.includes(key)) {
693
+ continue;
694
+ }
695
+
696
+ const currentValue = target[key as keyof typeof target];
697
+
698
+ // Get corresponding env var value
699
+ const envValue = this.getEnvValue(key, currentValue);
700
+
701
+ // If env var exists and differs from default value, inject it
702
+ if (!this.isEmpty(envValue) && envValue !== currentValue) {
703
+ target[key as keyof typeof target] = envValue;
704
+ }
705
+ }
706
+ }
707
+
708
+ /**
709
+ * Get environment variable value
710
+ */
711
+ private getEnvValue<D>(key: string, defaultValue?: D): D {
712
+ const { prefix = '', source = {} } = this.options;
713
+
714
+ // Convert camelCase to UPPER_SNAKE_CASE
715
+ // appName → APP_NAME
716
+ // feApiBaseUrl → FE_API_BASE_URL
717
+ const formattedKey = key.replace(/([a-z])([A-Z])/g, '$1_$2').toUpperCase();
718
+
719
+ // Add prefix
720
+ const envKey = `${prefix}${formattedKey}`;
721
+
722
+ // Get env var value
723
+ const value = source[envKey];
724
+
725
+ // If it's a JSON string, parse it
726
+ if (typeof value === 'string' && this.isJSONString(value)) {
727
+ return JSON.parse(value);
728
+ }
729
+
730
+ return (value ?? defaultValue) as D;
731
+ }
732
+
733
+ /**
734
+ * Check if value is empty
735
+ */
736
+ private isEmpty(value: any): boolean {
737
+ return value === undefined || value === null || value === '';
738
+ }
739
+
740
+ /**
741
+ * Check if it's a JSON string
742
+ */
743
+ private isJSONString(str: string): boolean {
744
+ try {
745
+ JSON.parse(str);
746
+ return true;
747
+ } catch {
748
+ return false;
749
+ }
750
+ }
751
+ }
752
+ ```
753
+
754
+ ### Injection Example
755
+
756
+ ```typescript
757
+ // Assuming the following environment variables:
758
+ VITE_APP_NAME=MyApp
759
+ VITE_FE_API_BASE_URL=https://api.example.com
760
+ VITE_AI_API_TOKEN=sk-xxxxx
761
+
762
+ // AppConfig initial state:
763
+ const appConfig = new AppConfig();
764
+ console.log(appConfig.appName); // ''
765
+ console.log(appConfig.feApiBaseUrl); // ''
766
+ console.log(appConfig.aiApiToken); // ''
767
+
768
+ // After Bootstrap initialization (after InjectEnv plugin execution):
769
+ await bootstrap.initialize();
770
+
771
+ console.log(appConfig.appName); // 'MyApp'
772
+ console.log(appConfig.feApiBaseUrl); // 'https://api.example.com'
773
+ console.log(appConfig.aiApiToken); // 'sk-xxxxx'
774
+ ```
775
+
776
+ ---
777
+
778
+ ## 📦 AppConfig Usage
779
+
780
+ ### 1. Use in Services (Recommended) ⭐
781
+
782
+ ```typescript
783
+ // src/base/services/UserService.ts
784
+ import { injectable, inject } from 'inversify';
785
+ import { IOCIdentifier } from '@config/IOCIdentifier';
786
+ import type { AppConfig } from '@/base/cases/AppConfig';
787
+
788
+ @injectable()
789
+ export class UserService {
790
+ constructor(
791
+ @inject(IOCIdentifier.AppConfig) private config: AppConfig,
792
+ @inject(UserApi) private api: UserApi
793
+ ) {}
794
+
795
+ async login(username: string, password: string) {
796
+ // ✅ Use API address from config
797
+ const response = await this.api.post(
798
+ `${this.config.userApiBaseUrl}/login`,
799
+ { username, password }
800
+ );
801
+
802
+ // ✅ Use storage key from config
803
+ this.storage.setItem(this.config.userTokenStorageKey, response.token);
804
+
805
+ return response.user;
806
+ }
807
+ }
231
808
  ```
232
809
 
233
- ## Usage in Code
810
+ ### 2. Use in UI Components
234
811
 
235
- ### 1. Direct Use of Environment Variables
812
+ ```typescript
813
+ // src/pages/base/HomePage.tsx
814
+ import { useIOC } from '@/uikit/hooks/useIOC';
236
815
 
237
- ```tsx
238
- // Using in components directly
239
- function App() {
240
- const apiUrl = import.meta.env.VITE_API_BASE_URL;
241
- const isDebug = import.meta.env.VITE_DEBUG === 'true';
816
+ function HomePage() {
817
+ // Get config through Hook
818
+ const config = useIOC('AppConfig');
242
819
 
243
820
  return (
244
821
  <div>
245
- <p>API URL: {apiUrl}</p>
246
- {isDebug && <p>Debug mode enabled</p>}
822
+ <h1>{config.appName}</h1>
823
+ <p>Version: {config.appVersion}</p>
824
+ <p>Environment: {config.env}</p>
825
+ {!config.isProduction && <p>🚧 Development Mode</p>}
247
826
  </div>
248
827
  );
249
828
  }
250
829
  ```
251
830
 
252
- ### 2. Using Through AppConfig
831
+ ### 3. Use in Plugins
832
+
833
+ ```typescript
834
+ // src/base/apis/feApi/FeApiBootstrap.ts
835
+ export class FeApiBootstarp implements BootstrapExecutorPlugin {
836
+ readonly pluginName = 'FeApiBootstarp';
837
+
838
+ onBefore({ parameters: { ioc } }: BootstrapContext): void {
839
+ const feApi = ioc.get<FeApi>(FeApi);
840
+ // ✅ Get config from IOC
841
+ const config = ioc.get<AppConfig>(IOCIdentifier.AppConfig);
842
+
843
+ // ✅ Use config to set API base URL
844
+ feApi.setBaseURL(config.feApiBaseUrl);
845
+
846
+ // Add other plugins
847
+ feApi.usePlugin(
848
+ new AuthTokenPlugin({
849
+ getToken: () => {
850
+ const storage = ioc.get(IOCIdentifier.LocalStorageEncrypt);
851
+ return storage.getItem(config.userTokenStorageKey);
852
+ }
853
+ })
854
+ );
855
+ }
856
+ }
857
+ ```
253
858
 
254
- ```tsx
255
- // Getting configuration through IOC
256
- function UserService() {
257
- const appConfig = IOC(IOCIdentifier.AppConfig);
859
+ ### 4. Use Environment Variables Directly in Code
258
860
 
259
- const apiUrl = appConfig.aiApiBaseUrl;
260
- const token = appConfig.aiApiToken;
861
+ ```typescript
862
+ // Note: Using import.meta.env directly is not recommended as it can't be managed by IOC
261
863
 
262
- // Using configuration for API calls
263
- const response = await fetch(`${apiUrl}/chat`, {
264
- headers: {
265
- Authorization: `Bearer ${token}`
266
- }
267
- });
864
+ // Not recommended: Direct use (bypasses AppConfig)
865
+ function MyComponent() {
866
+ const apiUrl = import.meta.env.VITE_FE_API_BASE_URL;
867
+ // ...
868
+ }
869
+
870
+ // ✅ Recommended: Use through AppConfig
871
+ function MyComponent() {
872
+ const config = useIOC('AppConfig');
873
+ const apiUrl = config.feApiBaseUrl;
874
+ // ...
268
875
  }
269
876
  ```
270
877
 
271
- ### 3. Using in Services
878
+ ---
272
879
 
273
- ```tsx
274
- @injectable()
275
- export class ApiService {
276
- constructor(@inject(IOCIdentifier.AppConfig) private appConfig: AppConfig) {}
880
+ ## 🚀 Advanced Usage
277
881
 
278
- async makeRequest() {
279
- const baseUrl = this.appConfig.aiApiBaseUrl;
280
- const token = this.appConfig.aiApiToken;
882
+ ### 1. Dynamically Modify Configuration
281
883
 
282
- return fetch(`${baseUrl}/api/endpoint`, {
283
- headers: {
284
- Authorization: `Bearer ${token}`
285
- }
286
- });
287
- }
884
+ Sometimes you may need to dynamically modify configuration at runtime (rather than through environment variables):
885
+
886
+ ```typescript
887
+ // ✅ Method 1: Modify before Bootstrap initialization
888
+ const appConfig = new AppConfig();
889
+
890
+ // Dynamically modify config
891
+ if (window.location.hostname.includes('localhost')) {
892
+ // Use different API address for local development
893
+ (appConfig as any).feApiBaseUrl = 'http://localhost:3000/api';
288
894
  }
289
- ```
290
895
 
291
- ## Environment Variables Injection Plugin
896
+ // Then pass to Bootstrap
897
+ const bootstrap = new Bootstrap({
898
+ envOptions: {
899
+ target: appConfig, // Use modified config
900
+ source: import.meta.env,
901
+ prefix: 'VITE_',
902
+ blackList: envBlackList
903
+ }
904
+ });
292
905
 
293
- ### 1. InjectEnv Plugin Working Principle
906
+ await bootstrap.initialize();
907
+ ```
294
908
 
295
- ```tsx
296
- // corekit-bridge/src/core/bootstrap/plugins/InjectEnv.ts
297
- export class InjectEnv implements BootstrapExecutorPlugin {
298
- readonly pluginName = 'InjectEnv';
909
+ ```typescript
910
+ // ✅ Method 2: Create config factory function
911
+ export function createAppConfig(): AppConfig {
912
+ const config = new AppConfig();
299
913
 
300
- constructor(protected options: InjectEnvConfig) {}
914
+ // Dynamically set config based on specific conditions
915
+ if (someCondition) {
916
+ (config as any).aiApiBaseUrl = 'https://custom-api.com';
917
+ }
301
918
 
302
- onBefore(): void {
303
- const { target, source, prefix, blackList } = this.options;
919
+ return config;
920
+ }
304
921
 
305
- // Iterate through target object properties
306
- for (const key in target) {
307
- if (blackList.includes(key)) {
308
- continue; // Skip properties in blacklist
309
- }
922
+ // Use in Bootstrap
923
+ const appConfig = createAppConfig();
924
+ ```
310
925
 
311
- const value = target[key as keyof typeof target];
312
- const envValue = this.env(key, value); // Get environment variable value
926
+ ### 2. Configuration Validation
313
927
 
314
- // If environment variable exists and differs from default value, inject it
315
- if (!this.isEmpty(envValue) && envValue !== value) {
316
- target[key as keyof typeof target] = envValue;
928
+ ```typescript
929
+ // src/base/cases/AppConfig.ts
930
+ export class AppConfig implements EnvConfigInterface {
931
+ // ... property definitions
932
+
933
+ /**
934
+ * Validate required configuration items
935
+ */
936
+ validate(): void {
937
+ const required: (keyof AppConfig)[] = [
938
+ 'appName',
939
+ 'feApiBaseUrl',
940
+ 'userTokenStorageKey'
941
+ ];
942
+
943
+ for (const key of required) {
944
+ if (!this[key]) {
945
+ throw new Error(`Missing required configuration: ${key}`);
317
946
  }
318
947
  }
319
948
  }
320
949
  }
950
+
951
+ // Use in Bootstrap
952
+ const appConfig = new AppConfig();
953
+
954
+ await bootstrap.initialize();
955
+
956
+ // Validate after initialization
957
+ appConfig.validate();
321
958
  ```
322
959
 
323
- ### 2. Environment Variable Retrieval Logic
960
+ ### 3. Configuration Composition
961
+
962
+ ```typescript
963
+ // ✅ Method 3: Compose config from multiple sources
964
+ const appConfig = new AppConfig();
965
+
966
+ const bootstrap = new Bootstrap({
967
+ envOptions: {
968
+ target: appConfig,
969
+ // Merge multiple config sources
970
+ source: Object.assign(
971
+ {},
972
+ import.meta.env, // Vite environment variables
973
+ { VITE_BOOT_HREF: window.location.href }, // Runtime info
974
+ window.__APP_CONFIG__ // Server-injected config
975
+ ),
976
+ prefix: 'VITE_',
977
+ blackList: envBlackList
978
+ }
979
+ });
980
+ ```
324
981
 
325
- ```tsx
326
- env<D>(key: string, defaultValue?: D): D {
327
- const { prefix = '', source = {} } = this.options;
982
+ ### 4. Conditional Configuration
328
983
 
329
- // Convert camelCase to SNAKE_CASE
330
- const formattedKey = key.replace(/([a-z])([A-Z])/g, '$1_$2').toUpperCase();
331
- const envKey = `${prefix}${formattedKey}`;
984
+ ```typescript
985
+ // src/core/bootstraps/BootstrapClient.ts
986
+ const appConfig = new AppConfig();
332
987
 
333
- const value = source[envKey];
988
+ // Set different config sources based on environment
989
+ const configSource =
990
+ import.meta.env.VITE_USER_NODE_ENV === 'production'
991
+ ? import.meta.env // Production: only use env vars
992
+ : {
993
+ ...import.meta.env,
994
+ ...window.__DEV_CONFIG__ // Development: allow window injection
995
+ };
334
996
 
335
- // If it's a JSON string, parse it
336
- if (typeof value === 'string' && InjectEnv.isJSONString(value)) {
337
- return JSON.parse(value);
997
+ const bootstrap = new Bootstrap({
998
+ envOptions: {
999
+ target: appConfig,
1000
+ source: configSource,
1001
+ prefix: 'VITE_',
1002
+ blackList: envBlackList
338
1003
  }
1004
+ });
1005
+ ```
339
1006
 
340
- return (value ?? defaultValue) as D;
341
- }
1007
+ ---
1008
+
1009
+ ## 🧪 Testing Configuration
1010
+
1011
+ ### 1. Mock AppConfig in Tests
1012
+
1013
+ ```typescript
1014
+ // __tests__/src/base/services/UserService.test.ts
1015
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
1016
+ import { UserService } from '@/base/services/UserService';
1017
+ import type { AppConfig } from '@/base/cases/AppConfig';
1018
+
1019
+ describe('UserService', () => {
1020
+ let userService: UserService;
1021
+ let mockConfig: AppConfig;
1022
+
1023
+ beforeEach(() => {
1024
+ // ✅ Create mock config
1025
+ mockConfig = {
1026
+ userApiBaseUrl: 'http://localhost:3000/api',
1027
+ userTokenStorageKey: '__test_token__',
1028
+ userInfoStorageKey: '__test_user__',
1029
+ isProduction: false
1030
+ } as AppConfig;
1031
+
1032
+ // Create service
1033
+ userService = new UserService(mockConfig, mockApi, mockStorage);
1034
+ });
1035
+
1036
+ it('should use config values', async () => {
1037
+ await userService.login('user', 'pass');
1038
+
1039
+ // ✅ Verify config values were used
1040
+ expect(mockApi.post).toHaveBeenCalledWith(
1041
+ `${mockConfig.userApiBaseUrl}/login`,
1042
+ expect.any(Object)
1043
+ );
1044
+ });
1045
+ });
342
1046
  ```
343
1047
 
344
- ## Best Practices
1048
+ ### 2. Test Different Environment Configurations
1049
+
1050
+ ```typescript
1051
+ // __tests__/src/base/cases/AppConfig.test.ts
1052
+ import { describe, it, expect } from 'vitest';
1053
+ import { AppConfig } from '@/base/cases/AppConfig';
1054
+
1055
+ describe('AppConfig', () => {
1056
+ it('should detect production environment', () => {
1057
+ const config = new AppConfig('production');
1058
+ expect(config.isProduction).toBe(true);
1059
+ });
1060
+
1061
+ it('should detect non-production environment', () => {
1062
+ const config = new AppConfig('localhost');
1063
+ expect(config.isProduction).toBe(false);
1064
+ });
345
1065
 
346
- ### 1. Environment Variable Naming Conventions
1066
+ it('should have default values', () => {
1067
+ const config = new AppConfig();
1068
+ expect(config.appName).toBe('');
1069
+ expect(config.userTokenStorageKey).toBe('__fe_user_token__');
1070
+ });
1071
+ });
1072
+ ```
1073
+
1074
+ ### 3. Test Environment Variable Injection
1075
+
1076
+ ```typescript
1077
+ // __tests__/src/core/bootstraps/BootstrapClient.test.ts
1078
+ import { describe, it, expect, vi } from 'vitest';
1079
+ import { BootstrapClient } from '@/core/bootstraps/BootstrapClient';
1080
+
1081
+ describe('BootstrapClient', () => {
1082
+ it('should inject environment variables to AppConfig', async () => {
1083
+ const mockArgs = {
1084
+ root: {},
1085
+ bootHref: 'http://localhost:3000',
1086
+ ioc: {
1087
+ create: vi.fn().mockReturnValue(mockIOC)
1088
+ }
1089
+ };
1090
+
1091
+ // Execute startup
1092
+ await BootstrapClient.main(mockArgs);
1093
+
1094
+ // ✅ Verify config was injected
1095
+ const globals = (mockArgs.root as any).feGlobals;
1096
+ expect(globals.appConfig).toBeDefined();
1097
+ expect(globals.appConfig.appName).toBeTruthy();
1098
+ });
1099
+ });
1100
+ ```
1101
+
1102
+ ---
1103
+
1104
+ ## 💎 Best Practices
1105
+
1106
+ ### 1. ✅ Use Environment Variable Prefix
347
1107
 
348
1108
  ```bash
349
- # ✅ Good naming
1109
+ # ✅ Good naming: Use VITE_ prefix
350
1110
  VITE_APP_NAME=MyApp
351
1111
  VITE_API_BASE_URL=https://api.example.com
352
- VITE_USER_TOKEN_STORAGE_KEY=user_token
353
- VITE_DEBUG=true
354
1112
 
355
- # ❌ Bad naming
356
- VITE_app_name=MyApp
357
- VITE_API_BASE_URL=https://api.example.com
358
- VITE_USER_TOKEN_STORAGE_KEY=user_token
359
- VITE_DEBUG=true
1113
+ # ❌ Wrong naming: No prefix
1114
+ APP_NAME=MyApp
1115
+ API_BASE_URL=https://api.example.com
360
1116
  ```
361
1117
 
362
- ### 2. Sensitive Information Handling
1118
+ ### 2. ✅ Use .env.local for Sensitive Information
363
1119
 
364
1120
  ```bash
365
1121
  # .env.local (not committed to git)
366
- VITE_API_KEY=your_secret_key
367
- VITE_DATABASE_PASSWORD=your_password
1122
+ VITE_AI_API_TOKEN=sk-your-secret-key
1123
+ VITE_DATABASE_PASSWORD=your-password
368
1124
 
369
- # .env.template (committed to git, as template)
370
- VITE_API_KEY=your_api_key_here
371
- VITE_DATABASE_PASSWORD=your_password_here
1125
+ # .gitignore
1126
+ .env.local
372
1127
  ```
373
1128
 
374
- ### 3. Type Safety
1129
+ ### 3. Provide .env.template
375
1130
 
376
- ```tsx
377
- // Define environment variables type
378
- interface EnvVariables {
379
- VITE_APP_NAME: string;
380
- VITE_API_BASE_URL: string;
381
- VITE_DEBUG: boolean;
382
- VITE_PORT: number;
383
- }
1131
+ ```bash
1132
+ # .env.template (committed to git)
1133
+ # Team members can copy this file as .env.local and fill in actual values
384
1134
 
385
- // Use in AppConfig
386
- export class AppConfig implements EnvConfigInterface {
387
- readonly appName: string = '';
388
- readonly apiBaseUrl: string = '';
389
- readonly debug: boolean = false;
390
- readonly port: number = 3000;
391
- }
1135
+ VITE_AI_API_TOKEN=your-api-token-here
1136
+ VITE_DATABASE_PASSWORD=your-password-here
392
1137
  ```
393
1138
 
394
- ### 4. Environment Variables Validation
1139
+ ### 4. Use Type-safe Configuration
395
1140
 
396
- ```tsx
397
- // Validate required environment variables at application startup
398
- export class AppConfig implements EnvConfigInterface {
399
- constructor() {
400
- this.validateRequiredEnvVars();
401
- }
1141
+ ```typescript
1142
+ // Good practice: Access through AppConfig
1143
+ const config = useIOC('AppConfig');
1144
+ const apiUrl = config.feApiBaseUrl; // ✅ Type-safe
402
1145
 
403
- private validateRequiredEnvVars(): void {
404
- const required = ['VITE_API_BASE_URL', 'VITE_APP_NAME'];
1146
+ // ❌ Bad practice: Direct access to env vars
1147
+ const apiUrl = import.meta.env.VITE_FE_API_BASE_URL; // ❌ May be undefined
1148
+ ```
405
1149
 
406
- for (const envVar of required) {
407
- if (!import.meta.env[envVar]) {
408
- throw new Error(`Missing required environment variable: ${envVar}`);
409
- }
410
- }
411
- }
1150
+ ### 5. Add Comments to AppConfig
1151
+
1152
+ ```typescript
1153
+ export class AppConfig {
1154
+ /**
1155
+ * AI API base URL
1156
+ * @description Injected from VITE_AI_API_BASE_URL environment variable
1157
+ * @default 'https://api.openai.com/v1'
1158
+ * @example 'https://api.openai.com/v1'
1159
+ */
1160
+ readonly aiApiBaseUrl = 'https://api.openai.com/v1';
412
1161
  }
413
1162
  ```
414
1163
 
415
- ## Debugging and Troubleshooting
1164
+ ### 6. Avoid Environment Checks in Code
416
1165
 
417
- ### 1. Check Environment Variables Loading
1166
+ ```typescript
1167
+ // ❌ Bad: Check environment in code
1168
+ if (process.env.NODE_ENV === 'production') {
1169
+ apiUrl = 'https://api.production.com';
1170
+ } else {
1171
+ apiUrl = 'http://localhost:3000';
1172
+ }
418
1173
 
419
- ```tsx
420
- // Check environment variables in console
421
- console.log('import.meta.env:', import.meta.env);
422
- console.log('AppConfig:', IOC(IOCIdentifier.AppConfig));
1174
+ // ✅ Good: Manage through config
1175
+ const config = useIOC('AppConfig');
1176
+ const apiUrl = config.feApiBaseUrl; // Automatically uses correct value based on environment
423
1177
  ```
424
1178
 
425
- ### 2. Common Issues
426
-
427
- **Issue 1: Environment Variables Not Injected**
1179
+ ### 7. Configuration Naming Conventions
428
1180
 
429
1181
  ```bash
430
- # Check environment variable prefix
431
- # Make sure to use VITE_ prefix
432
- VITE_APP_NAME=MyApp # ✅ Correct
433
- APP_NAME=MyApp # ❌ Wrong, won't be injected
1182
+ # Good naming: Clear and specific
1183
+ VITE_FE_API_BASE_URL=https://api.example.com
1184
+ VITE_USER_TOKEN_STORAGE_KEY=__fe_user_token__
1185
+ VITE_AI_API_REQUIRE_TOKEN=true
1186
+
1187
+ # ❌ Bad naming: Vague, abbreviated
1188
+ VITE_API=https://api.example.com
1189
+ VITE_KEY=__token__
1190
+ VITE_REQ=true
434
1191
  ```
435
1192
 
436
- **Issue 2: Environment Variable Files Not Loaded**
1193
+ ---
1194
+
1195
+ ## ❓ FAQ
1196
+
1197
+ ### Q1: Why aren't my environment variables being injected?
1198
+
1199
+ **A:** Check the following points:
1200
+
1201
+ 1. **Environment variable prefix**
437
1202
 
438
1203
  ```bash
439
- # Check file naming
440
- .env.development # ✅ Correct
441
- .env.dev # ❌ Wrong, Vite doesn't recognize it
1204
+ # Correct: Use VITE_ prefix
1205
+ VITE_APP_NAME=MyApp
1206
+
1207
+ # ❌ Wrong: No prefix
1208
+ APP_NAME=MyApp
1209
+ ```
1210
+
1211
+ 2. **AppConfig property name**
1212
+
1213
+ ```typescript
1214
+ // ✅ Correct: Property exists
1215
+ export class AppConfig {
1216
+ readonly appName = ''; // ← VITE_APP_NAME will inject here
1217
+ }
1218
+
1219
+ // ❌ Wrong: No corresponding property
1220
+ export class AppConfig {
1221
+ // No appName property, VITE_APP_NAME won't be injected
1222
+ }
442
1223
  ```
443
1224
 
444
- **Issue 3: Environment Variables Filtered by Blacklist**
1225
+ 3. **Blacklist configuration**
445
1226
 
446
- ```tsx
447
- // Check blacklist configuration
1227
+ ```typescript
1228
+ // config/common.ts
448
1229
  export const envBlackList = ['env', 'userNodeEnv'];
449
- // Make sure your environment variables are not in the blacklist
1230
+ // Make sure your property is not in the blacklist
450
1231
  ```
451
1232
 
452
- ### 3. Debugging Tools
1233
+ ### Q2: How to use different configurations in different environments?
453
1234
 
454
- ```tsx
455
- // Create debugging tool
456
- export class EnvDebugger {
457
- static logEnvVars(config: AppConfig): void {
458
- console.group('Environment Variables Debug');
459
- console.log('Current Mode:', import.meta.env.MODE);
460
- console.log('AppConfig:', config);
461
- console.log('All Env Vars:', import.meta.env);
462
- console.groupEnd();
1235
+ **A:** Use the `--mode` parameter:
1236
+
1237
+ ```json
1238
+ {
1239
+ "scripts": {
1240
+ "dev": "vite --mode localhost", // Load .env.localhost
1241
+ "dev:staging": "vite --mode staging", // Load .env.staging
1242
+ "build:prod": "vite build --mode production" // Load .env.production
463
1243
  }
464
1244
  }
1245
+ ```
465
1246
 
466
- // Use in development environment
467
- if (import.meta.env.DEV) {
468
- EnvDebugger.logEnvVars(IOC(IOCIdentifier.AppConfig));
469
- }
1247
+ ### Q3: How to handle sensitive information?
1248
+
1249
+ **A:** Use `.env.local`:
1250
+
1251
+ ```bash
1252
+ # .env.local (not committed to git)
1253
+ VITE_AI_API_TOKEN=sk-your-secret-key
1254
+
1255
+ # .gitignore
1256
+ .env.local
1257
+ ```
1258
+
1259
+ ### Q4: Can configuration be dynamically modified at runtime?
1260
+
1261
+ **A:** Yes, but it needs to be done before Bootstrap initialization:
1262
+
1263
+ ```typescript
1264
+ const appConfig = new AppConfig();
1265
+
1266
+ // ✅ Modify before Bootstrap initialization
1267
+ (appConfig as any).feApiBaseUrl = 'https://custom-api.com';
1268
+
1269
+ const bootstrap = new Bootstrap({
1270
+ envOptions: {
1271
+ target: appConfig, // Use modified config
1272
+ source: import.meta.env,
1273
+ prefix: 'VITE_',
1274
+ blackList: envBlackList
1275
+ }
1276
+ });
1277
+
1278
+ await bootstrap.initialize();
470
1279
  ```
471
1280
 
472
- ## Summary
1281
+ ### Q5: Why recommend using AppConfig instead of import.meta.env directly?
1282
+
1283
+ **A:**
1284
+
1285
+ | Feature | import.meta.env | AppConfig |
1286
+ | -------------------------- | ------------------- | ---------------------------- |
1287
+ | **Type Safety** | ❌ May be undefined | ✅ Complete type definitions |
1288
+ | **Default Values** | ❌ None | ✅ Has default values |
1289
+ | **Testability** | ❌ Hard to mock | ✅ Easy to mock |
1290
+ | **Centralized Management** | ❌ Scattered | ✅ Unified management |
1291
+ | **Runtime Modification** | ❌ Not possible | ✅ Possible |
1292
+
1293
+ ### Q6: What's the difference between environment variables and config files?
1294
+
1295
+ **A:**
1296
+
1297
+ **Environment variables:** Suitable for:
1298
+
1299
+ - Configuration that differs by environment (API addresses, tokens, etc.)
1300
+ - Sensitive information
1301
+ - Configuration that needs to be modified during deployment
1302
+
1303
+ **Config files (config/):** Suitable for:
1304
+
1305
+ - Application logic configuration (routes, themes, i18n, etc.)
1306
+ - Configuration that doesn't change with environment
1307
+ - Code-level configuration
1308
+
1309
+ ---
1310
+
1311
+ ## 📚 Related Documentation
1312
+
1313
+ - [Project Architecture Design](./index.md) - Understand overall architecture
1314
+ - [Bootstrap Initializer](./bootstrap.md) - Bootstrap details
1315
+ - [IOC Container](./ioc.md) - Dependency injection details
1316
+ - [Global Variable Encapsulation](./global.md) - Browser API encapsulation
1317
+
1318
+ ---
1319
+
1320
+ ## 🎉 Summary
1321
+
1322
+ The environment variable management system, through the combination of **Bootstrap + AppConfig + IOC**, provides:
1323
+
1324
+ 1. **Environment Isolation** 🌍 - Different environments use different configs, no code changes needed
1325
+ 2. **Type Safety** 🔒 - Complete type checking through TypeScript
1326
+ 3. **Centralized Management** 📦 - All config managed uniformly in AppConfig
1327
+ 4. **Auto Injection** ⚡ - Bootstrap automatically injects env vars to AppConfig
1328
+ 5. **Easy to Test** 🧪 - Can easily mock AppConfig for testing
1329
+ 6. **Flexible Extension** 🚀 - Supports multiple config sources and dynamic modification
473
1330
 
474
- The environment variables injection system provides:
1331
+ Through proper use of environment variable management, you can build a more robust, flexible, and maintainable application architecture.
475
1332
 
476
- 1. **Environment Isolation**: Different environments use different configurations
477
- 2. **Type Safety**: Type checking through TypeScript
478
- 3. **Centralized Management**: All configurations are managed uniformly in AppConfig
479
- 4. **Flexible Configuration**: Support for multiple environment variable files
480
- 5. **Security Handling**: Sensitive information can be managed locally through .env.local
1333
+ ---
481
1334
 
482
- Through proper use of environment variables injection, applications can run correctly in different environments while maintaining configuration flexibility and security.
1335
+ **Feedback:**
1336
+ If you have any questions or suggestions about environment variable management, please discuss in the team channel or submit an Issue.