# App Data Flow Documentation This document explains the complete data flow architecture of the Enterprise Asset Management application, using the Assets view as an example. ## 📊 Data Flow Architecture Overview ``` Assets View → Assets Store → Asset Repository → Base Repository → Directus API → Database ↓ ↓ ↓ ↓ ↓ ↓ User UI State Mgmt Business Logic HTTP Client REST API PostgreSQL ``` ## 🔄 Step-by-Step Data Journey ### **Step 1: User Navigates to Assets View** **File:** `/frontend/src/views/Assets.vue` ```javascript // When component mounts onMounted(async () => { uiStore.setPageTitle('Assets'); await loadData(); // This starts the data flow }); ``` ### **Step 2: View Calls the Assets Store** **File:** `/frontend/src/views/Assets.vue` → Lines 427-429 ```javascript const loadData = async () => { // Authentication happens first await authService.ensureAuthenticated(); // Then data loading begins await assetsStore.fetchAssets(); // 🎯 This starts the chain await assetsStore.fetchCategories(); await assetsStore.fetchLocations(); }; ``` ### **Step 3: Assets Store Coordinates the Request** **File:** `/frontend/src/stores/assets.js` → Lines 85-105 ```javascript async fetchAssets(params = {}) { this.isLoading = true; // 📊 Update UI state this.error = null; try { const queryParams = { page: this.pagination.page, limit: this.pagination.limit, ...params, }; // 🔗 Delegate to repository layer const response = await assetRepository.getAll(queryParams); // 📦 Store data in state this.assets = response.data || []; this.pagination.total = response.meta?.total_count || 0; } catch (error) { this.error = error.message; throw error; } finally { this.isLoading = false; // 📊 Update UI state } } ``` **🎯 Store Responsibilities:** - **State Management** - Holds assets data in reactive state - **Loading States** - Manages `isLoading`, `error` flags - **Pagination** - Tracks page, limit, total count - **Cache Invalidation** - Calls cache service when data changes - **Error Handling** - Catches and stores error messages ### **Step 4: Asset Repository Adds Business Logic** **File:** `/frontend/src/repositories/AssetRepository.js` → Lines 9-30 ```javascript async getAll(params = {}) { try { const searchParams = { ...params, // 🔗 Define what related data to fetch fields: [ '*', // All asset fields 'category_id.id', // Category relationship 'category_id.name', 'category_id.color', 'location_id.id', // Location relationship 'location_id.name', 'location_id.building', 'location_id.floor', 'vendor_id.id', // Vendor relationship 'vendor_id.name', ], }; // 🔗 Delegate to base repository return await super.getAll(searchParams); } catch (error) { throw this.handleError(error); } } ``` **🎯 Repository Responsibilities:** - **Business Logic** - Asset-specific query parameters - **Relationship Mapping** - Define what related data to fetch - **Error Transformation** - Convert API errors to user-friendly messages - **QR Code Generation** - Asset-specific features - **Data Validation** - Business rule enforcement ### **Step 5: Base Repository Handles HTTP Communication** **File:** `/frontend/src/repositories/BaseRepository.js` → Lines 10-18 ```javascript async getAll(params = {}) { try { // 🌐 Make HTTP request to Directus API const response = await this.api.get(`/items/${this.collection}`, { params, // Query parameters (fields, filters, pagination) }); return response.data; // Return Directus response } catch (error) { throw this.handleError(error); } } ``` **🎯 Base Repository Responsibilities:** - **HTTP Communication** - Axios-based API calls - **URL Construction** - Build REST endpoints (`/items/assets`) - **Parameter Serialization** - Convert objects to query strings - **Response Handling** - Extract data from HTTP responses - **Generic CRUD** - Reusable create, read, update, delete operations ### **Step 6: Directus Service Manages Authentication** **File:** `/frontend/src/services/directus.js` → Lines 15-27 ```javascript // Request interceptor adds auth token directusApi.interceptors.request.use( (config) => { const token = localStorage.getItem('directus_token'); if (token) { config.headers.Authorization = `Bearer ${token}`; // 🔐 Add auth } return config; } ); ``` **🎯 Directus Service Responsibilities:** - **Authentication** - Add Bearer tokens to requests - **Token Refresh** - Automatic token renewal - **Base URL Configuration** - API endpoint setup - **Request/Response Interceptors** - Global middleware - **Development Auto-auth** - Seamless development experience ### **Step 7: HTTP Request to Directus API** ```http GET http://localhost:8055/items/assets?fields=*,category_id.id,category_id.name,category_id.color,location_id.id,location_id.name,location_id.building,location_id.floor,vendor_id.id,vendor_id.name Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ``` ### **Step 8: Directus Queries PostgreSQL Database** **Database Schema:** From `/schema/init.sql` ```sql -- Directus executes this SQL query SELECT a.*, c.id as "category_id.id", c.name as "category_id.name", c.color as "category_id.color", l.id as "location_id.id", l.name as "location_id.name", l.building as "location_id.building", l.floor as "location_id.floor", v.id as "vendor_id.id", v.name as "vendor_id.name" FROM assets a LEFT JOIN asset_categories c ON a.category_id = c.id LEFT JOIN locations l ON a.location_id = l.id LEFT JOIN vendors v ON a.vendor_id = v.id WHERE a.organization_id = '70562576-ac3e-4d84-b3a6-6d0d52b8cc10'; ``` ### **Step 9: Database Returns Raw Data** ```json { "data": [ { "id": "cd89112d-510d-4f02-acb2-bdcd6242cd2d", "name": "Frontend Test Laptop", "asset_identifier": "TEST-FRONTEND-1752412612", "status": "active", "acquisition_cost": "1200.00", "category_id": { "id": "4a607979-0b7c-4f04-b42a-f78616922312", "name": "Office Furniture", "color": "#4CAF50" }, "location_id": { "id": "0ead8a26-b691-45a5-be55-2ad5143f078e", "name": "Conference Room", "building": "Building A" } } ] } ``` ### **Step 10: Data Flows Back Through the Chain** ```javascript // BaseRepository receives HTTP response response.data ← HTTP Response // AssetRepository receives structured data return response.data ← BaseRepository // Store receives and processes data this.assets = response.data || [] ← AssetRepository // Vue reactive system triggers re-render assets.value ← Store (Pinia reactive state) ``` ### **Step 11: Assets View Processes Data for Display** **File:** `/frontend/src/views/Assets.vue` → Lines 333-362 ```javascript const displayedAssets = computed(() => { // 🔄 Transform raw data for UI display let filtered = assets.value.map(asset => ({ ...asset, // Extract nested relationship data for display category: asset.category_id?.name || 'Unknown', category_color: asset.category_id?.color || '#9E9E9E', location: asset.location_id ? `${asset.location_id.name}${asset.location_id.building ? ` - ${asset.location_id.building}` : ''}` : 'Unknown' })); // Apply filters (search, category, status) if (search.value) { const searchTerm = search.value.toLowerCase(); filtered = filtered.filter(asset => asset.name.toLowerCase().includes(searchTerm) || asset.asset_identifier.toLowerCase().includes(searchTerm) ); } return filtered; }); ``` ### **Step 12: Vue Renders the Data** **File:** `/frontend/src/views/Assets.vue` → Lines 104-113 ```vue :key="asset.id" cols="12" sm="6" md="4" lg="3" > ``` ## 🎯 Role Summary of Each Layer ### **1. 📄 Views/Components (Presentation Layer)** - **User Interface** - Display data and handle user interactions - **Event Handling** - Respond to clicks, form submissions - **Data Transformation** - Format data for display (dates, currency, etc.) - **Loading States** - Show spinners, empty states, errors ### **2. 🗂️ Stores (State Management Layer)** - **Global State** - Hold application data accessible across components - **Reactivity** - Trigger UI updates when data changes - **Caching** - Avoid redundant API calls - **State Coordination** - Manage loading, error, and success states ### **3. 🏢 Repositories (Business Logic Layer)** - **Domain Logic** - Asset-specific business rules and operations - **Data Mapping** - Transform between API and application models - **Relationship Handling** - Define what related data to fetch - **Validation** - Ensure data integrity and business rules ### **4. ⚡ Base Repository (Infrastructure Layer)** - **HTTP Communication** - Generic REST API operations - **Error Handling** - Convert HTTP errors to application errors - **Request Configuration** - Headers, timeouts, interceptors - **Response Processing** - Extract data from HTTP responses ### **5. 🔐 Services (Cross-Cutting Concerns)** - **Authentication** - Token management and security - **Caching** - Performance optimization - **Permissions** - Access control - **Configuration** - Environment-specific settings ## 📁 File Structure Reference ``` enterprise-asset-management/ ├── frontend/ │ ├── src/ │ │ ├── views/ │ │ │ ├── Assets.vue # 📄 Presentation Layer │ │ │ ├── AddAsset.vue │ │ │ └── EditAsset.vue │ │ ├── stores/ │ │ │ ├── assets.js # 🗂️ State Management │ │ │ ├── ui.js │ │ │ └── auth.js │ │ ├── repositories/ │ │ │ ├── BaseRepository.js # ⚡ Infrastructure Layer │ │ │ ├── AssetRepository.js # 🏢 Business Logic │ │ │ └── AuthRepository.js │ │ ├── services/ │ │ │ ├── directus.js # 🔐 API Service │ │ │ ├── auth.js # 🔐 Auth Service │ │ │ ├── permissions.js # 🔐 Permission Service │ │ │ └── cache.js # 🔐 Cache Service │ │ └── components/ │ │ └── assets/ │ │ ├── AssetForm.vue # 📄 Reusable Component │ │ └── AssetCard.vue ├── schema/ │ └── init.sql # 🗄️ Database Schema └── scripts/ ├── setup-permissions-enhanced.sh # 🔧 Permission Setup └── verify-permissions.sh # 🔧 Permission Verification ``` ## 🔄 Data Flow Patterns ### **Create Asset Flow** ``` AssetForm → emit('submit') → AddAsset.vue → assetsStore.createAsset() → AssetRepository.create() → BaseRepository.create() → POST /items/assets → Database INSERT → Success Response → Cache Invalidation → UI Update ``` ### **Update Asset Flow** ``` AssetForm → emit('submit') → EditAsset.vue → assetsStore.updateAsset() → AssetRepository.update() → BaseRepository.update() → PATCH /items/assets/{id} → Database UPDATE → Success Response → Cache Invalidation → UI Update ``` ### **Authentication Flow** ``` View → authService.ensureAuthenticated() → Check localStorage token → If expired: authService.refreshToken() → directusApi interceptor → Add Bearer token to request headers → Continue with API call ``` This architecture provides **separation of concerns**, **testability**, **maintainability**, and **scalability** for the asset management application!