> ## Documentation Index
> Fetch the complete documentation index at: https://shinydapps-bd9fa40b.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Flux Système

> Diagrammes visuels de chaque flux de la plateforme l402-kit — paiement, authentification, abonnement et infrastructure.

Cette page documente chaque flux majeur de la plateforme l402-kit sous forme de diagrammes de séquence et d'organigrammes. Chaque section associe un visuel à une explication concise de ce qui se passe et pourquoi cela fonctionne ainsi. Commencez par le Flux 1 (cœur L402) pour comprendre le fondement cryptographique, puis lisez les flux pertinents pour votre intégration.

***

## 1. Flux de Paiement L402 Principal

Le cycle de requête fondamental. Pas de comptes, pas de mots de passe — juste un reçu cryptographique.

Lorsqu'un client accède pour la première fois à un endpoint protégé, il reçoit une réponse HTTP 402 contenant deux éléments : une facture BOLT11 Lightning et un macaroon. Le client paie la facture via le Lightning Network (généralement en moins d'une seconde), reçoit un preimage de 32 octets comme preuve, et réessaie la requête avec `Authorization: L402 <macaroon>:<preimage>`. Le serveur vérifie le jeton localement en utilisant `SHA256(preimage) === macaroon.hash` — pas d'appel à la base de données, pas d'aller-retour réseau, latence inférieure à la milliseconde. Une fois vérifié, le jeton est valide jusqu'à son expiration. Les requêtes suivantes réutilisent le même en-tête.

```mermaid theme={null}
sequenceDiagram
    participant C as Client / AI Agent
    participant S as Your API Server
    participant L as Lightning Network
    participant B as Blink (provider)

    C->>S: GET /api/data (no token)
    S-->>C: 402 Payment Required<br/>WWW-Authenticate: L402 macaroon="...", invoice="lnbc..."

    Note over C,L: Client pays the Lightning invoice
    C->>L: pay(invoice)
    L-->>C: preimage (32-byte proof of payment)

    C->>S: GET /api/data<br/>Authorization: L402 <macaroon>:<preimage>
    Note over S: SHA256(preimage) === macaroon.hash?<br/>Verified in <1ms locally. No DB call.
    S-->>C: 200 OK + data
```

**Propriétés clés :**

* La vérification est entièrement locale — pas d'appel réseau, pas de consultation de base de données
* `preimage` = preuve cryptographique de paiement (reçu Lightning)
* `macaroon` = JSON base64 `{hash, exp}` signé avec SHA-256

***

## 2. Anatomie du Jeton

L'en-tête `Authorization` contient deux composants séparés par un deux-points. Le **macaroon** est un objet JSON encodé en base64 `{hash, exp}` — il indique au serveur quel hash de paiement attendre et quand le jeton expire. Le **preimage** est le secret de 32 octets que le Lightning Network a retourné au payeur. Ensemble, ils forment un identifiant infalsifiable et autonome que tout serveur peut vérifier hors ligne.

```mermaid theme={null}
flowchart LR
    T["Authorization: L402 &lt;macaroon&gt;:&lt;preimage&gt;"]
    T --> M["macaroon\nbase64({ hash, exp })\nSigned by SHA-256"]
    T --> P["preimage\n32-byte hex secret\nSHA256(preimage) = hash"]
    M --> V["Server verifies:\nSHA256(preimage) === hash\nexp > now()"]
```

***

## 3. Mode Géré — Flux de Partage des Frais

Lorsque vous utilisez `ManagedProvider`, l402kit.com crée la facture, reçoit le paiement et transfère automatiquement 99,7 % vers votre Lightning Address. Les 0,3 % de frais de plateforme couvrent le routage Lightning et l'infrastructure API. Votre portefeuille ne touche jamais au Cloudflare Worker — le partage est un paiement Lightning côté serveur déclenché après la vérification de la requête du client, utilisant votre Lightning Address pour générer une nouvelle facture BOLT11 à la volée.

```mermaid theme={null}
sequenceDiagram
    participant C as Client
    participant V as Cloudflare Worker<br/>/api/invoice
    participant B as Blink API<br/>(ShinyDapps wallet)
    participant S as Supabase
    participant O as Owner wallet<br/>(you@yourdomain.com)

    C->>V: POST /api/invoice<br/>{priceSats, ownerAddress}
    V->>B: lnInvoiceCreate(priceSats)
    B-->>V: {paymentRequest, paymentHash}
    V-->>C: 402 + invoice

    Note over C,B: Client pays invoice
    C->>B: pay(invoice)
    B-->>C: preimage

    C->>V: GET /api/data + L402 token
    V->>S: INSERT payments<br/>{payment_hash, endpoint, amount_sats}
    V->>V: POST /api/split<br/>(fire-and-forget)
    V->>B: sendPayment(owner, 99.7%)
    B-->>O: ⚡ sats received
    V-->>C: 200 OK + data
```

***

## 4. Flux d'Abonnement Pro

Les abonnements Pro suivent un schéma L402 similaire mais ajoutent un état persistant. Le client paie une facture unique et reçoit un enregistrement d'abonnement de 30 jours dans Supabase. La confirmation de paiement arrive soit via un webhook Blink (chemin rapide, \~2 secondes) soit via un polling (solution de repli pour les portefeuilles qui ne déclenchent pas de webhooks). Les appels `/api/pro-check` suivants vérifient l'horodatage `expires_at` sans nouveau paiement.

```mermaid theme={null}
sequenceDiagram
    participant U as User (VS Code)
    participant V as Cloudflare Worker
    participant B as Blink API
    participant S as Supabase
    participant W as Blink Webhook

    U->>V: POST /api/pro-subscribe<br/>{lightningAddress, tier}
    V->>B: lnInvoiceCreate(amountSats)
    B-->>V: {paymentRequest, paymentHash}
    V->>S: INSERT pro_access<br/>{address, payment_hash, expires_at: null}
    V-->>U: {paymentRequest, paymentHash}

    Note over U,B: User pays invoice in their wallet
    U->>B: pay(invoice)

    alt Webhook path (fast)
        B->>W: POST /api/blink-webhook<br/>{type: "transaction.ln.invoice.paid"}
        W->>S: PATCH pro_access<br/>SET expires_at = now + 30d
    else Poll path (fallback)
        U->>V: GET /api/pro-poll?paymentHash=...
        V->>B: lnInvoice(paymentHash) → status
        V->>S: PATCH pro_access SET expires_at
        V-->>U: {active: true, expires_at}
    end

    U->>V: GET /api/pro-check?address=...
    V->>S: SELECT expires_at WHERE address=?
    V-->>U: {active: true, tier: "pro"}
```

***

## 5. LNURL-auth — Preuve de Propriété du Portefeuille (Suppression de Données)

Prouve que vous possédez un portefeuille Lightning sans mot de passe. Requis avant la suppression des données du compte.

```mermaid theme={null}
sequenceDiagram
    participant U as User (VS Code)
    participant V as Cloudflare<br/>/api/lnurl-auth
    participant W as Lightning Wallet<br/>(Phoenix, Blink…)
    participant S as Supabase<br/>lnurl_challenges
    participant D as Cloudflare<br/>/api/delete-data

    U->>V: GET /api/lnurl-auth<br/>?lightningAddress=you@yourdomain.com
    V->>V: k1 = randomBytes(32)
    V->>S: INSERT {k1, lightning_address, expires_at: +5min}
    V-->>U: {k1, lnurl} — show as QR code

    Note over U,W: User scans QR with Lightning wallet
    W->>W: Sign k1 with secp256k1<br/>key derived for this domain
    W->>V: GET /api/lnurl-auth<br/>?tag=login&k1=…&sig=…&key=…
    V->>V: secp256k1.verify(sig, k1, pubkey)
    V->>V: token = randomBytes(32), TTL 10min
    V->>S: PATCH {verified: true, pubkey, token}
    V-->>W: {status: "OK"}

    loop Poll every 2s
        U->>V: GET /api/lnurl-auth?poll=<k1>
        V->>S: SELECT verified, token WHERE k1=?
        V-->>U: {verified: true, token: "abc…"}
    end

    U->>D: POST /api/delete-data<br/>{lightningAddress, token}
    D->>S: SELECT WHERE token=? → verified? expired?
    D->>S: PATCH token = null (revoke — single use)
    D->>S: DELETE payments WHERE owner_address=?
    D->>S: DELETE pro_access WHERE address=?
    D-->>U: {deleted: {payments: N, proAccess: true}}
```

***

## 6. Flux de Connexion LNURL-auth au Tableau de Bord

Authentification du tableau de bord réservée au propriétaire — DASHBOARD\_SECRET stocké dans les secrets Cloudflare Workers.

```mermaid theme={null}
sequenceDiagram
    participant O as Owner browser
    participant V as Cloudflare<br/>/api/lnurl-auth
    participant W as Owner Lightning Wallet
    participant S as Supabase<br/>lnurl_challenges
    participant D as Cloudflare<br/>/api/stats

    O->>V: GET /api/lnurl-auth?dashboard=1
    V->>V: k1 = randomBytes(32)
    V->>S: INSERT {k1, lightning_address: "__dashboard__", expires_at: +5min}
    V-->>O: {k1, lnurl} — show QR code

    Note over O,W: Owner scans QR with their Lightning wallet
    W->>W: Sign k1 with secp256k1 key
    W->>V: GET /api/lnurl-auth<br/>?tag=login&k1=…&sig=…&key=…
    V->>V: key === OWNER_PUBKEY? ✓
    V->>V: secp256k1.verify(sig, k1, key)
    V->>V: token = randomBytes(32), TTL 24h
    V->>S: PATCH {verified: true, pubkey, token, token_expires_at}
    V-->>W: {status: "OK"}

    loop Poll every 2s
        O->>V: GET /api/lnurl-auth?poll=<k1>
        V->>S: SELECT verified, token WHERE k1=?
        V-->>O: {verified: true, token: "abc…"}
    end

    O->>D: GET /api/stats<br/>x-lnurl-token: <token>
    D->>S: SELECT verified, pubkey, token_expires_at WHERE token=?
    D->>D: pubkey === OWNER_PUBKEY? ✓ not expired? ✓
    D-->>O: {totalPayments, totalSats, byDay, trend, recent…}
```

***

## 7. Vue d'Ensemble de l'Infrastructure

```mermaid theme={null}
flowchart TB
    subgraph CF["Cloudflare DNS (l402kit.com)"]
        DNS["l402kit.com\nCNAME → l402kit-pages.pages.dev"]
    end

    subgraph VCL["Cloudflare (Workers + Pages)"]
        LAND["Landing Page\nbackend/index.html"]
        API["Backend API\n/api/invoice → Edge Function\n/api/delete-data\n/api/lnurl-auth\n/api/pro-subscribe\n/api/stats (LNURL-auth)"]
        HOOK["Webhooks\n/api/blink-webhook"]
    end

    subgraph SB["Supabase (PostgreSQL + Edge Functions)"]
        PAY["payments\npayment_hash · amount_sats\nowner_address · endpoint"]
        PRO["pro_access\naddress · tier\nexpires_at · payment_hash"]
        LNURL["lnurl_challenges\nk1 · verified · token\ntoken_expires_at · pubkey"]
        EF["Edge Function: create-invoice\nBLINK_API_KEY (Supabase Secret)\nBLINK_WALLET_ID (Supabase Secret)"]
    end

    subgraph EXT["External Services"]
        BLINK["Blink Lightning\napi.blink.sv"]
    end

    CF --> VCL
    API --> SB
    HOOK --> SB
    EF --> BLINK
    BLINK --> HOOK
```

***

## 8. Sécurité du Preimage SHA-256

Pourquoi nous stockons `SHA256(preimage)` plutôt que le preimage brut :

```mermaid theme={null}
flowchart LR
    subgraph Lightning["Lightning Network (public)"]
        INV["BOLT11 Invoice\ncontains payment_hash = SHA256(preimage)"]
    end

    subgraph Client["Client (private)"]
        PRE["preimage\n32-byte secret\nproof of payment"]
    end

    subgraph DB["Supabase payments table"]
        STORED["payment_hash\n= SHA256(preimage)\nsafe to store"]
    end

    PRE -->|"SHA256()"| STORED
    INV -->|"already public"| STORED
    PRE -.->|"❌ never store raw"| DB

    style PRE fill:#ff4444,color:#fff
    style STORED fill:#22c55e,color:#fff
```

**Pourquoi c'est sécurisé :** Le `payment_hash` est déjà intégré dans chaque facture BOLT11 — il est public par conception. Seul le `preimage` est secret. Stocker le hash vous offre une protection contre la réutilisation sans exposition supplémentaire.
