# @goodgo/contracts-events Cross-runtime (Node + Python) event contracts for RFC-004's async messaging backbone. See [GOO-95](/GOO/issues/GOO-95) for the RFC and [GOO-172](/GOO/issues/GOO-172) for Phase 0. ## What lives here - `src/envelope.ts` — `EventEnvelope` TypeScript type + `EVENT_ENVELOPE_SCHEMA_VERSION`. - `src/uuid-v7.ts` — pure-Node UUIDv7 generator (no runtime deps). - `src/event-types.ts` — string-literal union of all known event types. - `schemas/envelope.schema.json` — JSON Schema for the envelope itself. - `schemas/.schema.json` — JSON Schema for each event payload. The `schemas/` directory is consumed by the Python AI services (`libs/ai-services`) via `redis-py` consumers — JSON Schema is the single source of truth across runtimes. ## Envelope shape ```ts interface EventEnvelope { schemaVersion: number; // bump when envelope itself changes eventId: string; // UUIDv7 — time-ordered, idempotency key eventType: string; // dotted: "payment.completed" occurredAt: string; // ISO-8601 UTC producer: string; // service name, e.g. "api" traceId: string; // OpenTelemetry-compatible (32 hex chars or "00…") payload: TPayload; // event-specific, validated by per-type schema } ``` `schemaVersion` starts at `1`. Bump only when the **envelope** changes; payload changes are versioned per event-type schema independently. ## First 3 schemas (Phase 0 deliverable) | Event type | Trigger | |----------------------|--------------------------------------------------| | `payment.completed` | Payment moves to `succeeded` after gateway IPN | | `listing.approved` | Moderation approves a listing | | `kyc.verified` | KYC review marks a user verified | Phase 1 (notifications cutover, [GOO-173](/GOO/issues/GOO-173)) will add the rest of the production event surface. ## Adding a new event type 1. Pick a stable dotted name (`.`). 2. Add a `schemas/.schema.json` JSON Schema describing the payload. 3. Add the literal to `src/event-types.ts`. 4. (Optional) Re-export a typed payload alias from `src/index.ts`. 5. Land + dual-publish for at least one sprint before any consumer hard-fails on it.