All checks were successful
Build and Deploy Nuxt / build (push) Successful in 35s
5.2 KiB
5.2 KiB
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 tofrontend/app/. Auto-imported composables includeuseAsyncData,useI18n,useRoute,useLocalePath, etc. - Backend reads
.env.developmentor.env.productionbased onNODE_ENV. RequiresDB_URIfor MongoDB. - Frontend runtime config key
public.apiBaseUrlsets the backend API URL used byuseApi(). - 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 vialang="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. Respectsprefers-color-schemeon first visit. - Theme setup runs via
setupTheme()composable called on app mount (app.vue).
Deployment
- Gitea Actions CI/CD triggers on push to
master, builds Docker images, pushes to Gitea registry. - SSHs into deploy host and runs
docker-compose pull && docker-compose up -d. - For manual deployment,
docker-compose.ymlorchestrates nginx + frontend + backend services. - Production process management uses PM2 via
ecosystem.config.js.