Documento técnico y funcional para Top y Choferes.top
Documentación de usuario
2025-12-29
Resumen ejecutable para Greenborn Software. Incluye modelo de datos en PostgreSQL, user stories, flujos, API y stack específico con pautas de implementación. Optimizado para copiar y pegar.
*Alcance y objetivos
*
- Propósito: Marketplace de servicios (Top, general de profesionales; Choferes.top, especializado en movilidad).
- Modelo operativo: Match cliente–prestador con pedidos, agenda, pagos y reputación.
- Roles: Administrador, Cliente, Prestador de servicio.
*Stack específico y pautas
*
- Backend: Node.js + NestJS (REST), TypeScript, JWT, Zod/DTOs para validación.
- Base de datos: PostgreSQL 15+, migraciones con Prisma o TypeORM.
- Cache/cola: Redis (rate limiting, sesiones, jobs de notificaciones).
- Frontend: Next.js 14 (App Router), React Server Components, TailwindCSS.
- Pagos: Mercado Pago (pref/checkout), webhooks con verificación de firma.
- Mensajería: WebSocket (Socket.IO) en canal por pedido, persistencia en DB.
- Infra: Docker Compose (api, web, db, redis), Nginx reverse proxy, HTTPS.
- Observabilidad: Pino (logs), OpenTelemetry, Healthcheck y readiness en API.
Modelo de datos en PostgreSQL (DDL)
Copiá y pegá. Incluye claves primarias, foráneas, índices y restricciones mínimas.
`sql
-- Extensiones útiles
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- Usuarios
CREATE TABLE usuarios (
id UUID PRIMARY KEY DEFAULT uuidgenerateuuid(),
rol TEXT NOT NULL CHECK (rol IN ('admin','cliente','prestador')),
email TEXT NOT NULL UNIQUE,
hash_password TEXT NOT NULL,
nombre TEXT NOT NULL,
telefono TEXT,
estado TEXT NOT NULL DEFAULT 'activo' CHECK (estado IN ('activo','suspendido')),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idxusuariosrol ON usuarios(rol);
-- Perfil de prestador
CREATE TABLE perfiles_prestador (
id UUID PRIMARY KEY DEFAULT uuidgenerateuuid(),
usuario_id UUID NOT NULL REFERENCES usuarios(id) ON DELETE CASCADE,
titulo TEXT NOT NULL,
descripcion TEXT,
zona TEXT NOT NULL,
disponibilidad JSONB NOT NULL DEFAULT '[]',
documentacion_verificada BOOLEAN NOT NULL DEFAULT FALSE,
rating_promedio NUMERIC(3,2) NOT NULL DEFAULT 0.0,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idxprestadorusuario ON perfilesprestador(usuarioid);
CREATE INDEX idxprestadorzona ON perfiles_prestador(zona);
-- Servicios
CREATE TABLE servicios (
id UUID PRIMARY KEY DEFAULT uuidgenerateuuid(),
prestadorid UUID NOT NULL REFERENCES perfilesprestador(id) ON DELETE CASCADE,
categoria TEXT NOT NULL,
subcategoria TEXT,
preciobase NUMERIC(12,2) NOT NULL CHECK (preciobase >= 0),
unidad TEXT NOT NULL CHECK (unidad IN ('porhora','portrayecto','fijo')),
politicacancelacion TEXT NOT NULL CHECK (politicacancelacion IN ('flexible','moderada','estricta')),
activo BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idxserviciosprestador ON servicios(prestador_id);
CREATE INDEX idxservicioscategoria ON servicios(categoria);
-- Pedidos
CREATE TABLE pedidos (
id UUID PRIMARY KEY DEFAULT uuidgenerateuuid(),
cliente_id UUID NOT NULL REFERENCES usuarios(id) ON DELETE RESTRICT,
servicio_id UUID NOT NULL REFERENCES servicios(id) ON DELETE RESTRICT,
prestadorid UUID NOT NULL REFERENCES perfilesprestador(id) ON DELETE RESTRICT,
fecha_solicitada TIMESTAMPTZ NOT NULL,
origen TEXT, -- requerido en choferes
destino TEXT, -- requerido en choferes
detalle TEXT,
montoestimado NUMERIC(12,2) NOT NULL CHECK (montoestimado >= 0),
estado TEXT NOT NULL CHECK (estado IN ('pendiente','aceptado','en_progreso','completado','cancelado')),
motivo_cancelacion TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT chkorigendestino CHECK (
(origen IS NOT NULL AND destino IS NOT NULL) OR (origen IS NULL AND destino IS NULL)
)
);
CREATE INDEX idxpedidoscliente ON pedidos(cliente_id);
CREATE INDEX idxpedidosprestador ON pedidos(prestador_id);
CREATE INDEX idxpedidosestado ON pedidos(estado);
CREATE INDEX idxpedidosfecha ON pedidos(fecha_solicitada);
-- Mensajes (chat por pedido)
CREATE TABLE mensajes (
id UUID PRIMARY KEY DEFAULT uuidgenerateuuid(),
pedido_id UUID NOT NULL REFERENCES pedidos(id) ON DELETE CASCADE,
emisor_id UUID NOT NULL REFERENCES usuarios(id) ON DELETE CASCADE,
contenido TEXT NOT NULL,
leido BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idxmensajespedido ON mensajes(pedido_id);
CREATE INDEX idxmensajesemisor ON mensajes(emisor_id);
-- Calificaciones
CREATE TABLE calificaciones (
id UUID PRIMARY KEY DEFAULT uuidgenerateuuid(),
pedido_id UUID NOT NULL UNIQUE REFERENCES pedidos(id) ON DELETE CASCADE,
cliente_id UUID NOT NULL REFERENCES usuarios(id) ON DELETE RESTRICT,
prestadorid UUID NOT NULL REFERENCES perfilesprestador(id) ON DELETE RESTRICT,
puntaje INT NOT NULL CHECK (puntaje BETWEEN 1 AND 5),
comentario TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idxcalifprestador ON calificaciones(prestador_id);
-- Pagos
CREATE TABLE pagos (
id UUID PRIMARY KEY DEFAULT uuidgenerateuuid(),
pedido_id UUID NOT NULL UNIQUE REFERENCES pedidos(id) ON DELETE CASCADE,
monto NUMERIC(12,2) NOT NULL CHECK (monto >= 0),
moneda TEXT NOT NULL DEFAULT 'ARS',
metodo TEXT NOT NULL,
estado TEXT NOT NULL CHECK (estado IN ('iniciado','aprobado','rechazado','reembolsado')),
referencia_gateway TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idxpagosestado ON pagos(estado);
-- Auditoría
CREATE TABLE auditoria (
id UUID PRIMARY KEY DEFAULT uuidgenerateuuid(),
usuario_id UUID REFERENCES usuarios(id) ON DELETE SET NULL,
accion TEXT NOT NULL,
entidad TEXT NOT NULL,
entidad_id UUID,
ip TEXT,
metadata JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idxauditoriausuario ON auditoria(usuario_id);
CREATE INDEX idxauditoriaentidad ON auditoria(entidad, entidad_id);
`
Diferenciación entre profesionales.top y Choferes.top
- Top (general):
- Categorías amplias: profesionales y oficios.
- Filtros avanzados: zona, precio, rating, disponibilidad.
- Unidad de cobro: flexible (por_hora, fijo).
- Choferes.top (movilidad):
- Campos específicos: origen/destino obligatorios, cálculo estimado por trayecto.
- Agenda: slots de turnos y zonas calientes.
- Política de cancelación: más estricta y ventanas de gracia cortas.
Roles y permisos
- Administrador:
- Permisos: CRUD global, moderación de servicios y calificaciones, verificación documental, gestión de categorías, reportes.
- Cliente:
- Permisos: crear pedidos, chatear, pagar, calificar, editar perfil, cancelar según política.
- Prestador:
- Permisos: publicar/editar servicios, aceptar/rechazar pedidos, chatear, marcar progreso y completar, configurar disponibilidad.
User stories esenciales
- Administrador:
- Moderación: Listar/filtrar servicios y calificaciones; ocultar contenido inapropiado.
- Verificación: Marcar perfiles como verificados con trazabilidad.
- Reportes: Métricas por zona y categoría; exportables CSV.
- Cliente:
- Descubrimiento: Filtrar por zona, precio, disponibilidad; ver rating y políticas.
- Solicitud: Crear pedido con fecha y ver monto estimado antes de confirmar.
- Comunicación: Chatear para ajustar detalles del servicio.
- Pago: Pagar seguro y recibir comprobante.
- Reputación: Calificar al finalizar.
- Prestador:
- Publicación: Crear servicios con precio y política.
- Agenda: Aceptar/rechazar; evitar solapes.
- Progreso: Cambiar estados hasta completado para habilitar cobro.
- Imagen: Responder a calificaciones.
Flujos operativos
- Alta de prestador:
- Registro: email + password → perfil prestador → documentos → revisión admin → verificado.
- Creación de pedido:
- Selección: servicio → fecha/hora → (choferes: origen/destino) → cálculo monto → confirmar.
- Asignación y ejecución:
- Prestador: recibe pedido → acepta/rechaza → chat → en_progreso → completado.
- Pago y feedback:
- Pago: webhook aprobado → comprobante → notificaciones.
- Calificación: cliente califica; promedio impacta ranking.
API mínima (NestJS, rutas sugeridas)
- Auth
- POST /auth/register: registro.
- POST /auth/login: token JWT.
- Usuarios
- GET /usuarios/me: perfil propio.
- PATCH /usuarios/me: actualizar perfil.
- Prestadores y servicios
- POST /prestadores: alta perfil prestador.
- GET /servicios: listado con filtros.
- POST /servicios: crear servicio.
- PATCH /servicios/{id}: editar.
- Pedidos
- POST /pedidos: crear.
- GET /pedidos/{id}: ver.
- PATCH /pedidos/{id}/estado: cambiar estado (máquina de estados validada).
- Mensajes
- POST /pedidos/{id}/mensajes: enviar.
- GET /pedidos/{id}/mensajes: listar.
- Pagos
- POST /pagos: iniciar pago.
- POST /pagos/webhook: recibir eventos gateway (verificar firma).
- GET /pagos/{id}: estado.
- Admin
- GET /admin/moderacion: revisión de servicios/calificaciones.
- PATCH /admin/prestadores/{id}/verificar: marcar verificado.
Reglas de negocio y validaciones
- Estados de pedido: pendiente → aceptado → en_progreso → completado; cancelado puede salir de pendiente/aceptado con política aplicada.
- Disponibilidad: bloqueo de slots al aceptar; prevención de solapes por prestador.
- Cancelación: penalización según política_cancelacion y hora del servicio.
- Calificaciones: una por pedido; puntaje 1–5; respuesta del prestador opcional.
- Pagos: idempotencia en creación; reconciliación por webhook; no completar pedido si pago rechazado.
- Auditoría: acciones sensibles (login, crear/editar servicio, cambiar estado) registradas.
Indicadores clave y panel admin
- Métricas:
- Pedidos por zona/categoría: volumen y conversión.
- Tiempo de respuesta: media por prestador.
- Tasa de cancelación: por política.
- Rating promedio: por categoría.
- Exportables: CSV/JSON de servicios, pedidos y calificaciones.
- Moderación: filtros por palabras prohibidas y spam en descripciones/comentarios.
Docker Compose (plantilla mínima)
yaml version: "3.9" services: db: image: postgres:15 environment: POSTGRES_USER: app POSTGRES_PASSWORD: app POSTGRES_DB: greenborn ports: ["5432:5432"] volumes: - db_data:/var/lib/postgresql/data redis: image: redis:7 ports: ["6379:6379"] api: build: ./api environment: DATABASE_URL: postgresql://app:app@db:5432/greenborn REDIS_URL: redis://redis:6379 MPWEBHOOKSECRET: change_me JWTSECRET: changeme depends_on: [db, redis] ports: ["3001:3001"] web: build: ./web environment: APIBASEURL: http://api:3001 depends_on: [api] ports: ["3000:3000"] volumes: db_data:
*Índices y rendimiento
*
- Búsquedas comunes: índices en rol, zona, categoría, estado, fecha_solicitada.
- Texto: pg_trgm opcional para búsqueda difusa en titulo/descripcion.
- Consultas críticas: usar paginación (limit/offset) y orden por created_at.
- Bloqueos: transacciones en cambios de estado y confirmación de pago.
**Roadmap corto
**
- Semana 1: Auth, Usuarios, Prestadores, Servicios, Búsqueda.
- Semana 2: Pedidos, Mensajes, Estados, Agenda.
- Semana 3: Pagos, Calificaciones, Políticas de cancelación, Webhooks.
- Semana 4: Panel admin, Métricas, Auditoría, Docker/Nginx.