Initial Commit
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
# OpenSpec Change: enterprise-schema-registry
|
||||
|
||||
- **Change ID**: enterprise-schema-registry
|
||||
- **Package**: `@suaveplan/schema-registry`
|
||||
- **Category**: universal
|
||||
- **Target path**: `universal/validation/schema-registry`
|
||||
- **Status**: PROPOSED
|
||||
- **Date**: 2026-04-19
|
||||
- **Reference spec**: `/mnt/s/web/suaveplan/enterprise/schema-registry.md`
|
||||
|
||||
## Summary
|
||||
|
||||
Greenfield rebuild of `@suaveplan/schema-registry` — Kafka-/Confluent-style schema registry. Stores versioned schemas per subject, runs backward/forward/full compatibility checks, emits structured diffs, and exposes pluggable stores (in-memory + database adapter). Used by event-sourcing, api contracts, and future `utils` package.
|
||||
|
||||
## Current-state audit (genesis)
|
||||
|
||||
Package does not exist yet — fresh build.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Workspace: `@suaveplan/error`, `@suaveplan/types`
|
||||
- External (via catalog): `zod`, `tslib`, `@opentelemetry/api`
|
||||
- Dev (via catalog): `vitest`, `@vitest/coverage-istanbul`, `fast-check`, `mitata`
|
||||
|
||||
## Preserved public surface
|
||||
|
||||
### Registry
|
||||
|
||||
- `SchemaRegistry`, `createSchemaRegistry`, `SchemaRegistryConfig`
|
||||
- `createSchemaIncompatibleError`, `SchemaCompatibilityError`
|
||||
|
||||
### Versioning / store
|
||||
|
||||
- `createSchemaVersion`, `MemorySchemaStore`, `DatabaseSchemaStore`, `resolveCompatibility`
|
||||
|
||||
### Compatibility
|
||||
|
||||
- `checkCompatibility`, `checkTransitiveCompatibility`
|
||||
- `buildTransitiveReport`, `checkTransitiveAgainstAll`, `isTransitiveMode`, `stripTransitive`, `TransitiveReport`, `TransitiveVersionResult`
|
||||
|
||||
### Diff
|
||||
|
||||
- `diffSchemas`, `formatDiffReport`
|
||||
|
||||
### Utils / constants
|
||||
|
||||
- `canonicalizeSchema`, `computeFingerprint`, `djb2Hash`, `flattenFields`, `isOptionalOrHasDefault`
|
||||
- `DEFAULT_COMPATIBILITY`, `DEFAULT_MAX_VERSIONS`
|
||||
|
||||
### Types / error codes
|
||||
|
||||
`CompatibilityMode`, `CompatibilityResult`, `DatabaseAdapter`, `DiffChangeType`, `LookupOptions`, `RegisterOptions`, `SchemaDefinition`, `SchemaDiffChange`, `SchemaDiffResult`, `SchemaField`, `SchemaStoreAdapter`, `SchemaType`, `SchemaVersion`, `SubjectConfig`, `SchemaRegistryErrorCode`, `registerSchemaRegistryErrorCodes`, `SCHEMA_REGISTRY_ERROR_METADATA`.
|
||||
|
||||
## New genesis additions
|
||||
|
||||
- Codes via `defineCodes`: `SCHEMA_REGISTRY.SUBJECT_NOT_FOUND`, `SCHEMA_REGISTRY.VERSION_NOT_FOUND`, `SCHEMA_REGISTRY.INCOMPATIBLE`, `SCHEMA_REGISTRY.STORE_ERROR`, `SCHEMA_REGISTRY.INVALID_SCHEMA`.
|
||||
- OTel counters `schema_registry.register.total`, `schema_registry.incompatible.total`; histogram `schema_registry.compatibility.duration_ms`.
|
||||
- Property tests: registering the same canonicalised schema twice returns the same version; compatibility transitivity across N versions.
|
||||
|
||||
## Impact
|
||||
|
||||
- Adds one new package: `universal/validation/schema-registry`
|
||||
- Adds one new spec capability: `schema-registry`
|
||||
- Unblocks `utils` (which currently depends on schema-registry on main).
|
||||
@@ -0,0 +1,41 @@
|
||||
# Capability Spec: schema-registry
|
||||
|
||||
**Package**: `@suaveplan/schema-registry`
|
||||
**Version**: 0.0.0 (genesis)
|
||||
**Status**: ADDED
|
||||
|
||||
---
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### SR-01 — Subject + version model
|
||||
|
||||
A subject MUST carry `SubjectConfig` and a sequence of `SchemaVersion { id, subject, version, schema, fingerprint, createdAt }`. `version` MUST be monotonic starting at `1`. `fingerprint` MUST be stable over canonicalised schema output.
|
||||
|
||||
### SR-02 — Canonicalisation
|
||||
|
||||
`canonicalizeSchema(schema)` MUST produce a deterministic, lexically sorted representation such that semantically identical schemas yield identical canonical output. `computeFingerprint(schema)` MUST hash the canonical form. `djb2Hash` MUST be a reference 32-bit DJB2 implementation.
|
||||
|
||||
### SR-03 — Compatibility modes
|
||||
|
||||
`CompatibilityMode` MUST include `'none' | 'backward' | 'backward-transitive' | 'forward' | 'forward-transitive' | 'full' | 'full-transitive'`. `checkCompatibility(current, candidate, mode)` MUST return `CompatibilityResult { compatible, violations }`. `checkTransitiveCompatibility(history, candidate, mode)` MUST evaluate against every prior version per the transitive mode.
|
||||
|
||||
### SR-04 — Register contract
|
||||
|
||||
`SchemaRegistry.register(subject, schema, options?)` MUST canonicalise, compute a fingerprint, look up an existing version by fingerprint, and reuse it if found. Otherwise it MUST check compatibility against the latest (or full history if transitive) and either persist a new version or throw `SchemaCompatibilityError` with code `SCHEMA_REGISTRY.INCOMPATIBLE`.
|
||||
|
||||
### SR-05 — Lookup
|
||||
|
||||
`get(subject, version?)` MUST return the latest version when `version` is omitted. `getByFingerprint(subject, fingerprint)` MUST be supported. Unknown subject MUST throw `SCHEMA_REGISTRY.SUBJECT_NOT_FOUND`; unknown version MUST throw `SCHEMA_REGISTRY.VERSION_NOT_FOUND`.
|
||||
|
||||
### SR-06 — Store contract
|
||||
|
||||
`SchemaStoreAdapter` MUST provide `list`, `put`, `get`, `getLatest`, `delete`. `MemorySchemaStore` MUST implement it synchronously; `DatabaseSchemaStore` MUST accept a `DatabaseAdapter` for durable storage. Both MUST pass the same contract test suite.
|
||||
|
||||
### SR-07 — Diff
|
||||
|
||||
`diffSchemas(prev, next)` MUST return `SchemaDiffResult` listing `SchemaDiffChange` entries (`added | removed | modified | type-changed | optionality-changed`). `formatDiffReport` MUST produce a human-readable Markdown summary.
|
||||
|
||||
### SR-08 — Observability
|
||||
|
||||
Every register / compatibility / diff call MUST record its corresponding OTel metric; incompatible registrations MUST increment `schema_registry.incompatible.total{subject, mode}`.
|
||||
@@ -0,0 +1,44 @@
|
||||
# Tasks: enterprise-schema-registry
|
||||
|
||||
## 1. Scaffold
|
||||
|
||||
- [x] 1.1 `universal/validation/schema-registry/`; 100/100/100/100; guard tests; CLAUDE/README/FOLDERS.
|
||||
|
||||
## 2. Errors + schemas
|
||||
|
||||
- [x] 2.1 `src/error-codes.ts` — `defineCodes` for `SCHEMA_REGISTRY.*`, metadata export, side-effect auto-register.
|
||||
- [x] 2.2 Zod schemas for `SchemaDefinition`, `SchemaField`, `SubjectConfig`, `SchemaVersion`, `CompatibilityResult`.
|
||||
|
||||
## 3. Utils + constants
|
||||
|
||||
- [x] 3.1 `src/constants/index.ts` — `DEFAULT_COMPATIBILITY`, `DEFAULT_MAX_VERSIONS`.
|
||||
- [x] 3.2 `src/utils/utils.ts` — `canonicalizeSchema`, `computeFingerprint`, `djb2Hash`, `flattenFields`, `isOptionalOrHasDefault`.
|
||||
|
||||
## 4. Diff
|
||||
|
||||
- [x] 4.1 `src/diff/schema-differ.ts` — `diffSchemas`, `formatDiffReport`.
|
||||
|
||||
## 5. Compatibility
|
||||
|
||||
- [x] 5.1 `src/compatibility/compatibility.ts` — `checkCompatibility`, `checkTransitiveCompatibility`.
|
||||
- [x] 5.2 `src/compatibility/transitive-checker.ts` — `buildTransitiveReport`, `checkTransitiveAgainstAll`, `isTransitiveMode`, `stripTransitive`.
|
||||
|
||||
## 6. Versioning + stores
|
||||
|
||||
- [x] 6.1 `src/core/versioning/versioning.ts` — `createSchemaVersion`, `MemorySchemaStore`, `resolveCompatibility`.
|
||||
- [x] 6.2 `src/store/database-store.ts` — `DatabaseSchemaStore` + `DatabaseAdapter` contract.
|
||||
|
||||
## 7. Registry
|
||||
|
||||
- [x] 7.1 `src/core/registry/registry.ts` — `SchemaRegistry`, `createSchemaRegistry`, `SchemaCompatibilityError`, `createSchemaIncompatibleError`.
|
||||
- [x] 7.2 OTel instrumentation.
|
||||
|
||||
## 8. Docs / barrel / subpath exports / README
|
||||
|
||||
## 9. Benchmarks
|
||||
|
||||
- [x] 9.1 Register / compatibility / diff on 1 000-version history.
|
||||
|
||||
## 10. Ship gate
|
||||
|
||||
- [x] 10.1 Verification sequence; fold + archive.
|
||||
Reference in New Issue
Block a user