chore: remove outdated planning documents from codebase

- Deleted several planning documents including ARCHITECTURE.md, CONCERNS.md, CONVENTIONS.md, INTEGRATIONS.md, STACK.md, STRUCTURE.md, and TESTING.md.
- These files were no longer relevant to the current project structure and development practices.
This commit is contained in:
2026-04-08 20:02:41 +02:00
parent 6b828aff67
commit 137041b0a3
15 changed files with 0 additions and 1459 deletions
-197
View File
@@ -1,197 +0,0 @@
# 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*
-212
View File
@@ -1,212 +0,0 @@
# Codebase Concerns
**Analysis Date:** 2026-04-07
## Tech Debt
**Missing 404 Page Implementation:**
- Issue: 404 catch-all route currently redirects to HomePage instead of a dedicated 404 page
- Files: `src/router/index.ts` (line 51: TODO comment)
- Impact: Users encountering invalid routes see the homepage instead of a proper error page, creating confusion and poor UX. SEO also treats all invalid URLs as the homepage.
- Fix approach: Create a new `NotFoundPage.vue` component in `src/views/` with proper 404 messaging, then update the route in `src/router/index.ts` to point to this component.
**Hardcoded GA Tracking ID:**
- Issue: Google Analytics tracking ID `G-CDVVNFY6MV` is hardcoded in multiple places
- Files: `index.html` (line 9), `src/router/index.ts` (line 109)
- Impact: Cannot change analytics without code updates. Difficult to manage different GA IDs for development vs production environments.
- Fix approach: Move tracking ID to environment variables (`.env`), access via `import.meta.env.VITE_GA_ID`.
**Hardcoded Site URL and Analytics:**
- Issue: URLs and site identifiers hardcoded throughout the codebase
- Files: `src/composables/useSeo.ts` (lines 103, 113, 143, 149), `src/config/site.ts` (line 69), `src/router/index.ts` (line 109)
- Impact: Difficult to deploy to different environments (staging vs production). Requires code changes for different domains.
- Fix approach: Move to environment configuration. Create environment-based config: `VITE_SITE_URL`, `VITE_SITE_DOMAIN`, etc.
**External Image Asset Dependency on Placeholder Service:**
- Issue: Missing images fallback to external placeholder.com service without reliability guarantee
- Files: `src/composables/useAssets.ts` (lines 18, 42)
- Impact: If placeholder.com goes down or is rate-limited, missing images break visually. External dependency increases load time.
- Fix approach: Use local SVG or base64-encoded placeholder image instead of external URL.
## Known Bugs
**Scroll Position Duplication:**
- Symptoms: Multiple scroll handlers (in router and App.vue) could cause double-scrolling or jank
- Files: `src/App.vue` (lines 14-18), `src/router/index.ts` (lines 62-82, 118-125)
- Trigger: Navigation between routes
- Workaround: Currently works, but behavior is fragile due to redundancy
**FormationPage Billing Toggle State Issue:**
- Symptoms: Billing toggle (monthly/annual) uses `isAnnual` state but HTML shows `billingType` variable
- Files: `src/views/FormationPage.vue` (lines 12-20, 41)
- Trigger: When switching between monthly and annual billing
- Workaround: Component probably has missing reactive computed for `billingType`
## Security Considerations
**v-html Usage in FAQ Component:**
- Risk: XSS vulnerability if FAQ answers contain user-generated content or external data
- Files: `src/components/ServiceFAQ.vue` (line 22: `<p v-html="faq.answer"></p>`)
- Current mitigation: FAQ content is hardcoded in component props (trusted source), but pattern is risky if content source changes
- Recommendations: Replace with v-text or plain text content. If HTML is needed, use a sanitization library like `DOMPurify`.
**Personal Information Exposed in Configuration:**
- Risk: Email, phone number, and social profile IDs hardcoded in public config
- Files: `src/config/site.ts` (lines 71-100), `index.html` (lines 88, 239-240)
- Current mitigation: This is intentional (portfolio/contact site), but increases spam/scraping risk
- Recommendations: Consider using form submission instead of direct email/phone links on sensitive pages. Monitor contact form for abuse.
**Hardcoded Analytics and AdSense IDs:**
- Risk: Analytics and AdSense IDs in HTML source reveal account information
- Files: `index.html` (lines 9, 19)
- Current mitigation: None - IDs are public by design (Google Analytics is meant to be public)
- Recommendations: Ensure AdSense account is properly secured with password/2FA. Monitor for unauthorized modifications.
**Discord User ID Exposed:**
- Risk: Discord user ID `370940770225618954` is hardcoded and publicly visible
- Files: `src/config/site.ts` (line 92)
- Current mitigation: Discord doesn't allow impersonation via ID alone, but enables targeted attacks
- Recommendations: Keep Discord contact via link only, without exposing raw user ID. Use Discord username instead.
## Performance Bottlenecks
**Eager Image Loading with import.meta.glob:**
- Problem: All images under `src/assets/images/**` are eagerly loaded into memory at startup
- Files: `src/composables/useAssets.ts` (line 6: `eager: true`)
- Cause: `eager: true` loads all matching modules immediately instead of lazy-loading on-demand
- Improvement path: Change to lazy loading and implement on-demand imports, or at minimum separate critical images from lazy ones.
**External Script Dependencies Block Rendering:**
- Problem: Google Analytics, Google AdSense, and Umami scripts are loaded synchronously
- Files: `index.html` (lines 9, 19, 239-240)
- Cause: Multiple external scripts without proper `async` loading strategy
- Improvement path: Ensure all external scripts use `async` or `defer` attributes. Currently Umami and GTM use `defer` (good), but ensure they don't block critical rendering path.
**No Lazy Loading on Images:**
- Problem: No lazy-loading attributes on images, causing initial page load to fetch all images
- Files: Multiple components (`src/components/layout/AppFooter.vue` line 35, `src/components/layout/AppHeader.vue` line 33)
- Cause: `loading="eager"` and `loading="lazy"` not used strategically
- Improvement path: Set `loading="lazy"` on all below-fold images. Keep only above-fold images with `loading="eager"`.
## Fragile Areas
**GalleryModal Event Listener Management:**
- Files: `src/components/GalleryModal.vue` (lines 44-50)
- Why fragile: Global document keydown listener added/removed on mount/unmount. If component unmounts unexpectedly, listener could remain attached or fail to attach.
- Safe modification: Add try-catch around removeEventListener. Consider using a ref-based approach or delegated events.
- Test coverage: No test coverage visible for keyboard navigation. Recommend adding unit tests for keyboard shortcuts.
**Image URL Resolution Fallback Chain:**
- Files: `src/composables/useAssets.ts` (lines 13-44)
- Why fragile: Multiple fallback layers (module lookup → URL construction → placeholder) make debugging hard. If one fallback path fails, error is silently logged.
- Safe modification: Add explicit logging for each fallback step. Document expected path formats clearly.
- Test coverage: Recommend unit tests for edge cases (empty path, missing extensions, malformed paths).
**SEO Composable DOM Manipulation:**
- Files: `src/composables/useSeo.ts` (lines 35-70)
- Why fragile: Directly manipulates DOM with `document.querySelector`, `createElement`, `appendChild`. No error handling if DOM structure changes.
- Safe modification: Use Vue's ref system or a dedicated SEO library (e.g., `@unhead/vue`). Add error boundaries.
- Test coverage: No test coverage for SSR compatibility or DOM cleanup on route changes.
**Route-based SEO Title Dependency:**
- Files: `src/composables/useSeo.ts` (lines 75-76)
- Why fragile: Relies on route being available in useRoute() hook. If used in wrong context (non-routed component), will fail silently.
- Safe modification: Add null checks. Consider creating a composable specifically for page-level SEO that enforces route dependency.
- Test coverage: Recommend tests for components used in and outside routing context.
## Scaling Limits
**Single-Page History State:**
- Current capacity: Router handles typical portfolio page count (6-8 pages)
- Limit: If projects list grows beyond 50-100 items, ProjectsPage.vue performance degrades (all projects loaded at once)
- Scaling path: Implement pagination or virtual scrolling in ProjectsPage. Use server-side filtering if projects become dynamic.
**Inline Image Modules:**
- Current capacity: ~15-20 images loaded eagerly in memory
- Limit: If image count exceeds 100+, startup time and memory usage increase significantly
- Scaling path: Migrate to lazy-loading strategy. Consider CDN for image serving in production.
**Localization Key Lookups:**
- Current capacity: 500+ localization keys across en.ts and fr.ts
- Limit: If keys exceed 1000+, lookup performance and bundle size become concerns
- Scaling path: Implement lazy-loaded locale files (load only active language). Consider JSON-based locale format for better optimization.
## Dependencies at Risk
**No Testing Framework:**
- Risk: Zero test coverage visible in codebase. Refactoring breaks are undetectable.
- Impact: Security fixes, performance optimizations, and feature additions are risky.
- Migration plan: Add Jest + Vue Test Utils. Start with critical paths (router guards, composables, SEO).
**Hardcoded Translation Keys:**
- Risk: If translation key structure changes, UI silently breaks (missing translations show key names)
- Impact: Refactoring translations is error-prone and breaks are not caught in CI
- Migration plan: Add TypeScript strict typing for i18n keys using type-safe i18n library.
**External Analytics Dependency:**
- Risk: If Google Analytics changes API or service, tracking breaks
- Impact: Loss of analytics data, no visibility into user behavior
- Migration plan: Already using Umami (self-hosted alternative). Consider making analytics provider pluggable.
## Missing Critical Features
**No Error Boundary:**
- Problem: No Vue error boundary or fallback component for runtime errors
- Blocks: Cannot gracefully handle component errors or show error UI
- Fix approach: Create an error boundary component using Vue 3 error handling hooks (errorCaptured), wrap main app with it.
**No Offline Support:**
- Problem: No service worker or offline fallback
- Blocks: Portfolio becomes completely unavailable if user loses connection
- Fix approach: Implement service worker with offline fallback. Cache critical assets (HTML, CSS, JS).
**No Loading States:**
- Problem: No skeleton loaders or loading indicators for async operations
- Blocks: Users don't know if page is loading or broken. Especially impacts image loading.
- Fix approach: Add skeleton screens for ProjectDetailPage. Add loading indicators for gallery modal.
**No Proper 404 Page:**
- Problem: 404 redirects to homepage (mentioned in Tech Debt)
- Blocks: Users cannot identify when they've hit an invalid URL
- Fix approach: Create NotFoundPage.vue with suggestions for navigation.
**No Analytics Event Tracking:**
- Problem: Only page views tracked, no event analytics (clicks, form submissions, etc.)
- Blocks: Cannot understand user behavior beyond page traffic
- Fix approach: Add event tracking for CTA clicks, social link clicks, gallery interactions.
## Test Coverage Gaps
**No Unit Tests:**
- What's not tested: Composables (useSeo, useAssets, useProjects, useI18n), utility functions
- Files: All of `src/composables/` and `src/data/`
- Risk: Refactoring introduces subtle bugs. Type safety is partial (TypeScript, but no runtime checks).
- Priority: High - composables are core to the app and impact SEO/styling
**No Component Tests:**
- What's not tested: Interactive components (GalleryModal, ServiceFAQ, language switcher, theme toggle)
- Files: `src/components/GalleryModal.vue`, `src/components/ServiceFAQ.vue`, `src/components/ThemeToggle.vue`, `src/components/LanguageSwitcher.vue`
- Risk: UI behavior breaks silently. Accessibility features (keyboard nav, ARIA) may regress.
- Priority: High - GalleryModal keyboard navigation and language switching are user-facing
**No Integration Tests:**
- What's not tested: Router navigation, SEO meta tag updates, i18n language switching across pages
- Files: `src/router/index.ts`, cross-file composable interactions
- Risk: Multi-step user flows break. SEO meta tags may not update correctly on navigation.
- Priority: Medium - can catch cross-cutting issues
**No E2E Tests:**
- What's not tested: Full user journeys (landing → project detail → gallery → contact)
- Framework: None (not using Cypress, Playwright, etc.)
- Risk: Visual regressions, layout issues, navigation bugs in real browser contexts
- Priority: Medium - would catch integration issues and performance regressions
**No Accessibility Tests:**
- What's not tested: Keyboard navigation, screen reader compatibility, color contrast, focus management
- Files: All components with interactive elements
- Risk: Accessibility fails silently. Users with disabilities cannot navigate.
- Priority: High - portfolio should be accessible to all users
---
*Concerns audit: 2026-04-07*
-225
View File
@@ -1,225 +0,0 @@
# Coding Conventions
**Analysis Date:** 2026-04-07
## Naming Patterns
**Files:**
- Vue components: PascalCase (e.g., `AppHeader.vue`, `ProjectCard.vue`)
- Composables: camelCase with `use` prefix (e.g., `useTheme.ts`, `useProjects.ts`)
- Utility/config files: camelCase (e.g., `site.ts`, `techstack.ts`)
- Data files: camelCase (e.g., `testimonials.ts`, `faq.ts`)
- Type definitions: camelCase in `types/index.ts`
**Functions:**
- All functions use camelCase (e.g., `toggleTheme`, `openGallery`, `getImageUrl`)
- Composables are named with `use` prefix: `useTheme()`, `useGallery()`, `useSeo()`
- Getter functions use `get` prefix: `getTheme()`, `getImageUrl()`
- Boolean functions/computed use `is`/`has` prefix: `isDark`, `hasNext`, `isOpen`
- Handler functions use verb + `Handler`: `toggleTheme`, `openGallery`, `closeGallery`
**Variables:**
- Refs and computed properties: camelCase (e.g., `isDark`, `currentIndex`, `isOpen`)
- Interfaces and types: PascalCase (e.g., `Props`, `SeoOptions`, `Theme`)
- Constants: UPPER_SNAKE_CASE for config constants (not extensively used in codebase)
- Private/module state: camelCase prefixed with `_` if truly private
**Types:**
- Type aliases: PascalCase (e.g., `type Theme = 'light' | 'dark'`)
- Interface names: PascalCase (e.g., `interface Props`, `interface SeoOptions`)
- Props interfaces: Always named `Props` (e.g., in `<script setup lang="ts">` components)
- Generic types from Vue use their original names (e.g., `Ref<boolean>`, `Computed<string>`)
## Code Style
**Formatting:**
- Tool: Prettier 3.5.3
- Semi-colons: **disabled** (`semi: false`)
- Quotes: **single quotes** (`singleQuote: true`)
- Print width: **100 characters** (`printWidth: 100`)
**Linting:**
- Tool: ESLint 9.22.0 with Vue support
- Config: `eslint.config.ts` using flat config format
- Plugins:
- `@vue/eslint-config-typescript` - TypeScript support
- `eslint-plugin-vue` v10.0.0 - Vue 3 rules
- `@vue/eslint-config-prettier/skip-formatting` - Prettier integration (skip-formatting enabled)
## Import Organization
**Order:**
1. Vue and framework imports (`vue`, `vue-router`, `pinia`, `vue-i18n`)
2. Type imports (use `import type` for TypeScript types)
3. Local components (`@/components/...`)
4. Composables (`@/composables/...`)
5. Utilities and helpers
6. Data and configuration files
7. Styles (scoped CSS imported at end of `<style>`)
**Path Aliases:**
- `@/` maps to `./src/` (configured in `tsconfig.app.json`)
- Always use `@/` prefix for imports from src directory
- Examples:
- `import AppHeader from '@/components/layout/AppHeader.vue'`
- `import { useTheme } from '@/composables/useTheme'`
- `import type { Project } from '@/types'`
- `import { techStack } from '@/data/techstack'`
## Error Handling
**Patterns:**
- Try-catch blocks wrap risky operations (e.g., dynamic imports, DOM manipulation)
- Fallback values provided when operations fail:
- In `useAssets()`: returns placeholder image URL if asset fails to load
- In `useSeo()`: gracefully handles missing meta elements by creating them
- Console warnings for non-critical failures:
- `console.warn('message')` for warnings during execution
- Error objects logged with context: `console.warn('Failed to load image: ${path}', error)`
- Silent failures with fallbacks preferred over throwing errors for UI operations
**Examples from codebase:**
```typescript
// In useAssets.ts - graceful fallback
if (!path || path.trim() === '') {
console.warn('getImageUrl called with empty or undefined path')
return `https://via.placeholder.com/400x300/f3f4f6/9ca3af?text=${encodeURIComponent('No image')}`
}
// In useSeo.ts - create if missing
let meta = document.querySelector(`meta[${property ? 'property' : 'name'}="${name}"]`)
if (!meta) {
meta = document.createElement('meta')
// ... setup ...
document.head.appendChild(meta)
}
```
## Logging
**Framework:** `console` object (no dedicated logging library)
**Patterns:**
- `console.warn()` for warnings (missing assets, invalid input)
- Logging only in composables for utility functions
- No console.log() in production code (only development/debugging)
- Error context included: `console.warn('context', error)`
## Comments
**When to Comment:**
- JSDoc comments for composable functions (exported functions)
- Inline comments for non-obvious logic (especially SEO handling in router)
- Comments explaining why (not what the code does)
- TODO comments for known issues: `// TODO: page 404` in `src/router/index.ts`
**JSDoc/TSDoc:**
- Composables include JSDoc for exported functions
- Example from `useAssets.ts`:
```typescript
/**
* Get image URL from assets folder
* @param path - Path like '@/assets/images/filename.webp' or 'filename.webp'
* @returns string - The image URL
*/
const getImageUrl = (path: string | undefined): string => { ... }
```
- Not consistently applied across all files; use when function signature isn't obvious
## Function Design
**Size:** Composables are typically 50-100 lines; keep focused on single responsibility
**Parameters:**
- Props interfaces always named `Props` in components
- Use destructuring in setup: `const { t } = useI18n()`
- Optional config objects in composables (e.g., `SeoOptions` with defaults)
- Explicit typing on all parameters
**Return Values:**
- Composables return object with all exposed functions and reactive state
- Always return computed versions of reactive state when exposing refs:
```typescript
return {
isOpen, // reactive ref
currentImage, // computed from ref
openGallery, // function
closeGallery // function
}
```
- Functions return early on validation failures with fallbacks
## Module Design
**Exports:**
- Composables export single named function: `export function useTheme() { ... }`
- Config files export named constants: `export const siteConfig: SiteConfig = { ... }`
- Type definitions export interfaces and types: `export interface Project { ... }`
- Data files export arrays or objects: `export const techStack: TechStack = { ... }`
**Barrel Files:**
- Not extensively used; direct imports preferred
- Only `src/types/index.ts` serves as barrel export for type definitions
- Components use direct imports: `import AppHeader from '@/components/layout/AppHeader.vue'`
**Component Structure (Vue SFC):**
- `<script setup lang="ts">` for all components (Vue 3 Composition API)
- Props validated with TypeScript interfaces
- Composables called at top of setup
- Computed properties for derived state
- Functions defined after setup calls
- `<template>` uses semantic HTML and accessibility attributes
- Scoped styles at bottom with `@import` for external stylesheets
**Example pattern from `AppHeader.vue`:**
```typescript
<script setup lang="ts">
import { ref, computed } from 'vue'
// Composables first
const { getImageUrl } = useAssets()
const { t } = useI18n()
// State
const isMenuOpen = ref(false)
// Computed
const navigation = computed(() => [ ... ])
// Functions
const toggleMenu = () => { ... }
</script>
```
## Type Safety
**TypeScript Configuration:**
- Version: ~5.8.0
- DOM-focused (`tsconfig.dom.json` from @vue/tsconfig)
- Path alias `@/*` points to `./src/*`
- Type checking enabled in build: `npm run type-check` runs `vue-tsc --build`
**Type Usage Patterns:**
- All component Props use interface definitions
- Composable return values typed explicitly
- Function parameters and return types annotated
- Type imports use `import type` syntax
- Avoid `any` type; use proper interfaces/generics
## Vue 3 Specific
**Composition API:**
- `<script setup>` syntax exclusively used
- No Options API in codebase
- Composables follow Composition API patterns
**Lifecycle Hooks:**
- `onMounted()` for initialization (theme loading, SEO setup)
- `onUnmounted()` for cleanup (removing DOM elements in useSeo)
- `watch()` for reactive side effects (theme changes)
**Reactivity:**
- `ref()` for primitive state
- `computed()` for derived state
- Avoid unnecessary reactivity; use constants when possible
- Return computed versions of refs from composables
---
*Convention analysis: 2026-04-07*
-180
View File
@@ -1,180 +0,0 @@
# External Integrations
**Analysis Date:** 2026-04-07
## APIs & External Services
**Analytics & Tracking:**
- Google Analytics (GTM)
- Measurement ID: `G-CDVVNFY6MV`
- Script: Injected in `index.html` lines 8-16
- Implementation: Inline gtag.js initialization with window.dataLayer
- Page tracking: Configured in `src/router/index.ts` lines 105-136 via `trackPageView()` function
- Tracks: Page path, title, and location on route changes
- Umami Analytics
- Website ID: `83631152-9b6b-4724-aad1-828459ff36dc`
- Hosted at: `umami.killiandalcin.fr`
- Script tag: `index.html` line 239
- Implementation: Self-hosted privacy-focused alternative to Google Analytics
**Advertising:**
- Google AdSense
- Client ID: `ca-pub-5219367964457248`
- Script: Async loaded in `index.html` lines 18-20
- Purpose: Display contextual ads on portfolio pages
**Social Integration:**
Social media links configured in `src/config/site.ts` (no direct API integration):
- GitHub/Gitea: `https://gitea.kamisama.ovh/kayjaydee`
- LinkedIn: `https://linkedin.com/in/killian-dal-cin`
- Discord: `https://discord.com/users/370940770225618954`
- Fiverr: `https://www.fiverr.com/users/mr_kayjaydee`
- Twitter: `@killiandalcin`
**Third-Party Services Referenced (Portfolio Content, Not Integrated):**
- Instagram API - Referenced in `src/components/TechBadge.vue` and `src/composables/useProjects.ts` as portfolio technology (instagram-bot project)
- Crowdin API - Referenced in `src/composables/useProjects.ts` as portfolio technology (crowdin status bot)
- Discord.js - Referenced in `src/composables/useProjects.ts` as portfolio technology (Discord bot development)
- NPM Package Registry - discord-image-generation published at `https://www.npmjs.com/package/discord-image-generation`
## Data Storage
**Databases:**
- None detected - Portfolio is static content
- Technologies showcased (not used in this app):
- MongoDB - Referenced in `src/data/techstack.ts`
- MySQL - Referenced in `src/data/techstack.ts`
- PostgreSQL - Referenced in `src/data/techstack.ts`
- Redis - Referenced in `src/data/techstack.ts`
- SQLite - Referenced in `src/data/techstack.ts`
**File Storage:**
- Local filesystem only
- Images: `src/assets/images/` directory
- Compiled assets: `dist/` directory (generated on build)
- Public assets: `public/` directory (favicon, manifest, logos, etc.)
**Caching:**
- Browser caching via content hash in filenames:
- Pattern: `assets/[ext]/[name]-[hash].[ext]` (configured in `vite.config.ts` lines 40-42)
- CSS: `assets/css/[name]-[hash].css`
- JS: `assets/js/[name]-[hash].js`
- No server-side caching layer detected
## Authentication & Identity
**Auth Provider:**
- None - Portfolio is fully public
- No authentication system implemented
- Fiverr links redirect to external Fiverr service for user authentication
## Monitoring & Observability
**Error Tracking:**
- None detected
- Errors not sent to external service
- Console errors only (JavaScript errors in browser dev tools)
**Logs:**
- Browser console logging only
- No server-side logging or aggregation
- Analytics events sent to Google Analytics and Umami for page views
**Performance Monitoring:**
- Google Analytics provides basic performance metrics
- Umami provides engagement metrics
- No dedicated APM (Application Performance Monitoring) service
## CI/CD & Deployment
**Hosting:**
- Static hosting environment (implied)
- Docker containerization available:
- Build image: `node:22-alpine` (lines 2-17 in `Dockerfile`)
- Runtime image: `nginx:stable-alpine` (lines 20-32 in `Dockerfile`)
- Port: 80
**CI Pipeline:**
- None detected in repository
- Build commands available:
- `npm run build` - Full build with type checking
- `npm run build-only` - Build only without type checking
**Deployment Configuration:**
- `Dockerfile` - Multi-stage Docker build:
1. Build stage: Node 22-alpine with npm install + build
2. Production stage: nginx serving built files
3. Custom nginx config: `nginx.conf`
- `nginx.conf` - SPA routing configuration:
- Listens on port 80 (IPv4 and IPv6)
- Document root: `/usr/share/nginx/html`
- Fallback: All non-file requests route to `/index.html` (SPA requirement)
## Environment Configuration
**Required for Development:**
- Node.js 22+
- npm 10+
**Required at Runtime:**
- No environment variables required (analytics IDs hardcoded in HTML)
- Optional (for containerization):
- Docker
- Docker Compose
**Hardcoded Configuration:**
- Google Analytics: `G-CDVVNFY6MV` - in `index.html` line 9
- Google AdSense: `ca-pub-5219367964457248` - in `index.html` line 19
- Umami Site ID: `83631152-9b6b-4724-aad1-828459ff36dc` - in `index.html` line 240
- Umami URL: `umami.killiandalcin.fr` - in `index.html` line 239
- Base URL: `https://killiandalcin.fr` - in multiple config files (`src/config/site.ts`, `index.html`)
**Secrets Location:**
- No secrets management system
- All credentials are public analytics/advertising IDs (not sensitive)
- No API keys, database passwords, or private credentials in codebase
## Webhooks & Callbacks
**Incoming:**
- None - Portfolio is read-only
**Outgoing:**
- Google Analytics pageview tracking:
- Method: GET requests to Google Analytics endpoint
- Triggered: On route navigation
- Data: Page path, title, URL
- Implementation: `src/router/index.ts` `trackPageView()` function
- Umami analytics events:
- Method: Beacon API (automatic page tracking)
- Triggered: Page load and navigation
- Data: Standard web vitals
## CDN & External Resources
**Fonts:**
- Preconnected in `index.html`:
- `https://fonts.googleapis.com`
- `https://fonts.gstatic.com`
- Actual fonts: Not loaded (preconnect only, fonts not referenced in CSS)
**Images & Media:**
- UI Avatar API:
- Service: `https://ui-avatars.com/api/`
- Usage: Testimonial avatars in `src/data/testimonials.ts` (4 instances)
- Pattern: Query-based avatar generation with initials and colors
- Placeholder Images:
- Service: `https://via.placeholder.com/`
- Usage: Fallback images in `src/composables/useAssets.ts`
- Pattern: 400x300 gray placeholders
- Portfolio Preview Image:
- Hosted at: `https://killiandalcin.fr/portfolio-preview.webp`
- Usage: Open Graph and Twitter meta tags (lines 42, 55 in `index.html`)
---
*Integration audit: 2026-04-07*
-164
View File
@@ -1,164 +0,0 @@
# Technology Stack
**Analysis Date:** 2026-04-07
## Languages
**Primary:**
- TypeScript ~5.8.0 - Full application development
- JavaScript (ES modules) - Frontend runtime
**Secondary:**
- HTML5 - Document structure (in `index.html`)
- CSS - Styling with Tailwind CSS
- Markdown - Documentation (README.md)
- YAML - Configuration (implied through Dockerfile)
## Runtime
**Environment:**
- Node.js 22 - Development and build environment
- Browser environment - Vue 3 SFC runtime
**Package Manager:**
- npm - Dependency management
- Lockfile: `package-lock.json` (present and tracked)
## Frameworks
**Core Frontend:**
- Vue 3.5.13 - Progressive JavaScript framework for UI
- Vue Router 4.5.0 - Client-side routing with lazy-loaded pages
- Pinia 3.0.1 - State management (minimal usage - currently only `counter.ts`)
- Vue I18n 9.14.4 - Internationalization (English and French locale files in `src/locales/`)
**Build & Dev:**
- Vite 6.2.4 - Build tool and dev server
- Config: `vite.config.ts` with Vue plugin, DevTools plugin, chunk splitting optimization
- Build output: `dist/` with CSS code splitting, Terser minification
- Vite Plugin Vue DevTools 7.7.2 - Development utilities
- @vitejs/plugin-vue 5.2.3 - Vue 3 SFC support
**Styling:**
- Tailwind CSS 4.1.10 - Utility-first CSS framework
- @tailwindcss/postcss 4.1.10 - PostCSS plugin for Tailwind
- PostCSS 8.5.6 - CSS transformation pipeline
- Autoprefixer 10.4.21 - Vendor prefix handling
- Terser 5.43.1 - JavaScript minification
**Code Quality:**
- ESLint 9.22.0 - Linting (config: `eslint.config.ts`)
- @vue/eslint-config-typescript 14.5.0
- @vue/eslint-config-prettier 10.2.0 - Prettier integration
- eslint-plugin-vue ~10.0.0
- Prettier 3.5.3 - Code formatting (config: `.prettierrc.json`)
- Format settings: `semi: false`, `singleQuote: true`, `printWidth: 100`
**Type Checking:**
- vue-tsc 2.2.8 - Vue component type checking
- TypeScript compiler with `type-check` npm script
**Head Management:**
- @vueuse/head 2.0.0 - Dynamic document head management for meta tags and SEO
## Key Dependencies
**Critical:**
- vue 3.5.13 - Core framework
- vue-router 4.5.0 - SPA routing with code splitting
- pinia 3.0.1 - State management store
- vue-i18n 9.14.4 - Multi-language support
**Infrastructure & Build:**
- vite 6.2.4 - Next-gen build tool with HMR
- tailwindcss 4.1.10 - Rapid UI development
- typescript 5.8.0 - Static typing and compilation
**Developer Tools:**
- eslint 9.22.0 - Code linting
- prettier 3.5.3 - Code formatting
- npm-run-all2 7.0.2 - Parallel script execution (used in build process)
- @tsconfig/node22 22.0.1 - TSConfig preset for Node 22
- @types/node 22.14.0 - Node.js type definitions
- jiti 2.4.2 - CommonJS loader for TypeScript modules
## Configuration
**Environment:**
- No `.env` files detected in source
- Google Analytics tracking ID hardcoded: `G-CDVVNFY6MV` (in `index.html`)
- Umami analytics script loaded from `umami.killiandalcin.fr` (in `index.html`)
- Google AdSense client ID hardcoded: `ca-pub-5219367964457248` (in `index.html`)
**Build Configuration:**
- `vite.config.ts` - Build optimizations:
- Path alias: `@/``./src/`
- CSS code splitting enabled
- Terser minification with console/debugger removal
- Manual chunk splitting: `vue-vendor` and `ui-components`
- Content hash in chunk filenames for cache busting
- Source maps disabled
- Chunk size warning limit: 1000 KB
**Type Configuration:**
- `tsconfig.json` - References `tsconfig.app.json` and `tsconfig.node.json`
- `tsconfig.app.json`:
- Extends `@vue/tsconfig/dom.json`
- Includes `src/**/*` and `*.vue` files
- Path alias: `@/*``./src/*`
- Excludes `src/**/__tests__/*`
**Linting Configuration:**
- `eslint.config.ts` - Flat config format:
- Files: `**/*.{ts,mts,tsx,vue}`
- Rules: Vue essential, TypeScript recommended
- Skips Prettier formatting enforcement
**Formatting Configuration:**
- `.prettierrc.json`:
- No semicolons
- Single quotes for strings
- 100 character line width
**PostCSS Configuration:**
- `postcss.config.js` - Tailwind CSS and Autoprefixer
**Tailwind Configuration:**
- `tailwind.config.js` - Content scanning for `index.html` and `src/**/*.{vue,js,ts,jsx,tsx}`
## Platform Requirements
**Development:**
- Node.js 22+ (specified in Dockerfile)
- npm 10+ (implied by Node 22)
- TypeScript 5.8+
- Any Unix-like shell (bash/zsh) or Windows with Node.js
**Production:**
- Docker - Multi-stage build with Node 22-alpine and nginx stable-alpine
- Web server: nginx (configured in `nginx.conf`)
- Deployment target: Static HTML served via nginx
- Base image: `nginx:stable-alpine`
- Document root: `/usr/share/nginx/html`
- Port: 80
- SPA fallback: All requests route to `/index.html`
**Browser Support:**
- JavaScript enabled (noscript fallback message in `index.html`)
- Modern browsers with ES2020+ support (Vite default targets)
## Scripts & Commands
```bash
npm run dev # Start Vite dev server with HMR
npm run build # Type check + build (parallel with npm-run-all2)
npm run type-check # Run vue-tsc type checking
npm run build-only # Build without type checking
npm run preview # Preview production build
npm run lint # Run ESLint with --fix
npm run format # Format src/ with Prettier
```
---
*Stack analysis: 2026-04-07*
-277
View File
@@ -1,277 +0,0 @@
# Codebase Structure
**Analysis Date:** 2026-04-07
## Directory Layout
```
portfolio/
├── .claude/ # Claude editor configuration
├── .planning/ # GSD planning documents
│ └── codebase/ # Architecture and analysis docs
├── .vscode/ # VS Code workspace settings
├── dist/ # Vite production build output
├── docs/ # Documentation files
├── node_modules/ # Dependencies (git-ignored)
├── old/ # Archived or deprecated code
├── public/ # Static assets served at root
│ └── images/ # Public static images
├── src/ # Application source code
│ ├── assets/ # Static assets imported in code
│ │ └── images/ # Project and UI images (webp format)
│ ├── components/ # Vue component library
│ │ ├── icons/ # Icon SVG components
│ │ ├── layout/ # Layout components (Header, Footer)
│ │ ├── sections/ # Page section components
│ │ ├── shared/ # Reusable UI components
│ │ ├── styles/ # Component-scoped CSS files
│ │ └── testimonials/ # Testimonial-related components
│ ├── composables/ # Vue composables (reusable logic)
│ ├── config/ # Application configuration
│ ├── data/ # Static data files (projects, testimonials, FAQ)
│ ├── i18n/ # Internationalization setup
│ ├── locales/ # Translation files (en.ts, fr.ts)
│ ├── plugins/ # Vue plugins
│ ├── router/ # Vue Router configuration
│ ├── stores/ # Pinia state stores
│ ├── types/ # TypeScript type definitions
│ ├── views/ # Page components (route targets)
│ │ └── styles/ # Page-level CSS files
│ ├── App.vue # Root component
│ ├── main.ts # Application entry point
│ └── style.css # Global stylesheet
├── .env* # Environment variables (git-ignored)
├── .eslintrc.ts # ESLint configuration
├── .gitignore # Git ignore rules
├── .prettierrc.json # Prettier code formatter config
├── eslint.config.ts # ESLint flat config
├── index.html # HTML entry point
├── package-lock.json # Dependency lock file
├── package.json # Project metadata and scripts
├── postcss.config.js # PostCSS configuration (Tailwind)
├── tailwind.config.js # Tailwind CSS configuration
├── tsconfig.app.json # TypeScript config for app code
├── tsconfig.json # Base TypeScript config
├── tsconfig.node.json # TypeScript config for build tools
├── vite.config.ts # Vite build configuration
└── [formation.md] # Formation page documentation (uncommitted)
```
## Directory Purposes
**src/components/**
- Purpose: Vue Single File Components for UI building blocks
- Contains: Presentational components organized by domain
- Key files: `AppHeader.vue`, `ProjectCard.vue`, `HeroSection.vue`
**src/components/layout/**
- Purpose: Layout wrapper components used across pages
- Contains: `AppHeader.vue`, `AppFooter.vue`
- Key files: Header navigation, footer with social links
**src/components/sections/**
- Purpose: Full-width page section components
- Contains: `HeroSection.vue`, `FeaturedProjectsSection.vue`, `ServicesSection.vue`, `CTASection.vue`
- Key files: Large reusable page sections with styling
**src/components/shared/**
- Purpose: Shared utility components
- Contains: `CTAButtons.vue`, `SectionCTA.vue`
- Key files: Reusable button groups and CTA patterns
**src/components/testimonials/**
- Purpose: Testimonial display components
- Contains: `TestimonialCard.vue`, `TestimonialsCTA.vue`, `TestimonialsStats.vue`
- Key files: Fiverr review display and stats
**src/composables/**
- Purpose: Vue 3 Composition API utilities for reusable logic
- Contains: Custom hooks for i18n, SEO, theme, projects, gallery, date formatting, assets, site config
- Key files: `useI18n.ts`, `useSeo.ts`, `useTheme.ts`, `useProjects.ts`
**src/stores/**
- Purpose: Pinia state management
- Contains: Global reactive state stores
- Key files: `counter.ts` (minimal unused example), `auth.ts` (new, for authentication)
**src/views/**
- Purpose: Page-level Vue components matching routes
- Contains: `HomePage.vue`, `ProjectsPage.vue`, `ProjectDetailPage.vue`, `AboutPage.vue`, `ContactPage.vue`, `FiverrPage.vue`, `FormationPage.vue`
- Key files: Route target components, each handles own SEO and data fetching
**src/router/**
- Purpose: Vue Router configuration and navigation logic
- Contains: Route definitions, navigation guards, analytics tracking
- Key files: `index.ts` (main router), `guards.ts` (new, for route guards)
**src/types/**
- Purpose: TypeScript interface definitions
- Contains: Project, Technology, TechStack, SocialLink, ContactInfo, FiverrService, SiteConfig interfaces
- Key files: `index.ts`
**src/data/**
- Purpose: Static data files (non-API)
- Contains: Project definitions, testimonials, tech stack, FAQ data
- Key files: `techstack.ts`, `testimonials.ts`, `faq.ts`
**src/config/**
- Purpose: Application-wide configuration constants
- Contains: Site configuration with contact info, social links, SEO settings, performance flags
- Key files: `site.ts` (siteConfig export)
**src/locales/**
- Purpose: Translation message files
- Contains: English and French translation objects
- Key files: `en.ts`, `fr.ts`
**src/i18n/**
- Purpose: vue-i18n setup and initialization
- Contains: i18n instance creation and locale loading
- Key files: `index.ts`
**src/assets/images/**
- Purpose: Images imported in code (processed by Vite)
- Contains: Tech stack icons, project images, app images in webp format
- Subdirs: `fiverr/`, `flowboard/` for project-specific images
**public/images/**
- Purpose: Static images served at root URL without processing
- Contains: Logos, favicons, og:image preview images
**dist/**
- Purpose: Vite production build output
- Contains: Optimized HTML, JS chunks, CSS, images
- Generated: Automatically by `npm run build`
## Key File Locations
**Entry Points:**
- `index.html` - HTML entry point with Google Analytics, AdSense, structured data schemas
- `src/main.ts` - Vue app initialization, plugin registration (Pinia, Router, i18n)
- `src/router/index.ts` - Route table and navigation hooks
**Configuration:**
- `vite.config.ts` - Build optimization, chunk splitting, alias resolution (@)
- `tsconfig.json` - Base TypeScript settings with references to app and node configs
- `tailwind.config.js` - Tailwind CSS customization
- `postcss.config.js` - PostCSS with Tailwind
- `.eslintrc.ts` - ESLint rules and Vue plugin
- `.prettierrc.json` - Code formatting rules
**Core Logic:**
- `src/App.vue` - Root component with theme init, layout structure, scroll on route change
- `src/composables/useI18n.ts` - i18n convenience wrapper with locale switching
- `src/composables/useSeo.ts` - Dynamic meta tag management for SPA
- `src/composables/useTheme.ts` - Theme state and persistence
- `src/config/site.ts` - Centralized site configuration and constants
**Testing:**
- No test files detected in committed code (*.test.ts, *.spec.ts not found)
- Test setup tools not configured (Jest/Vitest not in package.json)
## Naming Conventions
**Files:**
- Components: PascalCase.vue (e.g., `AppHeader.vue`, `ProjectCard.vue`)
- Composables: camelCase prefixed with 'use' (e.g., `useProjects.ts`, `useSeo.ts`)
- Data/Config: camelCase or lowercase (e.g., `techstack.ts`, `site.ts`)
- Pages/Views: PascalCase with 'Page' suffix (e.g., `HomePage.vue`, `ProjectsPage.vue`)
- CSS: Matches component name or function (e.g., `AppHeader.css`, `HomePage.css`)
- Types: camelCase in index.ts (e.g., `Project`, `Technology`, `SiteConfig`)
**Directories:**
- Feature directories: lowercase plural (e.g., `components/`, `composables/`, `views/`)
- Subdirectories: lowercase descriptive names (e.g., `layout/`, `sections/`, `shared/`)
- Asset subdirectories: descriptive lowercase (e.g., `images/`, `fiverr/`, `flowboard/`)
**Vue Components:**
- Props: camelCase in script, kebab-case in template (Vue standard)
- Methods: camelCase (e.g., `toggleTheme()`, `setMetaTag()`)
- Computed: camelCase (e.g., `isDark`, `currentLocale`)
- Refs: camelCase (e.g., `isMenuOpen`, `galleryIndex`)
- CSS classes: kebab-case (e.g., `.hero-title`, `.nav-link`, `.btn-primary`)
**Constants:**
- Global config exports: camelCase (e.g., `siteConfig`)
- Array constants in data files: camelCase plural (e.g., `testimonials`, `baseProjects`)
- Type/Interface names: PascalCase (e.g., `Project`, `Testimonial`, `Technology`)
## Where to Add New Code
**New Feature (e.g., New Page):**
- Primary code: `src/views/FeaturePage.vue`
- Add route: `src/router/index.ts` (add route object to routes array)
- Add SEO data: Route meta object with title/description
- Translations: Add keys to `src/locales/en.ts` and `src/locales/fr.ts`
- Data files: Create in `src/data/feature.ts` if needed
- Tests: Would go in `src/views/__tests__/FeaturePage.spec.ts` (not yet configured)
**New Component/Module:**
- Reusable component: `src/components/FeatureName.vue`
- Layout component: `src/components/layout/ComponentName.vue`
- Section component: `src/components/sections/SectionName.vue`
- Shared/utility component: `src/components/shared/UtilityName.vue`
- Component CSS: `src/components/styles/ComponentName.css` (imported in component)
**New Composable:**
- Implementation: `src/composables/useFeatureName.ts`
- Return: Object with reactive state and methods
- Pattern: Use `onMounted`/`onUnmounted` for lifecycle, return refs/computed/methods
- Export: Named export of function (not default)
**Utilities/Services:**
- Shared helpers: `src/composables/useUtilityName.ts` (if stateful) or create `src/utils/utilityName.ts` (if stateless)
- Type definitions: Add to `src/types/index.ts`
- Config constants: Add to `src/config/site.ts` or create new `src/config/featureName.ts`
**Styling:**
- Global styles: `src/style.css` (imported in main.ts)
- Component scoped: `<style scoped>` in .vue file or separate `src/components/styles/ComponentName.css`
- Page styles: `src/views/styles/PageName.css`
- Tailwind classes: Use directly in templates (no separate CSS needed for basic styling)
**Translations:**
- English messages: `src/locales/en.ts` (export default object with nested structure)
- French messages: `src/locales/fr.ts` (same structure as English)
- Usage in components: `const { t } = useI18n()` then `{{ t('section.key') }}`
**Data/State:**
- Static data: `src/data/featureName.ts` (export arrays/objects)
- Global state: `src/stores/featureName.ts` (defineStore with Pinia)
- Site config: Update `src/config/site.ts` with new configuration
## Special Directories
**dist/:**
- Purpose: Production build output
- Generated: Yes (by Vite during `npm run build`)
- Committed: No (in .gitignore)
- Content: Optimized HTML, JS chunks with hashes, CSS, images
**node_modules/:**
- Purpose: Installed npm dependencies
- Generated: Yes (by npm install)
- Committed: No (in .gitignore)
- Content: Third-party packages
**public/:**
- Purpose: Static files served at root during dev and prod
- Generated: No (manually maintained)
- Committed: Yes
- Content: favicon.ico, favicon.webp, site.webmanifest, static images
**.git/:**
- Purpose: Git version control metadata
- Generated: Yes (by git init)
- Committed: No (in .gitignore)
- Content: Commit history, branches, objects
**old/:**
- Purpose: Archived or deprecated code
- Generated: No (manually maintained)
- Committed: Yes
- Content: Previous versions of components or features
---
*Structure analysis: 2026-04-07*
-204
View File
@@ -1,204 +0,0 @@
# Testing Patterns
**Analysis Date:** 2026-04-07
## Test Framework
**Status:** NOT IMPLEMENTED
No testing framework is currently configured in this project. There are:
- No test files (no `.test.ts`, `.spec.ts`, `.test.vue`, or `.spec.vue` files found)
- No test runner configured (Jest, Vitest, Cypress, Playwright, etc.)
- No test configuration files in project root
**Recommendations for Implementation:**
Given this is a Vue 3 + TypeScript portfolio, recommended testing setup would be:
1. **Unit Testing:** Vitest (modern, Vue 3 native, fast)
- Lightweight alternative to Jest
- Built-in TypeScript support
- Fast HMR for test-driven development
2. **Component Testing:** Vitest + `@vue/test-utils`
- Test Vue components in isolation
- Mock composables and routing
3. **E2E Testing:** Playwright or Cypress
- Full user journey testing
- SEO/routing validation
- Analytics tracking verification
## Current Development Practices
**Build Pipeline:**
```bash
npm run type-check # Vue TypeScript compilation check
npm run build # Production build with type checking
npm run lint # ESLint with --fix flag
npm run format # Prettier formatting on src/
npm run dev # Vite dev server
```
**Type Safety as Testing:**
- Type-checking replaces some unit test coverage
- `npm run type-check` validates all TypeScript during build
- ESLint prevents common errors with Vue and TypeScript plugins
## What Should Be Tested (If Framework Were Added)
### Composables (`src/composables/`)
**`useTheme.ts` - Unit Tests Needed:**
- `toggleTheme()` flips isDark state
- `setTheme('dark')` / `setTheme('light')` correctly sets theme
- `getTheme()` returns current theme string
- `applyTheme()` sets correct class on `document.documentElement`
- `saveTheme()` persists to localStorage
- `loadTheme()` reads from localStorage and defaults to 'dark'
- Watch effect triggers applyTheme and saveTheme on isDark change
- onMounted initialization sequence
**`useGallery.ts` - Unit Tests Needed:**
- `openGallery(images, index)` sets state correctly
- `closeGallery()` resets all state
- `nextImage()` increments index when available
- `previousImage()` decrements index when available
- `goToImage(index)` validates index bounds
- Computed properties (`currentImage`, `hasNext`, `hasPrevious`) reflect correct values
- Body scroll overflow is managed correctly
**`useSeo.ts` - Unit Tests Needed:**
- Meta tags are created and updated correctly
- `setTitle()` updates document.title and og:title
- `setMetaTag()` creates new tags if missing
- `setLinkTag()` manages canonical links
- `setStructuredData()` adds JSON-LD scripts
- onUnmounted cleanup removes all added elements (no memory leaks)
- Structured breadcrumb data is generated for non-home routes
- Title suffix appended only when needed
**`useI18n.ts` - Unit Tests Needed:**
- `switchLocale()` changes locale and saves to localStorage
- `toggleLocale()` switches between en/fr
- Computed properties reflect current locale
- Invalid locales rejected
**`useAssets.ts` - Unit Tests Needed:**
- `getImageUrl()` resolves asset paths correctly
- Fallback placeholder returned for missing images
- Handles both `@/assets/images/` and plain filename formats
- Warns on console for missing/empty paths
- Graceful error handling with placeholder fallback
**`useProjects.ts` - Unit Tests Needed:**
- Projects computed array returns correct structure
- Translations applied to titles, descriptions, buttons
- Project count matches expected baseline (7 projects)
- Featured flag correctly identifies featured projects
**`useDateFormat.ts` - Unit Tests Needed:**
- `formatRelativeTime()` returns correct French/English strings
- Year boundaries handled correctly (1 year = "1 year ago", 2+ = "X years ago")
- Month, day granularity works in both locales
- Date parsing from DD/MM/YYYY format works correctly
### Router (`src/router/index.ts`)
**Navigation Tests:**
- All routes load their components (lazy-loaded pages)
- ScrollBehavior resets to top on normal navigation
- ScrollBehavior restores position on back/forward
- ScrollBehavior smooth-scrolls to hash anchors
- Meta tags (title, description) updated on route change
**TODO:** 404 page implementation and testing needed (see comment on line 51)
### Components (if component testing added)
**High-value components to test:**
- `AppHeader.vue` - Navigation links active state, mobile menu toggle
- `ProjectCard.vue` - Image loading, translated content, button visibility
- `ContactMethod.vue` - Props validation, conditional link component rendering
- `ServiceFAQ.vue` - Q&A toggle state, feature list rendering
## No Mocking Currently Used
Since there are no tests, no mocking framework is configured. When tests are added:
**What to Mock:**
- Vue Router (`useRouter`, `useRoute`) - use `@vue/test-utils` mocking
- localStorage - mock in test setup
- Window/Document APIs - mock in unit tests
- Dynamic image imports - mock in `useAssets` tests
- Translation (`useI18n`) - provide test translations
**What NOT to Mock:**
- Composable logic itself - test composables directly
- Type validation - let TypeScript handle it
- Vue reactivity - test against real ref/computed behavior
- Business logic in utility functions
## Missing Infrastructure
### Configuration Files Needed:
1. **Vitest config** (`vitest.config.ts`):
```typescript
import { defineConfig } from 'vitest/config'
import vue from '@vitejs/plugin-vue'
// ... rest of config
```
2. **Test utilities setup** (`src/__tests__/setup.ts`):
- Global test configuration
- Mock setup for localStorage, window
- Test utilities/helpers
3. **Component test examples** structure:
- `src/__tests__/unit/` for unit tests
- `src/__tests__/components/` for component tests
- Matching file structure to src/
### Package Dependencies Needed:
```json
{
"devDependencies": {
"vitest": "^1.x",
"@vue/test-utils": "^2.x",
"@testing-library/vue": "^8.x",
"happy-dom": "^12.x",
"playwright": "^1.x"
}
}
```
## Coverage Targets (If Implemented)
**Recommended targets:**
- Composables: 85%+ coverage (critical for reliability)
- Router: 90%+ coverage (navigation is critical)
- Components: 70%+ coverage (UI changes less frequently)
- Overall: 75%+ coverage
**High-risk areas needing coverage:**
- SEO meta tag manipulation (`useSeo`)
- Theme persistence and DOM manipulation (`useTheme`)
- Image asset loading with fallbacks (`useAssets`)
- Locale switching and persistence (`useI18n`)
## Development Testing Approach (Current)
Without automated tests, verification is manual:
1. **Type checking:** `npm run type-check` validates types
2. **Linting:** `npm run lint` catches code style issues
3. **Manual testing:** `npm run dev` starts dev server for browser testing
4. **Build validation:** `npm run build` ensures code compiles
This is appropriate for a portfolio site but would need proper testing for production applications or team projects.
---
*Testing analysis: 2026-04-07*
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB