# Wire SurrealDB job-persistence store into `@suaveplan/api-plugin-export` **Package**: `@suaveplan/api-plugin-export` **Status**: PROPOSED **Type**: follow-up (MODIFIED-Requirements) **Spec delta**: ./specs/api-plugin-export/spec.md ## Why `@suaveplan/api-plugin-export` shipped at `741e1b176` with the upstream §2 "Current-state assessment" surface only. The proposal (`openspec/archive/2026-05-19-add-api-plugin-export/proposal.md`) explicitly carved out `§3 "Job persistence" via SurrealDB`: > Upstream §2 ships the in-memory `Map`. SurrealDB persistence is §3 work and requires `surql/` migrations + integration tests against `@suaveplan/api-plugin-database`. Deferred. The dependencies that were missing at ship time — `@suaveplan/api-plugin-database`, `@suaveplan/surrealdb`, `@suaveplan/api-plugin-events` (canonical positional-SurQL pattern) — have now landed on genesis. This change wires the previously-excluded SurrealDB job-persistence store in. ## What changes - ADDED: `ExportJobStore` — formal async store contract (`get`, `set`, `delete`, `list`, `has`, `clear`) extracted from the implicit `Map` surface so two backends can co-exist behind the same name. - ADDED: `MemoryExportJobStore` — `Map` wrapper implementing `ExportJobStore`. Equivalent to the existing in-memory job store; keeps the in-memory path on the new typed contract. - ADDED: `SurrealExportStore` — SurrealDB-backed `ExportJobStore` implementation. CRUD over the `export_job` table using positional `$p0…$pN` placeholders (genesis canonical, matching `@suaveplan/api-plugin-events` repositories). Wraps every failure with `ExportError(EXPORT_CODES.JOB_PERSISTENCE_FAILED)`. - ADDED: `EXPORT_CODES.JOB_PERSISTENCE_FAILED` — surfaces SurrealDB driver / network / parse failures from the `SurrealExportStore`. Cause chain preserves the underlying error. - ADDED: `surql/tables/export_job.surql` migration — `DEFINE TABLE OVERWRITE export_job SCHEMAFULL` + every field on `ExportJobSchema` + indexes on `(status)`, `(format)`, `(resource)`, `(created_at)`. - ADDED: `ServiceRegistry` slot `exportJobStore: ExportJobStore` via module augmentation. Independent of the pre-existing `exportJobs: Map` slot, which remains for back-compat — callers wire whichever they want. - MODIFIED: `Public surface and side-effect imports` requirement — the package barrel now also re-exports `ExportJobStore`, `MemoryExportJobStore`, `SurrealExportStore`, and the `JOB_PERSISTENCE_FAILED` code; new subpath exports `./store/types`, `./store/memory/memory-store`, `./store/surreal/surreal-store`. ## Out of scope Hard-bound to "wire SurrealDB persistence". Specifically excluded from this change (per the calling instructions): - Re-plumbing `ExportRoutesDeps.jobs` from `Map` to `ExportJobStore`. The routes, the format writers (CSV / JSON / XLSX), and the streaming pipeline are untouched. Callers wire the new store directly until a future route-refactor change lands. - `GET /:id/download` handler — separate excluded item from the original migration; remains deferred. - Streaming exporters, S3 sink, OOXML extras, auth / rate-limit / idempotency / audit middleware composition, signed URLs, Parquet, scheduled exports — all unchanged from the original carve-out. ## Source mapping | Requirement | Source | Notes | |---|---|---| | `ExportJobStore` async contract | `enterprise/api-plugin-export.md §3` + `events.EventRepository` shape | Mirrors the `IEventRepository` async-CRUD convention. | | `SurrealExportStore` positional SurQL | `packages/api/api-plugin-events/src/repositories/event-repository/event-repository.ts` | Genesis-canonical `$p0`/`$p1` pattern. | | `export_job.surql` migration | Upstream `../suaveplan/packages/server/api-plugin-export/surql/` parity + `ExportJobSchema` shape | All `ExportJobSchema` fields persisted. | | `JOB_PERSISTENCE_FAILED` code | Genesis-wide `defineCodes` registry + `ExportError` hierarchy | New code; wired in `SurrealExportStore` only. | ## Impact ### Affected dependents `@suaveplan/api-plugin-export` ships at `0.1.0` with no genesis consumers yet: - `bunx turbo ls --filter=...@suaveplan/api-plugin-export` returns the package itself only — `[x] no action needed (no downstream consumers on genesis at this date)`. ### Migration note No consumer-visible behavior change. The pre-existing `Map`-based job slot (`exportJobs: Map`) is preserved unchanged. The new `ExportJobStore` interface and the two implementations (`MemoryExportJobStore`, `SurrealExportStore`) are additive surface; no existing call site is renamed, removed, or rerouted.