Files
The-transit-Project/.github/agents/shared-references/seed-data.md
T
Sven laptop 635a130f0b
Build and Push Docker Images / detect-changes (push) Successful in 11s
Build and Push Docker Images / build-auth-api (push) Successful in 1m0s
Build and Push Docker Images / build-employee-api (push) Successful in 1m2s
Build and Push Docker Images / build-transit-api (push) Successful in 1m1s
Build and Push Docker Images / build-error-log-api (push) Successful in 1m5s
Build and Push Docker Images / build-admin-ui (push) Successful in 1m13s
Build and Push Docker Images / build-monitoring-ui (push) Successful in 1m15s
Build and Push Docker Images / deploy-test-node (push) Successful in 3s
──────
### Summary of Changes
  1. Documentation Consolidation:
      • Relocated the docs/ folder and all repository .md files (README.md, DEPLOYMENT.md, DOCKER_README.md,
      DOMAINS_README.md, GETTING_STARTED.md, CI_CD_PORTAINER_GUIDE.md, ADMIN_DEPLOYMENT_SUMMARY.md,
      SECURITY_PRIVATE_FILES.md, handoff.md, azure-project-plan.md, plus service-specific READMEs) into .
      • Updated document links in README.md.
  2. AI Agent Project Map:
      • Created PROJECT_MAP.md in the project root containing complete architecture diagrams, service specs, ports, DB
      schemas, environment variables, and developer workflows.
      • Added PROJECT_MAP.md to .gitignore.
  3. Monitoring UI & Infrastructure Integration:
      • Added monitoring_ui service to docker-compose.yml (port 5175).
      • Configured Gitea workflow docker-build.yml for monitoring_ui builds.
      • Added CORS middleware headers in index.js.
      • Added nginx.conf copy step in Dockerfile.

  ──────
  ### Recommended Commit Message

    docs: consolidate project documentation into monitoring_ui and add agent project map

    - Move all markdown documentation files and docs/ folder into monitoring_ui/docs/
    - Update documentation hub index (monitoring_ui/docs/README.md) with relative paths
    - Generate comprehensive AI agent reference map (PROJECT_MAP.md) in repository root
    - Add PROJECT_MAP.md and monitoring_ui build output/env overrides to .gitignore
    - Integrate monitoring_ui service into docker-compose.yml and Gitea CI workflow
    - Configure CORS handling in employee_api for monitoring dashboard access
    ──────
  ### Alternative Short Commit Message

    refactor(docs): move docs to monitoring_ui and create AI agent PROJECT_MAP.md
2026-09-20 23:33:55 +02:00

301 lines
8.9 KiB
Markdown

<!-- azure-cor-disclaimer -->
> **Important:** This skill provides guidance and recommended instructions to assist the AI system. Outputs are not guaranteed to be complete, correct, secure, or applicable to every scenario. Results should be reviewed and validated by a human before being applied. The AI model may choose not to follow all instructions exactly, and additional verification may be required.
# Seed Data & Migrations
> Database schema management and realistic test data seeding patterns.
---
## Core Principle
**Repeatable, idempotent schema and data management.** Migrations run forward and backward cleanly. Seed data is realistic, usable in both dev and tests. Running seed twice does not duplicate data.
---
## When This Applies
This reference is used **only when project includes a database service** (PostgreSQL, CosmosDB, Azure SQL). If project only uses Blob Storage, Queue Storage, or Redis, skip this reference.
> ⛛ **CRITICAL**: Migration files and seed data scripts MUST contain actual code — not empty files or empty directories. Empty `seeds/migrations/` directory is #1 cause of runtime failures that unit tests cannot catch (mocks use in-memory Maps, not SQL tables). Every table in plan's Database Constraints section MUST have corresponding migration file with complete `CREATE TABLE` statement. Every migration file MUST have both `up()` and `down()` functions. `seeds/fixtures/seed-data.json` MUST contain realistic sample data.
---
## Migration Patterns
### TypeScript — Knex Migrations
#### Setup
```bash
npm install knex pg
npm install -D @types/pg
```
```typescript
// knexfile.ts
import { loadConfig } from './src/services/config';
const config = loadConfig();
export default {
client: 'pg',
connection: config.database.url,
migrations: {
directory: './seeds/migrations',
extension: 'ts',
},
seeds: {
directory: './seeds/data',
extension: 'ts',
},
};
```
#### Migration File
```typescript
// seeds/migrations/20260101000000_create_items.ts
import { Knex } from 'knex';
export async function up(knex: Knex): Promise<void> {
await knex.schema.createTable('items', (table) => {
table.uuid('id').primary().defaultTo(knex.fn.uuid());
table.string('name').notNullable();
table.text('description');
table.decimal('price', 10, 2).notNullable();
table.string('category').notNullable();
table.timestamp('created_at').defaultTo(knex.fn.now());
table.timestamp('updated_at').defaultTo(knex.fn.now());
});
// Add indexes
await knex.schema.alterTable('items', (table) => {
table.index('category');
table.index('created_at');
});
}
export async function down(knex: Knex): Promise<void> {
await knex.schema.dropTableIfExists('items');
}
```
#### Seed Script
```typescript
// seeds/seed.ts
import knex from 'knex';
import knexConfig from '../knexfile';
import seedData from './fixtures/seed-data.json';
async function seed() {
const db = knex(knexConfig);
try {
// Run migrations first
await db.migrate.latest();
console.log('Migrations applied.');
// Seed data — idempotent (upsert)
for (const item of seedData.items) {
await db('items')
.insert(item)
.onConflict('id')
.merge();
}
console.log(`Seeded ${seedData.items.length} items.`);
} finally {
await db.destroy();
}
}
seed().catch(console.error);
```
#### Seed Data Fixture
```json
// seeds/fixtures/seed-data.json
{
"items": [
{
"id": "seed-001",
"name": "Sample Widget",
"description": "A sample widget for development",
"price": 29.99,
"category": "widgets",
"created_at": "2026-01-15T10:00:00.000Z",
"updated_at": "2026-01-15T10:00:00.000Z"
},
{
"id": "seed-002",
"name": "Demo Gadget",
"description": "A demo gadget for development",
"price": 49.99,
"category": "gadgets",
"created_at": "2026-02-01T14:00:00.000Z",
"updated_at": "2026-02-01T14:00:00.000Z"
},
{
"id": "seed-003",
"name": "Test Doohickey",
"description": "A test doohickey for development",
"price": 9.99,
"category": "doohickeys",
"created_at": "2026-03-01T08:00:00.000Z",
"updated_at": "2026-03-01T08:00:00.000Z"
}
]
}
```
#### Package.json Scripts
```json
{
"scripts": {
"db:migrate": "knex migrate:latest",
"db:migrate:rollback": "knex migrate:rollback",
"db:seed": "tsx seeds/seed.ts",
"db:reset": "knex migrate:rollback --all && knex migrate:latest && npm run db:seed"
}
}
```
---
### Python and C# Migrations
For Python migration patterns (Alembic + SQLAlchemy), see [runtimes/python.md](.github/agents/shared-references/runtimes/python.md). For C# migration patterns (Entity Framework Core), see [runtimes/dotnet.md](.github/agents/shared-references/runtimes/dotnet.md).
---
## Testing Migrations & Seed Data
### TypeScript Tests
```typescript
// tests/seeds/migration.test.ts
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import knex, { Knex } from 'knex';
import knexConfig from '../../knexfile';
// These tests require a running database (integration tests)
// Skip if DATABASE_URL is not set
const shouldRun = !!process.env.DATABASE_URL;
describe.skipIf(!shouldRun)('Database Migrations', () => {
let db: Knex;
beforeAll(() => {
db = knex(knexConfig);
});
afterAll(async () => {
await db.destroy();
});
it('should run migrations forward', async () => {
await db.migrate.latest();
const tables = await db.raw(
"SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'"
);
const tableNames = tables.rows.map((r: any) => r.table_name);
expect(tableNames).toContain('items');
});
it('should run migrations backward', async () => {
await db.migrate.rollback(undefined, true);
const tables = await db.raw(
"SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'"
);
const tableNames = tables.rows.map((r: any) => r.table_name);
expect(tableNames).not.toContain('items');
});
it('should be idempotent (run forward twice without error)', async () => {
await db.migrate.latest();
await db.migrate.latest(); // Should not throw
});
});
```
```typescript
// tests/seeds/seedData.test.ts
import { describe, it, expect, beforeAll, beforeEach, afterAll } from 'vitest';
import knex, { Knex } from 'knex';
import knexConfig from '../../knexfile';
import seedData from '../../seeds/fixtures/seed-data.json';
const shouldRun = !!process.env.DATABASE_URL;
describe.skipIf(!shouldRun)('Seed Data', () => {
let db: Knex;
beforeAll(async () => {
db = knex(knexConfig);
await db.migrate.latest();
});
beforeEach(async () => {
await db('items').del(); // Clean slate
});
afterAll(async () => {
await db.migrate.rollback(undefined, true);
await db.destroy();
});
it('should seed correct number of rows', async () => {
for (const item of seedData.items) {
await db('items').insert(item).onConflict('id').merge();
}
const count = await db('items').count('* as total').first();
expect(Number(count?.total)).toBe(seedData.items.length);
});
it('should be idempotent (seeding twice produces same row count)', async () => {
// Seed once
for (const item of seedData.items) {
await db('items').insert(item).onConflict('id').merge();
}
// Seed again
for (const item of seedData.items) {
await db('items').insert(item).onConflict('id').merge();
}
const count = await db('items').count('* as total').first();
expect(Number(count?.total)).toBe(seedData.items.length);
});
});
```
---
## Fixture Data Guidelines
1. **Use realistic data** — Names, descriptions, values should look like real data, not "test1", "test2"
2. **Include edge cases** — Empty strings (where valid), long strings, special characters, Unicode, boundary numbers (0, negative, max)
3. **Use stable IDs** — Seed data should have predictable IDs (e.g., `seed-001`) so tests can reference specific records
4. **Keep fixtures in JSON** — Shared between seed scripts and test fixtures. Easy to read and modify.
5. **Separate seed data from test fixtures** — Seed data populates dev database. Test fixtures drive unit test assertions. May overlap but serve different purposes.
6. **Document fixture schema** — Add comment block or README explaining what each fixture covers
### Example Fixture Structure
```
seeds/
├── seed.ts ← Seed script (runs against real DB)
├── migrations/
│ └── 20260101_create_items.ts
└── fixtures/
└── seed-data.json ← Seed data (realistic dev data)
tests/
├── fixtures/
│ ├── items.json ← Test data (valid + invalid variations)
│ └── users.json ← Test data for another entity
└── mocks/
└── mockDatabase.ts ← Mock service pre-loaded with fixture data
```