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

3.3 KiB

name, description
name description
add-rpc 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-gatewayproto/ha/v1/*.proto (packages: entity, light, switch, event, common)
    • ai-gatewayproto/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:

    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:

    cd <service> && go vet ./... && go test ./...
    

Layering rule to enforce

Dependencies point inward only: adaptersappcore. 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.