# Repository Guidelines

This is a Kratos service template. This file owns the layering contract
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.
configs/                  Runtime config (config.yaml). No secrets.
internal/conf/            Config proto; generated by `make config`.
internal/server/          HTTP/gRPC server wiring.
internal/service/         Transport adapters; one file per resource.
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/security/        Security mechanisms such as admin JWT handling.
internal/utils/           Stateless, internal-only helper packages.
```

## Layering & dependency rules

Three model shapes flow through three layers. `biz` owns the DO, `data`
owns the PO; `service` is a pass-through that converts at its boundary.

```
   client ──► DTO ──► service ──► DO ──► biz ──► DO ──► data ──► PO ──► storage
                                  ▲                ▲
                                  │ declares       │ implements
                                  └─── repo IF ────┘

   DTO  Data Transfer Object — proto request / response.
   DO   Domain Object        — pure biz model, no proto, no storage tags.
   PO   Persistent Object    — storage shape, owned by `data`.
```

| Layer   | Owns | Speaks at boundary | Never speaks            |
|---------|------|--------------------|-------------------------|
| service | —    | DTO ↔ DO          | PO, storage client      |
| 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.
- `data` imports `biz` to implement the repo interface. Never `service`,
  never DTOs.
- `integration` implements external I/O boundaries and may import `biz` and
  provider SDKs. It is not a utility layer.
- `utils` contains stateless helpers only. It must not own clients, watchers,
  repositories, runtime configuration, or provider SDK lifecycles.
- `cmd` is the only place that wires all layers via Wire.

A change crossing these arrows the wrong way is a layering bug; fix the
design rather than add the import.

### Layer responsibilities

**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.
- Validate request inputs at the service boundary before delegating to the
  usecase.
- Return `biz` errors. No business rules, no storage access, no PO.

**biz (DO only)**

- 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 `ListOption` helpers — `ListFilter`, `ListOrderBy`, `ListOffset`,
  `ListLimit` — so callers compose queries without leaking storage
  primitives.

**data (DO ↔ PO)**

- _Repo shape_: implement `biz.<Resource>Repo`. The constructor returns
  the interface, never the concrete type:
  `func New<Resource>Repo(d *Data) biz.<Resource>Repo`.
- _PO and conversion_: define a PO when the storage shape diverges from
  the DO. PO types stay inside `data`. Use free functions
  `new<Resource>` (DO → PO, write) and `toBiz` (PO → DO, read).
  Driver-specific builder types never leave `data`.
- _Shared clients_: `*Data` (declared in `internal/data/data.go`) holds
  long-lived storage clients. Repos receive `*Data` and never construct
  their own clients.
- _Querying_: translate `ListOptions.Filter` and `ListOptions.OrderBy`
  into the storage driver's query language inside the repo.
- _Errors_: map driver errors to `biz` typed errors so callers above
  never branch on the driver.

**server**

- Construct HTTP/gRPC servers, apply middleware, register services. No
  translation, no business logic.

### Add-a-resource checklist

1. **DTO**: define `Create<Resource>` / `Get<Resource>` /
   `List<Resources>` / `Update<Resource>` / `Delete<Resource>` in
   `api/<domain>/<version>/`, then `make api`.
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`.

### Testing seam

Tests live beside the code they cover (`*_test.go`). Test layers in
isolation: service tests fake the usecase, biz tests fake the repo, data
tests exercise repo implementations at the storage boundary.

## Generation & generated files

Regenerate via `make api`, `make config`, or `make all`; never hand-edit
`*.pb.go`, `*_grpc.pb.go`, `*_http.pb.go`, or `wire_gen.go`.

## Naming & error reasons

- Resource: `<Resource>` (e.g., `Todo`); collection RPC:
  `List<Resources>`.
- Types: repo `<Resource>Repo`, usecase `<Resource>Usecase`, service
  `<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`.

## Commits & security

- Conventional Commits: `feat:`, `fix:`, `refactor:`, `chore(deps):`,
  `docs:`, `test:`. Regenerated files belong in the same commit as
  their source.
- Never commit real credentials in `configs/config.yaml`.
