Files
portfolio/.planning/codebase/ARCHITECTURE.md
T
2026-04-07 22:47:51 +02:00

8.9 KiB

Architecture

Analysis Date: 2026-04-07

Pattern Overview

Overall: Vue 3 SPA (Single Page Application) with component-based architecture and SSR-friendly design patterns

Key Characteristics:

  • Client-side routing with lazy-loaded views for performance optimization
  • Composition API-based composables for shared logic and state management
  • Global state managed via Pinia stores
  • Multi-language support with vue-i18n
  • Theme switching with localStorage persistence
  • SEO-optimized with dynamic meta tags and structured data
  • Google Analytics and GTM integration for tracking

Layers

Presentation Layer (Components):

  • Purpose: Render UI and handle user interactions
  • Location: src/components/
  • Contains: Vue Single File Components organized by domain (layout, sections, shared, testimonials, icons)
  • Depends on: Composables for data access and side effects, Router for navigation
  • Used by: Views and other components

View Layer (Pages):

  • Purpose: Page-level component assembly and routing targets
  • Location: src/views/
  • Contains: Full page components (HomePage, ProjectsPage, ContactPage, AboutPage, FiverrPage, FormationPage, ProjectDetailPage)
  • Depends on: Composables (useSeo, useI18n, useProjects), components, data stores
  • Used by: Router for navigation

Business Logic Layer (Composables):

  • Purpose: Encapsulate reusable logic, data fetching, and side effects
  • Location: src/composables/
  • Contains: Vue composables for projects, SEO, i18n, themes, galleries, date formatting, assets, site config
  • Depends on: Types, stores, external libraries (vue-router, vue-i18n)
  • Used by: Components and views

Data/State Layer (Stores & Data):

  • Purpose: Global state and static data management
  • Location: src/stores/, src/data/
  • Contains: Pinia stores, static project data, testimonials, tech stack, FAQs
  • Depends on: Types, composables (useI18n for localized data)
  • Used by: Composables and components

Configuration Layer:

  • Purpose: Application-wide settings and configuration
  • Location: src/config/, src/router/, src/i18n/
  • Contains: Site configuration, router setup, i18n initialization, locale messages
  • Depends on: Types, data
  • Used by: Main entry point and throughout app

Type Definitions:

  • Purpose: TypeScript interfaces and types
  • Location: src/types/index.ts
  • Contains: Project, Technology, TechStack, SocialLink, ContactInfo, FiverrService, SiteConfig interfaces

Data Flow

1. Initial Page Load:

  1. index.html loads with embedded Google Analytics and Google AdSense scripts
  2. src/main.ts initializes Vue app, Pinia store, router, and i18n
  3. src/App.vue applies theme from localStorage and renders AppHeader + RouterView + AppFooter
  4. Router initializes and loads HomePage or requested route
  5. useTheme() applies saved theme class to document
  6. useI18n() loads saved locale from localStorage

2. Route Navigation:

  1. User clicks link or navigates directly
  2. Router's beforeEach hook updates document title and meta description from route.meta
  3. Router's afterEach hook triggers scroll to top and Google Analytics page view tracking
  4. Target view component mounts and runs useSeo() for SEO metadata
  5. View renders child components with fetched data
  6. Components subscribe to composables for reactive data

3. Data Access Pattern (Example: Projects):

  1. Component imports useProjects() composable
  2. Composable accesses base project data from src/data/ or static store
  3. Composable uses useI18n() to localize strings
  4. Component receives computed reactive projects array
  5. Component renders with v-for or passes data to child components

4. Theme Switching:

  1. ThemeToggle component toggles isDark ref in useTheme()
  2. Watch handler applies class to document.documentElement
  3. Watch handler saves to localStorage
  4. Browser CSS respects dark class on document

5. Language Switching:

  1. LanguageSwitcher component calls switchLocale() from useI18n()
  2. vue-i18n locale updates and all {{ t() }} expressions re-evaluate
  3. New locale saved to localStorage
  4. Computed properties like homeFAQs in HomePage.vue re-evaluate with new translations

State Management:

  • Global: Pinia stores (currently minimal - useCounterStore exists but unused)
  • Composable State: Reactive refs in composables (theme, locale, gallery state)
  • Component State: Local reactive refs for UI state (menu toggle, form inputs)
  • Persistence: localStorage for theme and locale preferences
  • Server-Side Data: Static JSON-like data in src/data/ files, not fetched from API

Key Abstractions

useI18n() Composable:

  • Purpose: Unified i18n access with convenience methods
  • Examples: src/composables/useI18n.ts
  • Pattern: Wraps vue-i18n's useI18n(), adds locale switching and computed locale state
  • Usage: Available in all components via injection

useSeo() Composable:

  • Purpose: Dynamic SEO tag management for SPA
  • Examples: src/composables/useSeo.ts
  • Pattern: Lifecycle hooks to create/remove meta tags on mount/unmount, prevents tag duplication
  • Usage: Called in view components with options object for title, description, OG tags, structured data

useProjects() Composable:

  • Purpose: Project data access with localization
  • Examples: src/composables/useProjects.ts
  • Pattern: Base data stored separately, computed properties merge translations on read
  • Usage: Returns computed projects array that updates when language changes

useTheme() Composable:

  • Purpose: Centralized theme state and persistence
  • Examples: src/composables/useTheme.ts
  • Pattern: Reactive boolean with computed getter, watch for persistence, DOM manipulation
  • Usage: Injected globally in App.vue, consumed by ThemeToggle component

TechStack Interface:

  • Purpose: Typed structure for technology categories
  • Examples: src/types/index.ts
  • Pattern: Categorized array structure (programming, front, database, devtools, operating_systems, socials)
  • Usage: Imported in src/data/techstack.ts and AboutPage.vue

SiteConfig:

  • Purpose: Single source of truth for site-wide settings
  • Examples: src/config/site.ts
  • Pattern: Exported constant object with typed structure, includes contact info, social links, SEO config
  • Usage: Imported where needed for links, contact info, performance settings

Entry Points

HTML Entry Point:

  • Location: index.html
  • Triggers: Browser page load
  • Responsibilities: Define DOM root (#app), load analytics/ads scripts, include meta tags, defer main.ts loading

Application Entry Point:

  • Location: src/main.ts
  • Triggers: After HTML DOM ready
  • Responsibilities: Create Vue app, install plugins (Pinia, Router, i18n), mount to #app

Router Entry Point:

  • Location: src/router/index.ts
  • Triggers: App.use(router) in main.ts
  • Responsibilities: Define route table, implement beforeEach/afterEach hooks for SEO and analytics

Root Component:

  • Location: src/App.vue
  • Triggers: After Vue app mounts
  • Responsibilities: Initialize theme, render layout structure (header + router-view + footer), handle route-change scroll behavior

View Components:

  • Location: src/views/*.vue
  • Triggers: Router navigation to matching path
  • Responsibilities: Page-specific SEO setup via useSeo(), compose sections and content, manage page-level state

Error Handling

Strategy: Graceful degradation with fallback content; no explicit error boundaries detected

Patterns:

  • Lazy-loaded routes with no 404 component (TODO comment in router) - currently redirects to HomePage
  • SEO composable safely creates/finds meta elements before updating
  • Theme fallback to 'dark' if localStorage empty
  • Locale fallback to 'en' if not in localStorage
  • Gallery modal (GalleryModal.vue) handles missing images gracefully
  • Contact form likely has validation but not visible in read scope

Cross-Cutting Concerns

Logging: Console-based or via external services - no custom logger detected; development uses Vue DevTools plugin

Validation: Form validation in components (ContactPage uses validation likely); no centralized validation layer

Authentication: No built-in auth system - portfolio is public facing; new auth stores/views added (LoginView, RegisterView, VerifyEmailView, DashboardView, ForgotPasswordView, guards.ts) but not integrated into main router

SEO: Centralized via useSeo() composable and router hooks; dynamic meta tags, Open Graph, Twitter cards, structured data; Google Analytics via gtag in router afterEach; Umami analytics via deferred script tag in index.html

Performance: Code splitting via lazy routes, vendor chunk separation in vite.config.ts, CSS code splitting enabled, Terser minification, webp image support configured, lazy image loading configurable in siteConfig

Accessibility: ARIA labels on interactive elements (AppHeader navigation, buttons); semantic HTML (header, nav, main, section roles); focus styles defined in App.vue


Architecture analysis: 2026-04-07