forked from alterminal/alterminal
重組前檢查點:根目錄 main package
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
# 重組 alterminal:根目錄 main 拆分為 cmd/ + internal/ 套件
|
||||
|
||||
採「精簡 ~6 包」方案,進入點移至 `cmd/alterminal/`。模組路徑 `alterminal` 不變,所有新套件在 `internal/` 下。
|
||||
|
||||
## 目標結構
|
||||
|
||||
```
|
||||
alterminal/
|
||||
├── cmd/alterminal/main.go # 新:進入點(chi 路由裝配、/health、CLI 分派)
|
||||
├── internal/
|
||||
│ ├── auth/ # 認證領域 + 所有非管理頁 HTTP
|
||||
│ │ ├── user.go + user_test.go # User、Role、argon2id(原 user.go)
|
||||
│ │ ├── session.go # Session、CookieName、Create/Get/Delete
|
||||
│ │ ├── login.go + login_test.go # POST /login(JSON+表單)
|
||||
│ │ ├── loginpage.go + loginpage_test.go # 模板 embed、CSRF、GET /login、GET /
|
||||
│ │ ├── logout.go + logout_test.go # POST /logout
|
||||
│ │ ├── static.go + static_test.go # /static/(embed assets)
|
||||
│ │ ├── notfound.go + notfound_test.go # 自訂 404
|
||||
│ │ ├── dbtest_test.go # 新:auth 專用測試 DB helper(見下)
|
||||
│ │ ├── templates/ # 原 templates/ 整批搬入
|
||||
│ │ └── assets/ # 原 assets/ 整批搬入
|
||||
│ ├── application/
|
||||
│ │ └── application.go + application_test.go # Application(RP 註冊)模型
|
||||
│ ├── store/
|
||||
│ │ └── db.go # Open(openDB)、EnvOr(envOr)、AutoMigrate
|
||||
│ ├── admin/
|
||||
│ │ ├── adminkeys.go + adminkeys_test.go
|
||||
│ │ └── adminapplications.go + adminapplications_test.go # requireAdmin 兩檔同包,維持私有
|
||||
│ ├── cli/
|
||||
│ │ ├── createaccount.go + createaccount_test.go
|
||||
│ │ └── updatepassword.go + updatepassword_test.go
|
||||
│ ├── testdb/
|
||||
│ │ └── testdb.go # 新:New(t)(原 adminkeys_test.go 的 newTestDB)
|
||||
│ └── jwk/ # 不動
|
||||
├── go.mod / go.sum / README.md / tools/
|
||||
```
|
||||
|
||||
依賴方向(無循環):`auth`(僡 stdlib + x/crypto)← `application`(密碼雜湊、Token)← `store`(AutoMigrate)← `cli`/`testdb`;`admin` → `auth` + `application` + `jwk`;`cmd` → 全部。
|
||||
|
||||
## 識別字重新命名(跨套件需要者才 export)
|
||||
|
||||
**auth 對外**:`hashPassword`→`HashPassword`、`verifyPassword`→`VerifyPassword`(application 需要)、`newRandomToken`→`NewToken`(application 需要)、`sessionCookieName`→`CookieName`、`createSession/getSession/deleteSession`→`CreateSession/GetSession/DeleteSession`(admin 測試與 handler 需要)、`renderHTML`→`RenderHTML`、`newCSRFToken/verifyCSRF`→`NewCSRFToken/VerifyCSRF`、`csrfCookieName`→`CSRFCookieName`、模板單例 `adminKeysTmpl/adminApplicationsTmpl/adminApplicationNewTmpl`→`AdminKeysTmpl/AdminApplicationsTmpl/AdminApplicationNewTmpl`(admin 套件渲染用;全部模板仍集中 embed 於 auth,layout.html 共用不拆)、handler 工廠 `LoginPageHandler/AccountPageHandler/LoginHandler/LogoutHandler/StaticHandler/NotFoundHandler`。
|
||||
|
||||
**auth 維持私有**:`authenticateUser`、`dummyPasswordHash`、`ErrInvalidCredentials`、`writeJSON/writeError`(login+logout 同包;未來 OIDC 需要時再提升)、`renderAccountPage/renderLoginPage/renderLoggedInPage`、cookie 設定/清除、`loginTmpl/loggedInTmpl/notFoundTmpl`、`csrfTTL/sessionTTL`、argon2 常數。
|
||||
|
||||
**application**:`getApplicationByClientID`→`GetByClientID`(原註解即標明供未來 /authorize、/token 使用),其餘已 exported 不動。
|
||||
|
||||
**store**:`openDB`→`Open`、`envOr`→`EnvOr`。**admin**:八個 handler 維持原名但改 exported(如 `KeysPageHandler`、`ApplicationsCreateHandler`),`requireAdmin` 私有。**cli**:`runCommand`→`Run(args []string)`,其餘私有。**testdb**:`New(t *testing.T) *gorm.DB`(行為同原 newTestDB:連不上 PG 則 t.Skipf)。
|
||||
|
||||
## Import cycle 處理(關鍵)
|
||||
|
||||
`auth` 的整合測試**不可**匯入 `store`/`testdb`(它們會匯入 auth 模型做 AutoMigrate,形成測試循環)。因此在 auth 套件內新增 `dbtest_test.go`:自建測試 DB 連線,只 migrate + truncate `users`、`sessions` 兩表(login/logout/loginpage 整合測試只需要這兩張);admin 與 application 的測試用 `testdb.New(t)`(完整四表)。
|
||||
|
||||
## 其他配合調整
|
||||
|
||||
1. **go:embed**:`//go:embed templates/*.html`、`//go:embed assets` 語法不變(embed 為套件目錄相對),`templates/`、`assets/` 實體搬入 `internal/auth/`;模板內 `/static/css/main.css` URL 不受影響。
|
||||
2. **Tailwind**:建置指令改為 `tools/tailwindcss -i internal/auth/assets/css/input.css -o internal/auth/assets/css/main.css --minify`,實際執行一次驗證 v4 自動掃描仍涵蓋新模板路徑(比對輸出與現況)。
|
||||
3. **README.md**:重寫「專案結構(目標)」為實際新結構;`go run .`→`go run ./cmd/alterminal`、`go build -o alterminal .`→`go build -o alterminal ./cmd/alterminal`、CLI 範例、模板路徑說明同步更新。
|
||||
4. **main.go**:原 `/users/{name}` demo 路由與 `/health` 內聯 handler 原樣搬入 `cmd/alterminal/main.go`。
|
||||
5. 根目錄既有編譯產物 `alterminal` binary 不動(下次 build 覆蓋)。
|
||||
|
||||
## 實施步驟
|
||||
|
||||
0. (可選,建議)目前不是 git repo:先 `git init` + initial commit 做檢查點,方便事後 diff 與回退。**若你不要此步,請在核准時註明刪除。**
|
||||
1. `mkdir` + `mv` 搬移檔案與 templates/、assets/;根目錄只留 go.mod、go.sum、README.md、.gitignore、.zcodeignore、tools/、(可選 git init)。
|
||||
2. 逐套件改 package 宣告、匯入路徑(`alterminal/internal/...`)與上表識別字重新命名;搬移 `newTestDB`→testdb、新增 auth 的 dbtest_test.go。
|
||||
3. `gofmt -l .`、`go vet ./...`、`go build ./...`。
|
||||
4. `go test ./...`(本機 PostgreSQL 有起就會跑整合測試,否則按原設計 skip)。
|
||||
5. Tailwind 重建驗證 + smoke test:`go run ./cmd/alterminal` 起服務,curl `/health`、`/login`(應回 HTML 登入頁)、`/static/css/main.css`。
|
||||
6. 更新 README;更新記憶檔 alterminal-progress.md(結構重組完成、下一步 OIDC 不變)。
|
||||
|
||||
行為完全不變:路由、模板、Cookie 名稱、CSRF 機制、CLI 介面、環境變數都照舊,純粹移動 + 重新命名。
|
||||
@@ -0,0 +1,40 @@
|
||||
# 實作 `create-account` CLI 子指令
|
||||
|
||||
## 背景
|
||||
|
||||
alterminal(Go + chi + GORM + PostgreSQL 的 OIDC 服務)目前 `User` 模型(user.go)與 argon2id 密碼雜湊已完成,但沒有任何建立帳號的入口。要在二進位檔加入 CLI 子指令:`./alterminal create-account ...`,不帶參數時行為不變(啟動 HTTP 伺服器)。
|
||||
|
||||
## 指令介面
|
||||
|
||||
```
|
||||
alterminal create-account -username alice -email alice@example.com [-name "Alice"] [-email-verified] [-password secret]
|
||||
```
|
||||
|
||||
- `-username`(必填):登入帳號,限制 `^[A-Za-z0-9._-]+$`、長度 ≤ 64
|
||||
- `-email`(必填):以 `net/mail.ParseAddress` 驗證格式,長度 ≤ 255
|
||||
- `-name`(選填):顯示名稱,長度 ≤ 255
|
||||
- `-email-verified`(選填,預設 false):設定 OIDC `email_verified` claim
|
||||
- `-password`(選填):密碼,最小長度 8(OWASP 建議)。**省略時以互動式無回顯提示輸入兩次**(用 `golang.org/x/term.ReadPassword`),兩次不一致則報錯;非終端機環境(管線)未提供旗標時直接報錯提示改用 `-password`
|
||||
|
||||
## 檔案變更
|
||||
|
||||
1. **新增依賴**:`go get golang.org/x/term`(與既有 x/crypto 同屬 golang.org/x)
|
||||
2. **main.go**:在 `main()` 開頭加入子指令分派——`len(os.Args) > 1` 時交給 `runCommand(os.Args[1:])`,否則照常啟動伺服器;伺服器部分程式碼不動
|
||||
3. **新增 `createaccount.go`**(沿用根目錄、`package main` 的現有風格):
|
||||
- `runCommand`:分派子指令;僅有 `create-account`,未知子指令印用法後離開
|
||||
- `runCreateAccount(args)`:
|
||||
1. `flag.NewFlagSet("create-account", flag.ExitOnError)` 解析旗標,欄位 `strings.TrimSpace`
|
||||
2. `validateAccountInput` 驗證 username/email/name(可單元測試的純函式)
|
||||
3. `resolvePassword`:旗標優先,否則互動輸入兩次
|
||||
4. 重用 `openDB()`(含 AutoMigrate,確保資料表存在)
|
||||
5. 建立 `User` 並呼叫現有的 `SetPassword`(argon2id)
|
||||
6. 重複檢查:先以查詢提供友善錯誤(帳號已存在 / Email 已存在),`db.Create` 再以 `gorm.ErrDuplicatedRows` 兜底(並發保護)
|
||||
7. 成功輸出 `帳號建立成功:id=1 username=alice email=alice@example.com`(不印密碼);失敗經 `log.Fatal("create-account: ", err)` 離開(與現有 main 錯誤風格一致)
|
||||
- 使用者面向訊息採繁體中文(與 README、程式註解一致)
|
||||
4. **新增 `createaccount_test.go`**:仿照 `user_test.go` 的 table-driven 純邏輯測試——`validateAccountInput` 各種非法輸入、密碼長度檢查(不含需要 DB 或 TTY 的部分,專案目前無 DB 測試基礎設施)
|
||||
5. **README.md**:在「快速開始」加入「建立使用者帳號」小節(指令、旗標、互動輸入說明);Roadmap 的「使用者系統」僅完成一環,維持未勾選
|
||||
|
||||
## 驗證
|
||||
|
||||
- `go build ./...`、`go vet ./...`、`go test ./...`
|
||||
- 煙霧測試:若本機 PostgreSQL 有啟動,執行 `go run . create-account -username smoke -email smoke@example.com -password testpass1`,確認成功輸出、重複執行收到「已存在」錯誤、`CheckPassword` 可驗證;無 DB 時以單元測試與建置結果為準
|
||||
Reference in New Issue
Block a user