# khairinkamarizal/portfolio architecture

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

- Interactive diagram: https://gitdiagram.com/khairinkamarizal/portfolio
- Repository: https://github.com/khairinkamarizal/portfolio

## Overview

khair.ink is a personal portfolio with writing, selected-work, and an AI message experience; the repository also contains substantial finance-ledger and business-card capture features. The main visitor journey is browsing the portfolio and its work or writing, while finance and card capture form distinct application workflows. The sampled finance code confirms dashboard requests, ledger query planning and D1-backed repository behavior; other unsampled routes are shown as capabilities from the tree and README, without assuming their internal call wiring.

Main entry points: [`app/app.vue`](https://github.com/khairinkamarizal/portfolio/blob/main/app/app.vue) (Nuxt App Shell), [`app/pages/index.vue`](https://github.com/khairinkamarizal/portfolio/blob/main/app/pages/index.vue) (Portfolio Home), [`app/pages/finance.vue`](https://github.com/khairinkamarizal/portfolio/blob/main/app/pages/finance.vue) (Finance Dashboard), [`app/composables/useFinanceDashboard.ts`](https://github.com/khairinkamarizal/portfolio/blob/main/app/composables/useFinanceDashboard.ts) (Dashboard State)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_portfolio["Portfolio"]
  node_app["Nuxt App Shell<br/>[app.vue]"]
  node_home["Portfolio Home<br/>[index.vue]"]
  node_about["Profile Page<br/>[about.vue]"]
  node_message["AI Message<br/>[message.vue]"]
  node_contact["Contact Form<br/>[ContactForm.vue]"]
end

subgraph group_content["Writing And Work"]
  node_work["Work Showcase<br/>[work.vue]"]
  node_projectdata["Project Data<br/>[projects.ts]"]
  node_writinglist["Writing Index<br/>[index.vue]"]
  node_post["Writing Post<br/>[&#91;slug&#93;.vue]"]
  node_contentstore[("Writing Content<br/>[content.config.ts]")]
end

subgraph group_finance["Finance Ledger"]
  node_financepage["Finance Dashboard<br/>[finance.vue]"]
  node_dashboard["Dashboard State"]
  node_financeui["Finance Views<br/>[FinanceQuery.vue]"]
  node_queryapi["Ledger Query API<br/>[query.post.ts]"]
  node_financeapi["Finance APIs"]
  node_querylogic["Query Planner<br/>[finance-query.ts]"]
  node_repository["Ledger Repository"]
  node_d1[("Finance D1")]
end

subgraph group_cards["Card Capture"]
  node_cardcapture["Card Capture<br/>[CardCapture.vue]"]
  node_cardreview["Card Review<br/>[CardReviewForm.vue]"]
  node_cardapi["Card Scan API<br/>[scan.post.ts]"]
  node_cardsheets["Sheets Export<br/>[append.post.ts]"]
end

subgraph group_services["Server Services"]
  node_gemini{{"Gemini API"}}
  node_vertex{{"Vertex AI"}}
  node_googlevision{{"Google Vision"}}
  node_sheets[("Google Sheets")]
  node_browserstorage[("Browser Storage")]
end

node_visitor(("Site Visitor"))

node_visitor -->|"opens site"| node_app
node_app -->|"renders route"| node_home
node_home -->|"selects projects"| node_projectdata
node_home -->|"queries recent posts"| node_contentstore
node_visitor -->|"browses work"| node_work
node_work -->|"reads projects"| node_projectdata
node_visitor -->|"browses writing"| node_writinglist
node_writinglist -->|"queries posts"| node_contentstore
node_visitor -->|"opens post"| node_post
node_post -->|"loads article"| node_contentstore
node_visitor -->|"asks question"| node_message
node_message -.->|"requests response"| node_gemini
node_visitor -->|"sends message"| node_contact
node_visitor -->|"opens dashboard"| node_financepage
node_financepage -->|"uses state"| node_dashboard
node_dashboard -->|"fetches ledger data"| node_financeapi
node_dashboard -->|"submits question"| node_queryapi
node_financepage -->|"renders query"| node_financeui
node_queryapi -->|"plans and executes"| node_querylogic
node_querylogic -->|"interprets filters"| node_vertex
node_querylogic -->|"queries ledger"| node_d1
node_financeapi -->|"reads and updates"| node_repository
node_repository -->|"reads and writes"| node_d1
node_visitor -->|"scans card"| node_cardcapture
node_cardcapture -->|"reviews draft"| node_cardreview
node_cardcapture -->|"submits image"| node_cardapi
node_cardapi -.->|"extracts text"| node_googlevision
node_visitor -->|"exports contact"| node_cardsheets
node_cardsheets -.->|"appends record"| node_sheets
node_app -->|"persists preferences"| node_browserstorage

click node_app "https://github.com/khairinkamarizal/portfolio/blob/main/app/app.vue"
click node_home "https://github.com/khairinkamarizal/portfolio/blob/main/app/pages/index.vue"
click node_about "https://github.com/khairinkamarizal/portfolio/blob/main/app/pages/about.vue"
click node_message "https://github.com/khairinkamarizal/portfolio/blob/main/app/pages/message.vue"
click node_contact "https://github.com/khairinkamarizal/portfolio/blob/main/app/components/ContactForm.vue"
click node_work "https://github.com/khairinkamarizal/portfolio/blob/main/app/pages/work.vue"
click node_projectdata "https://github.com/khairinkamarizal/portfolio/blob/main/app/data/projects.ts"
click node_writinglist "https://github.com/khairinkamarizal/portfolio/blob/main/app/pages/writing/index.vue"
click node_post "https://github.com/khairinkamarizal/portfolio/blob/main/app/pages/writing/%5Bslug%5D.vue"
click node_contentstore "https://github.com/khairinkamarizal/portfolio/blob/main/content.config.ts"
click node_financepage "https://github.com/khairinkamarizal/portfolio/blob/main/app/pages/finance.vue"
click node_dashboard "https://github.com/khairinkamarizal/portfolio/blob/main/app/composables/useFinanceDashboard.ts"
click node_financeui "https://github.com/khairinkamarizal/portfolio/blob/main/app/components/finance/FinanceQuery.vue"
click node_queryapi "https://github.com/khairinkamarizal/portfolio/blob/main/server/api/finance/query.post.ts"
click node_financeapi "https://github.com/khairinkamarizal/portfolio/blob/main/server/api/finance/transactions.get.ts"
click node_querylogic "https://github.com/khairinkamarizal/portfolio/blob/main/server/utils/finance-query.ts"
click node_repository "https://github.com/khairinkamarizal/portfolio/blob/main/server/utils/finance-repository.ts"
click node_cardcapture "https://github.com/khairinkamarizal/portfolio/blob/main/app/components/cards/CardCapture.vue"
click node_cardreview "https://github.com/khairinkamarizal/portfolio/blob/main/app/components/cards/CardReviewForm.vue"
click node_cardapi "https://github.com/khairinkamarizal/portfolio/blob/main/server/api/cards/scan.post.ts"
click node_cardsheets "https://github.com/khairinkamarizal/portfolio/blob/main/server/api/cards/sheets/append.post.ts"

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_home,node_about,node_message,node_contact toneBlue
class node_work,node_projectdata,node_writinglist,node_post,node_contentstore toneAmber
class node_financepage,node_dashboard,node_financeui,node_queryapi,node_financeapi,node_querylogic,node_repository,node_d1 toneMint
class node_cardcapture,node_cardreview,node_cardapi,node_cardsheets toneRose
class node_gemini,node_vertex,node_googlevision,node_sheets,node_browserstorage,node_visitor toneIndigo
```

## Components

### Portfolio

- [Nuxt App Shell](https://github.com/khairinkamarizal/portfolio/blob/main/app/app.vue): `app/app.vue`
- [Portfolio Home](https://github.com/khairinkamarizal/portfolio/blob/main/app/pages/index.vue): `app/pages/index.vue`
- [Profile Page](https://github.com/khairinkamarizal/portfolio/blob/main/app/pages/about.vue): `app/pages/about.vue`
- [AI Message](https://github.com/khairinkamarizal/portfolio/blob/main/app/pages/message.vue): `app/pages/message.vue`
- [Contact Form](https://github.com/khairinkamarizal/portfolio/blob/main/app/components/ContactForm.vue): `app/components/ContactForm.vue`

### Writing And Work

- [Work Showcase](https://github.com/khairinkamarizal/portfolio/blob/main/app/pages/work.vue): `app/pages/work.vue`
- [Project Data](https://github.com/khairinkamarizal/portfolio/blob/main/app/data/projects.ts): `app/data/projects.ts`
- [Writing Index](https://github.com/khairinkamarizal/portfolio/blob/main/app/pages/writing/index.vue): `app/pages/writing/index.vue`
- [Writing Post](https://github.com/khairinkamarizal/portfolio/blob/main/app/pages/writing/%5Bslug%5D.vue): `app/pages/writing/[slug].vue`
- [Writing Content](https://github.com/khairinkamarizal/portfolio/blob/main/content.config.ts): `content.config.ts`

### Finance Ledger

- [Finance Dashboard](https://github.com/khairinkamarizal/portfolio/blob/main/app/pages/finance.vue): `app/pages/finance.vue`
- [Dashboard State](https://github.com/khairinkamarizal/portfolio/blob/main/app/composables/useFinanceDashboard.ts): `app/composables/useFinanceDashboard.ts`
- [Finance Views](https://github.com/khairinkamarizal/portfolio/blob/main/app/components/finance/FinanceQuery.vue): `app/components/finance/FinanceQuery.vue`
- [Ledger Query API](https://github.com/khairinkamarizal/portfolio/blob/main/server/api/finance/query.post.ts): `server/api/finance/query.post.ts`
- [Finance APIs](https://github.com/khairinkamarizal/portfolio/blob/main/server/api/finance/transactions.get.ts): `server/api/finance/transactions.get.ts`
- [Query Planner](https://github.com/khairinkamarizal/portfolio/blob/main/server/utils/finance-query.ts): `server/utils/finance-query.ts`
- [Ledger Repository](https://github.com/khairinkamarizal/portfolio/blob/main/server/utils/finance-repository.ts): `server/utils/finance-repository.ts`
- **Finance D1**

### Card Capture

- [Card Capture](https://github.com/khairinkamarizal/portfolio/blob/main/app/components/cards/CardCapture.vue): `app/components/cards/CardCapture.vue`
- [Card Review](https://github.com/khairinkamarizal/portfolio/blob/main/app/components/cards/CardReviewForm.vue): `app/components/cards/CardReviewForm.vue`
- [Card Scan API](https://github.com/khairinkamarizal/portfolio/blob/main/server/api/cards/scan.post.ts): `server/api/cards/scan.post.ts`
- [Sheets Export](https://github.com/khairinkamarizal/portfolio/blob/main/server/api/cards/sheets/append.post.ts): `server/api/cards/sheets/append.post.ts`

### Server Services

- **Gemini API**
- **Vertex AI**
- **Google Vision**
- **Google Sheets**
- **Browser Storage**

### Other components

- **Site Visitor**

## Connections

- Site Visitor → Nuxt App Shell: opens site
- Nuxt App Shell → Portfolio Home: renders route
- Portfolio Home → Project Data: selects projects
- Portfolio Home → Writing Content: queries recent posts
- Site Visitor → Work Showcase: browses work
- Work Showcase → Project Data: reads projects
- Site Visitor → Writing Index: browses writing
- Writing Index → Writing Content: queries posts
- Site Visitor → Writing Post: opens post
- Writing Post → Writing Content: loads article
- Site Visitor → AI Message: asks question
- AI Message → Gemini API: requests response
- Site Visitor → Contact Form: sends message
- Site Visitor → Finance Dashboard: opens dashboard
- Finance Dashboard → Dashboard State: uses state
- Dashboard State → Finance APIs: fetches ledger data
- Dashboard State → Ledger Query API: submits question
- Finance Dashboard → Finance Views: renders query
- Ledger Query API → Query Planner: plans and executes
- Query Planner → Vertex AI: interprets filters
- Query Planner → Finance D1: queries ledger
- Finance APIs → Ledger Repository: reads and updates
- Ledger Repository → Finance D1: reads and writes
- Site Visitor → Card Capture: scans card
- Card Capture → Card Review: reviews draft
- Card Capture → Card Scan API: submits image
- Card Scan API → Google Vision: extracts text
- Site Visitor → Sheets Export: exports contact
- Sheets Export → Google Sheets: appends record
- Nuxt App Shell → Browser Storage: persists preferences
