Proyecto

General

Perfil

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.

Ficheros