From 40776b78e237185905f4fdba183638061ef8652f Mon Sep 17 00:00:00 2001 From: Rogee Date: Wed, 24 Dec 2025 11:02:05 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E8=B7=AF=E7=94=B1?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E6=A0=BC=E5=BC=8F=EF=BC=8C=E5=A2=9E=E5=BC=BA?= =?UTF-8?q?=E8=B7=AF=E7=94=B1=E4=B8=80=E8=87=B4=E6=80=A7=E5=92=8C=E5=8F=AF?= =?UTF-8?q?=E8=AF=BB=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 35 ++++++++++++++++++++++++++++ backend/app/http/super/order.go | 4 ++-- backend/app/http/super/routes.gen.go | 32 ++++++++++++------------- backend/app/http/super/tenant.go | 6 ++--- backend/app/http/super/user.go | 6 ++--- 5 files changed, 59 insertions(+), 24 deletions(-) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..7121789 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,35 @@ +# Repository Guidelines + +## Project Structure & Module Organization + +- `backend/`: Go API server (Fiber) + services + DB models/migrations. + - `backend/app/http/`: HTTP modules (e.g. `super/`, `tenant/`, `tenant_public/`). + - `backend/app/services/`: business logic; prefer GORM-Gen queries (`backend/database/models/*`). + - `backend/database/migrations/`: SQL migrations. + - `backend/docs/`: generated Swagger (`swagger.json/yaml`, `docs.go`). +- `frontend/`: + - `frontend/superadmin/`: platform super admin UI (Vite + Vue 3 + PrimeVue). + - `frontend/admin/`, `frontend/user/`: tenant admin/user apps. +- `specs/`: source-of-truth specs (e.g. DB schema). + +## Coding Style & Naming Conventions + +- **Backend rule of law**: all backend development MUST follow `backend/llm.txt` (HTTP/module layout, generated-file rules, GORM-Gen usage, transactions, comments, and route conventions). +- Go: run `gofmt` on changed files; keep HTTP handlers thin (bind → `services.*` → return). +- HTTP module directories are `snake_case`; path params are `camelCase` and prefer typed IDs like `:orderID` to avoid route conflicts. +- Avoid editing generated files (e.g. `backend/app/http/**/routes.gen.go`, `backend/docs/docs.go`); regenerate via `atomctl` instead. + +## Testing Guidelines + +- Go tests: `go test ./...` (some service tests exist under `backend/app/services/*_test.go`). +- Frontend: build + lint are the main checks (`npm -C frontend/superadmin run build && npm -C frontend/superadmin run lint`). + +## Commit & Pull Request Guidelines + +- Commits generally follow a simple convention like `feat: ...` / `fix: ...` / `chore: ...` (keep subject short and imperative). +- PRs: describe behavior change, list impacted APIs/pages, and include screenshots for UI changes (especially `frontend/superadmin/`). + +## Security & Configuration Tips + +- Configure API base via `VITE_API_BASE_URL` (superadmin). +- Keep secrets out of git; prefer local `backend/config.toml` overrides for DB/JWT settings. diff --git a/backend/app/http/super/order.go b/backend/app/http/super/order.go index 8982646..40f117b 100644 --- a/backend/app/http/super/order.go +++ b/backend/app/http/super/order.go @@ -41,7 +41,7 @@ func (*order) list(ctx fiber.Ctx, filter *dto.OrderPageFilter) (*requests.Pager, // @Param orderID path int64 true "OrderID" // @Success 200 {object} dto.SuperOrderDetail // -// @Router /super/v1/orders/:orderID [get] +// @Router /super/v1/orders/:orderID [get] // @Bind orderID path func (*order) detail(ctx fiber.Ctx, orderID int64) (*dto.SuperOrderDetail, error) { return services.Order.SuperOrderDetail(ctx, orderID) @@ -58,7 +58,7 @@ func (*order) detail(ctx fiber.Ctx, orderID int64) (*dto.SuperOrderDetail, error // @Param form body dto.SuperOrderRefundForm true "Form" // @Success 200 {object} models.Order // -// @Router /super/v1/orders/:orderID/refund [post] +// @Router /super/v1/orders/:orderID/refund [post] // @Bind orderID path // @Bind form body func (*order) refund(ctx fiber.Ctx, orderID int64, form *dto.SuperOrderRefundForm) (*models.Order, error) { diff --git a/backend/app/http/super/routes.gen.go b/backend/app/http/super/routes.gen.go index 08e0e5c..6ee4c36 100644 --- a/backend/app/http/super/routes.gen.go +++ b/backend/app/http/super/routes.gen.go @@ -61,8 +61,8 @@ func (r *Routes) Register(router fiber.Router) { r.order.list, Query[dto.OrderPageFilter]("filter"), )) - r.log.Debugf("Registering route: Get /super/v1/orders/:orderID -> order.detail") - router.Get("/super/v1/orders/:orderID"[len(r.Path()):], DataFunc1( + r.log.Debugf("Registering route: Get /super/v1/orders/:orderID -> order.detail") + router.Get("/super/v1/orders/:orderID"[len(r.Path()):], DataFunc1( r.order.detail, PathParam[int64]("orderID"), )) @@ -70,8 +70,8 @@ func (r *Routes) Register(router fiber.Router) { router.Get("/super/v1/orders/statistics"[len(r.Path()):], DataFunc0( r.order.statistics, )) - r.log.Debugf("Registering route: Post /super/v1/orders/:orderID/refund -> order.refund") - router.Post("/super/v1/orders/:orderID/refund"[len(r.Path()):], DataFunc2( + r.log.Debugf("Registering route: Post /super/v1/orders/:orderID/refund -> order.refund") + router.Post("/super/v1/orders/:orderID/refund"[len(r.Path()):], DataFunc2( r.order.refund, PathParam[int64]("orderID"), Body[dto.SuperOrderRefundForm]("form"), @@ -82,8 +82,8 @@ func (r *Routes) Register(router fiber.Router) { r.tenant.list, Query[dto.TenantFilter]("filter"), )) - r.log.Debugf("Registering route: Get /super/v1/tenants/:tenantID/users -> tenant.users") - router.Get("/super/v1/tenants/:tenantID/users"[len(r.Path()):], DataFunc2( + r.log.Debugf("Registering route: Get /super/v1/tenants/:tenantID/users -> tenant.users") + router.Get("/super/v1/tenants/:tenantID/users"[len(r.Path()):], DataFunc2( r.tenant.users, PathParam[int64]("tenantID"), Query[tenantdto.AdminTenantUserListFilter]("filter"), @@ -92,14 +92,14 @@ func (r *Routes) Register(router fiber.Router) { router.Get("/super/v1/tenants/statuses"[len(r.Path()):], DataFunc0( r.tenant.statusList, )) - r.log.Debugf("Registering route: Patch /super/v1/tenants/:tenantID -> tenant.updateExpire") - router.Patch("/super/v1/tenants/:tenantID"[len(r.Path()):], Func2( + r.log.Debugf("Registering route: Patch /super/v1/tenants/:tenantID -> tenant.updateExpire") + router.Patch("/super/v1/tenants/:tenantID"[len(r.Path()):], Func2( r.tenant.updateExpire, PathParam[int64]("tenantID"), Body[dto.TenantExpireUpdateForm]("form"), )) - r.log.Debugf("Registering route: Patch /super/v1/tenants/:tenantID/status -> tenant.updateStatus") - router.Patch("/super/v1/tenants/:tenantID/status"[len(r.Path()):], Func2( + r.log.Debugf("Registering route: Patch /super/v1/tenants/:tenantID/status -> tenant.updateStatus") + router.Patch("/super/v1/tenants/:tenantID/status"[len(r.Path()):], Func2( r.tenant.updateStatus, PathParam[int64]("tenantID"), Body[dto.TenantStatusUpdateForm]("form"), @@ -115,8 +115,8 @@ func (r *Routes) Register(router fiber.Router) { r.user.list, Query[dto.UserPageFilter]("filter"), )) - r.log.Debugf("Registering route: Get /super/v1/users/:userID/tenants -> user.tenants") - router.Get("/super/v1/users/:userID/tenants"[len(r.Path()):], DataFunc2( + r.log.Debugf("Registering route: Get /super/v1/users/:userID/tenants -> user.tenants") + router.Get("/super/v1/users/:userID/tenants"[len(r.Path()):], DataFunc2( r.user.tenants, PathParam[int64]("userID"), Query[dto.UserTenantPageFilter]("filter"), @@ -129,14 +129,14 @@ func (r *Routes) Register(router fiber.Router) { router.Get("/super/v1/users/statuses"[len(r.Path()):], DataFunc0( r.user.statusList, )) - r.log.Debugf("Registering route: Patch /super/v1/users/:userID/roles -> user.updateRoles") - router.Patch("/super/v1/users/:userID/roles"[len(r.Path()):], Func2( + r.log.Debugf("Registering route: Patch /super/v1/users/:userID/roles -> user.updateRoles") + router.Patch("/super/v1/users/:userID/roles"[len(r.Path()):], Func2( r.user.updateRoles, PathParam[int64]("userID"), Body[dto.UserRolesUpdateForm]("form"), )) - r.log.Debugf("Registering route: Patch /super/v1/users/:userID/status -> user.updateStatus") - router.Patch("/super/v1/users/:userID/status"[len(r.Path()):], Func2( + r.log.Debugf("Registering route: Patch /super/v1/users/:userID/status -> user.updateStatus") + router.Patch("/super/v1/users/:userID/status"[len(r.Path()):], Func2( r.user.updateStatus, PathParam[int64]("userID"), Body[dto.UserStatusUpdateForm]("form"), diff --git a/backend/app/http/super/tenant.go b/backend/app/http/super/tenant.go index fde1b0e..44a9bae 100644 --- a/backend/app/http/super/tenant.go +++ b/backend/app/http/super/tenant.go @@ -55,7 +55,7 @@ func (*tenant) create(ctx fiber.Ctx, form *dto.TenantCreateForm) (*models.Tenant // @Param filter query tenantdto.AdminTenantUserListFilter true "Filter" // @Success 200 {object} requests.Pager{items=dto.SuperTenantUserItem} // -// @Router /super/v1/tenants/:tenantID/users [get] +// @Router /super/v1/tenants/:tenantID/users [get] // @Bind tenantID path // @Bind filter query func (*tenant) users(ctx fiber.Ctx, tenantID int64, filter *tenantdto.AdminTenantUserListFilter) (*requests.Pager, error) { @@ -71,7 +71,7 @@ func (*tenant) users(ctx fiber.Ctx, tenantID int64, filter *tenantdto.AdminTenan // @Param tenantID path int64 true "TenantID" // @Param form body dto.TenantExpireUpdateForm true "Form" // -// @Router /super/v1/tenants/:tenantID [patch] +// @Router /super/v1/tenants/:tenantID [patch] // @Bind tenantID path // @Bind form body func (*tenant) updateExpire(ctx fiber.Ctx, tenantID int64, form *dto.TenantExpireUpdateForm) error { @@ -92,7 +92,7 @@ func (*tenant) updateExpire(ctx fiber.Ctx, tenantID int64, form *dto.TenantExpir // @Param tenantID path int64 true "TenantID" // @Param form body dto.TenantStatusUpdateForm true "Form" // -// @Router /super/v1/tenants/:tenantID/status [patch] +// @Router /super/v1/tenants/:tenantID/status [patch] // @Bind tenantID path // @Bind form body func (*tenant) updateStatus(ctx fiber.Ctx, tenantID int64, form *dto.TenantStatusUpdateForm) error { diff --git a/backend/app/http/super/user.go b/backend/app/http/super/user.go index 6a38bd4..573f60a 100644 --- a/backend/app/http/super/user.go +++ b/backend/app/http/super/user.go @@ -38,7 +38,7 @@ func (*user) list(ctx fiber.Ctx, filter *dto.UserPageFilter) (*requests.Pager, e // @Param filter query dto.UserTenantPageFilter true "Filter" // @Success 200 {object} requests.Pager{items=dto.UserTenantItem} // -// @Router /super/v1/users/:userID/tenants [get] +// @Router /super/v1/users/:userID/tenants [get] // @Bind userID path // @Bind filter query func (*user) tenants(ctx fiber.Ctx, userID int64, filter *dto.UserTenantPageFilter) (*requests.Pager, error) { @@ -54,7 +54,7 @@ func (*user) tenants(ctx fiber.Ctx, userID int64, filter *dto.UserTenantPageFilt // @Param userID path int64 true "UserID" // @Param form body dto.UserStatusUpdateForm true "Form" // -// @Router /super/v1/users/:userID/status [patch] +// @Router /super/v1/users/:userID/status [patch] // @Bind userID path // @Bind form body func (*user) updateStatus(ctx fiber.Ctx, userID int64, form *dto.UserStatusUpdateForm) error { @@ -70,7 +70,7 @@ func (*user) updateStatus(ctx fiber.Ctx, userID int64, form *dto.UserStatusUpdat // @Param userID path int64 true "UserID" // @Param form body dto.UserRolesUpdateForm true "Form" // -// @Router /super/v1/users/:userID/roles [patch] +// @Router /super/v1/users/:userID/roles [patch] // @Bind userID path // @Bind form body func (*user) updateRoles(ctx fiber.Ctx, userID int64, form *dto.UserRolesUpdateForm) error {