Use cases
One spec.Four kinds of work.
One DOGM spec describes a fictional dataset: its tables, how they join and the rules every row must pass. The same YAML file can seed a dev database, force the rare paths in QA, pin down an AI evaluation set or fill a demo account.
Where things stand: The in-browser demo runs today with shop, hiring and support scenarios. Hosted runs compile and run specs like these in the early-access beta, and the dogm CLI runs them on your machine; until its first release, you build it from source.
01 Use case
Application development
- Who it is for
- Developers building features against a local or shared development database.
- The problem
- Empty tables hide bugs, and a copy of production puts real customers on every laptop. Hand-written fixtures drift from the schema, and half their foreign keys point at nothing.
- How DOGM helps
- Every order belongs to a customer and every key resolves, by construction.
- Names, mobile numbers and cities follow Philippine formats, so screens look the way they will in production.
- Row counts are a run input, so one spec seeds a 50-row laptop database and a 10-million-row staging one.
spec_version: 1
locale: en-PH
tables:
customers:
rows: 200
primary_key: { column: customer_id, format: "CUS-{n:06}" }
columns:
full_name: { gen: person.full_name, pii: person.name }
email: { gen: person.email, from: full_name, unique: true, pii: person.email }
mobile: { gen: ph.mobile }
city: { gen: ph.city, weights: population }
orders:
rows_per_parent: { parent: customers, dist: uniform, min: 1, max: 3 }
primary_key: { column: order_id, format: "ORD-{n:07}" }
columns:
customer_id: { ref: customers.customer_id }
total_php: { gen: money, currency: PHP, between: [249, 12500] }02 Use case
QA and edge cases
- Who it is for
- QA engineers and testers who need the rare paths to show up on purpose.
- The problem
- Cancelled orders, refunds and empty optional fields are rare in real data, so a test run hits them by luck or not at all.
- How DOGM helps
- Weights turn up the rare states. Here, half of all orders are cancelled.
- A payment's status follows its order, so a cancelled order always has a refunded payment.
- Rules run on every row and land in the report, so a broken total shows up as a finding before it shows up in a bug ticket.
spec_version: 1
locale: en-PH
tables:
orders:
rows: 500
primary_key: { column: order_id, format: "ORD-{n:07}" }
columns:
item_count: { gen: int, between: [1, 5] }
unit_price_php: { gen: choice, values: [249, 399, 589, 1250, 2499], type: money }
total_php: { expr: "item_count * unit_price_php" }
status: { gen: choice, values: [processing, shipped, delivered, cancelled], weights: [1, 1, 1, 3] }
gift_note: { gen: text.sentence, nullable: 0.4 }
payments:
rows_per_parent: { parent: orders, exactly: 1 }
primary_key: { column: payment_id, format: "PAY-{n:07}" }
columns:
order_id: { ref: orders.order_id }
amount_php: { expr: "parent.total_php" }
status: { map: parent.status, cases: { cancelled: refunded, processing: pending }, default: paid }
rules:
- "payments.amount_php == parent.total_php"03 Use case
AI evaluation
- Who it is for
- Teams testing models, prompts or agents on conversations and records.
- The problem
- An evaluation only means something if you can rerun it on the same inputs, and real support logs are full of personal data.
- How DOGM helps
- The seed is a run input, not part of the spec: the same spec and seed give the same rows, in the same order.
- Reply threads alternate between customer and agent, and each reply's timestamp comes after the one before it.
- Message text comes from fixed lists, so nothing in the set describes a real person.
spec_version: 1
locale: en-PH
tables:
tickets:
rows: 300
primary_key: { column: ticket_id, format: "TCK-{n:06}" }
columns:
opened_at: { gen: datetime, between: [2026-01-05T00:00, 2026-03-26T00:00] }
category: { gen: choice, values: [billing, delivery, account, bug], weights: [3, 2, 1, 1] }
reply_count: { gen: int, between: [1, 4] }
replies:
rows_per_parent: { parent: tickets, count: "parent.reply_count" }
primary_key: { column: reply_id, format: "RPL-{n:07}" }
columns:
ticket_id: { ref: tickets.ticket_id }
author_role: { expr: "if(ordinal % 2 == 0, 'customer', 'agent')" }
sent_at: { gen: datetime, after: "coalesce(prev.sent_at, parent.opened_at)", within_minutes: [5, 600] }
body:
gen: choice
by: author_role
cases:
customer: ["It happens every morning, around 9:00.", "Still not working after a restart."]
agent: ["Thanks for reaching out. We're looking into this now.", "This is fixed on our side. Can you try again?"]
rules:
- "replies.sent_at > parent.opened_at"04 Use case
Demos and sales environments
- Who it is for
- Sales engineers, founders and product teams showing software to prospects.
- The problem
- A demo account full of lorem ipsum looks unfinished, and a demo built from a customer's data is a privacy incident waiting for a screen share.
- How DOGM helps
- Companies, job titles and peso salaries that read like a Philippine business.
- Government ID columns such as TIN are format-valid and labelled synthetic in the report. They are not guaranteed to differ from real numbers.
- Emails use reserved example domains, so a demo can never mail a real inbox.
spec_version: 1
locale: en-PH
tables:
companies:
rows: 12
primary_key: { column: company_id, format: "CMP-{n:04}" }
columns:
name: { gen: company.name }
region: { gen: ph.region }
employees:
rows_per_parent: { parent: companies, dist: uniform, min: 5, max: 40 }
primary_key: { column: employee_id, format: "EMP-{n:06}" }
columns:
company_id: { ref: companies.company_id }
full_name: { gen: person.full_name, pii: person.name }
email: { gen: person.email, from: full_name, pii: person.email }
job_title: { gen: job.title }
tin: { gen: ph.tin, pii: ph.tin }
salary_php: { gen: money, currency: PHP, dist: lognormal, median: 32000 }See it working
Try a scenarioin your browser.
The demo generates connected records, masks names and emails, runs the checks and exports CSV without leaving the page.
