birc-generator 0.5.5

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 (128) hide show
  1. package/.bircrc.example.json +14 -0
  2. package/AGENTS.md +20 -0
  3. package/PROJECT.md +83 -0
  4. package/README.md +300 -0
  5. package/bin/birc.js +645 -0
  6. package/bin/cli-util.js +428 -0
  7. package/bin/home-install.js +346 -0
  8. package/bin/update-check.js +153 -0
  9. package/implement.md +76 -0
  10. package/install.ps1 +156 -0
  11. package/install.sh +201 -0
  12. package/package.json +68 -0
  13. package/plopfile.js +1358 -0
  14. package/project-docs/AGENTS.md.hbs +12 -0
  15. package/project-docs/PROJECT.md.hbs +128 -0
  16. package/project-docs/implement.hbs +54 -0
  17. package/project-docs/test.hbs +31 -0
  18. package/scripts/install-bin.sh +72 -0
  19. package/scripts/update.sh +11 -0
  20. package/templates/aop/OperationLog.hbs +18 -0
  21. package/templates/aop/OperationLogAspect.hbs +95 -0
  22. package/templates/aop/build-gradle-dep.hbs +1 -0
  23. package/templates/base/Application.hbs +11 -0
  24. package/templates/base/ApplicationTests.java.hbs +11 -0
  25. package/templates/base/BaseService.hbs +15 -0
  26. package/templates/base/BaseServiceImpl.hbs +53 -0
  27. package/templates/base/EntityMapper.hbs +12 -0
  28. package/templates/base/README.md.hbs +56 -0
  29. package/templates/base/Result.hbs +48 -0
  30. package/templates/base/application-test.yml.hbs +27 -0
  31. package/templates/base/application.yml.hbs +18 -0
  32. package/templates/base/bircrc.hbs +14 -0
  33. package/templates/base/build.gradle.hbs +33 -0
  34. package/templates/base/gitignore.hbs +15 -0
  35. package/templates/client/ExternalApiClient.hbs +28 -0
  36. package/templates/client/ExternalApiClientConfig.hbs +26 -0
  37. package/templates/client/ExternalApiProperties.hbs +30 -0
  38. package/templates/client/application-yml-block.hbs +7 -0
  39. package/templates/controller.hbs +55 -0
  40. package/templates/dao.hbs +11 -0
  41. package/templates/docker/Dockerfile.hbs +29 -0
  42. package/templates/docker/docker-compose.prod.yml.hbs +65 -0
  43. package/templates/docker/docker-compose.yml.hbs +52 -0
  44. package/templates/docker/dockerignore.hbs +6 -0
  45. package/templates/docker/env.example.hbs +24 -0
  46. package/templates/dto-request.hbs +19 -0
  47. package/templates/dto-response.hbs +13 -0
  48. package/templates/email/EmailAsyncConfig.hbs +28 -0
  49. package/templates/email/EmailService.hbs +26 -0
  50. package/templates/email/EmailServiceImpl.hbs +49 -0
  51. package/templates/email/application-yml-block.hbs +19 -0
  52. package/templates/email/build-gradle-dep.hbs +2 -0
  53. package/templates/email/sample-template.hbs +16 -0
  54. package/templates/entity.hbs +46 -0
  55. package/templates/exception/ExceptionHandleController.hbs +16 -0
  56. package/templates/exception/NotFoundException.hbs +28 -0
  57. package/templates/exception/ProjectException.hbs +20 -0
  58. package/templates/exception.hbs +30 -0
  59. package/templates/file-upload/EmptyFileException.hbs +25 -0
  60. package/templates/file-upload/FileExtensionIllegalException.hbs +21 -0
  61. package/templates/file-upload/FileExtensionUtils.hbs +20 -0
  62. package/templates/file-upload/FileStorageProperties.hbs +37 -0
  63. package/templates/file-upload/FileStorageService.hbs +15 -0
  64. package/templates/file-upload/FileStorageServiceImpl.hbs +78 -0
  65. package/templates/file-upload/FileTooLargeException.hbs +21 -0
  66. package/templates/file-upload/FileUploadController.hbs +57 -0
  67. package/templates/file-upload/FileUtils.hbs +39 -0
  68. package/templates/file-upload/InvalidStoredFileException.hbs +21 -0
  69. package/templates/file-upload/application-yml-block.hbs +12 -0
  70. package/templates/gitlab-ci/gitlab-ci.hbs +158 -0
  71. package/templates/gradle-wrapper/gradle/wrapper/gradle-wrapper.jar +0 -0
  72. package/templates/gradle-wrapper/gradle/wrapper/gradle-wrapper.properties +8 -0
  73. package/templates/gradle-wrapper/gradlew +248 -0
  74. package/templates/gradle-wrapper/gradlew.bat +93 -0
  75. package/templates/log4j2/build-gradle-dep.hbs +6 -0
  76. package/templates/log4j2/log4j2-spring.xml.hbs +34 -0
  77. package/templates/mapper-gradle-dep.hbs +3 -0
  78. package/templates/mapper.hbs +11 -0
  79. package/templates/migration/add-column.hbs +4 -0
  80. package/templates/migration/create-table.hbs +9 -0
  81. package/templates/migration/custom.hbs +2 -0
  82. package/templates/migration/remove-column.hbs +4 -0
  83. package/templates/migration/seed.hbs +7 -0
  84. package/templates/multi-module/build.gradle.hbs +86 -0
  85. package/templates/multi-module/config/ApplicationConfig.java.hbs +33 -0
  86. package/templates/multi-module/config/Config.java.hbs +19 -0
  87. package/templates/multi-module/config/SecurityConfig.java.hbs +48 -0
  88. package/templates/multi-module/config/build.gradle.hbs +10 -0
  89. package/templates/multi-module/database-config/BaseDAO.java.hbs +31 -0
  90. package/templates/multi-module/database-config/BaseViewDAO.java.hbs +48 -0
  91. package/templates/multi-module/database-config/Config.java.hbs +14 -0
  92. package/templates/multi-module/database-config/JpaConfig.java.hbs +9 -0
  93. package/templates/multi-module/database-config/build.gradle.hbs +17 -0
  94. package/templates/multi-module/settings.gradle.hbs +9 -0
  95. package/templates/oauth/OAuth2LoginSuccessHandler.hbs +31 -0
  96. package/templates/oauth/application-yml-block.hbs +11 -0
  97. package/templates/oauth/build-gradle-dep.hbs +1 -0
  98. package/templates/openapi/OpenApiConfig.hbs +23 -0
  99. package/templates/openapi/build-gradle-dep.hbs +1 -0
  100. package/templates/pagination/GenericSpecification.hbs +76 -0
  101. package/templates/pagination/PageInfo.hbs +20 -0
  102. package/templates/pagination/PageRequest.hbs +27 -0
  103. package/templates/pagination/PageResponse.hbs +24 -0
  104. package/templates/pagination/Pager.hbs +37 -0
  105. package/templates/pagination/SearchCriteria.hbs +26 -0
  106. package/templates/pagination/SpecificationSupport.hbs +34 -0
  107. package/templates/permission/PermissionAspect.hbs +41 -0
  108. package/templates/permission/RequirePermission.hbs +18 -0
  109. package/templates/permission/build-gradle-dep.hbs +2 -0
  110. package/templates/scheduling/SampleSchedule.hbs +22 -0
  111. package/templates/scheduling/SchedulingConfig.hbs +13 -0
  112. package/templates/scheduling/application-yml-block.hbs +5 -0
  113. package/templates/sentry/SentryConfig.hbs +74 -0
  114. package/templates/sentry/application-yml-block.hbs +15 -0
  115. package/templates/sentry/build-gradle-dep.hbs +1 -0
  116. package/templates/service.hbs +9 -0
  117. package/templates/serviceImpl.hbs +23 -0
  118. package/templates/spotless/build-gradle-allprojects.hbs +16 -0
  119. package/templates/spotless/build-gradle-plugin.hbs +1 -0
  120. package/templates/spotless/spotless_formatter.xml +83 -0
  121. package/templates/sso/SsoAutoConfiguration.hbs +17 -0
  122. package/templates/sso/SsoProperties.hbs +27 -0
  123. package/templates/sso/application-yml-block.hbs +7 -0
  124. package/templates/valid-group/ValidGroup.hbs +20 -0
  125. package/test.md +56 -0
  126. package/uninstall.ps1 +60 -0
  127. package/uninstall.sh +76 -0
  128. package/versions.js +10 -0
@@ -0,0 +1,14 @@
1
+ {
2
+ "basePackage": "tw.edu.ntub.birc.activity",
3
+ "projectNameKebab": "campus-activity",
4
+ "multiModule": true,
5
+ "srcPath": "src/main/java",
6
+ "resourcesPath": "src/main/resources",
7
+ "applicationYmlPath": "src/main/resources/application.yml",
8
+ "buildGradlePath": "build.gradle",
9
+ "entityPackage": "tw.edu.ntub.birc.activity.databaseconfig.entity",
10
+ "daoPackage": "tw.edu.ntub.birc.activity.databaseconfig.dao",
11
+ "entityPath": "modules/campus-activity-database-config/src/main/java/tw/edu/ntub/birc/activity/databaseconfig/entity",
12
+ "daoPath": "modules/campus-activity-database-config/src/main/java/tw/edu/ntub/birc/activity/databaseconfig/dao",
13
+ "features": ["docker", "sso"]
14
+ }
package/AGENTS.md ADDED
@@ -0,0 +1,20 @@
1
+ # AGENTS.md
2
+
3
+ 這個 repo 是 BIRC 的 Plop generator,產出 Spring Boot 4 骨架。
4
+ 改這裡是在改「以後生出來的專案長什麼樣子」。
5
+
6
+ ## 文件怎麼用
7
+
8
+ 先讀這份,再只打開這次用得到的那一份。不要四份一起塞進上下文。
9
+
10
+ | 文件 | 何時讀 |
11
+ | --- | --- |
12
+ | [ponytail](https://github.com/DietrichGebert/ponytail/blob/main/skills/ponytail/SKILL.md) | 實作時決定**做多大**:Yagni、現成 `FEATURES`、最短能跑的 diff。這才是 implement 的手感。 |
13
+ | [PROJECT.md](PROJECT.md) | 要動架構、seam、feature、CLI、慣例。規範只活在這裡。 |
14
+ | [implement.md](implement.md) | 計畫已定,要把 ticket 做成 diff。步驟,不是規範。 |
15
+ | [test.md](test.md) | 開始寫或改測試。怎麼圍關鍵路徑、什麼算假綠燈。 |
16
+ | [project-docs/](project-docs/) | 改產出 Spring 專案給 agent 讀的文件。 |
17
+ | [README.md](README.md) | 改安裝、`birc` 指令、create 對 clone 的取捨。 |
18
+
19
+ 產出專案的 agent 文件由 `create`(`injectDocs`)或 `birc docs` 注入,`add` 不注入。
20
+ 給人看的 `README.md` 由 `create` 寫入,跟 `injectDocs` 無關。
package/PROJECT.md ADDED
@@ -0,0 +1,83 @@
1
+ # PROJECT.md
2
+
3
+ 這個 repo 的架構與慣例。改 generator 前先對齊這裡。產出專案的美學寫在 `project-docs/`,不要抄回這份。
4
+
5
+ 改 generator 時一樣夠用就停:能登記 `FEATURES` 就不要新 generator;能接
6
+ anchor 就不要重寫整份設定;推測以後會用到的模組先不要做。
7
+
8
+ ## Seam
9
+
10
+ 改 generator 時先點名 seam,再只動那一層:
11
+
12
+ | 要做的事 | Seam | 誰會吃到 |
13
+ | --- | --- | --- |
14
+ | 新的可選模組 | `FEATURES` + `templates/<key>/` | `create`、`add`(共用 `featureActions`) |
15
+ | `make` / `make:*` 骨架 | `templates/*.hbs` + `makeStackActions` / 單層 actions | `make`(整組)、`make:entity`、`make:model`、`make:mapper`、`make:service`、`make:controller`、`make:exception`、`make:migration` |
16
+ | 注入給產出專案的 agent 文件 | `project-docs/` | `create`(`injectDocs`)、`docs` |
17
+ | create 的基礎骨架 | `templates/base/`、`templates/multi-module/`、`templates/gradle-wrapper/` | `create`(含給人看的 `README.md`) |
18
+ | CLI 進入點 | `bin/birc.js`、`bin/home-install.js`、`install.sh` / `install.ps1` | `birc`(banner、版本、`update`、直接呼叫 node-plop) |
19
+
20
+ 完成條件:能說出這次只動哪一個 seam、哪幾個 generator 會吃到。
21
+
22
+ `create` 跟 `add` 對 feature 走同一條 `featureActions`。一個 feature 在 `FEATURES` 登記一次,兩邊生出同一組檔。
23
+
24
+ 功能清單與每個 feature 生哪些檔,以 `FEATURES` 為單一來源。
25
+ 版本號以根目錄 `versions.js` 為單一來源;template 只吃注入的 `*Version`。
26
+
27
+ `add` 是冪等的:已記在 `.bircrc.json.features` 的項目不再執行;舊專案即使漏記,
28
+ 既有檔與已插入 fragment 也要跳過。成功後才把新 feature 寫回 `.bircrc.json`。
29
+ `add` 會先預檢查 yml / gradle 的 anchor(要插 fragment 的 feature 才查,含 plugin 與 allprojects),失敗就不寫任何檔。
30
+ `birc add --force` 可覆寫已安裝 feature 的 Java / 資源檔,不重貼 yml / gradle。
31
+ `birc sync` 對全部已安裝 feature 做同樣的覆寫。
32
+
33
+ ## 改 feature
34
+
35
+ 1. 在 `FEATURES` 加一個 key:`label`、`files` / `resourceFiles` / `rootFiles`、`ymlBlock`、`gradleDep`、`gradlePlugin`、`gradleAllprojects`。
36
+ 完成條件:key 對得上 `templates/<key>/`;用不到的插入欄位是 `null`,`rootFiles` 只在有 repo 根檔時才出現。
37
+ 2. 補對應的 `.hbs`。Java 用 `{{basePackage}}`;路徑層級跟既有 feature 一樣(`service/`、`config/`、`client/`)。
38
+ 完成條件:`FEATURES` 列出的每個 `templateFile` 都在,dest 落在對的 root(Java → `root`,resources → `resourcesRoot`,repo 根檔 → `projectRoot`)。
39
+ 3. 要寫進 `application.yml` / `build.gradle` 時,做 append fragment,接在 **anchor** 後面:
40
+ - yml:`# birc-generator:config-anchor`
41
+ - gradle 依賴:`// birc-generator:dependency-anchor`(`gradleDep`,在 `dependencies {}`)
42
+ - gradle plugin:`// birc-generator:plugin-anchor`(`gradlePlugin`,在 `plugins {}`)
43
+ - gradle allprojects:`// birc-generator:allprojects-anchor`(`gradleAllprojects`,在 `allprojects {}`)
44
+ 完成條件:產出檔仍留著同一行 anchor,新內容在它後面。yml fragment 若再寫一個 top-level `spring:`,用 `---` 開新 YAML document(SnakeYAML 同一 document 重複 key 是後蓋前,不會 merge)。gradle 依賴 fragment 維持 `dependencies {}` 內的縮排;plugin / allprojects 不要塞進 `dependencies {}`。
45
+ 4. 用 `npx plop create` 與 `npx plop add` 各走一次,再重跑一次 `add`。
46
+ 完成條件:兩邊產出同一組檔與同一段 yml/gradle,anchor 行還在;第二次 `add`
47
+ 不改檔,`.bircrc.json.features` 只有一個同名 key。
48
+
49
+ ## 慣例
50
+
51
+ **make 一次整組。** `make` 串 `makeStackActions`:Entity + DAO + Mapper + DTO + Service + Controller。單層指令共用同一組 actions,不另寫一份。`make:entity` 產出 Entity、`XxxDAO extends BaseDAO`。`make:model` 同 Entity + DAO;`--migration` 生 `create_{table}_table`(表名跟 Entity 的 snake_case 對齊,`Flight` → `flight`),`--seed` 生下一版 `seed_{table}` SQL,`--controller` 生 Controller。`--soft-delete` 在 Entity 加 Hibernate `@SoftDelete(columnName = "deleted_at", strategy = TIMESTAMP)`,migration 加 `deleted_at TIMESTAMP NULL`;`deleteById` 不用改。不做 restore / withTrashed。`make:entity --dto` 與 `make:entity --mapper` 一併生 Mapper 與 Request / Response DTO(同一組檔)。`make:mapper` 連 Request / Response DTO,並把 MapStruct 依賴接到 `build.gradle` 的 dependency-anchor 後面(已有則跳過)。`make:service` 的 `XxxService extends BaseService`,CRUD 在 `BaseServiceImpl`;多出來的業務方法寫在 `XxxService` / `XxxServiceImpl`。指令是 `make:entity`,不是 `make::entity`。預設只生引入與初稿;加 `--example` 才生完整範例(CRUD、欄位、`@Column`)。`--example` 的 Entity 與 `make:migration` 一樣帶 `created_at` / `updated_at`(DB 填,JPA `insertable = false`),不進 CreateRequest。多模組時 Entity / DAO 落在 `databaseconfig`。路徑以 `.bircrc.json` 的 `entityPath` / `daoPath` 為準。
52
+
53
+ **例外走 ProjectException。** 基底是專案內的 `ProjectException`(`getErrorCode` / `getHttpStatus`),不是 starter 的 `BusinessException`。`create` 會生 `ProjectException`、`NotFoundException`、`ExceptionHandleController`、`web/Result`。`make:exception` 生的類別一律 `extends ProjectException`。Controller 回傳專案內 `Result<T>`,不引用 `tw.edu.ntub.birc.starter`。
54
+
55
+ **create 一定有 module。** `create` 固定產出 `config` + `database-config` 子模組,不再問單模組。`.bircrc.json` 的 `multiModule` 一律是 `true`。
56
+
57
+ **thin create。** `create` 產出最小可跑骨架(Application + 子模組 + BaseDAO + EntityMapper + BaseService + ProjectException + Result + Gradle wrapper + 勾選的 feature)。勾 `docker` 時會一併生 `docker-compose.prod.yml`、`.env.example`,並複製成 `.env`。`gitlabCi` 對齊 teaching-platform:Harbor build/push + SSH deploy,帳密走 GitLab CI/CD Variables。
58
+
59
+ **安裝入口。** `npm i -g`、`curl | bash`(`install.sh`)、`irm | iex`(`install.ps1`)三擇一。後兩種都落到 `~/.birc-generator`,shim 由 `bin/home-install.js` 寫。同一台不要混裝。
60
+
61
+ **產出專案的 agent 文件。** 來源是 `project-docs/`:`AGENTS.md`(目錄)、`PROJECT.md`(規範)、`implement.md`(流程)、`test.md`(測試寫法)。`create` 的 `injectDocs` 與 `docs` 會注入這四份。`add` 只加 feature,不注入、也不問。
62
+
63
+ **產出專案給人看的 README。** `create` 一定寫根目錄 `README.md`(啟動、`birc make`、anchor 不要刪),跟有沒有勾 `injectDocs` 無關。`docs` / `add` 不覆寫已有 README。
64
+
65
+ **名稱 helper。** `plopfile.js` 的 `pascalCase` / `camelCase` 只動第一個字母。`make:*` 會先把 `activity` / `user-profile` 收成 `Activity` / `UserProfile` 再進 template。
66
+
67
+ **版本只改一處。** Spring Boot、Flyway、Sentry、MapStruct、Spotless、dependency-management
68
+ plugin 與 starter 版本都在 `versions.js`;`create` / `add` / `make:mapper` 將它們注入 template。
69
+
70
+ **`birc` 的 dest。** `bin/birc.js` 把 plop 的 cwd 釘在這個 repo(找 `plopfile.js` 與 `templates/`),dest 與 `.bircrc.json` 走呼叫者目錄(`BIRC_PROJECT_ROOT` + `--dest`)。`create` / `update` 用目前目錄;目前目錄已有 `.bircrc.json`、或目標資料夾已在,`create` 會先失敗。`birc create --yes` 其餘用預設、不要問。`add` / `make:*` / `migrate` / `docs` 從目前目錄往上找 `.bircrc.json`,檔案落在找到的專案根。`birc add email sentry` 可帶 feature 名(也接受 `file-upload` 這種 kebab);沒帶參數仍互動勾選。打錯功能名會給近似建議。未知旗標會失敗並提示正確名稱。`docs` 用 `.bircrc.json` 的專案名,不再問。`make` 撞到已有檔會提示 `--force`;`--force` 覆寫那組 Java。`--fields` 沒配 `--example` 會提醒,欄位不會寫進 Entity。
71
+
72
+ **`birc update`。** 先 `detectInstallKind`:`npm` 跑 `npm install -g birc-generator@latest`。curl / PowerShell / clone 走 `bin/home-install.js`(不要再把 Windows 暫存路徑丟給 bash)。`~/.birc-generator` 的 kind 是 `home`,跟用 bash 還是 `irm | iex` 裝無關。
73
+
74
+ **多模組 gradle 與 add。** `templates/multi-module/build.gradle.hbs` 要留著三行 gradle
75
+ anchor:`dependencies {}` 的 `// birc-generator:dependency-anchor`、`plugins {}` 的
76
+ `// birc-generator:plugin-anchor`、`allprojects {}` 的
77
+ `// birc-generator:allprojects-anchor`。`add` 的 gradle append 只有 dest 檔裡有對應那一行才插得進去。
78
+
79
+ **`make:migration`。** Laravel 風格名稱:`create_users_table`、`add_votes_to_users_table`、`remove_votes_from_users_table`。檔案落在 `src/main/resources/db/migration/V{n}__{name}.sql`。
80
+
81
+ **`migrate`。** `birc migrate` 在目標專案跑 Gradle wrapper 的 `flywayMigrate`(Unix `./gradlew`,Windows `gradlew.bat`)。`migrate:reset` 是 `flywayClean` + `flywayMigrate`(`--force` 略過確認)。找不到 wrapper 或 spawn 失敗要印錯誤,不要只帶 banner 就結束。Flyway Community **沒有** Laravel 的 rollback;`migrate:rollback` 只說明這件事。undo 要 Flyway Teams 的 `flywayUndo` 加 `U{version}__*.sql`。
82
+
83
+ 產出的註解與注入文件用繁中,跟現有 template 一致。目標專案設定欄位以 `.bircrc.example.json` 與 `templates/base/bircrc.hbs` 為準。
package/README.md ADDED
@@ -0,0 +1,300 @@
1
+ # birc-generator
2
+
3
+ ```
4
+ ██████╗ ██╗██████╗ ██████╗ ██████╗ ███████╗███╗ ██╗███████╗██████╗ █████╗ ████████╗ ██████╗ ██████╗
5
+ ██╔══██╗██║██╔══██╗██╔════╝ ██╔════╝ ██╔════╝████╗ ██║██╔════╝██╔══██╗██╔══██╗╚══██╔══╝██╔═══██╗██╔══██╗
6
+ ██████╔╝██║██████╔╝██║ █████╗ ██║ ███╗█████╗ ██╔██╗ ██║█████╗ ██████╔╝███████║ ██║ ██║ ██║██████╔╝
7
+ ██╔══██╗██║██╔══██╗██║ ╚════╝ ██║ ██║██╔══╝ ██║╚██╗██║██╔══╝ ██╔══██╗██╔══██║ ██║ ██║ ██║██╔══██╗
8
+ ██████╔╝██║██║ ██║╚██████╗ ╚██████╔╝███████╗██║ ╚████║███████╗██║ ██║██║ ██║ ██║ ╚██████╔╝██║ ██║
9
+ ╚═════╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝
10
+ ```
11
+
12
+ BIRC 後端開新專案,常是把舊專案的 Controller 再抄一份。套件名改到一半、
13
+ DAO 繼承寫錯、例外類從 starter 抓來用,之後還要再修。
14
+
15
+ `birc` 把這段收成指令。裝一次之後,開專案用 `birc create`,生一組
16
+ CRUD 用 `birc make`。多模組目錄、`BaseDAO`、`ProjectException` 會先寫好。
17
+
18
+ 完整文件在
19
+ [GitLab wiki](https://gitlab.ntubimdbirc.tw/lucashsu95/birc-generator/-/wikis/home)
20
+ (開始使用、add / make / migrate)。這份 README 只留安裝與第一次用。
21
+
22
+ ## 安裝
23
+
24
+ 需要 Node 18 以上。一般只要裝全域的 `birc`,不必 clone。三種擇一:
25
+ npm、`curl | bash`、PowerShell 的 `irm | iex`。同一台不要混裝,PATH 會搶
26
+ 同一個 `birc`。改產生器、或要跑還沒發到 npm 的 commit,才 clone。
27
+
28
+ `birc update` 會自己判斷來源。npm 裝的等同
29
+ `npm install -g birc-generator@latest`;`curl` / PowerShell 裝的都拉
30
+ GitLab 到 `~/.birc-generator`。
31
+
32
+ ### npm
33
+
34
+ Win11、WSL、macOS、Linux 都可以。
35
+
36
+ ```bash
37
+ npm install -g birc-generator
38
+ ```
39
+
40
+ 裝好後跑 `birc --help`。之後更新、卸載:
41
+
42
+ ```bash
43
+ npm update -g birc-generator
44
+ npm uninstall -g birc-generator
45
+ ```
46
+
47
+ 使用時若偵測到新版本,會問要不要更新。說不要的話,同一版本 24 小時內
48
+ 不會再問。不想檢查就設 `BIRC_SKIP_UPDATE_CHECK=1`。CI 或不是互動終端
49
+ 也不會問。
50
+
51
+ ### curl | bash
52
+
53
+ 給 macOS、Linux、WSL、Git Bash。程式放到 `~/.birc-generator`,並把
54
+ `birc` 寫進使用者自己的 bin。不需要 sudo。PowerShell 不要貼這條:內建
55
+ `curl` 是 `Invoke-WebRequest`,會報找不到參數 `-fsSL`。改用下面的
56
+ PowerShell 安裝。
57
+
58
+ ```bash
59
+ curl -fsSL https://gitlab.ntubimdbirc.tw/lucashsu95/birc-generator/-/raw/main/install.sh | bash
60
+ ```
61
+
62
+ 關掉終端再開一次,跑 `birc --help`。之後更新用 `birc update`。還沒有
63
+ 這個指令的舊安裝,再跑一次上面的 `install.sh`。
64
+
65
+ 解除安裝:
66
+
67
+ ```bash
68
+ curl -fsSL https://gitlab.ntubimdbirc.tw/lucashsu95/birc-generator/-/raw/main/uninstall.sh | bash
69
+ ```
70
+
71
+ ### PowerShell
72
+
73
+ 給 Windows 原生 PowerShell 5.1 或 7。落地目錄跟 `curl | bash` 相同
74
+ (`%USERPROFILE%\.birc-generator`),所以之後的 `birc update` 是同一條路。
75
+ `irm | iex` 在記憶體執行,通常不必改 ExecutionPolicy。
76
+
77
+ ```powershell
78
+ irm https://gitlab.ntubimdbirc.tw/lucashsu95/birc-generator/-/raw/main/install.ps1 | iex
79
+ ```
80
+
81
+ 關掉終端再開一次,跑 `birc --help`。之後更新用 `birc update`。
82
+
83
+ 解除安裝:
84
+
85
+ ```powershell
86
+ irm https://gitlab.ntubimdbirc.tw/lucashsu95/birc-generator/-/raw/main/uninstall.ps1 | iex
87
+ ```
88
+
89
+ ## 第一次用
90
+
91
+ 找一個要放專案的目錄,執行:
92
+
93
+ ```bash
94
+ birc create
95
+ ```
96
+
97
+ 它會問專案名稱、base package(預設跟專案名走,例如 `campus-activity`
98
+ → `tw.edu.ntub.birc.campus.activity`)、要勾哪些功能(常用 / 登入 / 營運),
99
+ 以及要不要寫入
100
+ `AGENTS.md` / `PROJECT.md` / `implement.md` / `test.md`。docker、log4j2、
101
+ ValidGroup、Spotless 預設已勾。`create` 一定是多模組,沒有單模組選項。
102
+
103
+ 做完後會得到同名資料夾,裡面有:
104
+
105
+ - 根目錄的 `Application`、`build.gradle`、`application.yml`、`.bircrc.json`
106
+ - 給人看的 `README.md`(啟動、`birc make`、anchor;與 `injectDocs` 無關)
107
+ - `src/test/java/.../ApplicationTests.java` 與 H2 測試設定
108
+ - Gradle wrapper(`gradlew`、`gradle/wrapper/`)
109
+ - `modules/<專案名>-config`
110
+ - `modules/<專案名>-database-config`(`BaseDAO`、之後的 Entity / DAO 在這裡)
111
+
112
+ 產出的專案是 Spring Boot 4.0.5、Java 21。勾了 docker 的話,會順便把
113
+ `.env.example` 複製成 `.env`。指令結束後會印啟動、生骨架、打包的下一步。
114
+
115
+ 進到這個資料夾(有 `.bircrc.json` 的那一層)。先啟動資料庫,再把 `.env`
116
+ 載入目前的 shell,最後跑 Spring Boot。
117
+
118
+ Bash / Git Bash / WSL:
119
+
120
+ ```bash
121
+ cd campus-activity
122
+ docker compose up -d db
123
+ set -a && source .env && set +a
124
+ ./gradlew bootRun
125
+ ```
126
+
127
+ PowerShell:
128
+
129
+ ```powershell
130
+ cd campus-activity
131
+ docker compose up -d db
132
+ Get-Content .env | ForEach-Object {
133
+ if ($_ -match '^\s*([^#][^=]*)=(.*)$') {
134
+ Set-Item -Path "Env:$($matches[1].Trim())" -Value $matches[2].Trim().Trim('"')
135
+ }
136
+ }
137
+ .\gradlew.bat bootRun
138
+ ```
139
+
140
+ 再生一組骨架:
141
+
142
+ ```bash
143
+ birc make
144
+ ```
145
+
146
+ 輸入 `Activity` 或 `activity`,會一次寫出 Entity、DAO、Mapper、DTO、
147
+ Service、Controller。小寫會自動收成 PascalCase。只要其中一層,改跑
148
+ `birc make:entity` 或 `birc make:controller`。預設是初稿,完整範例加
149
+ `--example`。欄位可寫 `--fields title:String,startTime:LocalDateTime`,
150
+ 就不會再問一次(要配 `--example`,否則只會提醒、欄位不會寫進 Entity)。
151
+ 檔已存在時會停下來;要覆寫加 `--force`。
152
+
153
+ 腳本或課堂示範可 `birc create Practice --yes`,其餘用預設(docker、log4j2、
154
+ ValidGroup、Spotless、注入 agent 文件),不再問。
155
+
156
+ `create` 與 `update` 可以在任何目錄跑。其餘指令會從目前目錄往上找
157
+ `.bircrc.json`,不必先 `cd` 回專案根。目前目錄已經是 BIRC 專案、或同名
158
+ 資料夾已在,`create` 會停下來。不認得的 `--` 選項會失敗並提示接近的名稱。
159
+
160
+ ## 指令
161
+
162
+ | 指令 | 做什麼 |
163
+ | --- | --- |
164
+ | `birc create` | 開一個多模組 Spring Boot 4 專案。`--yes` 其餘用預設、不要問 |
165
+ | `birc update` | 更新本機 `birc`。npm 裝的跑 `npm install -g`;curl / PowerShell / clone 拉 GitLab `main` |
166
+ | `birc add` | 往既有專案加模組。沒帶名稱會互動勾選;`birc add email sentry` 直接加。`--force` 覆寫已選的已安裝 feature 檔 |
167
+ | `birc sync` | 用目前 template 覆寫全部已安裝 feature 的檔(不動 yml / gradle) |
168
+ | `birc make` | 一次生 Entity + DAO + Mapper + DTO + Service + Controller |
169
+ | `birc make:entity` | Entity、`XxxDAO`;加 `--dto`、`--mapper`、`--soft-delete`。已有檔要覆寫加 `--force` |
170
+ | `birc make:model` | 同 `make:entity`;加 `--migration` / `--seed` / `--controller` / `--soft-delete` |
171
+ | `birc make:mapper` | Mapper 和 CreateRequest / Response |
172
+ | `birc make:service` | `XxxService extends BaseService`,CRUD 在 `BaseServiceImpl` |
173
+ | `birc make:controller` | Controller |
174
+ | `birc make:exception` | 繼承 `ProjectException` 的例外類 |
175
+ | `birc make:migration` | Flyway SQL(`create_users_table`、`add_votes_to_users_table`) |
176
+ | `birc docs` | 補 `AGENTS.md` / `PROJECT.md` / `implement.md` / `test.md`(專案名從 `.bircrc.json` 讀) |
177
+ | `birc migrate` | 在專案裡跑 Gradle wrapper 的 `flywayMigrate`(Unix `./gradlew`,Windows `gradlew.bat`) |
178
+ | `birc migrate:rollback` | Flyway Community 做不到 rollback,指令會說明替代作法 |
179
+ | `birc migrate:reset` | `flywayClean` 後再 `flywayMigrate`(`--force` 略過確認) |
180
+
181
+ ```bash
182
+ birc create Practice --yes
183
+ birc make:entity User --dto
184
+ birc make:entity User --mapper
185
+ birc make:entity User --example
186
+ birc make:entity User --example --fields title:String,startTime:LocalDateTime
187
+ birc make:entity User --force
188
+ birc make:model Flight --migration
189
+ birc make:model Flight --seed
190
+ birc make:model Flight --controller
191
+ birc make:model Flight --soft-delete
192
+ birc make:model Flight --migration --soft-delete
193
+ birc make:migration create_users_table
194
+ birc add
195
+ birc add email
196
+ birc add email sentry
197
+ birc add file-upload
198
+ birc add --force
199
+ birc sync
200
+ birc migrate
201
+ ```
202
+
203
+ 指令是 `make:entity`,中間一條冒號,跟 Laravel artisan 一樣。
204
+ `birc add` 沒帶名稱時會問你要加哪些模組;也可以寫 `birc add docker` 或 `birc add file-upload`。
205
+ `make:migration add_votes_to_users_table` 裡的 `add_votes_...` 只是 SQL 檔名。
206
+
207
+ 各指令的細節見 wiki:[make](https://gitlab.ntubimdbirc.tw/lucashsu95/birc-generator/-/wikis/基礎/make)、
208
+ [add](https://gitlab.ntubimdbirc.tw/lucashsu95/birc-generator/-/wikis/基礎/add)、
209
+ [migrate](https://gitlab.ntubimdbirc.tw/lucashsu95/birc-generator/-/wikis/基礎/migrate)。
210
+
211
+ ## 建立專案時可以勾的功能
212
+
213
+ 勾了就會寫進專案裡。之後也能用 `birc add` 再補。完整對照見
214
+ [功能模組](https://gitlab.ntubimdbirc.tw/lucashsu95/birc-generator/-/wikis/開發人員/功能模組)。
215
+
216
+ | 畫面上的名稱 | 會多出什麼 |
217
+ | --- | --- |
218
+ | Docker | `Dockerfile`、`docker-compose.yml`、`docker-compose.prod.yml`、`.env.example`(建立時預設勾選,並複製成 `.env`) |
219
+ | Email | JavaMailSender、Thymeleaf 範本、`EmailService` |
220
+ | SSO | 校內單一登入(`SsoProperties` + `SsoAutoConfiguration` 原始碼,無外部依賴) |
221
+ | OAuth2 登入 | OAuth2 登入(範例接 Google) |
222
+ | 排程 | `@EnableScheduling` 和一個範例 Job |
223
+ | AOP 事件記錄 | `@OperationLog` 和對應的 Aspect |
224
+ | Client | 呼叫外部 API 的 RestClient 封裝 |
225
+ | Sentry | 錯誤追蹤設定與客戶端例外過濾 |
226
+ | Log4j2 | 取代預設 Logback,加入主控台、rolling file 與 MDC 格式(建立時預設勾選) |
227
+ | OpenAPI | springdoc、Swagger UI 與 Bearer JWT security scheme |
228
+ | 檔案上傳 | 本機磁碟上傳、`util/file` 檢查、上傳例外、`FileUploadController` |
229
+ | 分頁查詢 | `PageRequest` / `PageResponse`、`Pager`、`GenericSpecification` |
230
+ | 驗證群組 | `ValidGroup`(Create / Update / Delete / Submit),給 `@Validated` 與欄位 `groups`(建立時預設勾選) |
231
+ | 權限控管 | Spring Security 和 `@RequirePermission` |
232
+ | .gitlab-ci.yml | Harbor build/push 與 SSH deploy(對齊 teaching-platform;帳密放 GitLab CI/CD Variables) |
233
+ | Spotless | 根目錄 `spotless_formatter.xml`、Eclipse 4.31、`./gradlew spotlessApply`(建立時預設勾選) |
234
+
235
+ `birc add` 會在 `application.yml` 的 `# birc-generator:config-anchor`
236
+ 後面插入設定,在 `build.gradle` 的
237
+ `// birc-generator:dependency-anchor` 後面插入依賴,plugin 接
238
+ `// birc-generator:plugin-anchor`,`allprojects` 接
239
+ `// birc-generator:allprojects-anchor`。這幾行不要刪;缺了
240
+ `add` 會先失敗、不寫任何檔。已加入的模組會記在 `.bircrc.json.features`;
241
+ 再次執行 `add` 時會顯示為已安裝,不會重複生檔或插入設定。template 改了要
242
+ 覆寫已安裝模組的 Java / 資源檔時,用 `birc add --force` 或 `birc sync`
243
+ (全部已安裝),不會重貼 yml / gradle。
244
+
245
+ ## 生出來的程式長什麼樣
246
+
247
+ 多模組的切法是:API 在根專案,共用設定在 `*-config`,Entity / DAO 在
248
+ `*-database-config`。
249
+
250
+ DAO 繼承專案裡的 `BaseDAO`。查不到資料時丟 `NotFoundException`,它繼承
251
+ 專案自己的 `ProjectException` 與 `web.Result`,不是 starter 的 `BusinessException` / `Result`。
252
+ Mapper 用 MapStruct。Controller 只轉 DTO,業務寫在 Service。
253
+
254
+ 這些慣例跟 BIRC 現在在跑的後端專案一樣。產出專案給 agent 讀的目錄在
255
+ `AGENTS.md`,規範在 `PROJECT.md`。產生器自己先讀 [AGENTS.md](./AGENTS.md)。
256
+
257
+ ## 這包不會做的事
258
+
259
+ `make` 給的是 CRUD 骨架,查詢條件和權限要自己補。`create` 只出多模組,
260
+ 沒有單模組選項。K8s 不會一併產生。勾 `.gitlab-ci.yml` 時會帶 Harbor /
261
+ SSH 部署骨架,帳密仍放 GitLab CI/CD Variables,不要寫進 repo。
262
+
263
+ Flyway Community 沒有 Laravel 的 rollback。`birc migrate:rollback` 只會
264
+ 說明替代作法:再寫一筆往前的遷移。`birc migrate` 會真的跑 Gradle wrapper 的 `flywayMigrate`,不是只印指令。
265
+
266
+ ## 改這個產生器
267
+
268
+ 原始碼在 GitLab。npm 上的套件是同一份程式的發佈入口,改完要兩邊一起走。
269
+
270
+ clone 下來之後,在 repo 裡跑才會吃到你改的 template:
271
+
272
+ ```bash
273
+ git clone https://gitlab.ntubimdbirc.tw/lucashsu95/birc-generator.git
274
+ cd birc-generator
275
+ npm install
276
+ node bin/birc.js --help
277
+ npm test
278
+ npm run test:coverage
279
+ npm run test:mutation
280
+ ```
281
+
282
+ 改 template 或 `plopfile.js` 之前,先讀 [AGENTS.md](./AGENTS.md) 的目錄,
283
+ 規範在 [PROJECT.md](./PROJECT.md)。wiki 的
284
+ [改產生器](https://gitlab.ntubimdbirc.tw/lucashsu95/birc-generator/-/wikis/開發人員/改產生器)
285
+ 是給人看的精簡版。
286
+
287
+ 發版順序:先把改動推進 GitLab `main`,再改 `package.json` 的 `version`,
288
+ 最後 `npm publish`。只推 GitLab、不 publish 的話,`npm install -g` 的人
289
+ 拿不到新版;只 publish、不合進 `main` 的話,`curl | bash` /
290
+ `irm | iex` / `birc update` 會跟 npm 版本對不上。
291
+
292
+ ## 接下來
293
+
294
+ 裝好之後可以照這個順序走一次。
295
+
296
+ 1. 跑 `birc create` 開一個專案。
297
+ 2. `cd` 進專案,`docker compose up -d db`,載入 `.env` 後跑 Spring Boot
298
+ (Bash / PowerShell 寫法見上面「第一次用」)。
299
+ 3. 跑 `birc make` 生第一個實體。
300
+ 4. 打包用 `./gradlew build -x test`(Windows 用 `.\gradlew.bat`)。