home
  • Spanish (ES)
  • English (UK)
  • Portuguese (PT)
  • star Featured
  • Hermes Agent
  • draw UX Projects
  • person About me
  • mail Contact
arrow_back Back to project Home

Project documentation

Documentation · Conciergo

11 markdown files (product, architecture, API, auth, data, deploy…).

On this page Visión general 0% expand_more
Visión general Enlaces Stack Producto y features Problema Solución Características Landing Eventos Mapa Conexiones Perfil (Backstage) Invitados Arquitectura Diagrama lógico Capas Decisiones de runtime Estructura del workspace Superficie API Código de ejemplo (health) Autenticación Neon Auth Flujo Cómo se verifica Qué no hay Modelo de datos users events event_attendees matches messages Deploy Vercel Env Local Decisiones de producto y tech Match automático, no swipe Socket.io para el chat OpenAPI como fuente de verdad Neon Auth, no Clerk Invitados ven el cartel Retos y resultados Google Maps Loader Keys de Maps JIT user vs “Anonymous” Resultado Front React (no Angular) Qué se aplica Por qué está este doc

01-overview.md

Visión general · Conciergo

Conciergo es una app web mobile-first para ir a conciertos cuando no tienes compañía. Login con Neon Auth, feed y mapa de bolos, matching automático al apuntarte y chat 1-1 en tiempo real.

El producto vive en un workspace pnpm: front React+Vite (artifacts/conciergo), API Express (artifacts/api-server), contratos OpenAPI (lib/api-spec) y Postgres + Drizzle (lib/db).

Enlaces

  • Producción: conciergo-sigma.vercel.app
  • GitHub: código fuente
  • Health: GET /api/healthz → { "status": "ok" }

Stack

CapaTecnología
Monorepopnpm workspaces, TypeScript 5.9
WebReact, Vite, Tailwind 4, shadcn/ui, Framer Motion, Wouter
AuthNeon Auth (@neondatabase/neon-js + Better Auth). La API verifica el JWT con jose + JWKS
APIExpress 5, OpenAPI + Orval + Zod, Socket.io
DatosNeon Postgres + Drizzle ORM (users.auth_id)
MapasGoogle Maps JS + Places
ChatSocket.io (/api/socket.io)

02-product.md

Producto y features

Problema

Un gran bolo se pierde si no hay con quién ir. Los grupos de WhatsApp son caos; Tinder no es para conciertos; las apps de entradas no conectan a extraños con el mismo cartel.

Solución

Conciergo: feed de eventos, mapa, “voy” y match automático con el resto de asistentes. Cada match abre un chat 1-1 para cuadrar el viaje o el foso.

Características

Landing

Copy de cartel: «No dejes que un gran bolo se pierda». Entrar / Unirse (Neon Auth). Invitados pueden explorar eventos y mapa.

Eventos

Lista con filtro por género. Cards compactas (artista, venue, fecha). Usuarios logueados se apuntan; FAB para crear evento (venue via Places).

Mapa

Pins de Google Maps. Click → ficha y apuntarse. Invitados ven el mapa.

Conexiones

Matches del usuario + badge de no leídos. Chat en tiempo real (Socket.io).

Perfil (Backstage)

Nombre, ciudad, géneros, avatar de Neon Auth.

Invitados

Eventos y mapa abiertos. Conexiones, perfil y crear evento piden sesión.

03-architecture.md

Arquitectura

Diagrama lógico

React (Vite)  Conciergo
    │  Neon Auth (sesión + JWT)
    │  React Query → /api/*
    │  Socket.io → /api/socket.io
    ▼
Express 5  (/api)
    │  requireAuth → verifica JWT (jose + JWKS) + JIT user
    ▼
Neon Postgres  (Drizzle)
    users, events, event_attendees, matches, messages

Capas

  1. Front — artifacts/conciergo: Wouter, shadcn, layout sidebar desktop + bottom nav móvil.
  2. API — artifacts/api-server: rutas users, events, matches, health.
  3. Contrato — lib/api-spec/openapi.yaml → Orval genera hooks (lib/api-client-react) y Zod (lib/api-zod).
  4. DB — lib/db Drizzle.

Decisiones de runtime

  • Match automático al marcar asistencia: un match (y chat) con cada otro asistente.
  • Chat por Socket.io (/api/socket.io), autenticado con el mismo JWT.
  • JIT provisioning: el primer requireAuth inserta al usuario desde el sub de Neon Auth (users.auth_id).

04-monorepo.md

Estructura (pnpm workspace)

No es Angular/Nest. Es un monorepo Replit (pnpm-workspace.yaml).

PathRol
artifacts/conciergoApp React + Vite
artifacts/api-serverExpress + Neon Auth (jose)
artifacts/mockup-sandboxSandbox de UI (no prod)
lib/api-specOpenAPI + Orval
lib/api-client-reactHooks generados
lib/api-zodSchemas Zod generados
lib/dbDrizzle + schema
replit.mdRunbook del producto

Tras cambiar el spec: pnpm --filter @workspace/api-spec run codegen.

05-api.md

Superficie API

Base: /api. Fuente: lib/api-spec/openapi.yaml.

MétodoRutaAuthQué hace
GET/healthzpública{ status: "ok" }
GET/PUT/users/meJWT Neon AuthPerfil propio
GET/users/:userIdJWT Neon AuthPerfil ajeno
GET/eventsopcionalFeed + isAttending
POST/eventsJWT Neon AuthCrear bolo
POST/DELETE/events/:id/attendJWT Neon AuthApuntarse / salir (crea matches)
GET/matchesJWT Neon AuthConexiones + unread
GET/POST/matches/:id/messagesJWT Neon AuthHistorial de chat
WS/api/socket.ioJWT Neon AuthChat en tiempo real

Código de ejemplo (health)

router.get("/healthz", (_req, res) => {
  const data = HealthCheckResponse.parse({ status: "ok" });
  res.json(data);
});

HealthCheckResponse sale de Zod generado. Si el spec y el handler se desalinean, falla el typecheck.

06-auth.md

Autenticación (Neon Auth)

Flujo

  1. Landing → Entrar / Unirse (@neondatabase/neon-js + Better Auth, UI de @neondatabase/auth-ui).
  2. El front pide un JWT (getAccessToken) y lo manda como Authorization: Bearer.
  3. Las rutas protegidas usan requireAuth:
    • Sin token o JWT inválido → 401.
    • Primera llamada → INSERT en users (auth_id = sub, nombre + avatar del payload).
  4. Invitados ven Eventos y Mapa; Conexiones/Perfil/crear evento piden sesión.

Cómo se verifica

La API usa jose y el JWKS de Neon Auth (NEON_AUTH_BASE_URL/.well-known/jwks.json). El chat Socket.io valida el mismo token.

Qué no hay

No hay Clerk ni PIN. La sesión es de Neon Auth; la fila de negocio es users.auth_id.

07-data-model.md

Modelo de datos (Drizzle / Postgres)

users

id, auth_id (único, sub de Neon Auth), name, bio, avatar_url, music_genres[], city, created_at.

events

title, artist_name, venue_name, venue_address, date, lat, lng, genre, image_url, created_by_user_id.

event_attendees

Quién va a qué bolo. Al insertar, el servidor crea matches con el resto de asistentes.

matches

event_id + user_id_1 + user_id_2 (unique). Un chat por pareja y evento.

messages

Mensajes del match. El front cuenta unreadCount para el badge de Conexiones.

08-deploy-vercel.md

Deploy (Vercel)

Producción: https://conciergo-sigma.vercel.app

El front y la API se sirven en Vercel. El mismo proceso cubre el build de Vite y Express (/api, /api/socket.io).

Env

VariableDónde
DATABASE_URLNeon Postgres
NEON_AUTH_BASE_URL / NEON_AUTH_URLAPI (JWKS)
VITE_NEON_AUTH_URLFront (cliente Auth)
VITE_GOOGLE_MAPS_API_KEYMaps + Places

La key de Maps debe tener Maps JavaScript API y Places API.

Local

pnpm --filter @workspace/api-server run dev
pnpm --filter @workspace/conciergo run dev

09-decisions.md

Decisiones

Match automático, no swipe

Apuntarse a un evento es el gesto de matching. Evita un segundo feed tipo dating.

Socket.io para el chat

El historial sigue en REST; los mensajes en vivo van por Socket.io con el JWT de Neon Auth.

OpenAPI como fuente de verdad

Orval genera hooks y Zod. El typecheck del workspace pilla desvíos entre front y API.

Neon Auth, no Clerk

Email/social y sesión los resuelve Neon Auth (Better Auth). El dominio de negocio es el perfil y los matches (users.auth_id).

Invitados ven el cartel

Eventos + mapa sin login para que el landing no sea un muro. Crear y chatear sí piden cuenta.

10-challenges-results.md

Retos y aprendizajes

Google Maps Loader

La API clásica Loader de @googlemaps/js-api-loader v2 ya no existe (setOptions + importLibrary). Un preview Replit llegó a mostrar el overlay rojo de Vite. Hay que alinear la versión del loader con el código.

Keys de Maps

Sin Maps JS + Places activados, el mapa enseña «This page can’t load Google Maps correctly». Es configuración de GCP, no de UI.

JIT user vs “Anonymous”

Si Neon Auth aún no ha enviado el nombre, el primer insert usa el email o «Usuario». requireAuth reintenta actualizar el perfil.

Resultado

Un workspace que se entiende: spec → codegen → Express → React. El producto (compañía para un bolo) cabe en cuatro tabs.

11-angular-skill.md

Front en Conciergo

Este repo no usa Angular. El cliente es React + Vite + Tailwind 4 + shadcn. La skill Angular de Task Cloud no aplica.

Qué se aplica

PrácticaDónde
WouterRutas (/events, /events/map, /matches, /profile)
React QueryListados y estado de sesión
Neon AuthLanding signed-in → redirect /events
Framer MotionLanding y cards
Bottom nav + sidebarapp-layout.tsx (móvil / desktop)

Por qué está este doc

La suite featured 01–11 se llama igual que en Task Cloud / Presencia. Aquí el “11” documenta el techo real del front para no fingir un stack Angular.

On this page

Visión general Enlaces Stack Producto y features Problema Solución Características Landing Eventos Mapa Conexiones Perfil (Backstage) Invitados Arquitectura Diagrama lógico Capas Decisiones de runtime Estructura del workspace Superficie API Código de ejemplo (health) Autenticación Neon Auth Flujo Cómo se verifica Qué no hay Modelo de datos users events event_attendees matches messages Deploy Vercel Env Local Decisiones de producto y tech Match automático, no swipe Socket.io para el chat OpenAPI como fuente de verdad Neon Auth, no Clerk Invitados ven el cartel Retos y resultados Google Maps Loader Keys de Maps JIT user vs “Anonymous” Resultado Front React (no Angular) Qué se aplica Por qué está este doc

0% read

folder_zip Download all (ZIP)
Hermes Agent