/** * * **Current State:** The `AppController` seeder includes a dynamic regex and fallback system to resolve and assign a `phaseCode` attribute to blocks during block seeding (lines 75-94). * * **Intended Mutation:** Remove the dynamic regex resolution block and `phaseCode` mapping from `mappedBlock` within the `2. BLOCK SEEDING` loop to achieve flat block seeding. * * **Risk Mitigation:** Cross-entity validation is entirely shifted to the `FFB Production` ledger level, making the master block seeder 100% independent. */ import { Controller, Get, Logger, BadRequestException } from '@nestjs/common'; import { AppService } from './app.service'; import { PhaseService } from './site/services/phase.service'; import { BlockService } from './site/services/block.service'; import { FFBProductionService } from './FFB/services/ffb-production.service'; import * as fs from 'fs'; import * as path from 'path'; @Controller() export class AppController { private readonly logger: Logger = new Logger('AppController'); constructor( private readonly service: AppService, private readonly phaseService: PhaseService, private readonly blockService: BlockService, private readonly ffbService: FFBProductionService, ) { } @Get() getHello(): string { return this.service.getHello(); } @Get('seed') async seedSystemData() { this.logger.log('🚀 Starting chronological seeding...'); // Resolve JSON data file locations dynamically relative to process.cwd() const rootDir = process.cwd(); const phaseDataPath = path.resolve(rootDir, '../mongo stuff/PhaseData.json'); const blockDataPath = path.resolve(rootDir, '../mongo stuff/BlockData.json'); const ffbDataPath = path.resolve(rootDir, '../mongo stuff/FFBProductionData.json'); // 1. PHASE SEEDING if (!fs.existsSync(phaseDataPath)) { throw new BadRequestException(`PhaseData.json not found at ${phaseDataPath}`); } const rawPhases = JSON.parse(fs.readFileSync(phaseDataPath, 'utf8')); this.logger.log(`Found ${rawPhases.length} phases to process.`); for (const rawPhase of rawPhases) { try { const mappedPhase = { locId: Number(rawPhase.loc_id), phaseCode: rawPhase.name, description: rawPhase.description, locType: rawPhase.loc_type, }; await this.phaseService.create(mappedPhase); } catch (err) { this.logger.error(`Error inserting Phase ${rawPhase.name}: ${err.message}`); } } console.log('[SEED] Phase collection initialization pass complete.'); // 2. BLOCK SEEDING if (!fs.existsSync(blockDataPath)) { throw new BadRequestException(`BlockData.json not found at ${blockDataPath}`); } const rawBlocks = JSON.parse(fs.readFileSync(blockDataPath, 'utf8')); this.logger.log(`Found ${rawBlocks.length} blocks to process.`); for (const rawBlock of rawBlocks) { try { const mappedBlock = { locId: Number(rawBlock.loc_id), blockCode: rawBlock.blockCode, blockDesc: rawBlock.blockDesc, locType: rawBlock.loc_type, entryNo: Number(rawBlock.entry_no), entryYear: Number(rawBlock.entry_year), quarterPlanted: Number(rawBlock.quater_planted), monthPlanted: rawBlock.month_planted, totalTrees: Number(rawBlock.numOfTreesPlanted), totalMaturedTrees: Number(rawBlock.totalTreeMatured), totalImmaturedTrees: Number(rawBlock.totalTreeImmatured), totalDeadTrees: Number(rawBlock.totalTreeDead), plantedArea: Number(rawBlock.totalPlantedArea), initialPlantedArea: Number(rawBlock.initalPlantedArea), plantedLocUOM: rawBlock.plantedLocUOM, soilCondition: rawBlock.loc_soil_condition, }; await this.blockService.create(mappedBlock); } catch (err) { this.logger.error(`Error inserting Block ${rawBlock.blockCode}: ${err.message}`); } } console.log('[SEED] Block collection initialization pass complete.'); // 3. FFB TRANSACTION INGESTION & VECTOR ENRICHMENT STREAM if (!fs.existsSync(ffbDataPath)) { throw new BadRequestException(`FFBProductionData.json not found at ${ffbDataPath}`); } const rawFfbs = JSON.parse(fs.readFileSync(ffbDataPath, 'utf8')); // Trigger background seeder worker to prevent HTTP timeout this.runBackgroundFfbSeed(rawFfbs); this.logger.log(`[SEED] Ingestion worker spawned for all ${rawFfbs.length} records.`); return { status: 'success', message: `Chronological seeding initiated for ${rawFfbs.length} transaction records in the background. Monitor server logs for live updates.`, }; } private async runBackgroundFfbSeed(records: any[]) { const CHUNK_SIZE = 5; // Adjust down if CPU is weak, up to 10 if using a dedicated GPU const COOL_DOWN_MS = 1000; // 1 second pause between chunks to let the CPU breathe this.logger.log(`[WORKER] Beginning processing matrix for ${records.length} items...`); for (let i = 0; i < records.length; i += CHUNK_SIZE) { const chunk = records.slice(i, i + CHUNK_SIZE); this.logger.log(`[WORKER] Processing batch chunk ${Math.floor(i / CHUNK_SIZE) + 1} of ${Math.ceil(records.length / CHUNK_SIZE)}...`); for (const rawFfb of chunk) { try { const mappedFfb = { productionDate: rawFfb.productionDate ? new Date(rawFfb.productionDate) : new Date('2024-01-01'), prjCode: rawFfb.prj_code, actCode: rawFfb.act_code, actName: rawFfb.act_name, entityCode: rawFfb.entitycode, orgnId: rawFfb.orgn_id ? Number(rawFfb.orgn_id) : 0, orgnCode: rawFfb.orgn_code, orgnFullName: rawFfb.orgn_full_name, orgnAddress: rawFfb.orgn_address, orgnCompRegNo: rawFfb.orgn_comp_reg_no, phaseCode: rawFfb.phaseCode || 'PH01', phaseName: rawFfb.phaseName || 'PHASE 01', phaseDesc: rawFfb.phaseDesc || 'PHASE 01', blockCode: rawFfb.blockCode, blockName: rawFfb.blockName || null, blockDesc: rawFfb.blockDesc || null, truckNo: rawFfb.truck_no, millNo: rawFfb.mill_no, actEntryNo: rawFfb.act_entry_no ? Number(rawFfb.act_entry_no) : 0, actRound: rawFfb.act_round ? Number(rawFfb.act_round) : 0, weightChitNo: rawFfb.weight_chit_no, ownNetWeight: rawFfb.own_net_weight ? Number(rawFfb.own_net_weight) : null, netWeight: rawFfb.net_weight ? Number(rawFfb.net_weight) : 0, actUom: rawFfb.act_uom, noOfBunches: rawFfb.no_of_bunches ? Number(rawFfb.no_of_bunches) : 0, qtyUom: rawFfb.qty_uom, docActQty: rawFfb.doc_act_qty ? Number(rawFfb.doc_act_qty) : 0, locArea: rawFfb.loc_area ? Number(rawFfb.loc_area) : 0, locUom: rawFfb.loc_uom, budgetedFfb: rawFfb.budgeted_ffb ? Number(rawFfb.budgeted_ffb) : null, remarks: rawFfb.remarks || '', issues: rawFfb.issues || null, }; await this.ffbService.create(mappedFfb); } catch (err) { this.logger.error(`[WORKER ERROR] Step failed for record entry: ${err.message}`); } } // Enforce the event-loop cool down period if (i + CHUNK_SIZE < records.length) { await new Promise(resolve => setTimeout(resolve, COOL_DOWN_MS)); } } this.logger.log(`[WORKER] ✅ SUCCESS! Full ledger dataset vectorization and seeder run complete.`); } }