Skip to content

feat: non-prod sample market seed endpoint#281

Open
Davichi-1 wants to merge 1 commit into
Predictify-org:mainfrom
Davichi-1:feature/admin-seed
Open

feat: non-prod sample market seed endpoint#281
Davichi-1 wants to merge 1 commit into
Predictify-org:mainfrom
Davichi-1:feature/admin-seed

Conversation

@Davichi-1

Copy link
Copy Markdown

Overview

This PR adds an admin sample-market seed endpoint to the backend so E2E suites and demos have predictable data to work against in non-production environments. It introduces POST /api/admin/seed, which inserts a small, fixed batch of sample markets. The operation is idempotent, tracks the rows it seeds, and is unavailable in production.

Related Issue

Closes #160

Changes

⚙️ Seed Service

  • [ADD] src/services/seedService.ts
  • Added the core seed workflow for a fixed batch of 5 sample markets.
  • Idempotent: stable primary keys (seed-market-001005) + ON CONFLICT (id) DO NOTHING, so repeat runs insert nothing and report rows as skipped.
  • Tracks seeded rows by tagging metadata.seeded = true plus a seedBatchVersion; exposes listSeeded() to read them back.
  • Defense-in-depth SeedNotAllowedError guard so the service can never write sample data to a production database, even if called directly.
  • Emits a market.created structured log event per inserted row and writes an admin.seed_markets audit entry, both carrying a correlation id.
  • Uses a repository interface (SeedRepository) with a Drizzle implementation, kept injectable for testing.

🌐 Seed API Surface

  • [ADD] src/routes/admin/seed.ts

  • Added POST /api/admin/seed to trigger the seed.

  • Security layers (outermost first): production guard → 404 before auth (route is not even probeable); per-admin-token rate limit (30/min, IP fallback); requireAdmin JWT guard.

  • Input validation at the boundary with a strict body schema; unexpected fields return 400 validation_error in the standard error envelope.

  • [MODIFY] src/index.ts

  • Registered the new router at /api/admin/seed.

🧪 Tests

  • [ADD] tests/seedService.test.ts

  • Covers fresh seed, idempotent re-run (no inserts, no events), actor propagation, the production guard, the error shape, and the Drizzle repository.

  • [ADD] tests/adminSeed.test.ts

  • Covers the admin guard (missing/non-admin/expired JWT), success + context forwarding, idempotent response, body validation, production 404, rate-limit 429, and error mapping.

📚 Documentation

  • [ADD] docs/seed.md
  • Documents the endpoint, request/response shape, non-prod behavior, idempotency, tracking, the security layers, observability, and the error envelope.

Verification Results

npm run lint            ✅ changed files clean (pre-existing repo errors/warnings are unrelated)
npx tsc --noEmit        ✅ no errors in changed files (repo has pre-existing type errors)
npx jest tests/seedService.test.ts tests/adminSeed.test.ts   ✅ 20/20 passed
coverage (changed lines)  ✅ seedService.ts 95.2% · routes/admin/seed.ts 93.2% (>90%)
Acceptance Criteria Status
Non-prod only (404 in production, runs before auth)
Idempotent (ON CONFLICT DO NOTHING, repeat = 0 inserts)
Tracks seeded markets (metadata.seeded, listable)
Documentation shipped (docs/seed.md)
Secure (admin auth, rate limit, strict input validation)
Structured logging + audit with correlation ids
≥90% coverage on changed lines
Seed route + service tests pass

Note for reviewers: main currently has pre-existing build/test breakage that is unrelated to this change (e.g. src/utils/keyRing.ts references env.JWT_KEYS/env.JWT_ACTIVE_KID, which exist in src/config/env-schema.ts but not in src/config/env.ts; src/index.ts references undefined devicesRouter/stopIndexerHealthProbe). This PR does not touch those files and keeps its test isolated so it runs cleanly. Happy to open a separate PR for the main build fix if useful.

🤖 Generated with Claude Code

Add POST /api/admin/seed for development/staging/test environments that
inserts a small, fixed batch of sample markets for E2E and demos.

- Non-prod only: 404 in production (route hidden before auth) plus a
  service-level SeedNotAllowedError guard as defense-in-depth.
- Idempotent: stable primary keys + ON CONFLICT DO NOTHING; repeat calls
  insert nothing and report rows as skipped.
- Tracked: seeded rows tagged with metadata.seeded=true + batch version
  and listable via seedService.listSeeded().
- Secure: admin JWT guard, per-token rate limit, strict body validation
  with the standard error envelope, structured logging + audit trail with
  correlation ids.
- Documented in docs/seed.md; covered by route + service tests.

Closes Predictify-org#160

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@drips-wave

drips-wave Bot commented Jun 30, 2026

Copy link
Copy Markdown

@Davichi-1 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add admin endpoint to seed sample markets in non-prod environments

1 participant