Architecture
Component Hierarchy
graph TD
DMP[DataManagementPage.vue<br/>233 lines] --> NH[NavigationHeader<br/>organisms/backoffice]
DMP --> YS[Year Selection Card]
DMP --> MC[ModuleConfig × N<br/>organisms]
DMP --> ROS[ReductionObjectivesSection<br/>organisms<br/>463 lines]
YS --> YS1[Year Selector Dropdown]
YS --> YS2[Sync Units Button]
YS --> YC[Create Year Card<br/>when no config]
MC --> MCS[ModuleConfigSection<br/>molecules]
MC --> MUS[ModuleUploadsSection<br/>molecules]
MC --> MRD[ModuleRecalculationDialog<br/>molecules]
MC --> SC[SubmoduleConfig<br/>organisms<br/>43 lines]
MC --> DED[DataEntryDialog<br/>organisms<br/>36 lines]
MUS --> UC[UploadCard × 3<br/>molecules]
MUS --> SI[SubmoduleItem<br/>molecules]
UC --> UC1[UploadCardData]
UC --> UC2[UploadCardFactors]
UC --> UC3[UploadCardReferences]
DED --> DEDC[DataEntryDialogContent<br/>molecules<br/>270 lines]
ROS --> DED2[DataEntryDialog<br/>for reduction objectives]
Component Summary
| Type | Component | Lines | Responsibility |
| Organism | DataManagementPage.vue | 233 | Page root: year selection, module iteration, dialog orchestration |
| Organism | ModuleConfig.vue | 198 | Single module: expansion item with config, uploads, submodules |
| Organism | SubmoduleConfig.vue | 43 | Renders submodule list within a module |
| Organism | DataEntryDialog.vue | 36 | Thin wrapper around DataEntryDialogContent |
| Organism | ReductionObjectivesSection.vue | 463 | Reduction objectives: file uploads + 3 goal slots |
| Molecule | ModuleConfigSection.vue | 101 | Module enable/disable, uncertainty tagging |
| Molecule | ModuleUploadsSection.vue | 121 | Upload cards + recalculation triggers |
| Molecule | DataEntryDialogContent.vue | 270 | CSV upload, API connection, copy logic |
| Molecule | SubmoduleItem.vue | 250 | Individual submodule row with status |
| Molecule | ModuleRecalculationDialog.vue | 86 | Module-wide recalculation confirmation |
| Molecule | ComputedFactorDialog.vue | 57 | Computed factor regeneration dialog |
| Molecule | UploadCard.vue | 278 | Base upload card with download, cancel, status |
| Molecule | UploadCardData.vue | 66 | Data upload (CSV / API / copy) |
| Molecule | UploadCardFactors.vue | 89 | Factor upload (CSV / computed) |
| Molecule | UploadCardReferences.vue | 408 | Self-contained reference data upload with SSE + cancel |
Composables
graph LR
subgraph Composables
UDED[useDataEntryDialog.ts<br/>347 lines]
UMC[useModuleConfig.ts<br/>177 lines]
UREC[useRecalculation.ts<br/>200 lines]
USC[useSubmoduleConfig.ts<br/>253 lines]
end
UDED --> FS[Files Store]
UDED --> BDM[BackofficeDataManagement Store]
UMC --> YCS[YearConfig Store]
UREC --> BDM
USC --> YCS
| Composable | Lines | Responsibility |
useDataEntryDialog.ts | 347 | CSV upload, API connection, previous year copy, SSE job monitoring |
useModuleConfig.ts | 177 | Module enable/disable, uncertainty management, job status lookup |
useRecalculation.ts | 200 | Recalculation status tracking, trigger module/type recalculation |
useSubmoduleConfig.ts | 253 | Submodule enable/disable, threshold configuration |
Stores
useBackofficeDataManagement
classDiagram
class useBackofficeDataManagement {
+loading: boolean
+error: string|null
+syncJobs: Record~year, DataIngestionJob[]~
+currentYear: number|null
+sseConnection: EventSource|null
+fetchSyncJobsByYear(year)
+fetchLatestSyncJobsByYear(year)
+initiateSync(params)
+initiateComputedFactorSync(moduleTypeId, dataEntryTypeId, year)
+initiateEmissionRecalculation(moduleTypeId, dataEntryTypeId, year)
+initiateModuleEmissionRecalculation(moduleTypeId, year, onlyStale)
+subscribeToJobUpdates(jobId, callbacks)
+cancelJob(jobId, year)
+syncUnitsFromAccred(targetYear)
+getPreviousYearSuccessfulJobs(year, moduleTypeId, targetType)
+getSyncStatusByModule(moduleType, year): number
+getSyncResultByModule(moduleType, year): number
+getSuccessRate(job): number
+isJobFinished(moduleType, year): boolean
+hasJobSucceeded(moduleType, year): boolean
}
useYearConfigStore
classDiagram
class useYearConfigStore {
+config: YearConfigurationResponse|null
+loading: boolean
+notFound: boolean
+fetchConfig(year)
+createConfig(year, payload)
+updateConfig(year, payload)
+unifiedModuleConfig: Record~string, UnifiedModuleConfig~
+visibleModules: Module[]
+anyModuleIncomplete: boolean
+getModule(moduleName): UnifiedModuleConfig|null
+getSubmodule(moduleName, subKey): UnifiedSubmoduleConfig|null
+isModuleVisible(module): boolean
+isSubmoduleVisible(module, subKey): boolean
+isModuleIncomplete(module): boolean
+isSubmoduleIncomplete(sub): boolean
}
File Structure
frontend/src/
├── pages/back-office/
│ └── DataManagementPage.vue # Page root (233 lines)
├── components/
│ ├── organisms/data-management/
│ │ ├── ModuleConfig.vue
│ │ ├── SubmoduleConfig.vue
│ │ ├── DataEntryDialog.vue
│ │ └── ReductionObjectivesSection.vue
│ └── molecules/data-management/
│ ├── ModuleConfigSection.vue
│ ├── ModuleUploadsSection.vue
│ ├── DataEntryDialogContent.vue
│ ├── SubmoduleItem.vue
│ ├── ModuleRecalculationDialog.vue
│ ├── ComputedFactorDialog.vue
│ ├── UploadCard.vue
│ ├── UploadCardData.vue
│ ├── UploadCardFactors.vue
│ └── UploadCardReferences.vue
├── composables/
│ ├── useDataEntryDialog.ts
│ ├── useModuleConfig.ts
│ ├── useRecalculation.ts
│ └── useSubmoduleConfig.ts
├── stores/
│ ├── backofficeDataManagement.ts
│ └── yearConfig.ts
├── constant/
│ ├── backoffice-module-config.ts
│ └── modules.ts
└── api/http.ts