Files
goodgo-platform/scripts/seed-macro-infra.ts
Ho Ngoc Hai b22543d59e feat(seed): add MacroeconomicData and InfrastructureProject seed data
Add seed-macro-infra.ts with 144 macroeconomic data points (HCMC + Hanoi,
6 indicators, quarterly 2023-2025) and 15 infrastructure projects with
PostGIS coordinates (Metro Line 1, Thu Duc Innovation District, Ring Road 3,
Long Thanh Airport, Can Gio Bridge, etc.). Integrated into main seed pipeline.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-16 14:18:41 +07:00

402 lines
16 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Seed MacroeconomicData and InfrastructureProject tables.
*
* MacroeconomicData: 50+ rows — HCMC & Hanoi, quarterly 2023-Q1 → 2025-Q4.
* InfrastructureProject: 15 real projects with coordinates, status, dates, investment.
*/
import { type PrismaClient } from '@prisma/client';
// =============================================================================
// MacroeconomicData — HCMC & Hanoi, quarterly 20232025
// =============================================================================
interface MacroRow {
province: string;
indicator: string;
value: number;
unit: string;
period: string;
source: string;
}
const QUARTERS = [
'2023-Q1', '2023-Q2', '2023-Q3', '2023-Q4',
'2024-Q1', '2024-Q2', '2024-Q3', '2024-Q4',
'2025-Q1', '2025-Q2', '2025-Q3', '2025-Q4',
];
/**
* Helper: generate quarterly series with a base value and per-quarter growth.
*/
function quarterlySeries(
province: string,
indicator: string,
unit: string,
source: string,
baseValue: number,
quarterlyGrowth: number,
): MacroRow[] {
return QUARTERS.map((period, i) => ({
province,
indicator,
value: Math.round((baseValue + baseValue * quarterlyGrowth * i) * 100) / 100,
unit,
period,
source,
}));
}
function buildMacroData(): MacroRow[] {
const rows: MacroRow[] = [];
// ── Hồ Chí Minh ──────────────────────────────────────────
// GDP growth (% YoY per quarter)
const hcmcGdpGrowth = [5.8, 6.1, 6.4, 6.7, 6.2, 6.5, 6.8, 7.1, 6.9, 7.2, 7.0, 7.3];
QUARTERS.forEach((q, i) => rows.push({ province: 'Hồ Chí Minh', indicator: 'gdp_growth', value: hcmcGdpGrowth[i]!, unit: '%', period: q, source: 'GSO' }));
// CPI (% YoY)
const hcmcCpi = [3.1, 3.3, 3.5, 3.8, 4.0, 3.9, 4.1, 4.2, 3.8, 3.6, 3.5, 3.4];
QUARTERS.forEach((q, i) => rows.push({ province: 'Hồ Chí Minh', indicator: 'cpi', value: hcmcCpi[i]!, unit: '%', period: q, source: 'GSO' }));
// Population (persons, grows slowly)
rows.push(...quarterlySeries('Hồ Chí Minh', 'population', 'người', 'GSO', 9_800_000, 0.003));
// Construction permits (number per quarter)
const hcmcPermits = [1250, 1380, 1420, 1510, 1320, 1460, 1550, 1620, 1480, 1590, 1650, 1720];
QUARTERS.forEach((q, i) => rows.push({ province: 'Hồ Chí Minh', indicator: 'construction_permits', value: hcmcPermits[i]!, unit: 'giấy phép', period: q, source: 'Sở Xây dựng TP.HCM' }));
// FDI (million USD per quarter)
const hcmcFdi = [1650, 1800, 1920, 2050, 1780, 1950, 2100, 2200, 1900, 2080, 2150, 2300];
QUARTERS.forEach((q, i) => rows.push({ province: 'Hồ Chí Minh', indicator: 'fdi', value: hcmcFdi[i]!, unit: 'triệu USD', period: q, source: 'GSO' }));
// RE transaction volume (number of transactions per quarter)
const hcmcTxVol = [8500, 9200, 10100, 11500, 9800, 10500, 11200, 12800, 10200, 11000, 11800, 13500];
QUARTERS.forEach((q, i) => rows.push({ province: 'Hồ Chí Minh', indicator: 're_transaction_volume', value: hcmcTxVol[i]!, unit: 'giao dịch', period: q, source: 'Sở Xây dựng TP.HCM' }));
// ── Hà Nội ────────────────────────────────────────────────
// GDP growth
const hanoiGdpGrowth = [5.2, 5.5, 5.8, 6.0, 5.9, 6.2, 6.5, 6.8, 6.4, 6.7, 6.9, 7.1];
QUARTERS.forEach((q, i) => rows.push({ province: 'Hà Nội', indicator: 'gdp_growth', value: hanoiGdpGrowth[i]!, unit: '%', period: q, source: 'GSO' }));
// CPI
const hanoiCpi = [2.8, 3.0, 3.2, 3.5, 3.7, 3.6, 3.8, 3.9, 3.5, 3.3, 3.2, 3.1];
QUARTERS.forEach((q, i) => rows.push({ province: 'Hà Nội', indicator: 'cpi', value: hanoiCpi[i]!, unit: '%', period: q, source: 'GSO' }));
// Population
rows.push(...quarterlySeries('Hà Nội', 'population', 'người', 'GSO', 8_400_000, 0.0025));
// Construction permits
const hanoiPermits = [980, 1050, 1120, 1200, 1060, 1150, 1230, 1310, 1180, 1260, 1340, 1420];
QUARTERS.forEach((q, i) => rows.push({ province: 'Hà Nội', indicator: 'construction_permits', value: hanoiPermits[i]!, unit: 'giấy phép', period: q, source: 'Sở Xây dựng Hà Nội' }));
// FDI
const hanoiFdi = [1400, 1520, 1650, 1750, 1500, 1620, 1780, 1850, 1600, 1730, 1820, 1950];
QUARTERS.forEach((q, i) => rows.push({ province: 'Hà Nội', indicator: 'fdi', value: hanoiFdi[i]!, unit: 'triệu USD', period: q, source: 'GSO' }));
// RE transaction volume
const hanoiTxVol = [7200, 7800, 8500, 9600, 8100, 8800, 9500, 10800, 8600, 9300, 10000, 11200];
QUARTERS.forEach((q, i) => rows.push({ province: 'Hà Nội', indicator: 're_transaction_volume', value: hanoiTxVol[i]!, unit: 'giao dịch', period: q, source: 'Sở Xây dựng Hà Nội' }));
return rows;
}
// =============================================================================
// InfrastructureProject — 15 real projects with coordinates
// =============================================================================
interface InfraRow {
name: string;
province: string;
category: string;
status: string;
investmentVND: bigint;
startDate: Date | null;
completionDate: Date | null;
description: string;
impactRadius: number;
lat: number;
lng: number;
}
function buildInfraProjects(): InfraRow[] {
return [
// 1. Metro Line 1 (Bến Thành Suối Tiên)
{
name: 'Metro Bến Thành Suối Tiên (Tuyến 1)',
province: 'Hồ Chí Minh',
category: 'metro',
status: 'completed',
investmentVND: BigInt(43_700_000_000_000),
startDate: new Date('2012-08-28'),
completionDate: new Date('2024-12-22'),
description: 'Tuyến metro đầu tiên TP.HCM, 19.7km, 14 ga. Kết nối Quận 1 Thủ Đức Bình Dương.',
impactRadius: 3.0,
lat: 10.7721,
lng: 106.6980,
},
// 2. Metro Line 2 (Bến Thành Tham Lương)
{
name: 'Metro Bến Thành Tham Lương (Tuyến 2)',
province: 'Hồ Chí Minh',
category: 'metro',
status: 'planning',
investmentVND: BigInt(47_800_000_000_000),
startDate: new Date('2026-06-01'),
completionDate: new Date('2032-12-01'),
description: 'Tuyến metro số 2, 11.3km, 10 ga. Kết nối trung tâm đến Tân Bình, Q12.',
impactRadius: 2.5,
lat: 10.7731,
lng: 106.6930,
},
// 3. Thu Duc Innovation District (Khu đô thị sáng tạo Thủ Đức)
{
name: 'Khu Đô thị Sáng tạo Tương tác cao phía Đông (Thủ Đức)',
province: 'Hồ Chí Minh',
category: 'urban_development',
status: 'under_construction',
investmentVND: BigInt(300_000_000_000_000),
startDate: new Date('2020-01-01'),
completionDate: new Date('2040-12-01'),
description: 'Siêu dự án đô thị sáng tạo 21,172ha tại TP. Thủ Đức, gồm khu công nghệ cao, tài chính, giáo dục.',
impactRadius: 10.0,
lat: 10.8231,
lng: 106.7620,
},
// 4. Ring Road 3 (Vành đai 3 TP.HCM)
{
name: 'Đường Vành đai 3 TP.HCM',
province: 'Hồ Chí Minh',
category: 'highway',
status: 'under_construction',
investmentVND: BigInt(75_400_000_000_000),
startDate: new Date('2023-06-18'),
completionDate: new Date('2026-12-01'),
description: 'Tuyến vành đai 76km qua TP.HCM, Bình Dương, Đồng Nai, Long An. 4-8 làn xe.',
impactRadius: 5.0,
lat: 10.8500,
lng: 106.7800,
},
// 5. Long Thanh International Airport — Phase 1
{
name: 'Cảng Hàng không Quốc tế Long Thành Giai đoạn 1',
province: 'Đồng Nai',
category: 'airport',
status: 'under_construction',
investmentVND: BigInt(109_000_000_000_000),
startDate: new Date('2021-01-05'),
completionDate: new Date('2026-12-01'),
description: 'Sân bay quốc tế mới, công suất 25 triệu HK/năm (GĐ1), 100 triệu HK/năm (hoàn thành).',
impactRadius: 15.0,
lat: 10.9730,
lng: 107.0070,
},
// 6. Can Gio Bridge (Cầu Cần Giờ)
{
name: 'Cầu Cần Giờ',
province: 'Hồ Chí Minh',
category: 'bridge',
status: 'planning',
investmentVND: BigInt(10_000_000_000_000),
startDate: new Date('2025-12-01'),
completionDate: new Date('2028-12-01'),
description: 'Cầu dây văng nối Nhà Bè Cần Giờ, dài ~3.4km, rộng 6 làn xe. Mở khóa tiềm năng du lịch & BĐS Cần Giờ.',
impactRadius: 8.0,
lat: 10.6190,
lng: 106.7530,
},
// 7. Cao tốc TP.HCM Long Thành Dầu Giây (mở rộng)
{
name: 'Cao tốc TP.HCM Long Thành Dầu Giây (mở rộng)',
province: 'Hồ Chí Minh',
category: 'highway',
status: 'under_construction',
investmentVND: BigInt(9_000_000_000_000),
startDate: new Date('2024-03-01'),
completionDate: new Date('2027-06-01'),
description: 'Mở rộng từ 4 lên 8-10 làn xe, 55km. Giảm ùn tắc kết nối sân bay Long Thành.',
impactRadius: 4.0,
lat: 10.8350,
lng: 106.8600,
},
// 8. Cao tốc Bến Lức Long Thành
{
name: 'Cao tốc Bến Lức Long Thành',
province: 'Đồng Nai',
category: 'highway',
status: 'under_construction',
investmentVND: BigInt(31_300_000_000_000),
startDate: new Date('2014-07-01'),
completionDate: new Date('2026-09-01'),
description: 'Tuyến cao tốc 57.8km kết nối Long An TP.HCM Đồng Nai, vượt sông Sài Gòn.',
impactRadius: 5.0,
lat: 10.7200,
lng: 106.8500,
},
// 9. Metro Line 3 Hà Nội (Nhổn Ga Hà Nội)
{
name: 'Metro Nhổn Ga Hà Nội (Tuyến 3)',
province: 'Hà Nội',
category: 'metro',
status: 'under_construction',
investmentVND: BigInt(34_800_000_000_000),
startDate: new Date('2010-09-01'),
completionDate: new Date('2027-12-01'),
description: 'Tuyến metro 12.5km, 12 ga, kết nối Nhổn Cầu Giấy ga Hà Nội.',
impactRadius: 2.5,
lat: 21.0285,
lng: 105.8542,
},
// 10. Metro Line 2A Hà Nội (Cát Linh Hà Đông)
{
name: 'Metro Cát Linh Hà Đông (Tuyến 2A)',
province: 'Hà Nội',
category: 'metro',
status: 'completed',
investmentVND: BigInt(18_000_000_000_000),
startDate: new Date('2011-10-10'),
completionDate: new Date('2021-11-06'),
description: 'Tuyến đường sắt trên cao đầu tiên Hà Nội, 13.1km, 12 ga.',
impactRadius: 2.0,
lat: 21.0033,
lng: 105.8245,
},
// 11. Vành đai 4 Hà Nội
{
name: 'Đường Vành đai 4 Vùng Thủ đô Hà Nội',
province: 'Hà Nội',
category: 'highway',
status: 'under_construction',
investmentVND: BigInt(85_800_000_000_000),
startDate: new Date('2023-06-25'),
completionDate: new Date('2027-12-01'),
description: 'Tuyến vành đai 112km qua Hà Nội, Hưng Yên, Bắc Ninh. 6 làn cao tốc.',
impactRadius: 6.0,
lat: 21.0500,
lng: 105.9000,
},
// 12. Sân bay Tân Sơn Nhất Nhà ga T3
{
name: 'Nhà ga T3 Sân bay Tân Sơn Nhất',
province: 'Hồ Chí Minh',
category: 'airport',
status: 'under_construction',
investmentVND: BigInt(10_990_000_000_000),
startDate: new Date('2022-12-01'),
completionDate: new Date('2025-04-30'),
description: 'Nhà ga hành khách T3, công suất 20 triệu HK/năm, nâng tổng công suất TSN lên 50 triệu.',
impactRadius: 5.0,
lat: 10.8188,
lng: 106.6590,
},
// 13. Cảng trung chuyển quốc tế Cần Giờ
{
name: 'Cảng Trung chuyển Quốc tế Cần Giờ',
province: 'Hồ Chí Minh',
category: 'port',
status: 'planning',
investmentVND: BigInt(113_000_000_000_000),
startDate: new Date('2025-06-01'),
completionDate: new Date('2035-12-01'),
description: 'Siêu cảng trung chuyển container quốc tế tại Cần Giờ, công suất 10-15 triệu TEU/năm.',
impactRadius: 12.0,
lat: 10.4110,
lng: 106.9480,
},
// 14. Đường sắt tốc độ cao Bắc Nam (GĐ1)
{
name: 'Đường sắt Tốc độ cao Bắc Nam (Giai đoạn 1)',
province: 'Hà Nội',
category: 'railway',
status: 'planning',
investmentVND: BigInt(670_000_000_000_000),
startDate: new Date('2027-01-01'),
completionDate: new Date('2035-12-01'),
description: 'Đoạn Hà Nội Vinh & Nha Trang TP.HCM, tốc độ thiết kế 350km/h.',
impactRadius: 10.0,
lat: 21.0028,
lng: 105.8440,
},
// 15. Cao tốc Mỹ Phước Tân Vạn (mở rộng)
{
name: 'Cao tốc Mỹ Phước Tân Vạn (mở rộng)',
province: 'Bình Dương',
category: 'highway',
status: 'under_construction',
investmentVND: BigInt(4_500_000_000_000),
startDate: new Date('2023-09-01'),
completionDate: new Date('2026-06-01'),
description: 'Mở rộng kết nối các KCN Bình Dương với TP.HCM, từ 4 lên 8 làn xe.',
impactRadius: 3.0,
lat: 10.9800,
lng: 106.6530,
},
];
}
// =============================================================================
// Public seed function
// =============================================================================
export async function seedMacroAndInfra(prisma: PrismaClient) {
console.log('📈 Seeding macroeconomic data...');
const macroData = buildMacroData();
for (const d of macroData) {
await prisma.macroeconomicData.upsert({
where: {
province_indicator_period: {
province: d.province,
indicator: d.indicator,
period: d.period,
},
},
create: d,
update: { value: d.value, unit: d.unit, source: d.source },
});
}
console.log(`${macroData.length} macroeconomic data points seeded (HCMC + Hanoi, quarterly 20232025)`);
console.log('🏗️ Seeding infrastructure projects...');
const infraProjects = buildInfraProjects();
for (const p of infraProjects) {
const existing = await prisma.infrastructureProject.findFirst({
where: { name: p.name, province: p.province },
});
if (existing) {
// Update existing record with coordinates and dates if missing
await prisma.$executeRaw`
UPDATE "InfrastructureProject"
SET "status" = ${p.status},
"investmentVND" = ${p.investmentVND},
"startDate" = ${p.startDate},
"completionDate" = ${p.completionDate},
"description" = ${p.description},
"impactRadius" = ${p.impactRadius},
"location" = ST_SetSRID(ST_MakePoint(${p.lng}, ${p.lat}), 4326),
"updatedAt" = NOW()
WHERE "id" = ${existing.id}
`;
} else {
await prisma.$executeRaw`
INSERT INTO "InfrastructureProject" (
"id", "name", "province", "category", "status",
"investmentVND", "startDate", "completionDate",
"description", "impactRadius", "location",
"createdAt", "updatedAt"
) VALUES (
gen_random_uuid(), ${p.name}, ${p.province}, ${p.category}, ${p.status},
${p.investmentVND}, ${p.startDate}, ${p.completionDate},
${p.description}, ${p.impactRadius},
ST_SetSRID(ST_MakePoint(${p.lng}, ${p.lat}), 4326),
NOW(), NOW()
)
`;
}
}
console.log(`${infraProjects.length} infrastructure projects seeded (with coordinates)`);
}