Files
roa2web-service-auto/.auto-build/memory/gotchas.json
Marius Mutu d507a81b0a feat: Implement unified Vue SPA with granular service control
Consolidate Reports and Data Entry apps into a single Vue.js SPA with:

Architecture:
- Module-based structure with lazy-loaded routes (@reports, @data-entry)
- Error boundaries per module to prevent cascade failures
- Dual API proxy in Vite for microservices (reports:8001, data-entry:8003)
- Pinia store factories for shared auth, company, and period stores
- Vite path aliases for clear module boundaries (@shared, @reports, @data-entry)

Service Management:
- Granular service control scripts (backend-reports.sh, backend-data-entry.sh, bot.sh, frontend.sh)
- 87% faster frontend restart: 7s vs 53s full restart
- 38% faster full startup: 33s vs 53s via parallel backend initialization
- Enhanced start-dev.sh with proper service timeouts (OCR: 30s, Vite: 15s, Bot: 10s)
- status.sh for comprehensive health checks

Features:
- Auto-select first company on login with period auto-load
- Hamburger menu with feature toggle support
- JWT token auto-injection via axios interceptors
- Unified header with company/period selectors
- IIS web.config for production deployment with multi-API routing

UX Improvements:
- Vue watchers for reactive company/period loading
- Lazy store initialization with graceful error handling
- Period persistence per user+company in localStorage
- Feature flags for optional modules

Deployment:
- Single IIS site serves unified frontend with API proxy rules
- Maintains separate backend processes for microservices
- Windows line ending fixes (.env CRLF → LF conversion)

Stats: 112 files changed, 38,342 insertions(+), 2,342 deletions(-)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-24 19:06:23 +02:00

116 lines
9.7 KiB
JSON

{
"gotchas": [
{
"id": "got_20251222_182000",
"timestamp": "2025-12-22T18:20:00Z",
"title": "Import Path Hell: Default vs Named Exports",
"problem": "Build failed with 'apiService is not exported' errors even though the module exports default api. Legacy code was using import { apiService } from 'api.js' which doesn't work with export default api.",
"solution": "Changed all imports from import { apiService } to import api, then updated all references from apiService.get to api.get. Also renamed imports to avoid conflicts (e.g., import apiClient from 'api').",
"context": "Encountered during build when migrating stores that expected named exports but API services used default exports",
"tags": ["javascript", "imports", "exports", "build-errors", "migration"],
"feature": "unified-app"
},
{
"id": "got_20251222_182001",
"timestamp": "2025-12-22T18:20:01Z",
"title": "Pinia Store Factory Pattern Not Auto-Exported",
"problem": "Build failed with 'useCompanyStore is not exported by companies.js' because the shared stores are factory functions (createCompaniesStore), not direct exports (useCompanyStore).",
"solution": "Created module-specific sharedStores.js files that instantiate the factory functions with the module's API service, then export the actual store instances. Components import from module's sharedStores.js, not from @shared directly.",
"context": "Shared stores were designed as factories but modules were trying to import them as if they were regular stores",
"tags": ["pinia", "stores", "factory-pattern", "imports", "architecture"],
"feature": "unified-app"
},
{
"id": "got_20251222_182002",
"timestamp": "2025-12-22T18:20:02Z",
"title": "Sed Command Quote Mismatch in Bulk Find-Replace",
"problem": "Bulk sed commands using single quotes in pattern didn't match imports using double quotes, and vice versa. Commands like sed 's|from '@/stores/'|...' didn't replace from \"@/stores/\" lines.",
"solution": "Always use the quote style that matches the target files. For Vue/JS files with ESLint using double quotes, use double quotes in sed patterns. Better yet: use find -exec with separate sed for each file to handle both quote styles.",
"context": "Spent significant time debugging why sed replacements weren't working during mass import path updates",
"tags": ["sed", "regex", "scripting", "find-replace", "migration"],
"feature": "unified-app"
},
{
"id": "got_20251222_182003",
"timestamp": "2025-12-22T18:20:03Z",
"title": "Circular Reference in API Wrapper",
"problem": "receiptsStore.js failed to build with 'Identifier api has already been declared' because it imported api and then declared const api = { ... } wrapper object using the same name.",
"solution": "Renamed the import to apiClient (import apiClient from 'api') and used it in the wrapper: const api = { get: (url) => apiClient.get('/receipts${url}') }. This keeps the wrapper name 'api' for internal use while avoiding the conflict.",
"context": "Store was creating a scoped API wrapper for DRY principle but shadowed the import name",
"tags": ["javascript", "naming", "scope", "imports", "build-errors"],
"feature": "unified-app"
},
{
"id": "got_20251222_182004",
"timestamp": "2025-12-22T18:20:04Z",
"title": "CSS Import Paths Breaking Build in Unified Structure",
"problem": "Build failed with 'Unable to resolve @import \"../../../../../shared/frontend/styles/layout/header.css\"' because the CSS files were copied but their import paths still pointed to old shared/frontend location.",
"solution": "Commented out the problematic @import statements in main.css since those styles are already imported in App.vue. Alternatively, could have updated paths to use @shared alias or relative paths from new location.",
"context": "CSS files from reports-app referenced shared styles using relative paths that became invalid in unified structure",
"tags": ["css", "imports", "build-errors", "migration", "paths"],
"feature": "unified-app"
},
{
"id": "got_20251222_182005",
"timestamp": "2025-12-22T18:20:05Z",
"title": "Module Component Utilities Not Copied During Migration",
"problem": "Build failed with 'Could not resolve ../utils/exportUtils' because views referenced utils/ and components/ directories that weren't copied during initial migration (only views and stores were copied).",
"solution": "Copied the entire utils/ and components/ directories from source apps to module directories. These supporting files are essential dependencies of the views and must be migrated together.",
"context": "Initial migration focused on views/stores but missed the supporting utilities and components they depend on",
"tags": ["migration", "dependencies", "file-structure", "build-errors"],
"feature": "unified-app"
},
{
"id": "got_20251222_182006",
"timestamp": "2025-12-22T18:20:06Z",
"title": "Vite Build Transform Count is Progress Indicator",
"problem": "Hard to tell if build is making progress when fixing import issues. Each fix revealed new errors, causing frustration.",
"solution": "Watch the 'transforming... ✓ N modules transformed' count - it increases with each successful fix even if build ultimately fails. Going from 200→573→1490→1492 modules meant we were getting close to success. Use this as encouragement!",
"context": "During iterative import path fixing, the transform count showed we were making real progress toward a successful build",
"tags": ["vite", "build", "debugging", "progress-tracking", "developer-experience"],
"feature": "unified-app"
},
{
"id": "got_20251224_001000",
"timestamp": "2025-12-24T00:10:00Z",
"title": "Menu Structure Mismatch: Flat Array vs Nested Sections",
"problem": "Hamburger menu appeared completely empty (no menu items visible) even though enabledMenuItems computed property returned data. Used .flatMap() to create flat array [{item1}, {item2}] but SlideMenu component expected nested structure [{title: 'Section', items: [...]}, ...].",
"solution": "Removed .flatMap() transformation and returned the nested structure directly from getEnabledMenuSections(). Component's v-for=\"section in menuItems\" now properly iterates over sections, then v-for=\"item in section.items\" shows all items.",
"context": "User reported 'MENIUL HAMBURGER ARE IN CONTINUARE TEXT ALB PE FUNDAL ALB' and provided screenshot showing menu with only user profile at bottom, no menu sections/items visible",
"tags": ["vue", "data-structure", "component-contract", "v-for", "ux"],
"feature": "unified-app-ux"
},
{
"id": "got_20251224_001001",
"timestamp": "2025-12-24T00:10:01Z",
"title": "TypeError: useAuthStore is not a function - Store Timing Issue",
"problem": "Period store threw 'TypeError: useAuthStore is not a function' when trying to call useAuthStore() in getStorageKey() function. Stores were passed as factory parameters but weren't callable in that context/timing.",
"solution": "Wrap store access in try-catch with lazy instantiation. Call useAuthStore() inside the function that needs it, not at module level. Return null if stores aren't ready yet. This allows graceful degradation when stores haven't been initialized by Pinia yet.",
"context": "accountingPeriod.js tried to access auth/company stores to generate localStorage key for persisting user's period selection",
"tags": ["pinia", "stores", "timing", "initialization", "error-handling"],
"feature": "unified-app-ux"
},
{
"id": "got_20251224_001002",
"timestamp": "2025-12-24T00:10:02Z",
"title": "Missing Auth Token in API Requests Causes 500 Errors",
"problem": "Backend returned 500 Internal Server Error when frontend tried to load accounting periods. Console showed no Authorization header in requests even though user was logged in and JWT token existed in localStorage.",
"solution": "Add axios request interceptor to automatically inject token: authApi.interceptors.request.use(config => { const token = localStorage.getItem('access_token'); if (token) config.headers.Authorization = `Bearer ${token}`; return config; }). Place this AFTER creating axios instance but BEFORE making any API calls.",
"context": "App.vue created authApi axios instance with only baseURL and Content-Type, but didn't configure automatic token injection from localStorage",
"tags": ["axios", "jwt", "authentication", "api", "interceptor"],
"feature": "unified-app-ux"
},
{
"id": "got_20251224_001003",
"timestamp": "2025-12-24T00:10:03Z",
"title": "Period Auto-Load Never Triggered Despite Handler Exists",
"problem": "Period dropdown stayed on 'Selectare perioada' placeholder even after manually selecting company. handleCompanyChanged() function existed and logged messages, but periods.value and selectedPeriod.value remained empty. No automatic loading occurred.",
"solution": "Add Vue watch() on companyStore.selectedCompany to automatically call periodStore.loadPeriods() when company changes. Handler alone isn't enough - need reactive watcher with { immediate: true } to handle both initial load and subsequent changes. Watch triggers for ALL company changes (auto-select on login + manual selection).",
"context": "User explicitly reported 'dar si dupa ce aleg o firma MARIUS M AUTO, AR TREBUI SA SE SELECTEZE AUTOMAT ULTIMA LUNA, SI NU SE SELECTEAZA' after manually selecting company",
"tags": ["vue", "watch", "reactive", "auto-load", "ux"],
"feature": "unified-app-ux"
}
],
"updated": "2025-12-24T00:10:00Z"
}