#!/usr/bin/env python3
"""Generate 3 LPDI Word documents for Frank."""

from docx import Document
from docx.shared import Inches, Pt, Cm, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT
from docx.enum.section import WD_ORIENT
from docx.oxml.ns import qn
import datetime

# ── Shared helpers ──────────────────────────────────────────────

BLUE_LPDI = RGBColor(0x00, 0x3E, 0x88)
BLUE_ACCENT = RGBColor(0x00, 0x6E, 0xFF)
GRAY_DARK = RGBColor(0x37, 0x41, 0x51)
GRAY_LIGHT = RGBColor(0x6B, 0x72, 0x80)
WHITE = RGBColor(0xFF, 0xFF, 0xFF)

def setup_doc(title, subtitle):
    doc = Document()
    style = doc.styles['Normal']
    font = style.font
    font.name = 'Calibri'
    font.size = Pt(11)
    font.color.rgb = GRAY_DARK

    # Margins
    for section in doc.sections:
        section.top_margin = Cm(2.5)
        section.bottom_margin = Cm(2)
        section.left_margin = Cm(2.5)
        section.right_margin = Cm(2.5)

    # Title page
    p = doc.add_paragraph()
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    p.space_before = Pt(100)
    run = p.add_run(title)
    run.font.size = Pt(28)
    run.font.color.rgb = BLUE_LPDI
    run.font.bold = True

    p2 = doc.add_paragraph()
    p2.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run2 = p2.add_run(subtitle)
    run2.font.size = Pt(14)
    run2.font.color.rgb = GRAY_LIGHT

    p3 = doc.add_paragraph()
    p3.alignment = WD_ALIGN_PARAGRAPH.CENTER
    p3.space_before = Pt(30)
    run3 = p3.add_run(f"Fecha: {datetime.date.today().strftime('%d de %B de %Y')}")
    run3.font.size = Pt(11)
    run3.font.color.rgb = GRAY_LIGHT

    p4 = doc.add_paragraph()
    p4.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run4 = p4.add_run("Dominio: eco.lpdi.co")
    run4.font.size = Pt(11)
    run4.font.color.rgb = GRAY_LIGHT

    p5 = doc.add_paragraph()
    p5.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run5 = p5.add_run("Confidencial — LPDI / SWFactory")
    run5.font.size = Pt(10)
    run5.font.color.rgb = GRAY_LIGHT
    run5.font.italic = True

    doc.add_page_break()
    return doc

def add_heading1(doc, text):
    h = doc.add_heading(text, level=1)
    for run in h.runs:
        run.font.color.rgb = BLUE_LPDI
    return h

def add_heading2(doc, text):
    h = doc.add_heading(text, level=2)
    for run in h.runs:
        run.font.color.rgb = BLUE_ACCENT
    return h

def add_heading3(doc, text):
    h = doc.add_heading(text, level=3)
    for run in h.runs:
        run.font.color.rgb = GRAY_DARK
    return h

def add_para(doc, text, bold=False, italic=False):
    p = doc.add_paragraph()
    run = p.add_run(text)
    run.font.size = Pt(11)
    run.font.bold = bold
    run.font.italic = italic
    return p

def add_table(doc, headers, rows):
    table = doc.add_table(rows=1 + len(rows), cols=len(headers))
    table.style = 'Light Grid Accent 1'
    table.alignment = WD_TABLE_ALIGNMENT.CENTER
    # Header
    for i, h in enumerate(headers):
        cell = table.rows[0].cells[i]
        cell.text = h
        for p in cell.paragraphs:
            for run in p.runs:
                run.font.bold = True
                run.font.size = Pt(10)
    # Data rows
    for r_idx, row_data in enumerate(rows):
        for c_idx, val in enumerate(row_data):
            cell = table.rows[r_idx + 1].cells[c_idx]
            cell.text = str(val)
            for p in cell.paragraphs:
                for run in p.runs:
                    run.font.size = Pt(10)
    return table

def add_bullet(doc, text, bold_prefix=None):
    p = doc.add_paragraph(style='List Bullet')
    if bold_prefix:
        run_b = p.add_run(bold_prefix)
        run_b.font.bold = True
        run_b.font.size = Pt(11)
        run_n = p.add_run(text)
        run_n.font.size = Pt(11)
    else:
        run = p.add_run(text)
        run.font.size = Pt(11)
    return p


# ═══════════════════════════════════════════════════════════════
# DOCUMENTO 1: Reporte Actualizado de Correos
# ═══════════════════════════════════════════════════════════════

def generate_doc1():
    doc = setup_doc(
        "Reporte de Correos Electrónicos",
        "Sistema LPDI — Subsistema de Relacionamiento (SGR)"
    )

    # TOC placeholder
    add_heading1(doc, "Contenido")
    add_para(doc, "1. Resumen Ejecutivo")
    add_para(doc, "2. Infraestructura de Envío")
    add_para(doc, "3. Criterios de Diseño Visual")
    add_para(doc, "4. Catálogo Completo de Correos")
    add_para(doc, "5. Correos de Registro y Bienvenida")
    add_para(doc, "6. Correos de Gestión de Equipo")
    add_para(doc, "7. Correos de Gestión de Cuenta")
    add_para(doc, "8. Correos Automatizados (Cron Jobs)")
    add_para(doc, "9. Variables Dinámicas por Correo")
    add_para(doc, "10. Reglas de Negocio Asociadas")
    doc.add_page_break()

    # 1. Resumen
    add_heading1(doc, "1. Resumen Ejecutivo")
    add_para(doc, "El Sistema LPDI cuenta con un total de 22 correos electrónicos transaccionales que cubren todo el ciclo de vida del usuario y las entidades registradas en la plataforma. Los correos se distribuyen en 5 categorías funcionales:")
    add_bullet(doc, "Registro y Bienvenida: 4 correos (E01–E04)")
    add_bullet(doc, "Gestión de Equipo: 6 correos (E05–E10)")
    add_bullet(doc, "Gestión de Cuenta y Entidades: 5 correos (E11–E15)")
    add_bullet(doc, "Automatizados (Cron Jobs): 5 correos (E16–E20)")
    add_bullet(doc, "Alianzas / Beneficios: 2 correos (E21–E22)")
    add_para(doc, "Todos los correos son enviados en español neutro latinoamericano, con diseño visual unificado bajo los lineamientos de marca LPDI.")

    # 2. Infraestructura
    add_heading1(doc, "2. Infraestructura de Envío")
    add_table(doc,
        ["Componente", "Detalle"],
        [
            ["Librería", "Nodemailer v8.x"],
            ["Protocolo", "SMTP sobre TLS (puerto 465)"],
            ["Proveedor SMTP", "Resend (smtp.resend.com)"],
            ["Remitente", '"Ecosistema LPDI" <no-reply@lpdi.co>'],
            ["Dominio verificado", "lpdi.co"],
            ["Archivos fuente", "src/lib/server/email.ts (12 funciones)\nsrc/lib/server/email-team.ts (7 funciones)"],
            ["Patrón de envío", "Fire-and-forget: el envío no bloquea la operación principal. Errores se capturan con try/catch y se registran en console.error"],
        ]
    )

    # 3. Criterios visuales
    add_heading1(doc, "3. Criterios de Diseño Visual")
    add_para(doc, "Todos los correos siguen un diseño unificado aprobado por el cliente:", bold=True)
    add_table(doc,
        ["Elemento", "Valor", "Notas"],
        [
            ["Línea header", "border-top: 2px solid #006eff", "Siempre azul LPDI"],
            ["Línea footer", "border-top: 1px solid #e5e7eb", "Gris sutil"],
            ["Color título (h1)", "#003e88", "Azul oscuro LPDI"],
            ["Color texto body", "#374151", "Gris oscuro"],
            ["Color texto footer", "#9ca3af", "Gris claro"],
            ["Botón CTA", "background: #006eff, color: #fff, border-radius: 8px", "Azul LPDI"],
            ["Logo header", "https://eco.lpdi.co/lpdi-logo.png — 180px", ""],
            ["Logo footer", "Mismo logo — 80px, opacity 0.4", ""],
            ["Fondo body", "#f4f4f5", "Gris muy claro"],
            ["Fondo card", "#ffffff, border-radius: 12px", "Tarjeta blanca"],
            ["Fondo footer", "#f9fafb", ""],
            ["Tipografía", "System fonts (Segoe UI, Roboto, sans-serif)", "Compatibilidad email"],
        ]
    )

    add_heading2(doc, "3.1 Reglas de Copywriting")
    add_bullet(doc, "Español neutro LATAM: usar \"tienes\", \"puedes\" (nunca voseo)")
    add_bullet(doc, "No asumir el rol del destinatario: decir \"tu cuenta\" o \"tu registro\"")
    add_bullet(doc, "Distinción cuenta vs registro: \"cuenta\" = cuenta de usuario (login); \"registro\" = entidad registrada (startup/ICG)")
    add_bullet(doc, 'Footer estándar: "Ecosistema LPDI · eco.lpdi.co"')

    # 4. Catálogo completo
    doc.add_page_break()
    add_heading1(doc, "4. Catálogo Completo de Correos")
    add_para(doc, "La siguiente tabla presenta los 20 correos del sistema con su identificación, trigger, destinatario y archivo fuente.")

    add_table(doc,
        ["#", "Nombre", "Trigger", "Destinatario", "Asunto", "Archivo"],
        [
            ["E01", "Startup Welcome", "Registro exitoso de startup", "contact_email de la startup", "Bienvenido al Ecosistema LPDI — Confirma tu cuenta", "email.ts"],
            ["E02", "Startup Followup", "Cron 24-48h post-registro (email confirmado)", "contact_email + editores", "Aumenta el score de tu perfil en el Ecosistema LPDI", "email.ts"],
            ["E03", "Contact Welcome (ICG)", "Registro de ICG cuando el contacto es distinto al registrador", "contact_email del ICG", "[icgName] te ha asignado como contacto en el Ecosistema LPDI", "email.ts"],
            ["E04", "CEO Welcome", "Registro de startup cuando el CEO es distinto al registrador", "ceo_email", "Bienvenido al Ecosistema LPDI — [companyName]", "email.ts"],
            ["E05", "Team Invitation", "CEO agrega miembro en Panel 6", "Email del miembro invitado", "[addedByName] te ha incluido en el equipo de [companyName]", "email-team.ts"],
            ["E06", "Team Welcome (con edición)", "Miembro confirma invitación y tiene permisos de edición", "Email del miembro", "Bienvenido al equipo de [companyName] en el Ecosistema LPDI", "email-team.ts"],
            ["E07", "Team Welcome (sin edición)", "Miembro confirma invitación sin permisos de edición", "Email del miembro", "Bienvenido al equipo de [companyName] en el Ecosistema LPDI", "email-team.ts"],
            ["E08", "Team Rejection", "Miembro rechaza la invitación", "Email del miembro", "Confirmación: no haces parte del equipo de [companyName]", "email-team.ts"],
            ["E09", "CEO — Miembro Confirmó", "Miembro acepta invitación al equipo", "ceo_email", "[memberName] aceptó la invitación al equipo de [companyName]", "email-team.ts"],
            ["E10", "CEO — Miembro Rechazó", "Miembro rechaza invitación al equipo", "ceo_email", "[memberName] rechazó la invitación al equipo de [companyName]", "email-team.ts"],
            ["E11", "Account Deleted", "Usuario elimina su cuenta", "Email del usuario", "Tu cuenta en el Ecosistema LPDI ha sido eliminada", "email.ts"],
            ["E12", "Account Deleted + Entity", "Usuario único editor elimina cuenta", "Email del usuario", "Tu cuenta y tu registro en el Ecosistema LPDI han sido eliminados", "email.ts"],
            ["E13", "Entity Deleted (editor)", "Soft-delete de startup/ICG", "Emails de editores asociados", "El registro de [entityName] ha sido eliminado del Ecosistema LPDI", "email.ts"],
            ["E14", "Entity Deleted (viewer)", "Soft-delete de startup/ICG", "Emails de miembros sin edición", "El registro de [entityName] ha sido eliminado del Ecosistema LPDI", "email.ts"],
            ["E15", "Entity Restored", "Restauración de entidad soft-deleted", "Emails de todos los asociados", "[entityName] ha sido restaurado en el Ecosistema LPDI", "email.ts"],
            ["E16", "Startup Reminder (día 3)", "Cron: 3 días sin confirmar email", "contact_email", "Recordatorio: confirma tu cuenta en el Ecosistema LPDI", "email.ts"],
            ["E17", "Startup Reminder (día 6)", "Cron: 6 días sin confirmar email", "contact_email", "Último aviso: confirma tu cuenta en el Ecosistema LPDI", "email.ts"],
            ["E18", "Permission Change", "CEO cambia permisos de edición de un miembro", "Emails afectados", "Cambio de permisos en [companyName]", "email-team.ts"],
            ["E19", "Password Changed", "Usuario cambia su contraseña", "Email del usuario", "Tu contraseña ha sido actualizada — Ecosistema LPDI", "email.ts"],
            ["E20", "Team Reminder (días 3,6,7)", "Cron de reminders para invitaciones pendientes", "Email del miembro invitado", "Reenvío de E05 (Team Invitation)", "cron/team-reminders"],
            ["E21", "Solicitud de Alianza — LPDI", "Usuario envía 'Quiero ser aliado' desde el FP", "partners@lpdi.co (interno)", "Nueva solicitud de alianza — [nombre]", "email.ts"],
            ["E22", "Solicitud de Alianza — Usuario", "Mismo envío; acuse al solicitante", "Correo del usuario solicitante", "Recibimos tu solicitud de alianza — Ecosistema LPDI", "email.ts"],
        ]
    )

    # 4.1 Correos de Alianza (nuevos, Frank 2026-07-23)
    add_heading2(doc, "4.1 Correos de Alianza / Beneficios (E21–E22)")
    add_para(doc, "Se disparan cuando un usuario que aún no puede publicar beneficios envía una solicitud de alianza desde el pop-up «Quiero ser aliado» (endpoint /api/alianzas). Son DOS versiones distintas (Frank 76.g):")
    add_para(doc, "E21 — Solicitud de Alianza (interno):", bold=True)
    add_bullet(doc, "Destinatario: partners@lpdi.co (correo de contacto con aliados; reply-to al usuario).")
    add_bullet(doc, "Contenido en dos secciones: «Datos del usuario solicitante» (nombres y apellidos, correo, teléfono, LinkedIn) y «Datos de la entidad» (nombre, rol, correo corporativo, página web, LinkedIn), más el mensaje. Los campos vacíos no se muestran.")
    add_para(doc, "E22 — Solicitud de Alianza (acuse al usuario):", bold=True)
    add_bullet(doc, "Destinatario: el correo del usuario solicitante.")
    add_bullet(doc, "Contenido: acuse de recibo («Recibimos tu solicitud de alianza») + botón para agendar una reunión (lpdi.co/agenda30min). Best-effort: su fallo no bloquea la solicitud.")

    # 5-8: Detalle por categoría
    doc.add_page_break()
    add_heading1(doc, "5. Correos de Registro y Bienvenida (E01–E04)")

    add_heading2(doc, "E01 — Startup Welcome")
    add_para(doc, "Propósito:", bold=True)
    add_para(doc, "Correo de bienvenida enviado inmediatamente después de que un usuario completa el formulario de registro simplificado de startup. Contiene el enlace de confirmación de cuenta.")
    add_para(doc, "Trigger:", bold=True)
    add_para(doc, "Registro exitoso en /registro-startup → signUp en Supabase Auth → insert en tabla startups → envío de E01.")
    add_para(doc, "Contenido:", bold=True)
    add_bullet(doc, "Saludo personalizado con el nombre de la startup")
    add_bullet(doc, "Explicación breve de qué es el Ecosistema LPDI")
    add_bullet(doc, "Botón CTA: \"Confirmar mi cuenta\" (enlace a /auth/confirmar-startup con token OTP)")
    add_bullet(doc, "Nota sobre expiración: la cuenta se elimina si no se confirma en 7 días")
    add_para(doc, "Variables dinámicas:", bold=True)
    add_table(doc, ["Variable", "Origen", "Ejemplo"],
        [
            ["companyName", "Campo del formulario de registro", "TechStartup SAS"],
            ["confirmUrl", "Generada: eco.lpdi.co/auth/confirmar-startup?token=...", "URL con token OTP"],
        ]
    )

    add_heading2(doc, "E02 — Startup Followup")
    add_para(doc, "Propósito:", bold=True)
    add_para(doc, "Correo de seguimiento enviado automáticamente entre 24 y 48 horas después del registro, solo si el usuario ya confirmó su email. Incentiva al usuario a completar el formulario detallado y aumentar el score de completitud.")
    add_para(doc, "Trigger:", bold=True)
    add_para(doc, "Cron job /api/cron/startup-followup (ejecución cada hora). Filtra startups creadas hace 24-48h con email confirmado.")
    add_para(doc, "Contenido:", bold=True)
    add_bullet(doc, "Recordatorio del score actual del perfil")
    add_bullet(doc, "Invitación a completar el formulario detallado")
    add_bullet(doc, "Botón CTA: \"Ver mi registro\" (enlace al dashboard)")
    add_para(doc, "Destinatarios: contact_email de la startup + emails de editores asociados (startup_founders con can_edit_form=true).")

    add_heading2(doc, "E03 — Contact Welcome (ICG)")
    add_para(doc, "Propósito:", bold=True)
    add_para(doc, "Cuando alguien registra un ICG y designa a otra persona como contacto (email diferente), el sistema crea automáticamente una cuenta para ese contacto y le envía este correo con instrucciones para establecer su contraseña.")
    add_para(doc, "Trigger:", bold=True)
    add_para(doc, "Registro de ICG en /registro-icg → contact_email ≠ email del registrador → createUser con password temporal → envío de E03.")
    add_para(doc, "Contenido:", bold=True)
    add_bullet(doc, "Notificación de que fue designado como contacto del ICG")
    add_bullet(doc, "Nombre de la organización ICG que lo designó")
    add_bullet(doc, "Botón CTA: \"Establecer nueva contraseña\" (enlace de recovery)")
    add_bullet(doc, "Segundo CTA: \"Ver mi registro\" (enlace al dashboard)")
    add_para(doc, "Variables dinámicas:", bold=True)
    add_table(doc, ["Variable", "Origen"],
        [
            ["icgName", "Nombre de la organización ICG"],
            ["recoveryUrl", "URL de recovery generada por Supabase Auth"],
        ]
    )

    add_heading2(doc, "E04 — CEO Welcome")
    add_para(doc, "Propósito:", bold=True)
    add_para(doc, "Cuando se registra una startup y los datos del CEO corresponden a una persona diferente al registrador, el sistema crea una cuenta para el CEO y le envía este correo de bienvenida.")
    add_para(doc, "Trigger:", bold=True)
    add_para(doc, "Registro de startup → ceo_email ≠ email del registrador → ensureCeoUser (src/lib/server/ceo.ts) → envío de E04.")
    add_para(doc, "Contenido:", bold=True)
    add_bullet(doc, "Bienvenida al CEO con nombre de la startup")
    add_bullet(doc, "Enlace para confirmar cuenta o establecer contraseña")
    add_para(doc, "Ahora utiliza el nombre real del usuario logueado que está registrando la startup, obtenido de la tabla profiles (mejora implementada el 2 de junio de 2026).", italic=True)

    # 6. Equipo
    doc.add_page_break()
    add_heading1(doc, "6. Correos de Gestión de Equipo (E05–E10)")
    add_para(doc, "Estos correos gestionan todo el ciclo de vida de las invitaciones al equipo fundador/directivo de una startup. El flujo completo es:")
    add_bullet(doc, "El CEO o registrador agrega un miembro en el Panel 6 del formulario detallado")
    add_bullet(doc, "Se genera un token de invitación (base64url, 7 días de expiración)")
    add_bullet(doc, "Se envía E05 (invitación) al email del miembro")
    add_bullet(doc, "El miembro accede al enlace → página /team/confirmar → acepta o rechaza")
    add_bullet(doc, "Si acepta: E06 o E07 al miembro + E09 al CEO")
    add_bullet(doc, "Si rechaza: E08 al miembro + E10 al CEO")

    for eid, name, desc in [
        ("E05", "Team Invitation", "Invitación inicial al equipo. Contiene enlace con token único para confirmar o rechazar. El token expira en 7 días. Si no responde, recibe reminders automáticos (E20) en los días 3, 6 y 7."),
        ("E06", "Team Welcome (con edición)", "Confirmación de ingreso al equipo con permisos de edición del formulario de la startup. El miembro puede modificar datos del registro."),
        ("E07", "Team Welcome (sin edición)", "Confirmación de ingreso al equipo como miembro de solo lectura. Aparece listado en el equipo pero no puede editar el formulario."),
        ("E08", "Team Rejection Confirmation", "Confirmación al miembro de que rechazó la invitación. Su registro en startup_founders cambia a verification_status='rejected'."),
        ("E09", "CEO — Miembro Confirmó", "Notificación al CEO de que el miembro aceptó la invitación. Incluye nombre completo del miembro."),
        ("E10", "CEO — Miembro Rechazó", "Notificación al CEO de que el miembro rechazó la invitación. Incluye nombre del miembro y enlace al dashboard."),
    ]:
        add_heading2(doc, f"{eid} — {name}")
        add_para(doc, desc)

    # 7. Cuenta
    doc.add_page_break()
    add_heading1(doc, "7. Correos de Gestión de Cuenta (E11–E15)")

    for eid, name, desc in [
        ("E11", "Account Deleted", "Se envía cuando un usuario elimina voluntariamente su cuenta. La eliminación ejecuta la función RPC delete_account(user_id, reason) que limpia todos los datos asociados."),
        ("E12", "Account Deleted + Entity", "Variante de E11 para cuando el usuario que se elimina es el único editor de una startup o ICG. La entidad también se elimina. El correo informa ambas eliminaciones."),
        ("E13", "Entity Deleted (editor)", "Notificación enviada a todos los usuarios con permisos de edición (can_edit_form=true) cuando una startup o ICG es eliminada (soft-delete). Incluye información del período de gracia de 30 días y botón para restaurar."),
        ("E14", "Entity Deleted (viewer)", "Notificación enviada a miembros del equipo sin permisos de edición. Informativa: no incluye opción de restaurar ya que no tienen permisos."),
        ("E15", "Entity Restored", "Se envía a todos los usuarios asociados cuando una entidad soft-deleted es restaurada dentro del período de gracia de 30 días."),
    ]:
        add_heading2(doc, f"{eid} — {name}")
        add_para(doc, desc)

    add_heading2(doc, "E18 — Permission Change")
    add_para(doc, "Se envía cuando el CEO modifica los permisos de edición de un miembro del equipo (activa o desactiva can_edit_form). Notifica al miembro afectado.")

    add_heading2(doc, "E19 — Password Changed")
    add_para(doc, "Confirmación de cambio de contraseña. Se envía después de que el usuario actualiza su contraseña exitosamente desde /api/account/update-password.")

    # 8. Cron
    doc.add_page_break()
    add_heading1(doc, "8. Correos Automatizados — Cron Jobs (E16–E17, E20)")
    add_para(doc, "El sistema ejecuta 4 cron jobs (endpoints protegidos con CRON_SECRET) que disparan correos automáticos:")

    add_heading2(doc, "8.1 Startup Welcome Reminders (/api/cron/startup-welcome-reminders)")
    add_para(doc, "Frecuencia: cada hora. Identifica startups que no han confirmado su email:")
    add_bullet(doc, "Día 3 (E16): Reminder amigable — \"Recordatorio: confirma tu cuenta\"")
    add_bullet(doc, "Día 6 (E17): Reminder urgente — \"Último aviso: confirma tu cuenta\"")
    add_bullet(doc, "Día 8+: Soft-delete automático de la startup (sin correo adicional)")

    add_heading2(doc, "8.2 Startup Followup (/api/cron/startup-followup)")
    add_para(doc, "Frecuencia: cada hora. Envía E02 a startups creadas hace 24-48h que ya confirmaron su email.")

    add_heading2(doc, "8.3 Team Reminders (/api/cron/team-reminders)")
    add_para(doc, "Frecuencia: cada hora. Envía recordatorios (E20, reenvío de E05) para invitaciones de equipo pendientes en los días 3, 6 y 7.")

    add_heading2(doc, "8.4 Purge Entities (/api/cron/purge-entities)")
    add_para(doc, "Frecuencia: cada hora. Ejecuta la función RPC purge_expired_entities() que elimina definitivamente entidades soft-deleted con más de 30 días. No envía correo (la notificación se hizo en el momento del soft-delete).")

    # 9. Variables
    doc.add_page_break()
    add_heading1(doc, "9. Variables Dinámicas Utilizadas")
    add_table(doc,
        ["Variable", "Descripción", "Usado en"],
        [
            ["companyName", "Nombre de la startup o ICG", "E01, E02, E04, E05–E10, E13–E15"],
            ["icgName", "Nombre de la organización ICG", "E03"],
            ["confirmUrl", "URL de confirmación con token OTP", "E01, E04"],
            ["recoveryUrl", "URL de recovery de contraseña", "E03"],
            ["dashboardUrl", "URL del dashboard del usuario", "E02, E06, E07"],
            ["confirmTeamUrl", "URL con token de invitación al equipo", "E05, E20"],
            ["restoreUrl", "URL para restaurar entidad eliminada", "E13"],
            ["addedByName", "Nombre del usuario que agregó al miembro", "E05"],
            ["memberName", "Nombre del miembro que aceptó/rechazó", "E09, E10"],
            ["entityType", "Tipo de entidad (startup/ICG)", "E13, E14, E15"],
            ["entityName", "Nombre de la entidad eliminada/restaurada", "E13–E15"],
            ["score", "Score de completitud del perfil", "E02"],
        ]
    )

    # 10. Reglas
    add_heading1(doc, "10. Reglas de Negocio Asociadas")
    add_bullet(doc, "Los correos nunca bloquean la operación principal (patrón fire-and-forget)")
    add_bullet(doc, "Si un correo falla, se registra en console.error pero la operación continúa")
    add_bullet(doc, "Las cuentas creadas automáticamente (CEO, contacto ICG) reciben password temporal generado con crypto.randomBytes(12)")
    add_bullet(doc, "Los tokens de invitación al equipo expiran en 7 días")
    add_bullet(doc, "Las startups sin confirmación de email se eliminan automáticamente al día 8")
    add_bullet(doc, "El soft-delete tiene un período de gracia de 30 días antes de la purga definitiva")
    add_bullet(doc, "E18 (cambio de permisos) usa el nombre real del usuario logueado, obtenido de la tabla profiles")
    add_bullet(doc, "Los reminders de equipo (E20) se envían máximo 3 veces (días 3, 6 y 7)")

    path = "/home/clawd/playgrounds/pmo/LPDI_Reporte_Correos.docx"
    doc.save(path)
    print(f"Doc 1 saved: {path}")
    return path


# ═══════════════════════════════════════════════════════════════
# DOCUMENTO 2: Especificación Técnica Completa
# ═══════════════════════════════════════════════════════════════

def generate_doc2():
    doc = setup_doc(
        "Especificación Técnica Completa",
        "Sistema LPDI — Subsistema de Relacionamiento (SGR)"
    )

    # TOC
    add_heading1(doc, "Contenido")
    for item in [
        "1. Visión General del Sistema",
        "2. Stack Tecnológico",
        "3. Modelo de Datos",
        "4. Módulos Funcionales",
        "5. Sistema de Correos Electrónicos",
        "6. Autenticación y Autorización",
        "7. Integraciones Externas",
        "8. Sistema de Formularios",
        "9. Sistema de Scoring",
        "10. APIs y Endpoints",
        "11. Cron Jobs",
        "12. Glosario",
    ]:
        add_para(doc, item)
    doc.add_page_break()

    # 1. Visión General
    add_heading1(doc, "1. Visión General del Sistema")
    add_heading2(doc, "1.1 Propósito")
    add_para(doc, "El Sistema LPDI (La Punta del Iceberg) es una plataforma SaaS para la gestión de ecosistemas de innovación en Latinoamérica. El Subsistema de Relacionamiento (SGR) es el primer módulo en producción y gestiona:")
    add_bullet(doc, "Registro de Startups, PyMEs y Scaleups con formularios simplificados y detallados")
    add_bullet(doc, "Registro de ICGs (Inversionistas, Corporativos, Gestores de ecosistemas, Academia, Hubs)")
    add_bullet(doc, "Directorio público del ecosistema (consulta y filtrado)")
    add_bullet(doc, "Perfiles públicos de entidades y usuarios")
    add_bullet(doc, "Networking y matchmaking entre actores")
    add_bullet(doc, "Gestión de equipos fundadores/directivos con invitaciones")
    add_bullet(doc, "Sistema de scoring de completitud de perfiles")

    add_heading2(doc, "1.2 Dominio y Acceso")
    add_table(doc, ["Aspecto", "Detalle"],
        [
            ["URL producción", "https://eco.lpdi.co"],
            ["Repositorio", "GitHub (privado) — devlapuntadeliceberg/relacionamiento"],
            ["Deploy", "Vercel (auto-deploy desde branch main)"],
            ["Base de datos", "Supabase (PostgreSQL, instancia compartida con SGC)"],
        ]
    )

    # 2. Stack
    add_heading1(doc, "2. Stack Tecnológico")
    add_table(doc, ["Componente", "Tecnología", "Versión", "Rol"],
        [
            ["Framework web", "SvelteKit", "2.x", "Server-side rendering + routing + form actions"],
            ["UI", "Svelte", "4.x", "Componentes reactivos"],
            ["Lenguaje", "TypeScript", "5.x", "Tipado estático"],
            ["CSS", "Tailwind CSS", "3.4", "Utility-first CSS framework"],
            ["Base de datos", "Supabase (PostgreSQL)", "—", "Auth, DB, RLS, Storage, RPC"],
            ["Email", "Nodemailer + Resend SMTP", "8.x", "Envío de correos transaccionales"],
            ["Deploy", "Vercel + adapter-vercel", "5.4", "Hosting serverless"],
            ["Testing E2E", "Playwright", "1.59", "Tests end-to-end"],
            ["Testing unitario", "Vitest", "4.1", "Tests unitarios"],
            ["Build", "Vite", "5.x", "Bundler y dev server"],
            ["QR", "qrcode", "1.5", "Generación de códigos QR"],
        ]
    )

    add_heading2(doc, "2.1 Estructura de Directorios")
    add_para(doc, "src/lib/components/ — 28+ componentes reutilizables organizados por dominio (account, icg, profiles, startup, user)")
    add_para(doc, "src/lib/data/ — 8 archivos de datos estáticos y Single Source of Truth (SSOT)")
    add_para(doc, "src/lib/entities/ — Tipos TypeScript para startup, ICG y usuario")
    add_para(doc, "src/lib/server/ — 6 archivos de lógica server-only (email, team, CEO, consent, profile, taxonomías)")
    add_para(doc, "src/lib/stores/ — Svelte stores para estado global")
    add_para(doc, "src/lib/utils/ — 7 archivos helpers (scoring, validación, mapeo)")
    add_para(doc, "src/routes/ — 25+ rutas SvelteKit (páginas + APIs)")
    add_para(doc, "supabase/migrations/ — 43 archivos SQL de migración")

    # 3. Modelo de datos
    doc.add_page_break()
    add_heading1(doc, "3. Modelo de Datos")

    add_heading2(doc, "3.1 Tablas Principales")
    add_heading3(doc, "3.1.1 profiles")
    add_para(doc, "Usuarios del sistema. Se crea automáticamente al registrarse.")
    add_table(doc, ["Campo", "Tipo", "Descripción"],
        [
            ["id", "UUID (= auth.uid())", "Identificador único, vinculado a Supabase Auth"],
            ["email", "TEXT UNIQUE", "Email del usuario"],
            ["full_name", "TEXT", "Nombre completo"],
            ["avatar_url", "TEXT", "URL de imagen de perfil"],
            ["about_me", "TEXT", "Descripción personal"],
            ["country", "TEXT", "País"],
            ["city", "TEXT", "Ciudad"],
            ["company", "TEXT", "Empresa actual"],
            ["position", "TEXT", "Cargo"],
            ["phone", "TEXT", "Teléfono con código de país"],
            ["languages", "TEXT[]", "Idiomas"],
            ["linkedin", "TEXT", "URL de LinkedIn"],
            ["system_role", "SystemRole", "ADMIN / MANAGER / MEMBER"],
        ]
    )

    add_heading3(doc, "3.1.2 startups")
    add_para(doc, "Startups, PyMEs y Scaleups registradas en el ecosistema. Contiene ~50 campos organizados por panel temático.")
    add_table(doc, ["Campo clave", "Tipo", "Descripción"],
        [
            ["id", "UUID", "Identificador único"],
            ["registered_by_id", "UUID FK profiles", "Usuario que registró la entidad"],
            ["company_name", "TEXT", "Nombre de la empresa"],
            ["company_type", "CompanyType", "STARTUP / PYME / SCALEUP"],
            ["is_tech_based", "BOOLEAN", "Indica si es de base tecnológica"],
            ["country, city", "TEXT", "Ubicación principal"],
            ["contact_email", "TEXT", "Email de contacto principal"],
            ["status", "EntityStatus", "DRAFT / PENDING / APPROVED / REJECTED"],
            ["completion_score", "INTEGER (0-100)", "Score de completitud calculado"],
            ["deleted_at", "TIMESTAMPTZ", "Fecha de soft-delete (null si activa)"],
            ["delete_scheduled_for", "TIMESTAMPTZ", "Fecha de purga programada (30 días)"],
            ["ceo_user_id", "UUID FK auth.users", "ID del CEO en el sistema"],
            ["ceo_email, ceo_first_name, ceo_last_name", "TEXT", "Datos del CEO"],
        ]
    )
    add_para(doc, "Campos adicionales incluyen: descripción, pitch, industrias, necesidades, revenue, BRL/TRL/CRL levels, pitch deck URL, logo, redes sociales, y más de 20 campos específicos por panel.", italic=True)

    add_heading3(doc, "3.1.3 icgs")
    add_para(doc, "Inversionistas, Corporativos, Gestores y otros actores del ecosistema.")
    add_table(doc, ["Campo clave", "Tipo", "Descripción"],
        [
            ["id", "UUID", "Identificador único"],
            ["registered_by_id", "UUID FK profiles", "Usuario registrador"],
            ["organization_name", "TEXT", "Nombre de la organización"],
            ["icg_type", "IcgType", "Tipo: 7 opciones (ver enums)"],
            ["contact_user_id", "UUID FK auth.users", "Usuario contacto designado"],
            ["status", "EntityStatus", "Estado de la entidad"],
            ["is_public", "BOOLEAN", "Visible en el directorio público"],
            ["completion_score", "INTEGER (0-100)", "Score de completitud"],
            ["deleted_at", "TIMESTAMPTZ", "Soft-delete"],
        ]
    )

    add_heading3(doc, "3.1.4 startup_founders")
    add_para(doc, "Equipo fundador/directivo vinculado a una startup.")
    add_table(doc, ["Campo", "Tipo", "Descripción"],
        [
            ["id", "UUID", "Identificador"],
            ["startup_id", "UUID FK startups", "Startup a la que pertenece"],
            ["email", "TEXT", "Email del miembro"],
            ["first_name, last_name", "TEXT", "Nombre del miembro"],
            ["role", "TEXT", "Rol en la empresa"],
            ["can_edit_form", "BOOLEAN", "Permiso de edición del formulario"],
            ["verification_status", "TEXT", "pending / verified / rejected"],
            ["invitation_token", "TEXT UNIQUE", "Token de invitación (expira 7 días)"],
            ["user_id", "UUID FK auth.users", "Vinculado al crear cuenta"],
        ]
    )

    add_heading3(doc, "3.1.5 Otras tablas")
    add_table(doc, ["Tabla", "Descripción"],
        [
            ["strategic_needs", "Necesidades estratégicas de ICGs (category enum + subcategory)"],
            ["consent_log", "Audit trail de T&C: user_id, consent_type, version, IP, user_agent. Append-only."],
            ["profile_ecosystem_roles", "Relación N:N entre profiles y ecosystem_roles"],
            ["profile_catalogo_roles", "Roles de catálogo asignados a perfiles"],
        ]
    )

    add_heading2(doc, "3.2 Tablas de Catálogos (Taxonomías)")
    add_table(doc, ["Tabla", "Descripción", "Fuente"],
        [
            ["ecosystem_roles", "~40 roles activos en el ecosistema", "Supabase"],
            ["catalogo_industria / catalogo_sub_industria", "Industrias por segmento (ICG, startup tech, PyME)", "Supabase"],
            ["catalogo_necesidad", "Necesidades de negocio por categoría", "Supabase"],
            ["catalogo_tipo_empresa_icg", "Tipos de empresa ICG agrupados", "Supabase"],
            ["catalogo_red_social", "Plataformas de redes sociales", "Supabase"],
            ["catalogo_rango_revenue", "Rangos de facturación", "Supabase"],
            ["catalogo_genero", "Opciones de género", "Supabase"],
            ["paises", "Catálogo de países", "Supabase"],
            ["crl_levels", "Niveles CRL 1-9", "Supabase"],
        ]
    )

    add_heading2(doc, "3.3 Enums PostgreSQL")
    add_table(doc, ["Enum", "Valores"],
        [
            ["SystemRole", "ADMIN, MANAGER, MEMBER"],
            ["CompanyType", "STARTUP, PYME, SCALEUP"],
            ["EntityStatus", "DRAFT, PENDING, APPROVED, REJECTED"],
            ["IcgType", "INVESTOR_INDIVIDUAL, INVESTOR_INSTITUTIONAL, CORPORATE, MANAGER_SPECIALIZED, HUB_NETWORK, ACADEMIA, OTHER"],
            ["StrategicNeedCategory", "CAPITAL_FLOW, INNOVATION, BUSINESS_INTELLIGENCE, VALUE_CREATION, INSTITUTIONAL_SUPPORT, OTHER"],
        ]
    )

    add_heading2(doc, "3.4 Funciones RPC PostgreSQL")
    add_table(doc, ["Función", "Propósito"],
        [
            ["soft_delete_startup(id, user_id)", "Soft-delete con período de gracia 30 días"],
            ["soft_delete_icg(id, user_id)", "Soft-delete ICG con período de gracia 30 días"],
            ["restore_startup(id, user_id)", "Restaurar startup dentro del período de gracia"],
            ["restore_icg(id, user_id)", "Restaurar ICG dentro del período de gracia"],
            ["purge_expired_entities()", "Eliminación definitiva de entidades con 30+ días eliminadas"],
            ["delete_account(user_id, reason)", "Eliminación completa de cuenta y datos asociados"],
        ]
    )

    add_heading2(doc, "3.5 Row Level Security (RLS)")
    add_para(doc, "RLS está habilitado en TODAS las tablas. Las políticas principales son:")
    add_table(doc, ["Tabla", "Operación", "Regla"],
        [
            ["profiles", "SELECT/UPDATE/INSERT", "Solo el propio usuario (auth.uid() = id)"],
            ["startups", "ALL", "Owner (registered_by_id = auth.uid())"],
            ["startups", "SELECT", "Contact email match o founders vinculados"],
            ["icgs", "ALL", "Owner o contact_user_id"],
            ["icgs", "SELECT", "ICGs públicos (is_public=true, deleted_at IS NULL)"],
            ["consent_log", "INSERT", "Service role únicamente"],
            ["consent_log", "SELECT", "Solo propio (auth.uid() = user_id)"],
            ["consent_log", "UPDATE/DELETE", "PROHIBIDO (append-only)"],
            ["startup_founders", "ALL", "Via relación con startup owner"],
            ["Catálogos", "SELECT", "Público (anon + authenticated)"],
        ]
    )

    # 4. Módulos
    doc.add_page_break()
    add_heading1(doc, "4. Módulos Funcionales")

    modules = [
        ("4.1", "Landing / Home", "/", "Página pública de bienvenida con estadísticas del ecosistema, CTAs de registro para startups e ICGs, información general.", "Pública (sin autenticación)", "+page.svelte (584 LOC)"),
        ("4.2", "Autenticación", "/login, /auth/*", "Login con email+password, confirmación de cuenta por OTP, recuperación de contraseña, aceptación de T&C.", "Pública", "Supabase Auth + hooks.server.ts"),
        ("4.3", "Registro Startup Simplificado", "/registro-startup", "Formulario de una sola página para registro rápido. Crea cuenta Supabase + perfil + startup. Envía E01.", "Pública", "StartupSimplifiedFormShell.svelte\n+page.server.ts (423 LOC)"),
        ("4.4", "Registro Startup Detallado", "/dashboard/startups/nuevo-detallado", "Formulario multi-paso (6 paneles + equipo) con autosave. Paneles: Identidad Legal, Perfil Compañía, Modelo de Negocio, Tesis de Inversión, Equipo, Presencia Digital.", "Autenticado", "StartupDetailedFormShell.svelte\n+page.server.ts (733 LOC)"),
        ("4.5", "Registro ICG Público", "/registro-icg", "Registro de ICG con creación automática de cuenta para contacto si email difiere del registrador.", "Pública", "IcgFormShell.svelte\n+page.server.ts (813 LOC)"),
        ("4.6", "Registro ICG Dashboard", "/dashboard/icg/nuevo", "Registro de ICG desde el dashboard para usuarios ya autenticados.", "Autenticado", "IcgFormShell.svelte"),
        ("4.7", "Dashboard", "/dashboard", "Panel principal del usuario. Muestra startups e ICGs registrados, navegación lateral.", "Autenticado", "DashboardSidebar.svelte\n+page.server.ts (141 LOC)"),
        ("4.8", "Perfil Startup Público", "/perfil-startup", "Vista pública del perfil de una startup aprobada con todos sus datos y score.", "Pública", "StartupProfileView.svelte"),
        ("4.9", "Perfil ICG Público", "/perfil", "Vista pública del perfil de un ICG.", "Pública", "IcgProfileView.svelte"),
        ("4.10", "Perfil de Usuario", "/perfil-usuario, /dashboard/perfil-usuario", "Vista y edición del perfil personal del usuario.", "Autenticado", "UserProfileView.svelte\nUserDetailedFormShell.svelte"),
        ("4.11", "Ecosistema", "/ecosistema", "Directorio público de startups e ICGs aprobados. Filtros por tipo e industria.", "Pública", "+page.server.ts (178 LOC)"),
        ("4.12", "Networking", "/networking", "Herramienta de networking/matchmaking entre actores del ecosistema.", "Autenticado", "—"),
        ("4.13", "Consulta", "/dashboard/consulta/*", "Búsqueda y filtrado avanzado de startups e ICGs. Filtros server-side.", "Autenticado", "+page.server.ts (97 LOC c/u)"),
        ("4.14", "Gestión de Equipo", "Panel 6 + /team/*", "Agregar/gestionar equipo fundador. Invitaciones token-based. Confirmar/rechazar.", "Autenticado", "team.ts (405 LOC)\nemail-team.ts (316 LOC)"),
        ("4.15", "Gestión de Cuenta", "/api/account/*", "Eliminación de cuenta, cambio de email/password, asignación de editor, soft-delete/restore.", "Autenticado", "DeleteAccountModal.svelte\nTrashSection.svelte"),
    ]

    for num, name, routes, desc, auth, files in modules:
        add_heading2(doc, f"{num} {name}")
        add_table(doc, ["Aspecto", "Detalle"],
            [
                ["Rutas", routes],
                ["Descripción", desc],
                ["Autenticación", auth],
                ["Archivos clave", files],
            ]
        )

    # 5. Emails (referencia)
    doc.add_page_break()
    add_heading1(doc, "5. Sistema de Correos Electrónicos")
    add_para(doc, "El sistema cuenta con 20 correos electrónicos transaccionales. Para el detalle completo de cada correo (trigger, contenido, variables, reglas), consultar el documento complementario \"Reporte de Correos Electrónicos\".")
    add_para(doc, "Resumen: 4 correos de registro/bienvenida (E01-E04), 6 de gestión de equipo (E05-E10), 5 de gestión de cuenta/entidades (E11-E15), y 5 automatizados vía cron jobs (E16-E20).")
    add_para(doc, "Infraestructura: Nodemailer v8.x sobre SMTP (Resend), remitente no-reply@lpdi.co, templates HTML inline con branding LPDI.")

    # 6. Auth
    add_heading1(doc, "6. Autenticación y Autorización")
    add_heading2(doc, "6.1 Proveedor")
    add_para(doc, "Supabase Auth con email + password. No hay OAuth social configurado.")

    add_heading2(doc, "6.2 Flujo de Registro de Startup")
    add_bullet(doc, "1. Usuario llena formulario en /registro-startup")
    add_bullet(doc, "2. Server: supabaseAdmin.auth.signUp({email, password, email_confirm: false})")
    add_bullet(doc, "3. Se crea row en profiles y startups")
    add_bullet(doc, "4. Se envía E01 (Welcome) con enlace de confirmación")
    add_bullet(doc, "5. Usuario confirma email → verifyOtp({type:'signup'}) → redirect a /dashboard")
    add_bullet(doc, "6. Si no confirma en 7 días: reminders día 3 y 6, soft-delete día 8")

    add_heading2(doc, "6.3 Guard Global (hooks.server.ts)")
    add_para(doc, "Middleware ejecutado en CADA request:")
    add_bullet(doc, "Redirects de URLs legacy (normalización de case, renombres de rutas)")
    add_bullet(doc, "Setup del cliente Supabase server-side con cookies")
    add_bullet(doc, "TyC Guard: si usuario logueado sin consent_log → redirect a /aceptar-terminos")
    add_bullet(doc, "Bypass: /login, /auth/*, /api/*, /registro-*, /ecosistema, /team/confirmar")

    add_heading2(doc, "6.4 Roles y Permisos")
    add_para(doc, "SystemRole (ADMIN/MANAGER/MEMBER) existe como enum pero actualmente los permisos efectivos se controlan vía RLS:")
    add_bullet(doc, "Owner: registered_by_id = auth.uid() → full CRUD")
    add_bullet(doc, "Contact: contact_email/contact_user_id → read access")
    add_bullet(doc, "Team member: startup_founders con can_edit_form → edit access")

    # 7. Integraciones
    doc.add_page_break()
    add_heading1(doc, "7. Integraciones Externas")
    add_table(doc, ["Servicio", "Uso", "Configuración"],
        [
            ["Supabase", "Auth, DB PostgreSQL, RLS, Storage, RPC functions", "PUBLIC_SUPABASE_URL, SUPABASE_ROLE_KEY"],
            ["Resend (SMTP)", "Envío de correos transaccionales", "SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS"],
            ["Vercel", "Deploy automático desde branch main", "adapter-vercel, vercel.json"],
            ["Cloudflare", "DNS para dominio eco.lpdi.co", "Zona DNS gestionada externamente"],
            ["GeoNames API", "Autocompletado de ciudades por país (CityPicker)", "Endpoint /api/cities como proxy"],
        ]
    )

    # 8. Formularios
    add_heading1(doc, "8. Sistema de Formularios")
    add_table(doc, ["Formulario", "Ruta", "Pasos", "Componente"],
        [
            ["Registro Startup (simplificado)", "/registro-startup", "1 paso", "StartupSimplifiedFormShell"],
            ["Registro Startup (detallado)", "/dashboard/startups/nuevo-detallado", "6 paneles", "StartupDetailedFormShell"],
            ["Registro ICG", "/registro-icg", "Multi-panel", "IcgFormShell"],
            ["Registro ICG (dashboard)", "/dashboard/icg/nuevo", "Multi-panel", "IcgFormShell"],
            ["Registro Usuario Detallado", "/registro-usuario-detallado", "Multi-campo", "UserDetailedFormShell"],
            ["Perfil Usuario (edición)", "/dashboard/perfil-usuario/editar", "Multi-campo", "UserDetailedFormShell"],
            ["Login", "/login", "1 paso", "Inline"],
            ["Reset Password", "/auth/reset-password", "1 paso", "Inline"],
            ["Aceptar T&C", "/aceptar-terminos", "1 paso", "Inline"],
        ]
    )

    add_heading2(doc, "8.1 Componentes de Formulario Reutilizables")
    add_table(doc, ["Componente", "Descripción"],
        [
            ["IndustryPicker", "Selector jerárquico industria/subindustria con segmentos (tech/tradicional)"],
            ["BusinessNeedsPicker", "Selector de necesidades de negocio por categoría"],
            ["CityPicker", "Autocompletado de ciudades por país (API GeoNames)"],
            ["RegionCountryPicker", "Selector de región + países múltiples"],
            ["SocialMediaAdder", "Agregar redes sociales con validación de URL"],
            ["PhoneInput", "Input con código de país"],
            ["YearInput", "Input de año con validación (1900–actual)"],
            ["PasswordField", "Input con criterios visuales de fortaleza"],
            ["AutoSaveIndicator", "Indicador de estado de guardado automático"],
        ]
    )

    # 9. Scoring
    doc.add_page_break()
    add_heading1(doc, "9. Sistema de Scoring")
    add_para(doc, "El sistema calcula un score de completitud de 0 a 100 puntos para cada startup registrada, distribuido en 7 categorías:")
    add_table(doc, ["Panel", "Puntos", "Campos evaluados"],
        [
            ["Identidad Legal", "5", "companyName, city, operationsStartYear, isLegallyConstituted, fiscalDomicile, legalCompanyName"],
            ["Perfil Compañía", "20", "isTechBased, companyType, industries, operatingCountries, revenue, brlLevel, trlLevel"],
            ["Nivel Madurez / Modelo de Negocio", "15", "highConceptPitch, icp, problemStatement, solution, crlLevel, businessModelDescription"],
            ["Tesis de Inversión", "25", "businessNeeds, investmentNeeds, investmentSources, investmentTicket, investmentPurpose, previousInvestments, totalCapitalRaised, pitchDeckUrl"],
            ["Modelo de Negocio", "15", "Superpuesto con campos de Panel 3"],
            ["Equipo", "15", "tmrlLevel, teamComposition, ceoData, founders"],
            ["Presencia Digital", "5", "socialMedia, website, logoUrl"],
        ]
    )
    add_para(doc, "Archivo: src/lib/utils/profileScore.ts — mapeo: mapStartupToScore.ts, mapIcgToScore.ts")

    # 10. APIs
    add_heading1(doc, "10. APIs y Endpoints")
    add_table(doc, ["Endpoint", "Método", "Descripción", "Auth"],
        [
            ["/api/check-email", "POST", "Verificar si email ya existe", "No"],
            ["/api/check-company-name", "POST", "Verificar si nombre de empresa existe", "No"],
            ["/api/check-contact-email", "POST", "Verificar email de contacto", "No"],
            ["/api/user-profile-autosave", "POST", "Guardado automático de perfil de usuario", "Sí"],
            ["/api/entities/trash", "POST", "Soft-delete de startup/ICG", "Sí"],
            ["/api/entities/restore", "POST", "Restaurar entidad soft-deleted", "Sí"],
            ["/api/entities/delete", "POST", "Eliminación definitiva de entidad", "Sí"],
            ["/api/team/confirm", "POST", "Confirmar invitación al equipo", "No (token)"],
            ["/api/team/resend", "POST", "Reenviar invitación al equipo", "Sí"],
            ["/api/team/reject", "POST", "Rechazar invitación al equipo", "No (token)"],
            ["/api/account/delete", "POST", "Eliminar cuenta de usuario", "Sí"],
            ["/api/account/update-email", "POST", "Cambiar email de usuario", "Sí"],
            ["/api/account/update-password", "POST", "Cambiar contraseña", "Sí"],
            ["/api/account/assign-editor", "POST", "Asignar editor a entidad", "Sí"],
            ["/api/account/pre-delete-check", "GET", "Verificar dependencias antes de eliminar", "Sí"],
            ["/api/auth/accept-consent", "POST", "Aceptar T&C", "Sí"],
            ["/api/cities", "GET", "Proxy GeoNames para ciudades", "No"],
            ["/api/dev/email-preview", "GET", "Preview de templates de email (solo dev)", "Dev"],
        ]
    )

    # 11. Cron Jobs
    add_heading1(doc, "11. Cron Jobs")
    add_table(doc, ["Endpoint", "Frecuencia", "Descripción"],
        [
            ["/api/cron/startup-followup", "Cada hora", "Envía E02 a startups 24-48h post-registro con email confirmado"],
            ["/api/cron/team-reminders", "Cada hora", "Reminders días 3, 6, 7 para invitaciones de equipo pendientes"],
            ["/api/cron/purge-entities", "Cada hora", "Purga definitiva de entidades soft-deleted con 30+ días"],
            ["/api/cron/startup-welcome-reminders", "Cada hora", "Reminders días 3-4 y 6-7 para startups sin email confirmado. Día 8+ soft-delete automático"],
        ]
    )
    add_para(doc, "Todos protegidos con Bearer token (CRON_SECRET). Sin el header Authorization correcto, retornan 401.")

    # 12. Glosario
    doc.add_page_break()
    add_heading1(doc, "12. Glosario")
    add_table(doc, ["Término", "Definición"],
        [
            ["SGR", "Subsistema de Gestión de Relacionamiento — módulo principal del sistema LPDI"],
            ["ICG", "Inversionista, Corporativo o Gestor — actor del ecosistema que NO es startup"],
            ["SSOT", "Single Source of Truth — fuente única de datos canónicos"],
            ["RLS", "Row Level Security — políticas de acceso a nivel de fila en PostgreSQL"],
            ["Soft-delete", "Eliminación lógica con período de gracia (30 días) antes de purga definitiva"],
            ["Score", "Indicador de completitud del perfil (0-100 puntos)"],
            ["Panel", "Sección temática de un formulario multi-paso"],
            ["CRL", "Customer Readiness Level — nivel de madurez de la relación con clientes"],
            ["BRL", "Business Readiness Level — nivel de madurez del negocio"],
            ["TRL", "Technology Readiness Level — nivel de madurez tecnológica"],
            ["T&C", "Términos y Condiciones — requieren aceptación para usar la plataforma"],
            ["OTP", "One-Time Password — token de verificación de email"],
        ]
    )

    path = "/home/clawd/playgrounds/pmo/LPDI_Especificacion_Tecnica.docx"
    doc.save(path)
    print(f"Doc 2 saved: {path}")
    return path


# ═══════════════════════════════════════════════════════════════
# DOCUMENTO 3: Arquitectura Técnica
# ═══════════════════════════════════════════════════════════════

def generate_doc3():
    doc = setup_doc(
        "Arquitectura Técnica",
        "Sistema LPDI — Subsistema de Relacionamiento (SGR)"
    )

    # TOC
    add_heading1(doc, "Contenido")
    for item in [
        "1. Arquitectura General",
        "2. Arquitectura Frontend",
        "3. Arquitectura Backend",
        "4. Arquitectura de Base de Datos",
        "5. Seguridad",
        "6. DevOps y Deploy",
        "7. Patrones y Convenciones",
        "8. Dependencias Críticas",
        "9. Puntos de Extensión",
        "10. Recomendaciones para Desarrollos Futuros",
    ]:
        add_para(doc, item)
    doc.add_page_break()

    # 1. Arquitectura General
    add_heading1(doc, "1. Arquitectura General")

    add_heading2(doc, "1.1 Patrón Arquitectónico")
    add_para(doc, "El sistema sigue el patrón SSR híbrido de SvelteKit: server-side rendering con hidratación client-side. Los formularios usan SvelteKit form actions con progressive enhancement, lo que significa que funcionan sin JavaScript habilitado (formulario POST estándar) pero se mejoran con interactividad client-side cuando JS está disponible.")

    add_heading2(doc, "1.2 Capas del Sistema")
    add_table(doc, ["Capa", "Tecnología", "Responsabilidad"],
        [
            ["Presentación", "Svelte components + Tailwind CSS", "Renderizado de UI, interactividad, formularios"],
            ["Routing/Middleware", "SvelteKit hooks + layouts", "Auth guard, T&C guard, redirects, setup Supabase"],
            ["Lógica de negocio", "+page.server.ts + src/lib/server/*", "Form actions, load functions, email, equipo, scoring"],
            ["Datos", "Supabase client (service role)", "Queries, mutations, RPC, auth admin"],
            ["Infraestructura", "Vercel + Supabase", "Serverless functions (SSR), managed PostgreSQL"],
        ]
    )

    add_heading2(doc, "1.3 Flujo de Datos")
    add_para(doc, "El flujo típico de una solicitud sigue este camino:")
    add_bullet(doc, "1. Browser envía request HTTP")
    add_bullet(doc, "2. hooks.server.ts: middleware (redirects, T&C guard, setup cliente Supabase con cookies)")
    add_bullet(doc, "3. +layout.server.ts: safeGetSession() obtiene sesión y usuario validados server-side")
    add_bullet(doc, "4. +page.server.ts load(): ejecuta queries a Supabase (service role para operaciones admin)")
    add_bullet(doc, "5. +page.svelte: renderiza con datos del server, componentes Svelte, stores")
    add_bullet(doc, "6. Operaciones async: APIs (+server.ts) para autosave, delete, team management")

    add_heading2(doc, "1.4 Diagrama de Componentes")
    add_para(doc, "El sistema se compone de los siguientes bloques principales interconectados:")
    add_para(doc, "")
    add_table(doc, ["Bloque", "Componentes", "Conexiones"],
        [
            ["Browser (Cliente)", "Svelte components, Stores, Tailwind", "→ SvelteKit Server"],
            ["SvelteKit Server", "hooks.server.ts, +page.server.ts, +server.ts, lib/server/*", "→ Supabase, → Resend SMTP"],
            ["Supabase", "PostgreSQL + RLS + Auth + Storage + RPC", "← SvelteKit Server"],
            ["Resend SMTP", "Entrega de correos transaccionales", "← SvelteKit Server (Nodemailer)"],
            ["Vercel", "Hosting serverless, auto-deploy", "← Git push main"],
            ["Cloudflare", "DNS eco.lpdi.co, CDN", "→ Vercel"],
            ["GeoNames", "API de ciudades por país", "← /api/cities proxy"],
            ["Cron Jobs", "4 endpoints periódicos", "→ Supabase (queries), → SMTP (emails)"],
        ]
    )

    # 2. Frontend
    doc.add_page_break()
    add_heading1(doc, "2. Arquitectura Frontend")

    add_heading2(doc, "2.1 Sistema de Componentes")
    add_para(doc, "28+ componentes organizados por dominio funcional:")
    add_table(doc, ["Directorio", "Componentes", "Responsabilidad"],
        [
            ["components/account/", "DeleteAccountModal, DeleteEntityModal, TrashSection", "Gestión de cuenta y eliminación"],
            ["components/icg/", "IcgFormShell, icg-form-types", "Formularios de registro ICG"],
            ["components/profiles/", "IcgProfileView, StartupProfileView, UserProfileView", "Vistas de perfil público"],
            ["components/startup/", "StartupDetailedFormShell, StartupSimplifiedFormShell, startup-form-types", "Formularios de startup"],
            ["components/user/", "UserDetailedFormShell", "Formulario de perfil de usuario"],
            ["(raíz)", "DashboardSidebar, IndustryPicker, BusinessNeedsPicker, CityPicker, RegionCountryPicker, SocialMediaAdder, PhoneInput, YearInput, PasswordField, AutoSaveIndicator", "Componentes reutilizables"],
        ]
    )

    add_heading2(doc, "2.2 Estado Global (Stores)")
    add_para(doc, "Svelte stores en src/lib/stores/ para estado compartido entre componentes. El patrón principal es:")
    add_bullet(doc, "Server load functions pasan datos iniciales al componente vía props")
    add_bullet(doc, "Componentes usan stores locales para estado de UI (formularios, modales)")
    add_bullet(doc, "Autosave se maneja con debounce client-side → POST a /api/user-profile-autosave")

    add_heading2(doc, "2.3 Routing y Layouts")
    add_para(doc, "File-based routing de SvelteKit con 2 grupos lógicos:")
    add_bullet(doc, "Rutas públicas: /, /login, /registro-startup, /registro-icg, /ecosistema, /perfil-startup, /perfil, /perfil-usuario, /team/confirmar")
    add_bullet(doc, "Rutas autenticadas: /dashboard/* (perfil-usuario, startups, icg, consulta)")
    add_bullet(doc, "Root layout (+layout.svelte): Setup Supabase client-side, hidratación de sesión")
    add_bullet(doc, "Dashboard layout: DashboardSidebar con navegación lateral contextual")

    add_heading2(doc, "2.4 Diseño Visual")
    add_table(doc, ["Aspecto", "Implementación"],
        [
            ["Tema", "Dark theme premium (slate-900 → green-950)"],
            ["Acentos", "green-400 / green-500 / green-600"],
            ["Tipografía", "Plus Jakarta Sans (Google Fonts)"],
            ["Estilo", "Glassmorphism (bg-white/10, backdrop-blur-xl)"],
            ["Responsive", "Mobile-first con breakpoints Tailwind estándar"],
            ["Formularios", "Stepper visual con progreso, autosave, indicadores de estado"],
        ]
    )

    # 3. Backend
    doc.add_page_break()
    add_heading1(doc, "3. Arquitectura Backend")

    add_heading2(doc, "3.1 Load Functions")
    add_para(doc, "Cada +page.server.ts exporta una función load() que:")
    add_bullet(doc, "Obtiene la sesión del usuario vía event.locals.safeGetSession()")
    add_bullet(doc, "Ejecuta queries a Supabase con el cliente server-side")
    add_bullet(doc, "Carga catálogos/taxonomías vía taxonomies.ts (451 LOC — carga dinámica desde Supabase)")
    add_bullet(doc, "Retorna datos tipados al componente Svelte")

    add_heading2(doc, "3.2 Form Actions")
    add_para(doc, "SvelteKit Actions para formularios POST. Patrón típico:")
    add_bullet(doc, "Extraer datos del FormData")
    add_bullet(doc, "Validar server-side (tipos, required, unicidad vía check-email)")
    add_bullet(doc, "Ejecutar operación en Supabase (insert, update, signUp)")
    add_bullet(doc, "Enviar emails relevantes (fire-and-forget)")
    add_bullet(doc, "Retornar resultado o redirect")

    add_heading2(doc, "3.3 API Routes")
    add_para(doc, "16 endpoints +server.ts para operaciones que no encajan en form actions:")
    add_bullet(doc, "Validaciones asíncronas (check-email, check-company-name)")
    add_bullet(doc, "Operaciones CRUD async (autosave, entity management)")
    add_bullet(doc, "Flujo de equipo (confirm, resend, reject — usan tokens, no sesión)")
    add_bullet(doc, "Account management (delete, update-email, update-password)")
    add_bullet(doc, "4 cron endpoints protegidos con CRON_SECRET")

    add_heading2(doc, "3.4 Lógica Server (src/lib/server/)")
    add_table(doc, ["Archivo", "LOC", "Responsabilidad"],
        [
            ["email.ts", "~400", "12 funciones de envío de correo con templates HTML"],
            ["email-team.ts", "316", "7 funciones de correo para invitaciones de equipo"],
            ["team.ts", "405", "Lógica de invitación, confirmación, rechazo de equipo"],
            ["ceo.ts", "111", "ensureCeoUser: creación automática de cuenta CEO"],
            ["consent.ts", "33", "logConsent: audit trail de T&C"],
            ["profile.ts", "25", "ensureProfile: creación de perfil post-auth"],
            ["taxonomies.ts", "451", "Carga dinámica de catálogos desde Supabase"],
        ]
    )

    # 4. BD
    doc.add_page_break()
    add_heading1(doc, "4. Arquitectura de Base de Datos")

    add_heading2(doc, "4.1 Evolución del Schema")
    add_para(doc, "43 migraciones SQL numeradas (001-043) que evolucionan el schema progresivamente:")
    add_table(doc, ["Rango", "Descripción"],
        [
            ["001-003", "Setup inicial: profiles, enums, tablas principales, RLS básico"],
            ["004-018", "Evolución de startups: detailed profile, campos JSONB, fixes de tipos"],
            ["019-026", "Tablas de catálogos: industrias, necesidades, países, género, redes sociales"],
            ["027-028", "Storage buckets RLS, RLS críticas refinadas"],
            ["029-037", "Índices únicos, limpieza legacy, relajación de constraints"],
            ["038", "Soft-delete con período de gracia 30 días"],
            ["039", "Cron de followup para scoring"],
            ["040", "Consent log (audit trail T&C)"],
            ["041", "Team invitations (verificación opt-in)"],
            ["042-043", "Cron de reminders para equipo y bienvenida"],
        ]
    )

    add_heading2(doc, "4.2 Índices Clave")
    add_table(doc, ["Índice", "Tabla", "Tipo", "Propósito"],
        [
            ["profiles_email_key", "profiles", "UNIQUE", "Unicidad de email"],
            ["ecosystem_roles_category_name_key", "ecosystem_roles", "UNIQUE", "Unicidad categoría+nombre"],
            ["idx_startup_founders_invitation_token", "startup_founders", "UNIQUE PARTIAL", "Búsqueda de token (WHERE token IS NOT NULL)"],
            ["idx_startup_founders_pending_invitations", "startup_founders", "PARTIAL", "Invitaciones pendientes (WHERE status='pending')"],
            ["idx_startup_founders_user_id", "startup_founders", "PARTIAL", "Búsqueda por user_id (WHERE user_id IS NOT NULL)"],
            ["idx_consent_log_user_id", "consent_log", "B-TREE", "Consulta de consentimiento por usuario"],
            ["idx_consent_log_type_version", "consent_log", "B-TREE", "Consulta por tipo y versión"],
        ]
    )

    add_heading2(doc, "4.3 Funciones y Triggers")
    add_para(doc, "6 funciones RPC en PostgreSQL para operaciones complejas que requieren atomicidad:")
    add_bullet(doc, "soft_delete_startup/icg: Marca deleted_at y programa delete_scheduled_for a 30 días")
    add_bullet(doc, "restore_startup/icg: Limpia deleted_at y delete_scheduled_for")
    add_bullet(doc, "purge_expired_entities: Elimina definitivamente registros con delete_scheduled_for < now()")
    add_bullet(doc, "delete_account: Elimina perfil, entidades asociadas, y datos de auth")

    # 5. Seguridad
    doc.add_page_break()
    add_heading1(doc, "5. Seguridad")

    add_heading2(doc, "5.1 Row Level Security (RLS)")
    add_para(doc, "RLS habilitado en TODAS las tablas. Principios:")
    add_bullet(doc, "Principio de mínimo privilegio: cada usuario solo ve/modifica sus propios datos")
    add_bullet(doc, "Catálogos: acceso público de lectura (anon + authenticated)")
    add_bullet(doc, "consent_log: append-only (sin UPDATE/DELETE), solo INSERT vía service role")
    add_bullet(doc, "Service role: usado exclusivamente server-side para operaciones admin")

    add_heading2(doc, "5.2 Autenticación")
    add_bullet(doc, "Supabase Auth con email+password (no OAuth social)")
    add_bullet(doc, "Tokens OTP para confirmación de email")
    add_bullet(doc, "Password recovery vía enlace de Supabase Auth")
    add_bullet(doc, "Passwords temporales generados con crypto.randomBytes(12)")

    add_heading2(doc, "5.3 Autorización y Guards")
    add_bullet(doc, "T&C Guard global en hooks.server.ts: fuerza aceptación de términos")
    add_bullet(doc, "Token-based invitations para equipo (7 días de expiración)")
    add_bullet(doc, "CRON_SECRET como Bearer token para proteger endpoints de cron")
    add_bullet(doc, "Session validation server-side: getSession() + getUser() (doble verificación)")

    add_heading2(doc, "5.4 Protección de Datos")
    add_bullet(doc, "Variables de entorno en Vercel (SUPABASE_ROLE_KEY, SMTP_PASS, CRON_SECRET)")
    add_bullet(doc, "Consent audit trail con IP + user_agent (cumplimiento legal)")
    add_bullet(doc, "Input sanitization server-side (trim, lowercase emails, validación de tipos)")
    add_bullet(doc, "Soft-delete con período de gracia para prevenir pérdida accidental de datos")
    add_bullet(doc, "Fire-and-forget emails: errores de envío no exponen información al usuario")

    # 6. DevOps
    add_heading1(doc, "6. DevOps y Deploy")

    add_heading2(doc, "6.1 Pipeline de Deploy")
    add_bullet(doc, "Repositorio: GitHub (privado) — devlapuntadeliceberg/relacionamiento")
    add_bullet(doc, "Branch principal: main")
    add_bullet(doc, "Deploy automático: git push main → Vercel auto-deploy")
    add_bullet(doc, "Adapter: @sveltejs/adapter-vercel v5.4")
    add_bullet(doc, "Git author obligatorio: dev@lapuntadeliceberg.co")

    add_heading2(doc, "6.2 Variables de Entorno Requeridas")
    add_table(doc, ["Variable", "Descripción", "Sensible"],
        [
            ["PUBLIC_SUPABASE_URL", "URL de la instancia Supabase", "No"],
            ["PUBLIC_SUPABASE_ANON_KEY", "API key pública de Supabase", "No"],
            ["SUPABASE_ROLE_KEY", "Service role key (bypasa RLS)", "Sí"],
            ["SMTP_HOST", "Host del servidor SMTP (smtp.resend.com)", "No"],
            ["SMTP_PORT", "Puerto SMTP (465)", "No"],
            ["SMTP_USER", "Usuario SMTP", "Sí"],
            ["SMTP_PASS", "Password SMTP (API key de Resend)", "Sí"],
            ["CRON_SECRET", "Bearer token para cron endpoints", "Sí"],
        ]
    )

    add_heading2(doc, "6.3 Dominios y DNS")
    add_table(doc, ["Dominio", "Servicio", "Proveedor"],
        [
            ["eco.lpdi.co", "Aplicación web principal", "Cloudflare DNS → Vercel"],
            ["lpdi.co", "Dominio raíz (email, DNS)", "Cloudflare"],
        ]
    )

    # 7. Patrones
    doc.add_page_break()
    add_heading1(doc, "7. Patrones y Convenciones")

    add_heading2(doc, "7.1 Convenciones de Código")
    add_table(doc, ["Aspecto", "Convención"],
        [
            ["Variables/funciones", "camelCase"],
            ["Componentes", "PascalCase"],
            ["Archivos", "kebab-case"],
            ["Commits", "Español, imperativos (\"Agregar formulario startup\")"],
            ["Queries", "SIEMPRE vía +page.server.ts o +server.ts (nunca desde el browser)"],
        ]
    )

    add_heading2(doc, "7.2 Patrones de Diseño")
    add_bullet(doc, "SSOT (Single Source of Truth): Datos canónicos en src/lib/data/ (entity-types.ts, investment-categories.ts). Lint scripts verifican que no haya duplicación en el codebase.")
    add_bullet(doc, "Fire-and-forget emails: Los envíos de correo no bloquean la operación principal. Errores se capturan silenciosamente.")
    add_bullet(doc, "Autosave por panel: Los formularios detallados guardan automáticamente cada panel con debounce.")
    add_bullet(doc, "Progressive enhancement: Formularios funcionan sin JS (form POST estándar), se mejoran con Svelte.")
    add_bullet(doc, "Soft-delete con gracia: Entidades eliminadas tienen 30 días de recuperación antes de la purga definitiva.")
    add_bullet(doc, "Token-based verification: Invitaciones al equipo usan tokens criptográficos con expiración.")

    add_heading2(doc, "7.3 Manejo de Errores")
    add_bullet(doc, "handleError en hooks.server.ts: log detallado server-side, mensaje genérico al cliente")
    add_bullet(doc, "Form actions: retornan fail(400, {error}) o fail(500, {error})")
    add_bullet(doc, "APIs: retornan JSON con status code apropiado")
    add_bullet(doc, "Emails: catch silencioso (console.error) — el usuario no ve errores de envío")

    # 8. Dependencias
    add_heading1(doc, "8. Dependencias Críticas")
    add_table(doc, ["Dependencia", "Versión", "Rol", "Criticidad"],
        [
            ["@supabase/ssr + @supabase/supabase-js", "—", "Cliente Supabase SSR-compatible", "Alta"],
            ["nodemailer", "8.x", "Envío de emails vía SMTP", "Alta"],
            ["@sveltejs/adapter-vercel", "5.4", "Deploy en Vercel", "Alta"],
            ["tailwindcss", "3.4", "Framework CSS", "Media"],
            ["qrcode", "1.5", "Generación de códigos QR", "Baja"],
            ["playwright", "1.59", "Testing E2E", "Dev"],
            ["vitest", "4.1", "Testing unitario", "Dev"],
            ["tsx", "—", "Ejecución de scripts TS (linters, changelog)", "Dev"],
        ]
    )

    # 9. Puntos de extensión
    doc.add_page_break()
    add_heading1(doc, "9. Puntos de Extensión")
    add_para(doc, "El sistema está diseñado para ser extensible en los siguientes puntos:")

    add_heading2(doc, "9.1 Nuevos Tipos de Entidad")
    add_para(doc, "Para agregar un nuevo tipo de entidad (ej: Aceleradoras, Mentores):")
    add_bullet(doc, "Crear nueva tabla en Supabase con migración SQL")
    add_bullet(doc, "Definir tipos en src/lib/data/ (SSOT)")
    add_bullet(doc, "Crear FormShell y ProfileView components")
    add_bullet(doc, "Agregar rutas de registro y dashboard")
    add_bullet(doc, "Extender el scoring si aplica")

    add_heading2(doc, "9.2 Nuevos Módulos")
    add_para(doc, "Para conectar nuevos módulos al sistema:")
    add_bullet(doc, "Las rutas autenticadas bajo /dashboard/* comparten el mismo layout y sidebar")
    add_bullet(doc, "La sesión y el cliente Supabase están disponibles vía event.locals")
    add_bullet(doc, "Los catálogos se cargan dinámicamente vía taxonomies.ts")
    add_bullet(doc, "El sistema de permisos actual (RLS + owner pattern) puede extenderse con nuevas policies")

    add_heading2(doc, "9.3 Integración con Subsistema de Gestión del Conocimiento (SGC)")
    add_para(doc, "El SGR comparte la misma instancia de Supabase con el SGC. Para integrar:")
    add_bullet(doc, "Ambos subsistemas comparten la tabla profiles y auth de Supabase")
    add_bullet(doc, "Se pueden crear foreign keys entre tablas del SGR y SGC")
    add_bullet(doc, "Las RLS policies pueden extenderse para acceso cross-subsistema")

    add_heading2(doc, "9.4 Nuevos Correos Electrónicos")
    add_para(doc, "Para agregar un nuevo correo:")
    add_bullet(doc, "Crear función en email.ts o email-team.ts siguiendo el patrón existente")
    add_bullet(doc, "Usar el template HTML base (mismos estilos, logo, footer)")
    add_bullet(doc, "Respetar los criterios de diseño documentados (colores, copy, estructura)")
    add_bullet(doc, "Patrón fire-and-forget: envolver en try/catch")

    # 10. Recomendaciones
    add_heading1(doc, "10. Recomendaciones para Desarrollos Futuros")

    add_heading2(doc, "10.1 Arquitectura")
    add_bullet(doc, "Considerar implementar un sistema de roles basado en SystemRole (ADMIN/MANAGER/MEMBER) con checks server-side, además del RLS actual")
    add_bullet(doc, "Evaluar migración a Svelte 5 (runes) cuando sea estable para aprovechar nuevo modelo de reactividad")
    add_bullet(doc, "Implementar caché de catálogos para reducir queries repetitivas a Supabase")

    add_heading2(doc, "10.2 Testing")
    add_bullet(doc, "Expandir cobertura de tests E2E con Playwright para todos los flujos críticos")
    add_bullet(doc, "Agregar tests unitarios para lógica de scoring y funciones de email")
    add_bullet(doc, "Implementar tests de RLS policies directo en PostgreSQL")

    add_heading2(doc, "10.3 Infraestructura")
    add_bullet(doc, "Considerar upgrade a Supabase Pro para PITR (Point-in-Time Recovery)")
    add_bullet(doc, "Implementar monitoring de cron jobs (alertas si fallan)")
    add_bullet(doc, "Agregar logging estructurado para trazabilidad de operaciones")

    add_heading2(doc, "10.4 Seguridad")
    add_bullet(doc, "Implementar rate limiting en endpoints de registro y login")
    add_bullet(doc, "Agregar CAPTCHA o equivalente en formularios públicos")
    add_bullet(doc, "Implementar CSP (Content Security Policy) headers")
    add_bullet(doc, "Considerar 2FA para cuentas con acceso a múltiples entidades")

    path = "/home/clawd/playgrounds/pmo/LPDI_Arquitectura_Tecnica.docx"
    doc.save(path)
    print(f"Doc 3 saved: {path}")
    return path


# ═══════════════════════════════════════════════════════════════
# Main
# ═══════════════════════════════════════════════════════════════

if __name__ == "__main__":
    p1 = generate_doc1()
    p2 = generate_doc2()
    p3 = generate_doc3()
    print(f"\nAll 3 documents generated successfully:")
    print(f"  1. {p1}")
    print(f"  2. {p2}")
    print(f"  3. {p3}")
