diff --git a/agents.md b/agents.md new file mode 100644 index 0000000..54451e2 --- /dev/null +++ b/agents.md @@ -0,0 +1,67 @@ +# go-redis-inventory — agents map + +Redis-backed **inventory + reservation** service. Tracks stock levels and +runs atomic reservation operations via Lua scripts; also consumes an +`inventory_changed` pub/sub channel to mirror upstream changes. + +## Where to start + +- `README.md` — start here, it has the high-level intent. +- `pkg/inventory/types.go` — all the data structures (`InventoryItem`, + `InventoryReference`, `CartReserveRequest`, …). +- `pkg/inventory/redis_service.go` — basic get / batch get / reserve path + + the Lua scripts (`reserveScript`, `reservationCheck`). +- `pkg/inventory/redis_reservation_service.go` — cart-shaped reservations + with release/availability semantics + corresponding `_test.go`. +- `pkg/inventory/listener.go` — `InventoryChangeListener` on the + `inventory_changed` pub/sub channel. +- `pkg/inventory/adapter.go` — `ReservationPolicyAdapter` bridging to + `platform/inventory.ReservationPolicy`. + +## Architecture + +- **Two responsibilities, one process**: (1) hold and serve inventory state; + (2) mirror upstream changes via pub/sub. +- **Atomicity**: reservation idempotency and TTL semantics come from Lua + scripts embedded here. The scripts are the seam — if they change, the + test in `redis_reservation_service_test.go` is the contract. +- **Adapter**: the `ReservationPolicyAdapter` is the seam to + `platform/inventory`. Two adapters (this service and any other downstream + caller) is what makes it a real seam, not a hypothetical one. + +## Important files by area + +| Area | File | +| ----------------------------- | --------------------------------------------------- | +| Domain model | `pkg/inventory/types.go` | +| Core service | `pkg/inventory/redis_service.go` | +| Reservation service (cart) | `pkg/inventory/redis_reservation_service.go` | +| Pub/sub listener | `pkg/inventory/listener.go` | +| Platform adapter | `pkg/inventory/adapter.go` | +| Reservation tests | `pkg/inventory/redis_reservation_service_test.go` | + +## Cross-project seams + +- **`platform/inventory`**: implements `ReservationPolicy` via the adapter. +- **`go-cart-actor`**: consumes reservations through that adapter. +- **Redis pub/sub**: receives `inventory_changed` events. + +## Improvement suggestions + +- **`types.go` carries mixed concerns** — `InventoryItem` (storage) sits + next to `CartReserveRequest` (request). Split into `types/` + (storage-level) and `types/cart.go` (request) so callers can depend on + only the slice they need. +- **Two reservation services**: `redis_service.go` has its own reserve, + `redis_reservation_service.go` has another, plus a `Level` type + (`level.go`). The relationship between them isn't documented; an + architecture paragraph at the top of the package would help + (`doc.go` or `pkg/inventory/README.md`). +- **`listener.go` is single-channel** — it consumes only `inventory_changed`. + If more channels need the same lifecycle (reconnect, dedupe, back-off), + factor out a tiny `pubsub.Consumer` and let the listener wrap it. +- **Lua scripts live inside Go source.** Promote them to `.lua` files, + registered via `//go:embed` — that makes them version-controlled and + testable independently of the Go code. +- **No config validation.** A malformed `REDIS_URL`/`CHANNEL` boots and + fails at first call. Fail fast in `main.go` with explicit error messages.