Saltar a contenido

Primeros Pasos / Getting Started

Requisitos / Requirements

  • Docker 24+ y Docker Compose v2
  • 4 GB RAM mínimo (8 GB recomendado en producción)
  • Puertos libres: 19080, 19180, 15432, 19900, 19901, 16379

Los servicios internos siguen escuchando en 8001-8011/8080 dentro de la red Docker orpycamcp-net; lo que cambia son los puertos publicados al host (rango 19xxx / 15432 / 16379) para no chocar con otras pilas de desarrollo. Ver tabla completa en Arquitectura.

Instalación local (desarrollo) / Local Installation (development)

# 1. Clonar el repositorio
git clone https://gitlab.com/orpyca/orpyca-mcp.git
cd orpyca-mcp

# 2. Levantar la infraestructura completa
docker compose --profile dev up -d

# 3. Verificar que los servicios estén corriendo
docker compose ps

URLs de acceso / Access URLs

Servicio / Service URL Credenciales dev
API Gateway (docs) http://localhost:19080/docs
Frontend (SvelteKit) http://localhost:19300
Keycloak Admin http://localhost:19180/admin admin / orpycamcp_dev
MinIO Console http://localhost:19901 orpycamcp / orpycamcp_dev
PostgreSQL localhost:15432 orpycamcp / orpycamcp
MailHog (email dev) http://localhost:8025

Primer radicado / First Document Registration

# 1. Obtener token de acceso (vía el gateway, no directo al servicio)
TOKEN=$(curl -s -X POST 'http://localhost:19080/api/v1/auth/token' \
  -H 'Content-Type: application/json' \
  -d '{"username": "operador", "password": "orpycamcp_dev"}' \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")

# 2. Radicar un documento de entrada
curl -X POST 'http://localhost:19080/api/v1/documents/' \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "subject": "Solicitud de información pública",
    "document_type": "entrada",
    "sender_name": "Ciudadano Juan Pérez",
    "sender_email": "juan@ejemplo.com"
  }'

La respuesta incluye el número de radicado asignado (ej: 2024-DEMO-E-000001).

Agregar un tenant (institución) / Add a tenant (institution)

curl -X POST 'http://localhost:19080/api/v1/tenants/' \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "slug": "mi_entidad",
    "name": "Mi Entidad Pública",
    "code": "MENT"
  }'

Esto aprovisiona automáticamente el schema tenant_mi_entidad en PostgreSQL.

Cargar la TRD inicial (seed) / Load initial TRD (seed)

OrpycaMCP incluye un script reutilizable para sembrar la Tabla de Retención Documental (TRD) de un tenant a partir de un JSON. El proyecto trae como referencia la TRD de FondeCund (150+ series).

1. Exportar la TRD de tu institución a un JSON compatible:

{
  "entidad": "Mi Entidad Pública",
  "version": "2024-01-01",
  "dependencias": [
    {
      "nombre": "Departamento",
      "series": [
        {
          "codigo": 100,
          "nombre": "SERIE DOCUMENTAL",
          "retencion_gestion": 5,
          "retencion_central": 10,
          "disposicion_final": "Conservación total",
          "subseries": []
        }
      ]
    }
  ]
}

Las disposiciones finales en español se mapean a los códigos de OrpycaMCP (conserve, eliminate, transfer).

2. Generar el SQL de migración para tu tenant:

python3 scripts/migrate_trd_from_fondecund.py \
  mi_entidad_trd.json \
  --tenant-slug mi_entidad \
  --output services/archive-service/migrations/003_trd_mi_entidad.sql

3. Aplicar la migración en el schema del tenant:

docker compose exec postgres psql -U orpycamcp -d orpycamcp_db \
  -c "SET search_path TO tenant_mi_entidad;" \
  -f services/archive-service/migrations/003_trd_mi_entidad.sql

Más ejemplos de uso end-to-end

Estos ejemplos asumen que ya tienes $TOKEN del paso anterior. El contrato completo de cada endpoint está en Referencia de API; el detalle de negocio detrás de cada entidad está en Dominio documental.

Crear un expediente y vincular un radicado

# 1. Crear el expediente (requiere TRD configurada para la serie)
curl -X POST 'http://localhost:19080/api/v1/expedientes/' \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"nombre": "Contrato 2024-001 — Suministro de papelería", "serie_id": "uuid-serie"}'
# Respuesta: { "id": "uuid-expediente", "estado": "open", ... }

# 2. Vincular el radicado creado antes
curl -X POST 'http://localhost:19080/api/v1/expedientes/uuid-expediente/radicados' \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"radicado_id": "uuid-radicado"}'

# 3. Cerrar el expediente (genera y firma el índice electrónico, ver Ciclo de vida)
curl -X PATCH 'http://localhost:19080/api/v1/expedientes/uuid-expediente' \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"estado": "closed"}'

Firmar electrónicamente un radicado

curl -X POST 'http://localhost:19080/api/v1/signature/' \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"radicado_id": "uuid-radicado"}'
# Respuesta: { "firma_id": "uuid", "estado": "firmado", "sha256": "...", "firmado_at": "..." }

Consultar al asistente conversacional

curl -X POST 'http://localhost:19080/api/v1/assistant/chat' \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"message": "¿Qué radicados de entrada tengo pendientes esta semana?"}'
# Respuesta: texto en lenguaje natural con citas a los radicados consultados (RAG, solo lectura)

La interfaz web: primeros pasos

Con la plataforma levantada, el frontend queda en http://localhost:19300.

1. La landing pública (/)

La raíz del sitio es una página pública que no requiere sesión: describe qué es OrpycaMCP, el marco normativo que implementa (Ley 594/2000, Acuerdo AGN 060/2001), sus capacidades y su linaje respecto a Orfeo, y termina en la licencia AGPL v3. Es la puerta de entrada del producto y el único lugar del sitio donde se usa el logotipo completo.

Si el navegador ya tiene una sesión activa, / redirige automáticamente (302) a /dashboard: un usuario autenticado nunca ve la landing. Para volver a verla, cerrar sesión desde el menú de usuario.

Desde la landing, «Iniciar sesión» lleva a /login, que arranca el flujo OAuth2 Authorization Code + PKCE contra Keycloak (el intercambio del código y la custodia del token ocurren server-side; el JWT vive en una cookie httpOnly y nunca es visible al JavaScript del navegador).

2. El panel personal (/dashboard)

Tras iniciar sesión, el panel abre con cuatro módulos personales —lo que le toca hacer a este usuario, no las cifras del tenant:

Módulo Qué muestra
01 Radicados pendientes Radicados distribuidos o en trámite que esperan acción
02 Actividad reciente Últimos radicados sobre los que hubo movimiento
03 Alertas Radicados abiertos cuya fecha de vencimiento (due_date, RF-RAD-04) está próxima o vencida
04 Favoritos Los destinos de navegación que el usuario haya fijado en el sidebar

Las métricas agregadas del tenant (radicados por estado, top dependencias, actividad mensual) siguen disponibles, pero en una sección secundaria colapsable, cerrada por defecto, y solo si el usuario tiene el permiso SGD_PERM_ESTADISTICA — el mismo que habilita la vista /reportes.

3. Búsqueda global desde cualquier pantalla

La barra superior lleva un campo de búsqueda global disponible en todas las pantallas autenticadas. Se puede enfocar con el atajo de teclado / (el atajo se inhibe si el foco ya está dentro de un campo de texto, para no interferir con la escritura). En pantallas estrechas el campo se despliega desde un icono de lupa.

Al enviar, la búsqueda navega a /busqueda?q=<término>, que es la misma vista de búsqueda full-text (FTS de PostgreSQL, GET /api/v1/search a través del gateway) con sus filtros avanzados. Como el término viaja en la URL, cualquier búsqueda es enlazable y compartible, y el botón "atrás" del navegador funciona como se espera.

4. Favoritos en la barra lateral

Cada entrada del menú lateral tiene un control de fijar/desfijar. Los ítems fijados suben a una sección «Favoritos» al principio del menú y aparecen también en el módulo 04 del panel. Los favoritos se guardan en el navegador, separados por institución y usuario, así que dos usuarios del mismo equipo no comparten lista.

Los favoritos no eluden el RBAC: si a un usuario se le retira un permiso, la entrada correspondiente desaparece tanto del menú como de sus favoritos, sin necesidad de limpiarla a mano. Como en todo el frontend, esto es defensa en profundidad: el backend revalida permiso y clearance en cada petición.

Ver también: Pantallas del sistema para la contraparte de cada uno de estos ejemplos en la interfaz web.