# linked-faker — Version Plan > **Random values give you one field. linked-faker gives you a database.** Generate realistic relational test data with valid relationships. ``` Random values linked-faker ↓ ↓ one field Users ──────┐ ↓ Orders ─────→ Products ↓ Categories ``` **No manual IDs. No seed scripts. No broken foreign keys.** --- ## Product Direction The developer experience we're building toward: ```ts import { defineSchema, generate, belongsTo, faker } from 'linked-faker'; const schema = defineSchema({ users: entity({ count: 100, fields: { name: faker('person.fullName'), email: faker('internet.email'), }, }), orders: entity({ count: 500, fields: { status: oneOf(['pending', 'paid', 'cancelled']), total: number({ min: 10, max: 500 }), }, relations: { userId: belongsTo('users'), }, }), }); const data = generate(schema, { seed: 42 }); ``` Then: ```bash npx linked-faker generate ``` And eventually: ```bash npx linked-faker prisma ``` --- ## Architecture Principles Core stays **ORM-agnostic**. Optional integrations live in subpath exports — never in core. ``` linked-faker (core) │ ┌─────────────┼─────────────┐ ↓ ↓ ↓ JSON CSV SQL │ ┌─────────────────┼───────┐ ↓ ↓ ↓ PostgreSQL MySQL SQLite ``` Optional integrations (later, demand-driven): ``` linked-faker/prisma ← prioritize first linked-faker/drizzle ← only if demand linked-faker/mongoose ← only if demand ``` **Not spending early time on:** Drizzle adapter, Kysely adapter, plugin ecosystem, 10 SQL dialects, complex UI. --- ## Three Core Concepts The API is built around three ideas: | Concept | Purpose | Example | |---------|---------|---------| | **Entity** | A table / collection | `entity({ count: 100, ... })` | | **Field** | A column value | `faker('person.fullName')`, `oneOf([...])` | | **Relation** | A foreign key | `belongsTo('users')`, `hasMany('products')` | String-based API from v1.0 remains supported. Helper APIs are added on top for readability. --- ## 90-Day Roadmap (Priority Order) | Phase | Focus | Priority | Target | |-------|-------|----------|--------| | 1 | Core correctness + post-generation validation | 🔴 | v1.1 ✅ | | 2 | TypeScript inference (`InferSchema`) | 🔴 | v2.0 | | 3 | Seed + deterministic generation (guaranteed) | 🔴 | v1.1 ✅ | | 4 | Helper API (`entity`, `faker`, `belongsTo`, …) | 🔴 | v1.1 ✅ | | 5 | CLI (`init`, `generate`, `validate`, `inspect`) | 🟠 | v2.0 | | 6 | SQL / JSON / CSV export polish | 🟠 | v2.0 | | 7 | Self-referencing relations | 🟠 | v2.1 | | 8 | Prisma schema import | 🟠 | v2.5 | | 9 | Scenarios + realistic distributions | 🟡 | v2.5 | | 10 | Streaming generation | 🟡 | v3.0 | | 11 | Playground (web UI) | 🟡 | v3.0 | --- ## Version 1.0 — Core (Shipped) **Status:** ✅ Shipped Foundation: declarative schema → valid relational fake data. ### API - `defineSchema()` — schema definition with validation - `generate()` — full dataset generation - `exportAs()` — JSON, CSV, SQL export ### Schema & Entities - Entity definitions with fixed `count` - Auto-generated IDs with customizable `idPrefix` - Field generators: - Built-in generator paths (`'person.fullName'`) - Custom functions `(record, index) => value` - Static values (`'customer'`, `true`, etc.) ### Relations (string-based) - **Belongs-to** — `userId: { ref: 'users' }` - **Many-to-many** — `productIds: { ref: 'products', many: true, min, max }` - **Filtered** — `filter: (record) => boolean` - **Cascading counts** — `countPerParent: { ref, min, max }` - **Parent linking** — `linkedToParent: true` ### Generation Engine - Topological sort (dependency order) - Circular dependency detection - Schema validation with helpful error messages - Reproducible output via `{ seed: number }` ### Export | Format | Output | |--------|--------| | `json` | Single file, keyed by entity | | `csv` | One file per entity | | `sql` | `INSERT` statements — postgres, mysql, sqlite | ### Package - ESM + CJS dual build - TypeScript types (manual, not inferred from schema yet) - Built-in field generators (zero required dependencies) - Zero ORM dependencies --- ## Version 1.1 — Correctness & Trust **Status:** ✅ Shipped Make the core promise bulletproof before adding features. ### Post-Generation Validation ```ts const result = generate(schema, { seed: 42, validate: true, }); ``` Internal verification of every invariant: - ✓ All FK values exist in referenced entities - ✓ Many-relations have no duplicate IDs within a record - ✓ `min` / `max` constraints respected - ✓ Filters respected (only matching records linked) - ✓ Parent relationships correct (`linkedToParent`, `countPerParent`) - ✓ IDs unique within each entity Validation becomes a **core selling point**, not an implementation detail. ### Deterministic Seed Guarantee ```ts const a = generate(schema, { seed: 42 }); const b = generate(schema, { seed: 42 }); // a === b (byte-identical) generate(schema, { seed: 43 }); // different dataset ``` Documented promise: > If you report a bug, give us the **seed + schema** and we can reproduce the exact dataset. Valuable for: unit tests, integration tests, CI, bug reproduction, local dev. ### Built-In Generators Core includes its own field generators — zero required dependencies: - Built-in generator paths: `person.fullName`, `internet.email`, `commerce.*`, `date.*`, etc. - Helper API: `faker()`, `oneOf()`, `number()`, `fixed()`, `belongsTo()`, `hasMany()`, `fromParent()`, `entity()` - Seeded internal RNG for relations and field generation - Custom functions and static values (unchanged) Install: `npm install linked-faker` — no peer deps. --- ## Version 2.0 — Developer Experience **Status:** Planned **Priority:** 🔴 / 🟠 Readable API, typed output, CLI, export polish. ### Helper API (on top of string API) **Entities** ```ts users: entity({ count: 100, fields: { ... }, relations: { ... }, }) ``` **Fields** ```ts fields: { name: faker('person.fullName'), email: faker('internet.email'), status: oneOf(['pending', 'paid', 'cancelled']), total: number({ min: 10, max: 500 }), role: fixed('customer'), } ``` **Relations** ```ts relations: { userId: belongsTo('users'), productIds: hasMany('products', { min: 1, max: 5 }), userId: belongsTo('users', { where: (user) => user.isActive }), userId: fromParent(), // when using countPerParent } ``` Schemas should feel like describing a database. ### TypeScript Inference ```ts const schema = defineSchema({ ... }); const data = generate(schema); data.users[0].name // string ✓ data.users[0].email // string ✓ data.users[0].foo // TypeScript error ✓ ``` - `InferSchema` exported type - Autocomplete for built-in generator paths - Typed relation refs (catch typos at compile time) ### CLI ```bash npx linked-faker init # creates linked-faker.config.ts npx linked-faker generate # generate from config npx linked-faker generate --seed 42 npx linked-faker generate --count 10000 npx linked-faker validate # FK integrity check npx linked-faker inspect # schema graph + counts preview ``` **`inspect` output example:** ``` Dataset Graph Category ↓ Product ↓ Order ↓ User Entities ──────────────── users 100 products 500 orders 2,000 Relations ──────────────── orders.userId → users.id orders.productId → products.id products.categoryId → categories.id ``` Catches schema mistakes before generation. ### Export Polish SQL export hardened for **PostgreSQL + SQLite first** (MySQL follows): - Correct handling of UUID, integer, string, boolean, null, Date, JSON, arrays - Proper escaping per dialect - JSON and CSV edge cases (nested objects, arrays, empty entities) ### Self-Referencing Relations ```ts employees: entity({ count: 100, relations: { managerId: belongsTo('employees', { nullable: true, excludeSelf: true }), }, }) ``` --- ## Version 2.5 — Realism & Prisma **Status:** Planned **Priority:** 🟠 / 🟡 ### Prisma Schema Import (moved up — high impact) Today: ``` Developer → writes linked-faker schema → generate data ``` Target: ``` Prisma schema → linked-faker → generate relational data ``` ```bash npx linked-faker prisma generate ``` Automatically understands: ``` User → Order → Product → Category ``` Optional subpath: `linked-faker/prisma` — **not in core**. ### Realistic Distributions Real databases aren't "every user = exactly 5 orders." ```ts status: weighted([ ['active', 0.7], ['pending', 0.2], ['blocked', 0.1], ]) orders: entity({ countPerParent: { ref: 'users', distribution: 'power-law', // 10% → 0, 30% → 1–2, 40% → 3–10, … min: 0, max: 20, }, }) ``` ### Scenarios ```ts generate(schema, { scenario: 'production-like' }); // or in schema: users: entity({ count: scenario({ small: 10, large: 100_000 }), }) ``` Built-in presets: `emptyDatabase`, `smallDataset`, `productionLike`, `highVolume`. Useful for testing environments, not just one-off seeding. ### Reference Examples (docs) Five complete schema examples shipped as recipes: | Example | Entity graph | |---------|-------------| | **SaaS** | Organization → Users → Teams → Projects → Tasks → Comments | | **E-commerce** | Category → Product → Order → OrderItem → User | | **Social network** | User → Posts → Comments, Followers | | **Marketplace** | User → Seller → Products, Orders | | **Blog** | Author → Post → Comment | --- ## Version 3.0 — Scale & Ecosystem **Status:** Planned **Priority:** 🟡 ### Streaming Generation For datasets that shouldn't live entirely in memory: ```ts for await (const batch of generateStream(schema, { batchSize: 1000 })) { await insert(batch); } ``` Target: 1M+ users, 500k orders, 2M products without OOM. ### Playground (Marketing) Web UI — understand the package in 30 seconds: ``` ┌─────────────────────────────────────────────────────┐ │ linked-faker Playground │ ├───────────────────────┬─────────────────────────────┤ │ Schema (editor) │ Generated Data (live) │ │ │ │ │ [Generate] [Copy] │ users | orders | products │ │ [Download JSON] │ │ │ [Download SQL] │ FK links visualized │ │ [Change Seed] │ │ └───────────────────────┴─────────────────────────────┘ ``` ### Optional ORM Integrations (demand-driven only) | Subpath | When | |---------|------| | `linked-faker/prisma` | v2.5 (schema import) — seed helper in v3 if needed | | `linked-faker/drizzle` | Only if clear user demand | | `linked-faker/mongoose` | Only if clear user demand | Core package **never** depends on an ORM. --- ## Version Summary | Version | Focus | Key deliverables | |---------|-------|------------------| | **1.0** ✅ | Core | Schema, relations, export, seed | | **1.1** ✅ | Trust + built-ins | `validate: true`, deterministic seed, own generators, helper API | | **2.0** | DX | Helper API, TypeScript inference, CLI, `inspect`, SQL polish | | **2.1** | Relations | Self-referencing | | **2.5** | Realism + Prisma | Distributions, scenarios, Prisma schema import | | **3.0** | Scale | Streaming, playground, optional ORM seed helpers | --- ## Out of Scope (Early) | Item | Reason | |------|--------| | Drizzle / Kysely adapters | Demand-driven only; not v2 priority | | Plugin ecosystem | Core must stabilize first | | 10 SQL dialects | Postgres + SQLite first | | Complex schema builder UI | Playground comes after CLI + types | | Live DB connection in core | Export + user's ORM | | GraphQL schema generation | Different product | --- ## Positioning Cheat Sheet | | Single-value generators | linked-faker | |---|-------------------------|--------------| | **Output** | One random field | Entire coherent dataset | | **FKs** | Manual | Automatic, always valid | | **Seeding** | Write loops yourself | One schema declaration | | **Tagline** | Random values | Random database | --- ## How to Contribute 1. Pick a phase from the 90-day roadmap above 2. Open an issue referencing this file and the target version 3. Core changes go in `src/` — ORM adapters go in optional subpaths only **Current release:** v1.1.0