Skip to content

KYC · Documentos del onboarding a Drive

Copia a una unidad compartida de Drive, ordenados por RFC, los documentos KYC que los clientes suben al backoffice, para que el proceso de KYC de Diego los lea por API y Legal & Compliance los revise.

En producción desde el 2026-10-01

Cloud Run kyc-drive-sync-prod (data-prod-sa), disparado por el Cloud Scheduler kyc-drive-sync-daily todos los días a las 7:00 MX con una ventana de 90 días. Carga inicial: clientes con movimiento desde el 2026-09-01 (el since del scheduler, para cubrir a los que estaban en onboarding); hasta el 30/11 la corrida cubre desde esa fecha y después manda la ventana. Pendiente con Diego: si su proceso necesita el índice en BigQuery (KYC_INDEX_TABLE).

¿Llegaste hasta acá desde…?

Si ves… Eso sale de… La lógica está en…
Una carpeta <NOMBRE> - <RFC> en la unidad compartida de KYC entities_kyc + bucket prod-v1-carriers-service-gcs; el nombre, de business_info.business_name kyc-drive-sync → cloud_run/docsync/sync.py y naming.py
Un archivo como POWER_OF_ATTORNEY_1a2b3c4d.pdf Tipo (kyc_name) + hash de la ruta de origen (sin fecha) cloud_run/docsync/naming.py
Un archivo con otro formato de nombre en una carpeta de RFC Carga manual de operaciones (excepción) Fuera del proceso: nunca lo toca
Una ruta cs_files/<nombre>_<uuid>.<ext> y querés saber de qué cliente es entities_kyc.source_id → carriers o ss_shareholders → business_info.tax_id cloud_run/docsync/index.py

Resumen

Campo Valor
Origen Bucket GCS prod-v1-carriers-service-gcs (solo lectura) + índice svc_master_public.entities_kyc
Patrón Batch: índice en BigQuery, lectura de cada archivo por su ruta exacta, escritura en Drive comparando contra un estado deseado
Destino Unidad compartida de Drive (id en el secreto KYC_DRIVE_ID), una carpeta por cliente (<NOMBRE> - <RFC>) · índice por archivo (CSV; tabla de BigQuery a definir)
Frecuencia Diaria, 7:00 MX (Cloud Scheduler kyc-drive-sync-daily, ventana de 90 días)
Criticidad 🟡 Media
Dueño Data (Martin Fleming) · consumo: Analytics (Diego)
Repos kyc-drive-sync

Diagrama de linaje

graph LR
    BO[["🗂️ Backoffice<br/>entities_kyc (Airbyte)"]]
    GCS[("GCS prod-v1-carriers-service-gcs<br/>cs_files/ · carriers_files/ · shareholders_files/")]
    IDX["Índice por RFC<br/>entities_kyc + carriers + business_info + ss_shareholders"]
    SYNC["kyc-drive-sync<br/>Cloud Run · diario 7:00 MX"]
    DRV[("Drive · unidad compartida<br/>carpeta NOMBRE - RFC")]
    OUT[("Índice por archivo<br/>indice.csv · tabla BQ a definir")]
    OPS["Operaciones<br/>carga manual (excepción)"]
    DIEGO["Proceso de KYC de Diego<br/>Claude por API"]
    ANNY["Legal & Compliance"]

    BO --> IDX --> SYNC
    GCS -->|"objects.get por ruta exacta"| SYNC
    SYNC -->|"copia · no_vigentes"| DRV
    SYNC --> OUT
    OPS -.-> DRV
    DRV --> DIEGO
    OUT --> DIEGO
    DIEGO --> ANNY

    classDef src fill:#fde68a,stroke:#b45309,color:#000;
    classDef store fill:#bfdbfe,stroke:#1e40af,color:#000;
    class BO,GCS src;
    class DRV,OUT store;

Paso a paso

  1. Índice (index.py). Por cada archivo de entities_kyc.data.files: RFC del cliente (los documentos de accionistas se asignan al cliente vía ss_shareholders), tipo, estado, tipo de persona y ruta. Alcance de una corrida completa: clientes (PAYER) con algún documento actualizado desde la fecha de arranque o dentro de la ventana; de esos clientes entran todos sus documentos vigentes, aunque se hayan subido antes.
  2. Filtros (plan.py). Solo los tipos acordados con Diego (tabla de abajo), sin INVALID y sin rutas repetidas.
  3. Plan. Cada archivo se pide al bucket por su ruta exacta: el bucket nunca se lista (tiene todo suelto y lo usan otros servicios). Carpeta destino = <NOMBRE> - <RFC> (razón social de business_info, en mayúsculas y sin caracteres reservados; si el RFC tiene una fila de cliente y otra de proveedor de Adela, gana la del cliente; sin nombre, solo el RFC; el nombre va primero, como en las carpetas de expedientes de operaciones que lee vass-move-kyc); nombre = <TIPO>_<hash8>.<ext> (accionistas con prefijo SHAREHOLDER_; sin fecha, porque la de GCS es la de la migración desde S3 en los archivos viejos). La extensión sale de la ruta: los archivos migrados de S3 tienen content-type genérico.
  4. Reconciliación con Drive (sync.py, drive.py). Lista las copias del proceso bajo la carpeta raíz (marcadas con las properties source=kyc-drive-sync y source_sha1), copia lo que falta y mueve a <RFC>/no_vigentes/ las copias que dejaron de estar vigentes (reemplazadas o INVALID). Nunca borra nada. Las carpetas se reconocen por el RFC (property rfc, o nombre <RFC> o que termina en - <RFC>), nunca por el nombre completo: si la de un RFC de la corrida no tiene el nombre esperado, se renombra (carpetas_renombradas en el resumen; los archivos no se tocan). Solo evalúa los RFCs de la corrida: un cliente fuera de la ventana conserva su carpeta tal como estaba. Si una carpeta tiene dos copias del mismo archivo, queda la más vieja y las demás también pasan a no_vigentes/ (copias_duplicadas en el resumen; 0 en una corrida normal). Hay un tope de movimientos por corrida. La retención, si hiciera falta, es una decisión de Compliance y va en un proceso aparte.
  5. Salida. acciones.csv (qué se copió, qué ya estaba, qué pasó a no_vigentes/, qué carpetas se renombraron), indice.csv (una fila por archivo en Drive, con drive_file_id) y un resumen sin RFCs. Con --index-table (solo en corridas completas) reemplaza la tabla del índice en BigQuery.

Qué pasa en cada caso. No hay watermark: cada corrida diaria recalcula el estado deseado, así que si un día no corre la siguiente se pone al día. El backoffice guarda una fila por cliente y tipo de documento y la actualiza en el lugar (poder y acta de asamblea nunca tienen más de un archivo por fila).

En el backoffice En Drive, en la corrida siguiente
El cliente sube un archivo más y no toca el resto Se copia solo ese; el resto queda como ya_esta, sin volver a bajarlo
El cliente reemplaza un archivo Se copia el nuevo (cada carga es un objeto nuevo en GCS) y el viejo pasa a no_vigentes/
Un documento pasa a INVALID Su copia pasa a no_vigentes/
El cliente cambia la razón social La carpeta se renombra la próxima vez que el cliente entra en una corrida; los archivos no se tocan
Hay dos copias del mismo archivo en la carpeta Queda la más vieja; las demás pasan a no_vigentes/ y se cuentan en copias_duplicadas
El cliente queda fuera de la ventana No se toca: la carpeta queda como estaba. Si vuelve a tener movimiento, se copia solo lo nuevo
Operaciones sube algo a mano No se toca

Tipos que se copian (validado con Diego, 2026-09-30):

Documento kyc_name De quién
Estado de cuenta BANK_ACCOUNT_STATEMENTS Cliente
INE o identificaciones PERSONAL_IDENTIFICATION Persona física: la propia · moral: accionistas o representante
Acta de asamblea SHAREHOLDERS_MEETING_DOCUMENT Cliente
Poder POWER_OF_ATTORNEY Cliente
Comprobante de domicilio PROVE_OF_ADDRESS Cliente y accionistas

Fuera: acta constitutiva (CERTIFICATE_OF_INCORPORATION), buró (CREDIT_HISTORY, CSV/JSON) y opinión IMSS (IMSS_COMPLIANCE_OPINION).

Cargas manuales. Cuando un cliente no puede subir un documento por la plataforma y lo manda a operaciones, operaciones lo sube a mano en la carpeta del cliente y avisa a Diego para que corra su proceso a mano. Si operaciones tiene que crear la carpeta, alcanza con que se llame <RFC> o termine en - <RFC>: el proceso la reconoce y le pone el nombre completo. El proceso no toca esos archivos (no tienen su marca) y no aparecen en el índice.

Tablas que alimenta

Tabla Contenido Job que la carga
(a definir) índice por archivo rfc, entity_type, source_type, kyc_name, status, file_location, source_sha1, drive_file_id, drive_folder_id, drive_name, synced_at kyc-drive-sync con --index-table (corrida completa, reemplazo total)

Consumo aguas abajo

  • Proceso de KYC de Diego: lee los archivos de Drive (por drive_file_id del índice; sin índice, por la property rfc de carpetas y copias o el final - <RFC> del nombre de la carpeta, nunca por el nombre completo) y los datos de Syntage (modelos int_syntage_*, ver Syntage · KYC) y arma los campos del contrato con Claude por API.
  • Legal & Compliance: revisa los documentos en la unidad compartida.

Accesos a la unidad: solo miembros (acceso para no miembros desactivado). data-prod-sa como Administrador de contenido; el proceso de Diego como Lector; operaciones como Colaborador (cargas manuales); Data como Administrador. En personas físicas el nombre de la carpeta es el de la persona: es dato personal visible para todos los miembros, por eso el nombre no va a logs ni resúmenes.

Si falla 🛠️

Impacto: medio. El proceso de Diego no ve documentos nuevos; mientras tanto, Legal & Compliance los puede bajar del backoffice como antes.

Síntoma Dónde mirar Acción
No hubo corrida hoy Cloud Scheduler kyc-drive-sync-daily y la métrica kyc-drive-sync-runs (dashboard Data Processes → KYC Documentos Drive) Forzarla con gcloud scheduler jobs run kyc-drive-sync-daily --location us-central1: la corrida es idempotente
Corrida con status distinto de ok Log de cierre del servicio kyc-drive-sync-prod (jsonPayload.event="kyc_drive_sync_run") con_errores: la corrida siguiente reintenta solo lo que faltó · frenada: ver la fila del tope · error: credenciales, secreto o destino (filas de abajo)
Archivos en no_existe plan.csv (ruta y prefijo) Verificar la ruta en el bucket. En solvento-api la copia en cs_files/ tiene un TODO de posible eliminación: si el backend la saca, las rutas nuevas de entities_kyc quedan sin archivo
403 al leer el bucket organization-iam → bucket_permissions["prod-v1-carriers-service-gcs"] La service account necesita roles/storage.objectViewer
"no se pudo leer el secreto KYC_DRIVE_ID" Secret Manager de solvento-data-prod La identidad de la corrida necesita roles/secretmanager.secretAccessor; el secreto tiene que tener una versión activa con el id
"la unidad … o la carpeta raíz no se ven" (403/404 en Drive) Miembros y configuración de la unidad compartida; secreto KYC_DRIVE_ID y variable KYC_DRIVE_ROOT_FOLDER_ID data-prod-sa como Administrador de contenido y la unidad con acceso para personas fuera de Solvento; revisar los ids
copias_duplicadas mayor a 0 (log de cierre en WARNING) Detalle de la corrida o acciones.csv (filas duplicada) Ya se resolvió: las sobrantes quedaron en no_vigentes/. Si se repite, revisar quién copia o mueve a mano archivos del proceso
Una carpeta con la razón social vieja o solo con el RFC El cliente no entró en una corrida desde el cambio (fuera de la ventana), o hay otra carpeta del mismo RFC más vieja: esa es la que se usa Se renombra sola cuando el cliente tenga movimiento (para forzarla, una corrida por RFC con apply). Si son dos carpetas, mover a mano los archivos a la que se usa: el proceso los sigue reconociendo
"superan el tope de 50" (409) acciones.csv o el detalle de la respuesta (filas a_no_vigentes) Revisar si el índice llegó incompleto o cambiaron los tipos antes de subir --max-moves

Escalación: Data (Martin Fleming). Accesos a GCP y al bucket: DevOps.

Enlaces


Última actualización: 2026-10-05 · En producción desde el 2026-10-01. Pendiente con Diego: índice en BigQuery, si su proceso lo necesita.