Files
2026-05-27 23:29:53 +01:00

3.7 KiB

OpenSpec Change: enterprise-server-seed

  • Change ID: enterprise-server-seed
  • Package: @suaveplan/seed
  • Category: server/infra
  • Target path: server/infra/seed
  • Status: PROPOSED
  • Date: 2026-04-24
  • Reference spec: /mnt/s/web/suaveplan/enterprise/seed.md

Summary

Deliver @suaveplan/seed on the genesis branch from scratch at enterprise quality. The package provides a database seeding and fixture framework for development, testing, and demo environments. It exposes a SeedRunner with declarative SeedDefinition entries (each with name, run, optional dependsOn, condition, and teardown), ordered execution based on dependency graph, idempotent re-run via onConflict: 'skip' | 'update' | 'error', and a SeedContext injected into each handler carrying a DatabaseAdapter (from @suaveplan/db), logger, and factory helpers. Genesis adds Zod schemas, @suaveplan/error codes, OTel spans per seed step, and full integration tests against @suaveplan/db-sqlite.


Current-state audit (genesis)

Does not exist on genesis — fresh build.


Available workspace deps on genesis

Package Role
@suaveplan/error (workspace:^) Typed SEED.* error codes
@suaveplan/types (workspace:^) DatabaseLike, LoggerLike
@suaveplan/db (workspace:^) DatabaseAdapter interface
@suaveplan/logger (workspace:^) Structured logs
zod (catalog:forms) Options and definition schemas
@opentelemetry/api (catalog:observability) Spans + counters
tslib (catalog:build) Runtime helpers

Public API surface

class SeedRunner {
  constructor(options: SeedRunnerOptions)
  register(definition: SeedDefinition): void
  run(names?: string[]): Promise<SeedReport>
  teardown(names?: string[]): Promise<void>
}

function createSeedRunner(options: SeedRunnerOptions): SeedRunner

type SeedFn = (ctx: SeedContext) => Promise<void>

interface SeedDefinition {
  name: string
  run: SeedFn
  teardown?: SeedFn
  dependsOn?: string[]
  condition?: (ctx: SeedContext) => Promise<boolean>
  onConflict?: 'skip' | 'update' | 'error'   // default: 'skip'
}

interface SeedContext {
  db: DatabaseAdapter
  logger: LoggerLike
  env: string                // 'development' | 'test' | 'production'
}

interface SeedRunnerOptions {
  db: DatabaseAdapter
  env?: string               // default: process.env.NODE_ENV ?? 'development'
  logger?: LoggerLike
}

interface SeedReport {
  total: number
  ran: number
  skipped: number
  failed: number
  results: SeedStepResult[]
}

interface SeedStepResult {
  name: string
  status: 'ran' | 'skipped' | 'failed'
  duration: number
  error?: string
}

type SeedErrorCode =
  | 'SEED_CIRCULAR_DEPENDENCY'
  | 'SEED_STEP_FAILED'
  | 'SEED_DEFINITION_NOT_FOUND'
  | 'SEED_DEPENDENCY_NOT_REGISTERED'

function registerSeedErrorCodes(): void

File layout

server/infra/seed/
  package.json
  tsconfig.json
  vitest.config.ts
  src/
    index.ts
    error-codes.ts
    constants/index.ts
    types/
      seed.types.ts
      seed.types.md
    runner/
      seed-runner/
        seed-runner.ts
        seed-runner.md
        seed-runner.types.ts
        seed-runner.test.ts
        index.ts
    graph/
      dependency-graph/
        dependency-graph.ts
        dependency-graph.md
        dependency-graph.test.ts
        index.ts
  tests/
    integration.test.ts

Impact

Downstream: all server packages that need development data (auth, user, product seeds). Works with any @suaveplan/db-compatible adapter.

Prerequisites on Verdaccio: @suaveplan/error, @suaveplan/types, @suaveplan/db, @suaveplan/logger. Integration tests use @suaveplan/db-sqlite (dev dep).