Skip to content

Commit 26c20d8

Browse files
committed
content: añade LlarJove (RAG) y VitaLiber CRM/ERP v2
Tarjetas + páginas de detalle (ES/EN) de dos proyectos recientes: LlarJove, chatbot RAG de vivienda joven (Fastify + GPT-4 + React 19, demo en Railway, repo público), y VitaLiber CRM/ERP v2, reescritura multi-tenant con PostgreSQL RLS (Symfony 7 + API Platform 4 + React 18, repo privado). Estrenan las categorías ia-chatbots y arquitectura-avanzada. Build 22 páginas OK, 266 tests en verde.
1 parent 97424f7 commit 26c20d8

3 files changed

Lines changed: 208 additions & 0 deletions

File tree

apps/portfolio/messages/en.json

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,66 @@
588588
{ "label": "Data model", "value": "Database-per-tenant" }
589589
]
590590
},
591+
"llarjove-rag-chatbot": {
592+
"sections": [
593+
{
594+
"heading": "Context",
595+
"body": "Conversational assistant for young people aged 18-35 in Catalonia looking for housing: available aid (Bono Alquiler Joven, regional and municipal grants), tenant rights (LAU, deposits, rent updates) and active programs with their deadlines (Borsa Jove, HPO). Deployed in production on Railway with a public repository."
596+
},
597+
{
598+
"heading": "RAG pipeline",
599+
"body": "Offline ingestion of curated official documentation (aid programs, rights, guides and laws): loading, chunking, embeddings and a vector store. At runtime each question is embedded, context is retrieved through semantic search with reranking, and the answer is generated with GPT-4, validated and returned with cited sources and a confidence level."
600+
},
601+
{
602+
"heading": "Backend",
603+
"body": "Fastify + TypeScript API with the pipeline organized into modules (ingestion, retrieval, generation) and a chat endpoint. Responses return answer, sources and confidence so users can verify the information."
604+
},
605+
{
606+
"heading": "Frontend",
607+
"body": "React 19 + Vite 6 + Tailwind CSS v4 interface with a custom design system (brand identity, color and typography tokens) and 59 component tests with Vitest and Testing Library."
608+
},
609+
{
610+
"heading": "Approach",
611+
"body": "An applied-AI project with social impact: official housing information is scattered and hard to interpret; the assistant centralizes it and answers in plain language, always citing the official source."
612+
}
613+
],
614+
"metrics": [
615+
{ "label": "Stack", "value": "Fastify · GPT-4" },
616+
{ "label": "Frontend", "value": "React 19 + Vite" },
617+
{ "label": "Frontend tests", "value": "59" },
618+
{ "label": "Deployment", "value": "Railway" }
619+
]
620+
},
621+
"vitaliber-crm-erp-v2": {
622+
"sections": [
623+
{
624+
"heading": "Context",
625+
"body": "Complete rewrite of the legacy CRM/ERP of VitaLiber, a telemarketing company with 5-20 agents in intensive daily use. The previous system (MySQL, 28 tables) carried severe technical debt. V2 replaces it with a clean domain model: CRM, telemarketing, sales (publishing catalogue), billing with SEPA direct debit, and email."
626+
},
627+
{
628+
"heading": "Multi-tenant with Row-Level Security",
629+
"body": "Per-provider data isolation enforced in the database itself: PostgreSQL 15 with Row-Level Security policies. A Doctrine postConnect listener sets the active tenant per connection and verifies it against the user-provider access table. JWT authentication with refresh tokens and an active-provider selector. GDPR-aware design."
630+
},
631+
{
632+
"heading": "Backend and schema",
633+
"body": "REST API with Symfony 7 + API Platform 4 and Swagger UI. The schema is owned by SQL migrations with DBmate (Doctrine acts as a query layer only), organized into 7 logical PostgreSQL schemas (core, crm, tmk, sales, billing, comms, audit). Outbox-lite auditing: domain events are written in the same transaction."
634+
},
635+
{
636+
"heading": "End-to-end typed frontend",
637+
"body": "React 18 + strict TypeScript + Vite with Tailwind and shadcn/ui. The API client is generated from OpenAPI with orval: TanStack Query hooks, types and Zod schemas kept in sync with the backend. Internationalization with react-intl (Spanish base, ready for Catalan and English)."
638+
},
639+
{
640+
"heading": "Process and status",
641+
"body": "Phased delivery mirroring the migration plan (8 phases with GitHub milestones and issues): identity & access, catalogs, CRM, telemarketing, sales and communications already merged to main. Decisions documented in 7 ADRs, a PNPM + Composer + Taskfile monorepo, CI/CD and PHPUnit + Vitest test suites, including RLS isolation tests. Live-data-only migration, keeping the legacy database as a read-only archive."
642+
}
643+
],
644+
"metrics": [
645+
{ "label": "Phases delivered", "value": "6 of 8" },
646+
{ "label": "ADRs", "value": "7" },
647+
{ "label": "PostgreSQL schemas", "value": "7" },
648+
{ "label": "Isolation", "value": "Per-tenant RLS" }
649+
]
650+
},
591651
"fastbyte-api-servicios": {
592652
"sections": [
593653
{
@@ -713,6 +773,49 @@
713773
"categoryId": "facturacion-compliance",
714774
"imageUrl": "/images/projects/gestiono-mi-negocio.webp"
715775
},
776+
{
777+
"id": "llarjove-rag-chatbot",
778+
"title": "LlarJove — RAG housing assistant for young people",
779+
"description": "RAG chatbot that helps young people aged 18-35 in Catalonia find housing: available aid (Bono Alquiler Joven, regional and municipal grants), tenant rights (LAU) and active programs with deadlines. Full RAG pipeline over official sources: document ingestion and chunking, embeddings with semantic search and reranking, and GPT-4 generation that cites sources and reports a confidence level. Fastify + TypeScript backend and React 19 + Vite frontend with a custom design system. Deployed in production on Railway.",
780+
"tech": [
781+
"TypeScript",
782+
"Node.js",
783+
"Fastify",
784+
"RAG",
785+
"OpenAI GPT-4",
786+
"React 19",
787+
"Vite",
788+
"Tailwind CSS",
789+
"Docker",
790+
"Railway"
791+
],
792+
"links": {
793+
"github": "https://github.com/GMNAPI/llarjove",
794+
"demo": "https://llarjove-production.up.railway.app/"
795+
},
796+
"categoryId": "ia-chatbots"
797+
},
798+
{
799+
"id": "vitaliber-crm-erp-v2",
800+
"title": "VitaLiber CRM/ERP v2 — Multi-tenant rewrite with PostgreSQL RLS",
801+
"description": "Complete rewrite of a telemarketing company's legacy CRM/ERP (MySQL, 28 tables, severe technical debt) onto a modern, multi-tenant, GDPR-aware stack. Per-provider data isolation with PostgreSQL 15 Row-Level Security, a REST API built with Symfony 7 + API Platform 4 (JWT + refresh tokens) and a React 18 + TypeScript frontend with an OpenAPI-generated client (orval → TanStack Query + Zod). Phased delivery documented with ADRs: identity & access, catalogs, CRM, telemarketing, sales and email already merged to main; live-data-only migration keeping the legacy database as a read-only archive.",
802+
"tech": [
803+
"Symfony 7",
804+
"API Platform 4",
805+
"PHP 8.3",
806+
"PostgreSQL",
807+
"Row-Level Security",
808+
"React 18",
809+
"TypeScript",
810+
"TanStack Query",
811+
"Tailwind CSS",
812+
"shadcn/ui",
813+
"Docker",
814+
"Multi-tenant"
815+
],
816+
"links": {},
817+
"categoryId": "arquitectura-avanzada"
818+
},
716819
{
717820
"id": "vita-liber-erp-interno",
718821
"title": "Vita Liber - ERP Rescue & Modernisation",

apps/portfolio/messages/es.json

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,66 @@
588588
{ "label": "Modelo de datos", "value": "Database-per-tenant" }
589589
]
590590
},
591+
"llarjove-rag-chatbot": {
592+
"sections": [
593+
{
594+
"heading": "Contexto",
595+
"body": "Asistente conversacional para jóvenes de 18 a 35 años en Cataluña que buscan vivienda: ayudas disponibles (Bono Alquiler Joven, ayudas de la Generalitat y municipales), derechos como inquilino (LAU, fianza, actualizaciones de alquiler) y recursos activos con sus plazos (Borsa Jove, HPO). Desplegado en producción en Railway con repositorio público."
596+
},
597+
{
598+
"heading": "Pipeline RAG",
599+
"body": "Ingesta offline de documentación oficial curada (ayudas, derechos, guías y leyes): carga, chunking, embeddings y vector store. En runtime, cada pregunta se convierte en embedding, se recupera contexto por búsqueda semántica con reranking y se genera la respuesta con GPT-4, validada y acompañada de fuentes citadas y nivel de confianza."
600+
},
601+
{
602+
"heading": "Backend",
603+
"body": "API en Fastify + TypeScript con el pipeline organizado por módulos (ingestion, retrieval, generation) y un endpoint de chat. Las respuestas devuelven answer, sources y confidence para que el usuario pueda contrastar la información."
604+
},
605+
{
606+
"heading": "Frontend",
607+
"body": "Interfaz en React 19 + Vite 6 + Tailwind CSS v4 con design system propio (identidad de marca, tokens de color y tipografía) y 59 tests de componentes con Vitest y Testing Library."
608+
},
609+
{
610+
"heading": "Enfoque",
611+
"body": "Proyecto de IA aplicada con impacto social: la información oficial sobre vivienda está dispersa y es difícil de interpretar; el asistente la centraliza y la responde en lenguaje claro, citando siempre la fuente oficial."
612+
}
613+
],
614+
"metrics": [
615+
{ "label": "Stack", "value": "Fastify · GPT-4" },
616+
{ "label": "Frontend", "value": "React 19 + Vite" },
617+
{ "label": "Tests frontend", "value": "59" },
618+
{ "label": "Despliegue", "value": "Railway" }
619+
]
620+
},
621+
"vitaliber-crm-erp-v2": {
622+
"sections": [
623+
{
624+
"heading": "Contexto",
625+
"body": "Reescritura completa del CRM/ERP legacy de VitaLiber, una empresa de telemarketing con 5-20 agentes en uso diario intensivo. El sistema anterior (MySQL, 28 tablas) acumulaba una deuda técnica severa. La v2 lo sustituye con un modelo de dominio limpio: CRM, telemarketing, ventas (catálogo editorial), facturación con SEPA y email."
626+
},
627+
{
628+
"heading": "Multi-tenant con Row-Level Security",
629+
"body": "Aislamiento de datos por proveedor implementado en la propia base de datos: PostgreSQL 15 con políticas de Row-Level Security. Un listener postConnect de Doctrine establece el tenant activo por conexión y lo verifica contra la tabla de accesos usuario-proveedor. Autenticación JWT con refresh tokens y selector de proveedor activo. Diseño alineado con RGPD."
630+
},
631+
{
632+
"heading": "Backend y esquema",
633+
"body": "API REST con Symfony 7 + API Platform 4 y Swagger UI. El esquema lo gobiernan migraciones SQL con DBmate (Doctrine actúa solo como capa de consulta), organizado en 7 esquemas lógicos de PostgreSQL (core, crm, tmk, sales, billing, comms, audit). Auditoría outbox-lite: los eventos de dominio se escriben en la misma transacción."
634+
},
635+
{
636+
"heading": "Frontend tipado extremo a extremo",
637+
"body": "React 18 + TypeScript estricto + Vite con Tailwind y shadcn/ui. El cliente de API se genera desde OpenAPI con orval: hooks de TanStack Query, tipos y schemas de Zod sincronizados con el backend. Internacionalización con react-intl (base español, preparado para catalán e inglés)."
638+
},
639+
{
640+
"heading": "Proceso y estado",
641+
"body": "Entrega por fases espejando el plan de migración (8 fases con milestones e issues en GitHub): identidad y acceso, catálogos, CRM, telemarketing, ventas y comunicaciones ya fusionadas en main. Decisiones documentadas en 7 ADRs, monorepo PNPM + Composer + Taskfile, CI/CD y tests de PHPUnit y Vitest, incluidos tests de aislamiento RLS. Migración solo de datos vivos, con el legacy como archivo de solo lectura."
642+
}
643+
],
644+
"metrics": [
645+
{ "label": "Fases entregadas", "value": "6 de 8" },
646+
{ "label": "ADRs", "value": "7" },
647+
{ "label": "Esquemas PostgreSQL", "value": "7" },
648+
{ "label": "Aislamiento", "value": "RLS por tenant" }
649+
]
650+
},
591651
"fastbyte-api-servicios": {
592652
"sections": [
593653
{
@@ -713,6 +773,49 @@
713773
"categoryId": "facturacion-compliance",
714774
"imageUrl": "/images/projects/gestiono-mi-negocio.webp"
715775
},
776+
{
777+
"id": "llarjove-rag-chatbot",
778+
"title": "LlarJove — Asistente RAG de vivienda para jóvenes",
779+
"description": "Chatbot RAG que ayuda a jóvenes de 18-35 años en Cataluña a encontrar vivienda: ayudas (Bono Alquiler Joven, Generalitat, municipales), derechos como inquilino (LAU) y recursos activos con plazos. Pipeline RAG completo sobre fuentes oficiales: ingesta y chunking de documentos, embeddings con búsqueda semántica y reranking, y generación con GPT-4 que responde citando fuentes y con nivel de confianza. Backend Fastify + TypeScript y frontend React 19 + Vite con design system propio. Desplegado en producción en Railway.",
780+
"tech": [
781+
"TypeScript",
782+
"Node.js",
783+
"Fastify",
784+
"RAG",
785+
"OpenAI GPT-4",
786+
"React 19",
787+
"Vite",
788+
"Tailwind CSS",
789+
"Docker",
790+
"Railway"
791+
],
792+
"links": {
793+
"github": "https://github.com/GMNAPI/llarjove",
794+
"demo": "https://llarjove-production.up.railway.app/"
795+
},
796+
"categoryId": "ia-chatbots"
797+
},
798+
{
799+
"id": "vitaliber-crm-erp-v2",
800+
"title": "VitaLiber CRM/ERP v2 — Reescritura multi-tenant con PostgreSQL RLS",
801+
"description": "Reescritura completa del CRM/ERP legacy de una empresa de telemarketing (MySQL, 28 tablas, deuda técnica severa) sobre un stack moderno, multi-tenant y alineado con RGPD. Aislamiento de datos por proveedor con Row-Level Security en PostgreSQL 15, API REST con Symfony 7 + API Platform 4 (JWT + refresh tokens) y frontend React 18 + TypeScript con cliente generado desde OpenAPI (orval → TanStack Query + Zod). Entrega por fases documentada con ADRs: identidad y acceso, catálogos, CRM, telemarketing, ventas y email ya fusionados en main; migración solo de datos vivos manteniendo el legacy como archivo de solo lectura.",
802+
"tech": [
803+
"Symfony 7",
804+
"API Platform 4",
805+
"PHP 8.3",
806+
"PostgreSQL",
807+
"Row-Level Security",
808+
"React 18",
809+
"TypeScript",
810+
"TanStack Query",
811+
"Tailwind CSS",
812+
"shadcn/ui",
813+
"Docker",
814+
"Multi-tenant"
815+
],
816+
"links": {},
817+
"categoryId": "arquitectura-avanzada"
818+
},
716819
{
717820
"id": "vita-liber-erp-interno",
718821
"title": "Vita Liber - Rescate y Modernización de ERP",

apps/portfolio/src/shared/constants/project-slugs.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
export const PROJECT_SLUGS = [
99
'devfreelancer-client-tracker',
1010
'gestiono-mi-negocio-facturacion',
11+
'llarjove-rag-chatbot',
12+
'vitaliber-crm-erp-v2',
1113
'vita-liber-erp-interno',
1214
'fastbyte-api-servicios',
1315
'seedstockers-b2b-platform',

0 commit comments

Comments
 (0)