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
- Índice (
index.py). Por cada archivo deentities_kyc.data.files: RFC del cliente (los documentos de accionistas se asignan al cliente víass_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. - Filtros (
plan.py). Solo los tipos acordados con Diego (tabla de abajo), sinINVALIDy sin rutas repetidas. - 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 debusiness_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 leevass-move-kyc); nombre =<TIPO>_<hash8>.<ext>(accionistas con prefijoSHAREHOLDER_; 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. - Reconciliación con Drive (
sync.py,drive.py). Lista las copias del proceso bajo la carpeta raíz (marcadas con las propertiessource=kyc-drive-syncysource_sha1), copia lo que falta y mueve a<RFC>/no_vigentes/las copias que dejaron de estar vigentes (reemplazadas oINVALID). Nunca borra nada. Las carpetas se reconocen por el RFC (propertyrfc, 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_renombradasen 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 ano_vigentes/(copias_duplicadasen 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. - Salida.
acciones.csv(qué se copió, qué ya estaba, qué pasó ano_vigentes/, qué carpetas se renombraron),indice.csv(una fila por archivo en Drive, condrive_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_iddel índice; sin índice, por la propertyrfcde carpetas y copias o el final- <RFC>del nombre de la carpeta, nunca por el nombre completo) y los datos de Syntage (modelosint_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
- 📦 Repo:
kyc-drive-sync(README con fases, parámetros y cómo correrlo) - 🔗 Relacionado: Syntage · KYC · Airbyte · svc_master
Ú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.