Files
startover/packages/database/seeds/seed.ts
T
Johngreen 16bd2cb92a feat: Re:Link MVP 초기 구현 - 도메인/서비스/프론트엔드 전체
- 모노레포 구조 (Turborepo + pnpm): @relink/domain, @relink/shared, @relink/infrastructure, @relink/database, @relink/web
- 도메인 레이어: 매장(store), 매칭(matching), 업체(vendor), 보조금(subsidy), 계약/에스크로(contract) TDD 완료 (158 단위 테스트)
- 서비스 레이어: 전 도메인 서비스 함수 + 통합 테스트 (58 테스트)
- 프론트엔드: Next.js 15 App Router, 13개 페이지 (사용자 6 + 관리자 7)
- 인프라: PostgreSQL 16 + PostGIS, Prisma ORM, Docker Compose, AuditLog + OutboxEvent 패턴
- .env 파일 포함 (로컬 개발 기본값만 포함, 실제 시크릿 없음)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 17:39:56 +09:00

158 lines
4.4 KiB
TypeScript

import { PrismaClient } from '@prisma/client';
import { readFileSync } from 'node:fs';
import { resolve, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const prisma = new PrismaClient();
interface RegionRow {
code: string;
name_ko: string;
full_name_ko: string;
region_type: string;
parent_code: string;
depth: string;
path_code: string;
sort_order: string;
is_active: string;
is_beta_enabled: string;
latitude: string;
longitude: string;
}
interface IndustryRow {
code: string;
name_ko: string;
parent_code: string;
depth: string;
sort_order: string;
is_leaf: string;
is_active: string;
is_beta_enabled: string;
}
function parseCsv(filePath: string): Record<string, string>[] {
const content = readFileSync(filePath, 'utf-8');
const lines = content.trim().split('\n');
const headers = lines[0]!.split(',');
return lines.slice(1).map((line) => {
const values = line.split(',');
const row: Record<string, string> = {};
for (let i = 0; i < headers.length; i++) {
row[headers[i]!] = values[i] ?? '';
}
return row;
});
}
async function seedRegions(): Promise<void> {
const csvPath = resolve(__dirname, 'master-data/regions.v1.csv');
const rows = parseCsv(csvPath) as unknown as RegionRow[];
// code → id 매핑을 위한 맵
const codeToId = new Map<string, bigint>();
// depth 순으로 정렬하여 부모를 먼저 upsert
const sorted = [...rows].sort((a, b) => parseInt(a.depth) - parseInt(b.depth));
for (const row of sorted) {
const parentId = row.parent_code ? (codeToId.get(row.parent_code) ?? null) : null;
const result = await prisma.regionHierarchy.upsert({
where: { code: row.code },
update: {
nameKo: row.name_ko,
fullNameKo: row.full_name_ko || null,
regionType: row.region_type as never,
parentId,
depth: parseInt(row.depth),
pathCode: row.path_code,
sortOrder: parseInt(row.sort_order),
isActive: row.is_active === 'true',
isBetaEnabled: row.is_beta_enabled === 'true',
latitude: row.latitude ? parseFloat(row.latitude) : null,
longitude: row.longitude ? parseFloat(row.longitude) : null,
},
create: {
code: row.code,
nameKo: row.name_ko,
fullNameKo: row.full_name_ko || null,
regionType: row.region_type as never,
parentId,
depth: parseInt(row.depth),
pathCode: row.path_code,
sortOrder: parseInt(row.sort_order),
isActive: row.is_active === 'true',
isBetaEnabled: row.is_beta_enabled === 'true',
latitude: row.latitude ? parseFloat(row.latitude) : null,
longitude: row.longitude ? parseFloat(row.longitude) : null,
},
});
codeToId.set(row.code, result.id);
}
console.log(`Seeded ${sorted.length} regions`);
}
async function seedIndustries(): Promise<void> {
const csvPath = resolve(__dirname, 'master-data/industries.v1.csv');
const rows = parseCsv(csvPath) as unknown as IndustryRow[];
const codeToId = new Map<string, bigint>();
const sorted = [...rows].sort((a, b) => parseInt(a.depth) - parseInt(b.depth));
for (const row of sorted) {
const parentId = row.parent_code ? (codeToId.get(row.parent_code) ?? null) : null;
const result = await prisma.industryTaxonomy.upsert({
where: { code: row.code },
update: {
nameKo: row.name_ko,
parentId,
depth: parseInt(row.depth),
sortOrder: parseInt(row.sort_order),
isLeaf: row.is_leaf === 'true',
isActive: row.is_active === 'true',
isBetaEnabled: row.is_beta_enabled === 'true',
},
create: {
code: row.code,
nameKo: row.name_ko,
parentId,
depth: parseInt(row.depth),
sortOrder: parseInt(row.sort_order),
isLeaf: row.is_leaf === 'true',
isActive: row.is_active === 'true',
isBetaEnabled: row.is_beta_enabled === 'true',
},
});
codeToId.set(row.code, result.id);
}
console.log(`Seeded ${sorted.length} industries`);
}
async function main(): Promise<void> {
console.log('Starting seed...');
await seedRegions();
await seedIndustries();
console.log('Seed completed successfully');
}
main()
.catch((e) => {
console.error('Seed failed:', e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});