Frontend Architecture
This guide covers the frontend architecture of OpenRegister, including the Vue.js component structure, state management with Pinia, and the application initialization system.
Technology Stack
- Framework: Vue.js 2 (Options API)
- State Management: Pinia
- UI Components: Nextcloud Vue Components
- Icons: Material Design Icons (MDI)
- Build Tool: Webpack
- Language: JavaScript/TypeScript
Application Initialization
OpenRegister implements a centralized initialization system to hot-load essential application data at startup. This ensures that frequently used data is immediately available without requiring API calls when modals or components open.
Hot-Loading System
The initialization system pre-loads commonly used entities into their respective Pinia stores when the application starts. This eliminates loading delays when users interact with features like the Configuration modal, where organisations and applications are needed immediately.
Architecture Diagram
Hot-Loaded Entities
The following entities are hot-loaded at application startup:
Core Entities:
- Registers: Database register definitions
- Schemas: JSON schema definitions for data validation
Configuration Dependencies:
- Organisations: Organisation entities for multi-tenancy
- Applications: Application entities for access control
Extended Entities:
- Views: Custom view definitions
- Agents: AI agent configurations
- Sources: External data source connections
Implementation
Service Location
The initialization logic is centralized in:
src/services/AppInitializationService.js
Key Functions
initializeAppData()
The main initialization function that loads all essential data in parallel:
export async function initializeAppData() {
console.log('[AppInit] Starting application data initialization...')
const startTime = performance.now()
try {
// Load all essential data in parallel for maximum performance
await Promise.all([
// Core entities
loadRegisters(),
loadSchemas(),
// Configuration dependencies
loadOrganisations(),
loadApplications(),
// Extended entities
loadViews(),
loadAgents(),
loadSources(),
])
const endTime = performance.now()
console.log('[AppInit] ✓ All data loaded successfully in ' + Math.round(endTime - startTime) + 'ms')
} catch (error) {
console.error('[AppInit] ✗ Error during initialization:', error)
// Don't throw - allow app to continue even if some data fails to load
}
}
reloadAppData()
Forces a refresh of all hot-loaded data. This is called when switching organisations:
export async function reloadAppData() {
console.log('[AppInit] Reloading all application data...')
const startTime = performance.now()
try {
// Force reload all data in parallel
await Promise.all([
forceLoadRegisters(),
forceLoadSchemas(),
forceLoadOrganisations(),
forceLoadApplications(),
forceLoadViews(),
forceLoadAgents(),
forceLoadSources(),
])
const endTime = performance.now()
console.log('[AppInit] ✓ All data reloaded successfully in ' + Math.round(endTime - startTime) + 'ms')
} catch (error) {
console.error('[AppInit] ✗ Error during reload:', error)
}
}
Application Integration
The initialization is triggered in 'App.vue' when the application mounts:
// src/App.vue
import { initializeAppData } from './services/AppInitializationService.js'
export default {
name: 'App',
mounted() {
// Initialize hot-loading of essential application data
// This loads registers, schemas, organisations, applications, views, agents, and sources
initializeAppData()
// Set up dashboard store watchers
setupDashboardStoreWatchers()
},
}
Organisation Switching Integration
When a user switches organisations, all data is reloaded to reflect the new organisational context:
// src/views/organisation/OrganisationsIndex.vue
import { reloadAppData } from '../../services/AppInitializationService.js'
async setActiveOrganisation(uuid) {
try {
await organisationStore.setActiveOrganisationById(uuid)
this.showSuccessMessage('Active organisation changed successfully')
// Reload all hot-loaded data for the new organisation context
console.log('[OrganisationsIndex] Reloading application data after organisation switch...')
await reloadAppData()
} catch (error) {
this.showErrorMessage('Failed to change active organisation: ' + error.message)
}
}
Performance Benefits
Before Hot-Loading
When a user opened the Configuration modal:
- Modal opens
- Shows loading state
- Fetches organisations (500-2000ms)
- Fetches applications (500-2000ms)
- Modal becomes interactive (1000-4000ms total delay)