Nik Afiq 5c08e69bcb
All checks were successful
CI / test (push) Successful in 58s
CI / build-ai-gateway (push) Successful in 3m25s
CI / build-ha-gateway (push) Successful in 45s
CI / build-discord-bot (push) Successful in 40s
feat: add new skills and reviewers for architecture checks, README drift, and security audits
2026-07-22 23:28:50 +09:00

69 lines
3.3 KiB
Markdown

---
name: add-rpc
description: Scaffold a new gRPC RPC end-to-end (proto, buf generate, hexagonal ports/app/adapter layers, tests, README) following this repo's established pattern across ha-gateway, ai-gateway, and discord-bot.
---
# Add a gRPC RPC
Use this whenever a new RPC or field is being added to `ha-gateway`, `ai-gateway`, or a new
gRPC client call is being added to `discord-bot`. All three services share the same
hexagonal layering, so follow this order — do not skip layers or reach across them.
## Steps
1. **Identify the target service and proto package.**
- `ha-gateway``proto/ha/v1/*.proto` (packages: `entity`, `light`, `switch`, `event`, `common`)
- `ai-gateway``proto/ai/v1/ai.proto`
- `discord-bot` has no proto of its own; it only consumes `ha.v1` / `ai.v1` clients.
2. **Edit the `.proto` file** under `proto/<pkg>/v1/`. Add the message/RPC there first —
it is the source of truth; `gen/` is derived from it.
3. **Regenerate generated code:**
```bash
buf generate
```
This writes into `gen/<pkg>/v1/`. Never hand-edit files under `gen/`.
4. **Extend the port interface** in `internal/core/ports/`:
- `ports/driving/*.go` — the interface the gRPC adapter calls *into* (app-facing, inbound).
- `ports/driven/*.go` — the interface the app calls *out* to (HA REST, Ollama, ha-gateway
client, etc.), if the new RPC needs a new external call.
- `core/domain/*.go` — add/extend domain types here, not in adapter or proto types.
5. **Implement orchestration in `internal/app/`.** This is where business logic and
validation live — it depends only on `core/domain` and `core/ports`, never on
`adapters/*` types directly. Look at an existing file (e.g. `ha-gateway/internal/app/light.go`)
for the shape: a struct holding driven-port dependencies, constructed via `NewXApp(...)`.
6. **Wire the primary adapter** in `internal/adapters/primary/grpc/<feature>.go`. Implement
the generated server interface method, translate between proto types and domain types
(see `mapping.go` in ha-gateway for the existing translation pattern), and call the app
layer. Keep proto <-> domain conversion here, not in `app`.
7. **If the RPC needs a new outbound call**, implement it in the relevant
`internal/adapters/secondary/<name>/client.go`, implementing the `driven` port interface
from step 4.
8. **Add a test** using the repo's convention: plain `testing` package (no testify), with a
hand-written mock struct that implements the driven port interface using function fields
(see `ha-gateway/internal/app/entity_test.go` or `ai-gateway/internal/app/query_test.go`
for the pattern). Table-driven `t.Run` subtests are the norm.
9. **Update the service's `README.md`:**
- Move the RPC between "Implemented" and "Stubbed" in the gRPC API section if its status
changed.
- Add any new environment variables to the Configuration table (and to `.env.example`).
- Add any new package to the Package Map section if you created one.
10. **Verify:**
```bash
cd <service> && go vet ./... && go test ./...
```
## Layering rule to enforce
Dependencies point inward only: `adapters` → `app` → `core`. Never import
`internal/adapters/*` from `internal/app` or `internal/core`. Only `cmd/<entrypoint>/main.go`
is allowed to import across all layers to wire dependencies together.