优化结构
This commit is contained in:
@@ -6,19 +6,22 @@ agents must follow when changing the template.
|
||||
## Project structure
|
||||
|
||||
```
|
||||
api/<domain>/<version>/ Proto sources and generated stubs. Public contract.
|
||||
cmd/<app>/ Entrypoint, Wire injector, main.go.
|
||||
cmd/ Entrypoint, Wire injector, main.go.
|
||||
configs/ Runtime config (config.yaml). No secrets.
|
||||
internal/config/ Viper config models, loading, snapshots, and reloads.
|
||||
internal/global/ Process-wide shared resource registry.
|
||||
internal/server/ HTTP/gRPC server wiring.
|
||||
internal/service/ Transport adapters; one file per resource.
|
||||
internal/server/ Gin handlers, middleware, routers, static files, HTTP wiring.
|
||||
internal/service/dto/ Hand-written request and response DTOs.
|
||||
internal/service/ DTO/DO transport adapters; organized by domain.
|
||||
internal/biz/ Domain models, usecases, repo interfaces, errors.
|
||||
internal/data/ Repo implementations, database clients, migrations.
|
||||
internal/initialize/ First-install and configuration orchestration.
|
||||
internal/integration/ External I/O adapters: cache, email, payment, storage.
|
||||
internal/logging/ Application logging infrastructure.
|
||||
internal/modules/ Built-in module schema, seed, menu, API, and task contributions.
|
||||
internal/routecatalog/ HTTP route metadata and runtime policies.
|
||||
internal/worker/ Timed-task runtime and scheduler.
|
||||
internal/utils/ Stateless, internal-only helper packages.
|
||||
pkg/ Reusable infrastructure packages.
|
||||
web/ Vue administration frontend.
|
||||
```
|
||||
|
||||
## Layering & dependency rules
|
||||
@@ -32,7 +35,7 @@ owns the PO; `service` is a pass-through that converts at its boundary.
|
||||
│ declares │ implements
|
||||
└─── repo IF ────┘
|
||||
|
||||
DTO Data Transfer Object — proto request / response.
|
||||
DTO Data Transfer Object — hand-written HTTP request / response.
|
||||
DO Domain Object — pure biz model, no proto, no storage tags.
|
||||
PO Persistent Object — storage shape, owned by `data`.
|
||||
```
|
||||
@@ -43,9 +46,9 @@ owns the PO; `service` is a pass-through that converts at its boundary.
|
||||
| biz | DO | DO | DTO, PO, storage client |
|
||||
| data | PO | DO ↔ PO | DTO |
|
||||
|
||||
- `service` imports `api/...` (DTO) and `biz` (DO). Never `data`.
|
||||
- `biz` imports `api/...` only for error reason enums. Never `service`,
|
||||
never `data`. The repo interface declared here is the inversion seam.
|
||||
- `service` imports `internal/service/dto` (DTO) and `biz` (DO). Never `data`.
|
||||
- `biz` never imports `service` or `data`. The repo interface declared here
|
||||
is the inversion seam.
|
||||
- `data` imports `biz` to implement the repo interface. Never `service`,
|
||||
never DTOs.
|
||||
- `integration` implements external I/O boundaries and may import `biz` and
|
||||
@@ -61,15 +64,10 @@ design rather than add the import.
|
||||
|
||||
**service (DTO ↔ DO)**
|
||||
|
||||
- `convert<Resource>` parses an incoming proto into a DO. The reverse
|
||||
direction is built inline at the return site; the reply type is
|
||||
whatever the proto declares — usually the resource itself
|
||||
(`return &v1.<Resource>{...}, nil`), sometimes a list wrapper
|
||||
(`*v1.<Resources>Set`), or `&emptypb.Empty{}` for deletes. Inlining
|
||||
keeps each handler self-contained.
|
||||
- Embed `Unimplemented<Resource>ServiceServer`.
|
||||
- Parse AIP list requests via `filtering` / `ordering` / `pagination`;
|
||||
apply `fieldmask.Update` for partial updates.
|
||||
- Convert hand-written HTTP DTOs into DOs at the service boundary and build
|
||||
response DTOs from returned DOs.
|
||||
- Keep handlers focused on binding, authentication context, response envelopes,
|
||||
and transport-specific limits.
|
||||
- Validate request inputs at the service boundary before delegating to the
|
||||
usecase.
|
||||
- Return `biz` errors. No business rules, no storage access, no PO.
|
||||
@@ -78,8 +76,8 @@ design rather than add the import.
|
||||
|
||||
- Owns the DO (`type <Resource> struct` — no proto, no storage tags),
|
||||
the usecase, and the repo interface (`type <Resource>Repo interface`).
|
||||
- Owns typed errors built with `errors.NotFound` / `errors.BadRequest`
|
||||
plus the API error reason enum.
|
||||
- Owns typed errors built with `errors.NotFound` / `errors.BadRequest` and
|
||||
stable reason strings.
|
||||
- Owns `ListOption` helpers — `ListFilter`, `ListOrderBy`, `ListOffset`,
|
||||
`ListLimit` — so callers compose queries without leaking storage
|
||||
primitives.
|
||||
@@ -103,23 +101,23 @@ design rather than add the import.
|
||||
|
||||
**server**
|
||||
|
||||
- Construct HTTP/gRPC servers, apply middleware, register services. No
|
||||
translation, no business logic.
|
||||
- Construct the Gin engine and Kratos HTTP server, apply middleware, register
|
||||
handlers and routes. No persistence access or business rules.
|
||||
|
||||
### Add-a-resource checklist
|
||||
|
||||
1. **DTO**: define `Create<Resource>` / `Get<Resource>` /
|
||||
`List<Resources>` / `Update<Resource>` / `Delete<Resource>` in
|
||||
`api/<domain>/<version>/`, then `make api`.
|
||||
1. **DTO**: define request and response types in `internal/service/dto/`.
|
||||
2. **DO + repo interface**: declare both in `biz`; build the usecase on
|
||||
top of the interface.
|
||||
3. **Repo impl**: implement in `data` returning `biz.<Resource>Repo`;
|
||||
add a PO and the matching conversion helpers when storage shape
|
||||
diverges from DO.
|
||||
4. **Wiring**: register the repo constructor in `data.ProviderSet`, the
|
||||
usecase in `biz.ProviderSet`, the service in `service.ProviderSet`;
|
||||
register HTTP/gRPC services in `internal/server`.
|
||||
5. **Regenerate**: `make all` to refresh Wire and `go.mod`.
|
||||
4. **Transport**: add the service adapter, handler, router registration, and
|
||||
routecatalog metadata.
|
||||
5. **Wiring**: register the repo constructor in `data.ProviderSet`, the
|
||||
usecase in `biz.ProviderSet`, and the service/handler providers in their sets.
|
||||
6. **Regenerate**: run `make generate` or `make all` to refresh Wire and
|
||||
`go.mod`.
|
||||
|
||||
### Testing seam
|
||||
|
||||
@@ -129,8 +127,7 @@ tests exercise repo implementations at the storage boundary.
|
||||
|
||||
## Generation & generated files
|
||||
|
||||
Regenerate via `make api` or `make all`; never hand-edit
|
||||
`*.pb.go`, `*_grpc.pb.go`, `*_http.pb.go`, or `wire_gen.go`.
|
||||
Regenerate via `make generate` or `make all`; never hand-edit `wire_gen.go`.
|
||||
|
||||
## Naming & error reasons
|
||||
|
||||
@@ -140,8 +137,8 @@ Regenerate via `make api` or `make all`; never hand-edit
|
||||
`<Resource>Service`. PO types live inside `internal/data/`; pick a
|
||||
name that fits the storage driver and convert with
|
||||
`new<Resource>(do)` / `toBiz(po)` free functions.
|
||||
- Error reasons: declared in `api/<domain>/<version>/error_reason.proto`,
|
||||
surfaced as `Err<Resource><Cause>` in `biz`.
|
||||
- Error reasons use stable strings and are surfaced as
|
||||
`Err<Resource><Cause>` in `biz`.
|
||||
|
||||
## Commits & security
|
||||
|
||||
|
||||
Reference in New Issue
Block a user