# aranroig.com

Monorepo for aranroig.com — a personal portfolio website with blog, art gallery, and project showcase.

## Stack

- **Frontend**: Nuxt 4 + Vue 3 + TypeScript + SCSS
- **Backend**: Express 5 + Mongoose (MongoDB)
- **i18n**: @nuxtjs/i18n (English, Spanish, Catalan)
- **Content**: Nuxt Content v3 with Zod-sourced Markdown collections
- **Image optimization**: @nuxt/image
- **Build**: Vite
- **Deployment**: Docker Compose + Nginx reverse proxy + Gitea Actions CI/CD
- **Process management**: PM2 (production)

## Project Structure

```
├── backend/              # Express API server (port 5000)
│   └── src/
│       ├── index.js      # Entry point, single /api/test endpoint
│       └── db.js         # MongoDB connection via Mongoose
├── frontend/             # Nuxt application
│   ├── app/
│   │   ├── assets/css/   # Global SCSS: colors.scss (themes), fonts.scss, main.scss
│   │   ├── components/   # Vue components (TUI-styled)
│   │   │   ├── layouts/  # Page layout wrappers
│   │   │   ├── parts/    # Header, footer, navigation pieces
│   │   │   └── content/  # Blog, art content components
│   │   ├── composables/  # useApi(), theme.ts (light/dark + accent colors)
│   │   ├── i18n.config.ts# VueI18n fallback locale setup
│   │   └── pages/        # File-based routing (index, blog, art, contact)
│   ├── content/          # Markdown collections organized by locale
│   │   ├── fixed/        # Static pages per locale
│   │   ├── blog/         # Blog posts
│   │   ├── art/          # Art pieces
│   │   └── projects/     # Project cards
│   ├── i18n/locales/     # en.json, es.json, ca.json translation files
│   ├── content.config.ts # Content collection schemas (Zod)
│   └── nuxt.config.ts    # Nuxt config: modules, i18n, runtime config
├── docker-compose.yml    # Services: nginx, frontend, backend
├── nginx.conf            # Reverse proxy routing /api/ → backend:5000
├── ecosystem.config.js   # PM2 production deployment config
└── .gitea/workflows/     # Gitea Actions CI/CD (deploy on master push)
```

## Commands

From repo root:

| Command | Description |
|---------|-------------|
| `npm run dev` | Run frontend + backend concurrently with logging prefixes `[BACKEND]` and `[FRONTEND]` |
| `npm install` | Install monorepo dependencies (triggers `frontend/postinstall`) |

In `frontend/`:

| Command | Description |
|---------|-------------|
| `npm run dev` | Nuxt dev server with live reload |
| `npm run build` | Production build with `.env.production` |
| `npm run generate` | Static site generation |
| `npm run preview` | Preview built production output |

In `backend/`:

| Command | Description |
|---------|-------------|
| `npm run dev` | Nodemon on `src/index.js` (auto-restart, port 5000) |

## Development

- Use the monorepo root script: `npm run dev` — runs both frontend and backend in parallel.
- Frontend uses the `~/` alias mapping to `frontend/app/`. Auto-imported composables include `useAsyncData`, `useI18n`, `useRoute`, `useLocalePath`, etc.
- Backend reads `.env.development` or `.env.production` based on `NODE_ENV`. Requires `DB_URI` for MongoDB.
- Frontend runtime config key `public.apiBaseUrl` sets the backend API URL used by `useApi()`.
- Content lives in `frontend/content/` under collection folders (`blog`, `fixed`, `art`, `projects`), each with locale subdirectories (`en`, `es`, `ca`).

## Code Style

- Vue SFCs use `<script setup>` (TypeScript via `lang="ts"` where needed, plain JS otherwise).
- All styling is SCSS with scoped styles per component. Page-level blog/art pages use global styles.
- Mobile-first breakpoints: `600px`, `900px`, `1200px` (max-width queries).
- File names: kebab-case for components and pages.
- CSS variables driven by SCSS maps define themes (light/dark) and accent colors.
- TUI aesthetic: box-drawing characters, monospace font (**Hermit** / "Hurmit" via Nerd Fonts), `steps()` easing transitions, pixel-art SVG elements.

## Content Collections

Content frontmatter is validated with Zod schemas defined in `frontend/content.config.ts`:

| Collection | Fields |
|------------|--------|
| `blog` | title, slug, date, description |
| `art` | title, slug, thumb, date |
| `projects` | title, slug, description, link, tech (array) |
| `fixed` | title, slug, description |

Write Markdown files under the corresponding collection folder with locale subdirectories. Frontmatter must conform to the Zod schema.

## Theming

- Theme selector switches between light/dark modes and accent color palettes (dragon-themed names: katlum, solus, silang, nozt, albor).
- Preferences persist in `localStorage`. Respects `prefers-color-scheme` on first visit.
- Theme setup runs via `setupTheme()` composable called on app mount (`app.vue`).

## Deployment

1. Gitea Actions CI/CD triggers on push to `master`, builds Docker images, pushes to Gitea registry.
2. SSHs into deploy host and runs `docker-compose pull && docker-compose up -d`.
3. For manual deployment, `docker-compose.yml` orchestrates nginx + frontend + backend services.
4. Production process management uses PM2 via `ecosystem.config.js`.
