Skip to main content

Content Management System

Juan Roccia’s portfolio leverages Astro’s powerful content collections feature to provide type-safe, schema-validated content management for portfolio projects. This system ensures data consistency while maintaining the simplicity of Markdown-based authoring.

Astro Content Collections Overview

Content collections are Astro’s solution for managing structured content like blog posts, portfolio projects, and documentation. They provide:

Type Safety

Automatic TypeScript types generated from Zod schemas

Schema Validation

Frontmatter validated at build time, catching errors early

Query API

Simple getCollection() API for fetching content

Performance

Content pre-processed at build time for optimal runtime performance
Content collections live in the /src/content/ directory and are configured in config.ts files within each collection folder.

Work Collection Configuration

The portfolio’s work collection is defined in /src/content/work/config.ts:
import { defineCollection, z } from 'astro:content';

export const collections = {
  work: defineCollection({
    schema: z.object({
      title: z.string(),
      description: z.string(),
      publishDate: z.coerce.date(),
      tags: z.array(z.string()),
      img: z.string(),
      img_alt: z.string().optional(),
    }),
  }),
};

Schema Breakdown

Each field in the schema serves a specific purpose:
FieldTypeRequiredPurpose
titlestringYesProject name displayed in UI
descriptionstringYesBrief project summary for preview cards
publishDatedate (coerced)YesPublication date for sorting (newest first)
tagsstring[]YesTechnology tags for categorization
imgstringYesPath to project image (relative to /public)
img_altstringNoAccessibility alt text for image
1

Zod Schema Definition

Zod (z) provides runtime validation and type inference for frontmatter
2

Type Coercion

z.coerce.date() automatically converts string dates to Date objects
3

Optional Fields

.optional() makes img_alt field non-required, defaulting to empty string
4

Array Validation

z.array(z.string()) ensures tags is always an array of strings

Markdown-Based Project Entries

Each portfolio project is a Markdown file in /src/content/work/ with frontmatter and content:
---
title: AudioGPT
publishDate: 2024-03-10 00:00:00
img: /assets/stock-2.jpg
img_alt: AudioGPT application interface
description: |
  Aplicación de inteligencia artificial que convierte texto a voz con diversas opciones de personalización y control.
tags:
  - AI
  - Audio Generation
  - Web App
  - Speech Synthesis
---

## AudioGPT: Generación de voz avanzada con IA

Este proyecto combina tecnologías de procesamiento de lenguaje natural y síntesis de voz para convertir texto en audio de alta calidad con diferentes voces, acentos y estilos emocionales.

### Estado: En desarrollo (próximamente disponible)

### Características principales

- Conversión de texto a voz con múltiples opciones de personalización
- Selección entre diferentes voces, acentos y idiomas
- Control de parámetros como velocidad, tono y énfasis emocional
- Exportación de audio en diferentes formatos y calidades
- Historial de generaciones para acceder fácilmente a conversiones anteriores
- Interfaz responsiva que funciona en dispositivos móviles y de escritorio

### Tecnologías implementadas

El proyecto utiliza una combinación de tecnologías de vanguardia:

- APIs de modelos avanzados de lenguaje para el procesamiento de texto
- Algoritmos de síntesis de voz neuronal para una reproducción natural del habla
- Frontend desarrollado con React para una experiencia de usuario fluida
- Sistema de autenticación para guardar configuraciones y preferencias de usuario
- Optimización del rendimiento para procesar textos largos sin pérdida de calidad

### Aplicaciones prácticas

AudioGPT está diseñado para servir a múltiples propósitos:

- Creación de contenido para podcasts y audiolibros
- Asistencia para personas con discapacidad visual
- Herramienta educativa para aprendizaje de idiomas
- Desarrollo de interfaces de voz para aplicaciones y servicios
- Producción de voces en off para videos y presentaciones

Este proyecto representa un avance significativo en la intersección entre la inteligencia artificial y la tecnología de audio, ofreciendo a los usuarios una herramienta versátil para generar contenido de voz de alta calidad con mínimo esfuerzo.

Frontmatter Structure

title: AudioGPT
description: |
  Aplicación de inteligencia artificial que convierte 
  texto a voz con diversas opciones de personalización...
  • Title: Concise project name
  • Description: Multi-line string using | for line breaks
  • Used in preview cards and SEO metadata

Fetching Collection Data

Astro provides the getCollection() function to query content collections:
---
import { getCollection } from 'astro:content';

// Fetch all projects, sort by date descending, take 4 most recent
const projects = (await getCollection('work'))
  .sort((a, b) => b.data.publishDate.valueOf() - a.data.publishDate.valueOf())
  .slice(0, 4);
---

<Grid variant="offset">
  {
    projects.map((project) => (
      <li>
        <PortfolioPreview project={project} />
      </li>
    ))
  }
</Grid>

Query Operations

1

Fetch Collection

await getCollection('work') returns an array of all entries in the work collection
2

Sort by Date

.sort() arranges projects chronologically using publishDate.valueOf() for numeric comparison
3

Limit Results

.slice(0, 4) takes only the first 4 items (used on home page for featured projects)
4

Map to Components

.map() renders each project as a PortfolioPreview component

Type Safety in Components

Content collections automatically generate TypeScript types for use in components:
---
import type { CollectionEntry } from 'astro:content';

interface Props {
  project: CollectionEntry<'work'>;
}

const { data, slug } = Astro.props.project;
---

<a class="card" href={`/work/${slug}`}>
  <span class="title" transition:name={`title-${slug}`}>
    {data.title}
  </span>
  <img 
    src={data.img} 
    transition:name={`img-${slug}`} 
    alt={data.img_alt || ''} 
    loading="lazy" 
    decoding="async" 
  />
</a>

Type Benefits

Autocomplete

IDE provides suggestions for data.title, data.img, etc.

Error Detection

TypeScript catches typos like data.titel at development time

Refactoring Safety

Changing schema automatically updates types everywhere

Documentation

Type definitions serve as inline documentation for data shape

Dynamic Route Generation

Content collections integrate seamlessly with Astro’s dynamic routing:
---
import { getCollection } from 'astro:content';
import type { CollectionEntry } from 'astro:content';

// Generate static paths for all work entries
export async function getStaticPaths() {
  const work = await getCollection('work');
  return work.map(entry => ({
    params: { slug: entry.slug },
    props: { entry },
  }));
}

type Props = {
  entry: CollectionEntry<'work'>;
};

const { entry } = Astro.props;
const { Content } = await entry.render();
---

<BaseLayout title={entry.data.title} description={entry.data.description}>
  <article>
    <img src={entry.data.img} alt={entry.data.img_alt} />
    <h1>{entry.data.title}</h1>
    <Content />
  </article>
</BaseLayout>

Dynamic Routing Flow

1

getStaticPaths()

Function runs at build time to generate all possible routes
2

Map Collection Entries

Each entry generates a route with { slug: entry.slug } parameter
3

Pass Entry as Prop

Full entry object passed to page component for rendering
4

Render Markdown Content

await entry.render() compiles Markdown to HTML as <Content /> component

Schema Validation Benefits

The Zod schema provides runtime validation that catches errors during development:

Validation Examples

---
title: My Project
# ERROR: publishDate is required
description: A great project
tags: ["Web"]
img: /assets/project.jpg
---
Build Error:
[error] Content Schema Error: "publishDate" is required

Content Directory Structure

/src/content/work/
├── config.ts              # Collection schema definition
├── audiogpt.md           # Project entry
├── blog.md               # Project entry
├── casa-del-tapicero.md  # Project entry
├── encontrar-mascotas.md # Project entry
└── ...                   # Additional projects
File names (minus .md extension) become the URL slug. For example, audiogpt.md creates the route /work/audiogpt.

Adding New Projects

To add a new portfolio project:
1

Create Markdown File

Create a new .md file in /src/content/work/ with a URL-friendly filename
2

Add Frontmatter

Include all required fields (title, description, publishDate, tags, img) in YAML frontmatter
3

Write Content

Add project details, features, technologies, and images below the frontmatter
4

Add Project Image

Place the project image in /public/assets/ and reference it in frontmatter
5

Build & Verify

Run npm run build to validate schema and generate the new project page
---
title: My New Project
publishDate: 2024-03-15 00:00:00
img: /assets/new-project.jpg
img_alt: Screenshot of new project interface
description: |
  A comprehensive description of what this project does and why it's important.
tags:
  - React
  - TypeScript
  - API Integration
---

## Project Overview

Detailed information about the project...

### Key Features

- Feature 1
- Feature 2
- Feature 3

### Technologies Used

Description of the technology stack...

Content Collection Advantages

Using Astro content collections for portfolio management provides significant benefits:

Developer Experience

Type safety, autocomplete, and instant error feedback during development

Maintainability

Centralized schema makes it easy to add fields or change validation rules

Performance

All content processed at build time, no runtime validation overhead

Flexibility

Full Markdown support with frontmatter for structured data

Portability

Markdown files are plain text, easily migrated or version controlled

Separation of Concerns

Content authors work with Markdown, developers work with components
Astro’s content collections strike the perfect balance between the simplicity of Markdown-based content and the power of type-safe, schema-validated data management - ideal for portfolio websites that need both ease of use and reliability.

Build docs developers (and LLMs) love