Saltar al contenido
Documentación del sistema
Producción operativaActualizado hoy4 servicios

Un producto que puedes abrir por dentro.

Este portfolio es la interfaz pública de un pequeño sistema distribuido. Nuxt renderiza la experiencia, Rust expone los datos, Python ejecuta procesos internos y PostgreSQL mantiene las relaciones.

Estado del sistema/system/status
RuntimeOperational
En línea

Métricas internas del servicio: dependencias, pools, jobs y uptime. No se registran visitas ni comportamiento de usuarios.

Uptime3d 18h
APIv0.1.0
DB latency2 ms
Requests
Servicioschecks concurrentes
PostgreSQLhealthy / healthy
healthy
Python workerFastAPI · jobs
healthy
GitHub sync37 repos · 12 lenguajes
healthy
SMTPmail
disabled
GitHub sync · 13/8/26, 15:22 · 1840 msEsperando comprobación
Mapa de arquitecturaPetición pública
NavegadorNuxt SSR + hidratación
API RustAxum · puerto 8000
Capa de datosPools reader / writer
PostgreSQLDominios separados

Aplicación / 01

Frontend

Una interfaz renderizada en servidor, tipada y construida con una capa visual Tailwind-first.

01

Nuxt 4

Rutas por archivos, SSR, metadatos SEO y composables para mantener las páginas predecibles.

02

Vue 3

Componentes reactivos pequeños para filtros, formularios, hora local y movimiento.

03

Tailwind 4

Layout, color, tipografía y responsive viven en utilidades. El CSS manual queda limitado a efectos globales.

04

Contratos tipados

Proyectos, repositorios, clientes y colaboradores comparten un único modelo de datos.

05

Carga por recurso

Cada vista solicita solo los endpoints que necesita. Un fallo parcial conserva el resto del contenido disponible.

06

Recuperación SSR

Tras una recarga, Nuxt hidrata el estado del servidor y reintenta en cliente únicamente los recursos que fallaron.

app/composables/usePortfolio.ts
1const repositories = useAsyncData(2    'portfolio-repositories',3    () => $fetch('/repositories'),4)5 6// Cada recurso conserva su propio estado y error.7// La hidratación reintenta solo las peticiones fallidas.8retryAfterHydration(repositories.error, repositories.refresh)

Aplicación / 02

API pública

El servicio Rust es el borde de lectura del sistema y el único backend expuesto al navegador.

MétodoRuta
GET/projectsProyectos publicados y metadatos de cada caso.
GET/projects/{slug}Detalle de un proyecto publicado por su slug.
GET/repositoriesRepositorios públicos con lenguajes y colaboradores.
GET/repositories/{slug}Detalle de un repositorio público por su slug.
GET/clientsRelaciones de cliente vinculadas al trabajo.
POST/contactEnvío de contacto limitado mediante el pool de escritura.
GET/Health check raíz para monitores y comprobaciones manuales.
GET/system/statusEstado concurrente de base de datos, worker, GitHub y SMTP.

Aplicación / 03

Python / Procesos internos

Python/FastAPI trabaja detrás del producto: arranca los jobs, sincroniza GitHub y mantiene actualizado el grafo de repositorios sin entrar en la ruta de lectura del navegador.

Ver documentación de jobs /jobs · /jobs/status
1
Arranque controlado

El lifespan de FastAPI levanta APScheduler una sola vez y deja preparado el job diario, con zona horaria de Madrid.

lifespan → scheduler
2
Lectura de GitHub

El cliente recorre los repositorios de la cuenta y obtiene metadatos, lenguajes, temas y colaboradores.

GitHubClient.process_repositories()
3
Escritura acotada

Cada entidad se actualiza con el rol de sincronización. Si falta una pieza, ese repositorio se omite sin tumbar el resto del ciclo.

sync_writer · fail soft
4
Relaciones resueltas

Repositorios, cuentas y proyectos quedan relacionados en PostgreSQL para que Rust pueda leerlos sin repetir trabajo.

accounts → repositories → projects
Ciclo del workerindependiente de la petición
Al iniciar

Se programa una primera ejecución breve después del arranque para no esperar al primer ciclo nocturno.

Cada noche

El job vuelve a ejecutarse a las 00:00 y refresca solo la fuente que cambia: GitHub.

Si falta configuración

Sin token o con credenciales inválidas, el proceso se detiene y deja la API pública intacta.

Al apagar

El lifespan cierra el scheduler para no dejar tareas colgando ni duplicar ejecuciones.

crons/tasks/github_sync.py
1async def sync_github():2    repositories = client.process_repositories()3    for repository in repositories:4        owner_id = db.upsert_account(repository.owner)5        repo_id = db.upsert_repository(repository, owner_id)6        db.sync_languages(repo_id, repository.languages)7        db.sync_topics(repo_id, repository.topics)8        db.sync_contributors(repo_id, repository.contributors)9 10# Rust solo lee el resultado ya relacionado.

Datos / 01

PostgreSQL

Los dominios se mantienen separados mientras las claves foráneas preservan las relaciones que aparecen en la interfaz.

P

portfolio

Proyectos y clientes con visibilidad, estado, fechas y enlaces externos.

G

github

Metadatos, lenguajes y colaboradores de repositorios de GitHub.

C

contact

Solicitudes de contacto escritas mediante una ruta y un rol restringidos.

Operaciones / 01

Docker

Cuatro imágenes especializadas forman una unidad desplegable sin mezclar responsabilidades de ejecución.

Puerto 3000
frontendnode:24-alpine · Nuxt Nitro
Puerto 8000
rust-apirust:1.96 · Axum
Puerto
python-apipython:3.11 · FastAPI
Puerto 5432
dbpostgres:18 · volumen persistente
docker-compose.yml
1services:2  rust-api: 3    build:4      context: ./backends/rust-api5    env_file: 6      - ./backends/.env7    ports: 8      - "8082:8000"  9    depends_on:10      - db11    restart: unless-stopped12  python-api:13    build:14      context: ./backends/python-api 15    environment:

Operaciones / 02

Ciclo de petición

El navegador recibe datos relacionados sin conocer las credenciales, los procesos internos ni el modelo relacional.

1Nuxt solicita los datos

Cada vista activa los recursos que necesita. Las páginas de proyectos relacionan tres respuestas; GitHub y Source code solo consultan repositorios.

2Rust aplica los límites

Axum valida CORS y rate limiting antes de consultar mediante el pool lector.

3El frontend relaciona

Los registros de repositorio y cliente se asocian a cada proyecto antes del render.

4El worker actualiza

Los procesos programados refrescan los metadatos sin intervenir en la petición pública.

Operaciones / 03

Límites y seguridad

La superficie pública es pequeña: orígenes restringidos, métodos limitados, roles distintos y escrituras protegidas.

CORS por allowlistSolo GET y POSTRol api_readerRol sync_writer120 peticiones/min3 contactos/minFiltrado de datos privadosNo-SQLiNo-XSSNo-CSRF

Apéndice

Por qué está construido así

La arquitectura es más explícita de lo que un portfolio necesita. Ese es el objetivo: el sitio demuestra los principios de ingeniería que describe.

Ver proyectos

Código / 01

Source code

La implementación completa de esta web es pública. El repositorio portfolio contiene el frontend, las APIs, los esquemas y la composición Docker que describe esta documentación.

El repositorio portfolio no aparece en la respuesta pública.