# dluisvaldivia/dvportfolio architecture

> Architecture diagram of the GitHub repository dluisvaldivia/dvportfolio, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-09-30). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/dluisvaldivia/dvportfolio
- Repository: https://github.com/dluisvaldivia/dvportfolio

## Overview

This is a bilingual personal portfolio site with project, profile, contact, blog, and accessibility-checker experiences, plus a browser-backed admin workflow for managing blog posts. The main visitor flow is routed through the app shell to portfolio pages or blog listings and posts; admin users log in, pass a protected route, and edit or manage posts. The README is brief, so the map relies mainly on the sampled route declarations and source references; unsampled features such as Rates are shown without speculative connections.

Main entry points: [`src/App.tsx`](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/App.tsx) (Router and shell), [`src/controllers/blogController.ts`](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/controllers/blogController.ts) (Blog data and storage), [`src/view/pages/Home.tsx`](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/pages/Home.tsx) (Portfolio home), [`src/controllers/authController.ts`](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/controllers/authController.ts) (Authentication)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_app["App shell"]
  node_app["Router and shell<br/>[App.tsx]"]
  node_bootstrap["React bootstrap<br/>[main.tsx]"]
  node_navbar["Navigation<br/>[Navbar.tsx]"]
  node_not_found["Not found page<br/>[NotFound.tsx]"]
  node_back_to_top["Back to top<br/>[backToTop.tsx]"]
end

subgraph group_portfolio["Portfolio experience"]
  node_home["Portfolio home<br/>[Home.tsx]"]
  node_project_cards["Project cards<br/>[cardList.tsx]"]
  node_card["Project card<br/>[card.tsx]"]
  node_cards_data["Project data<br/>[cardsData.ts]"]
  node_hero["Animated hero<br/>[data-grid-hero.tsx]"]
  node_rates["Rates page<br/>[Rates.tsx]"]
  node_accessibility["Accessibility checker"]
end

subgraph group_blog["Blog publishing"]
  node_blog_list["Blog listing<br/>[Blog.tsx]"]
  node_blog_post["Blog post view<br/>[BlogPost.tsx]"]
  node_blog_logic["Blog data and storage<br/>[blogController.ts]"]
  node_blog_seed["Seed posts<br/>[blogData.ts]"]
end

subgraph group_admin["Administration"]
  node_admin_login["Admin login<br/>[AdminLogin.tsx]"]
  node_auth["Authentication<br/>[authController.ts]"]
  node_private_route["Route guard<br/>[PrivateRoute.tsx]"]
  node_dashboard["Post dashboard<br/>[AdminDashboard.tsx]"]
  node_editor["Post editor<br/>[PostEditor.tsx]"]
  node_rich_editor["Rich editor<br/>[RichEditor.tsx]"]
  node_toolbar["Editor toolbar<br/>[Toolbar.tsx]"]
end

subgraph group_shared["Shared services"]
  node_storage[("Browser storage")]
  node_i18n["Translations<br/>[i18n.ts]"]
  node_theme["Theme controller<br/>[themeController.ts]"]
  node_page_title["Page title hook<br/>[usePageTitle.ts]"]
end

node_visitor(("Visitor"))
node_checker_api["Accessibility API"]
node_contact_service["EmailJS service"]

node_visitor -->|"opens"| node_app
node_bootstrap -->|"renders"| node_app
node_bootstrap -->|"loads"| node_i18n
node_app -->|"renders"| node_navbar
node_app -->|"routes to"| node_home
node_app -->|"routes to"| node_blog_list
node_app -->|"routes to"| node_blog_post
node_app -->|"routes to"| node_accessibility
node_app -->|"routes to"| node_admin_login
node_app -->|"guards routes"| node_private_route
node_app -->|"routes to"| node_dashboard
node_app -->|"routes to"| node_editor
node_app -->|"routes to"| node_not_found
node_app -->|"renders"| node_back_to_top
node_app -->|"sets theme"| node_theme
node_home -->|"renders"| node_project_cards
node_home -->|"renders"| node_hero
node_project_cards -->|"renders"| node_card
node_project_cards -->|"reads"| node_cards_data
node_home -->|"sends contact"| node_contact_service
node_accessibility -->|"fetches report"| node_checker_api
node_blog_list -->|"loads posts"| node_blog_logic
node_blog_post -->|"loads post"| node_blog_logic
node_blog_logic -->|"merges seeds"| node_blog_seed
node_blog_logic -->|"reads and writes"| node_storage
node_admin_login -->|"checks credentials"| node_auth
node_private_route -->|"checks session"| node_auth
node_auth -->|"stores session"| node_storage
node_dashboard -->|"logs out"| node_auth
node_dashboard -->|"manages posts"| node_blog_logic
node_editor -->|"saves post"| node_blog_logic
node_editor -->|"renders"| node_rich_editor
node_rich_editor -->|"uses"| node_toolbar
node_theme -->|"reads and writes"| node_storage

click node_app "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/App.tsx"
click node_bootstrap "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/main.tsx"
click node_navbar "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/components/Navbar.tsx"
click node_home "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/pages/Home.tsx"
click node_project_cards "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/components/cardList.tsx"
click node_card "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/components/card.tsx"
click node_cards_data "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/models/cardsData.ts"
click node_hero "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/components/data-grid-hero.tsx"
click node_rates "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/pages/Rates.tsx"
click node_accessibility "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/pages/AccessibilityChecker.tsx"
click node_blog_list "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/pages/Blog.tsx"
click node_blog_post "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/pages/BlogPost.tsx"
click node_blog_logic "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/controllers/blogController.ts"
click node_blog_seed "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/models/blogData.ts"
click node_admin_login "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/pages/admin/AdminLogin.tsx"
click node_auth "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/controllers/authController.ts"
click node_private_route "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/components/PrivateRoute.tsx"
click node_dashboard "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/pages/admin/AdminDashboard.tsx"
click node_editor "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/pages/admin/PostEditor.tsx"
click node_rich_editor "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/components/admin/RichEditor.tsx"
click node_toolbar "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/components/admin/Toolbar.tsx"
click node_i18n "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/i18n.ts"
click node_theme "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/controllers/themeController.ts"
click node_page_title "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/hooks/usePageTitle.ts"
click node_not_found "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/pages/NotFound.tsx"
click node_back_to_top "https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/components/backToTop.tsx"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_app,node_bootstrap,node_navbar,node_not_found,node_back_to_top toneBlue
class node_home,node_project_cards,node_card,node_cards_data,node_hero,node_rates,node_accessibility toneAmber
class node_blog_list,node_blog_post,node_blog_logic,node_blog_seed,node_checker_api toneMint
class node_admin_login,node_auth,node_private_route,node_dashboard,node_editor,node_rich_editor,node_toolbar toneRose
class node_storage,node_i18n,node_theme,node_page_title,node_visitor,node_contact_service toneIndigo
```

## Components

### App shell

- [Router and shell](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/App.tsx): `src/App.tsx`
- [React bootstrap](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/main.tsx): `src/main.tsx`
- [Navigation](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/components/Navbar.tsx): `src/view/components/Navbar.tsx`
- [Not found page](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/pages/NotFound.tsx): `src/view/pages/NotFound.tsx`
- [Back to top](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/components/backToTop.tsx): `src/view/components/backToTop.tsx`

### Portfolio experience

- [Portfolio home](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/pages/Home.tsx): `src/view/pages/Home.tsx`
- [Project cards](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/components/cardList.tsx): `src/view/components/cardList.tsx`
- [Project card](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/components/card.tsx): `src/view/components/card.tsx`
- [Project data](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/models/cardsData.ts): `src/models/cardsData.ts`
- [Animated hero](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/components/data-grid-hero.tsx): `src/components/data-grid-hero.tsx`
- [Rates page](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/pages/Rates.tsx): `src/view/pages/Rates.tsx`
- [Accessibility checker](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/pages/AccessibilityChecker.tsx): `src/view/pages/AccessibilityChecker.tsx`

### Blog publishing

- [Blog listing](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/pages/Blog.tsx): `src/view/pages/Blog.tsx`
- [Blog post view](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/pages/BlogPost.tsx): `src/view/pages/BlogPost.tsx`
- [Blog data and storage](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/controllers/blogController.ts): `src/controllers/blogController.ts`
- [Seed posts](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/models/blogData.ts): `src/models/blogData.ts`

### Administration

- [Admin login](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/pages/admin/AdminLogin.tsx): `src/view/pages/admin/AdminLogin.tsx`
- [Authentication](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/controllers/authController.ts): `src/controllers/authController.ts`
- [Route guard](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/components/PrivateRoute.tsx): `src/view/components/PrivateRoute.tsx`
- [Post dashboard](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/pages/admin/AdminDashboard.tsx): `src/view/pages/admin/AdminDashboard.tsx`
- [Post editor](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/pages/admin/PostEditor.tsx): `src/view/pages/admin/PostEditor.tsx`
- [Rich editor](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/components/admin/RichEditor.tsx): `src/view/components/admin/RichEditor.tsx`
- [Editor toolbar](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/view/components/admin/Toolbar.tsx): `src/view/components/admin/Toolbar.tsx`

### Shared services

- **Browser storage**
- [Translations](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/i18n.ts): `src/i18n.ts`
- [Theme controller](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/controllers/themeController.ts): `src/controllers/themeController.ts`
- [Page title hook](https://github.com/dluisvaldivia/dvportfolio/blob/main/src/hooks/usePageTitle.ts): `src/hooks/usePageTitle.ts`

### Other components

- **Visitor**
- **Accessibility API**
- **EmailJS service**

## Connections

- Visitor → Router and shell: opens (evidence: `src/App.tsx`)
- React bootstrap → Router and shell: renders (evidence: `src/main.tsx`)
- React bootstrap → Translations: loads (evidence: `src/main.tsx`)
- Router and shell → Navigation: renders (evidence: `src/App.tsx`)
- Router and shell → Portfolio home: routes to (evidence: `src/App.tsx`)
- Router and shell → Blog listing: routes to (evidence: `src/App.tsx`)
- Router and shell → Blog post view: routes to (evidence: `src/App.tsx`)
- Router and shell → Accessibility checker: routes to (evidence: `src/App.tsx`)
- Router and shell → Admin login: routes to (evidence: `src/App.tsx`)
- Router and shell → Route guard: guards routes (evidence: `src/App.tsx`)
- Router and shell → Post dashboard: routes to (evidence: `src/App.tsx`)
- Router and shell → Post editor: routes to (evidence: `src/App.tsx`)
- Router and shell → Not found page: routes to (evidence: `src/App.tsx`)
- Router and shell → Back to top: renders (evidence: `src/App.tsx`)
- Router and shell → Theme controller: sets theme (evidence: `src/App.tsx`)
- Portfolio home → Project cards: renders (evidence: `src/view/pages/Home.tsx`)
- Portfolio home → Animated hero: renders (evidence: `src/view/pages/Home.tsx`)
- Project cards → Project card: renders (evidence: `src/view/components/cardList.tsx`)
- Project cards → Project data: reads (evidence: `src/view/components/cardList.tsx`)
- Portfolio home → EmailJS service: sends contact (evidence: `src/view/pages/Home.tsx`)
- Accessibility checker → Accessibility API: fetches report (evidence: `src/view/pages/AccessibilityChecker.tsx`)
- Blog listing → Blog data and storage: loads posts (evidence: `src/view/pages/Blog.tsx`)
- Blog post view → Blog data and storage: loads post (evidence: `src/view/pages/BlogPost.tsx`)
- Blog data and storage → Seed posts: merges seeds (evidence: `src/controllers/blogController.ts`)
- Blog data and storage → Browser storage: reads and writes (evidence: `src/controllers/blogController.ts`)
- Admin login → Authentication: checks credentials (evidence: `src/view/pages/admin/AdminLogin.tsx`)
- Route guard → Authentication: checks session (evidence: `src/view/components/PrivateRoute.tsx`)
- Authentication → Browser storage: stores session (evidence: `src/controllers/authController.ts`)
- Post dashboard → Authentication: logs out (evidence: `src/view/pages/admin/AdminDashboard.tsx`)
- Post dashboard → Blog data and storage: manages posts (evidence: `src/view/pages/admin/AdminDashboard.tsx`)
- Post editor → Blog data and storage: saves post (evidence: `src/view/pages/admin/PostEditor.tsx`)
- Post editor → Rich editor: renders (evidence: `src/view/pages/admin/PostEditor.tsx`)
- Rich editor → Editor toolbar: uses (evidence: `src/view/components/admin/RichEditor.tsx`)
- Theme controller → Browser storage: reads and writes (evidence: `src/controllers/themeController.ts`)
