📄 SKILL.md

← Vault

name: doccorretor-link-flow

description: DocCorretor public upload link flow — generate link without existing client, broker creates client + uploads documents

category: devops


DocCorretor Public Upload Link Flow

Architecture Overview

Problem: Generate a shareable link for brokers to upload client documents WITHOUT requiring an existing client in the system.

Solution: Token-based public links where the broker self-registers the client on first access.

`

Admin clicks "Link para corretor"

→ creates "Documentos" folder (client_id = NULL) ← CRITICAL: folder created HERE, not later

→ creates link record with folder_id pointing to that folder

→ Link shown in Sheet → copied to clipboard

→ Broker opens link → sees client registration form → submits

→ API updates the PRE-CREATED folder with client_id → redirect to upload

`

The Critical Bug: client_id Determines the Flow

The upload.$token.tsx page decides what to show based on whether client_id is NULL or filled:

`typescript

// From upload.$token.tsx useEffect:

const r = await fetch(/api/public/validate-upload-link?token=...);

const data = await r.json();

if (!data.client_id) {

setShowClientForm(true); // → mostra formulário de novo cliente

} else {

// → tem client_id = vai direto pra upload (pula criação de cliente)

setNewClientId(data.client_id);

setNewFolderId(data.folder_id);

}

`

The current correct flow (generateClientLink in index.tsx):

`typescript

async function generateClientLink() {

const folderId = crypto.randomUUID();

// 1. Criar pasta "Documentos" IMEDIATAMENTE quando link é gerado

await supabase.from("client_folders").insert({

id: folderId,

client_id: null, // será atualizado quando externo preencher

name: "Documentos",

created_by: u.user.id,

});

// 2. Criar link com folder_id apontando para a pasta já criada

await supabase.from("client_upload_links").insert({

client_id: null,

token,

folder_id: folderId, // pasta pré-criada

created_by: u.user.id,

});

}

`

Pre-creation flow (current, working):

1. Admin clicks "Link para corretor" → folder "Documentos" created with client_id=null → link inserted with folder_id

2. External opens link → validates token → shows new client form

3. External fills form → API fetches folder_id from link → updates pre-created folder with client_id

4. External redirected to upload page

This is the ONLY correct flow as of Maio 2026. Never create folder inside create-client-with-link.ts — it should already exist.

Why pre-create the folder: The admin expects the link to be "ready" the moment it's generated. By pre-creating the folder with client_id=null, when the external person fills the form and the API updates the folder with the real client_id, no new folder needs to be created — just an UPDATE, which is faster and more reliable.

`typescript

// ✅ CORRECT — link SEM client_id = força formulário de novo cliente

const { error } = await supabase.from("client_upload_links").insert({

client_id: null, // null = externo preenche formulário e cria cliente

token,

created_by: u.user.id,

});

// ❌ WRONG (bug) — link COM client_id = pula criação de cliente

const { error } = await supabase.from("client_upload_links").insert({

client_id: pendingClientId, // bug: externo não podia criar cliente

token,

created_by: u.user.id,

});

`

Database Schema

Tables used: