fix: Correction erreurs TypeScript, nettoyage et réorganisation documentation
- Correction toutes erreurs TypeScript : - Variables non utilisées supprimées - Types optionnels corrigés (exactOptionalPropertyTypes) - Imports corrigés (PLATFORM_BITCOIN_ADDRESS depuis platformConfig) - Gestion correcte des propriétés optionnelles - Suppression fichiers obsolètes : - code-cleanup-summary.md (redondant) - todo-implementation*.md (todos obsolètes) - corrections-completed.md, fallbacks-found.md (corrections faites) - implementation-summary.md (redondant) - documentation-plan.md (plan, pas documentation) - Suppression scripts temporaires : - add-ssh-key.sh - add-ssh-key-plink.sh - Réorganisation documentation dans docs/ : - architecture.md (nouveau) - commissions.md (nouveau) - implementation-summary.md - remaining-tasks.md - split-and-transfer.md - commission-system.md - commission-implementation.md - content-delivery-verification.md Toutes erreurs TypeScript corrigées, documentation centralisée.
This commit is contained in:
parent
4735ee71ab
commit
f7bd7faa73
@ -1,47 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Script to add SSH public key to remote server using plink (PuTTY)
|
|
||||||
# Usage: ./add-ssh-key-plink.sh
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
REMOTE_HOST="155.133.129.88"
|
|
||||||
REMOTE_USER="admin"
|
|
||||||
REMOTE_PASSWORD="GHDKkpNUNuFePQb4KZ4%"
|
|
||||||
SSH_KEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFURI5emj/BtYj6fgO6JnqH8csxJeSlyWkLs1DcPdoVp titouan.tabere@gmail.com"
|
|
||||||
|
|
||||||
echo "Adding SSH key to ${REMOTE_USER}@${REMOTE_HOST} using plink..."
|
|
||||||
|
|
||||||
# Remote script to execute
|
|
||||||
REMOTE_SCRIPT="mkdir -p ~/.ssh && chmod 700 ~/.ssh && AUTH_KEYS_FILE=\$HOME/.ssh/authorized_keys && KEY_TO_ADD='${SSH_KEY}' && if [ -f \"\$AUTH_KEYS_FILE\" ] && grep -qF \"\$KEY_TO_ADD\" \"\$AUTH_KEYS_FILE\"; then echo 'SSH key already exists in authorized_keys'; else echo \"\$KEY_TO_ADD\" >> \"\$AUTH_KEYS_FILE\" && echo 'SSH key added successfully'; fi && chmod 600 \"\$AUTH_KEYS_FILE\" && echo 'SSH key setup completed'"
|
|
||||||
|
|
||||||
# Check if plink is available
|
|
||||||
if command -v plink &> /dev/null || [ -f "/c/Program Files/PuTTY/plink.exe" ]; then
|
|
||||||
PLINK_CMD="plink"
|
|
||||||
if [ -f "/c/Program Files/PuTTY/plink.exe" ]; then
|
|
||||||
PLINK_CMD="/c/Program Files/PuTTY/plink.exe"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Using plink for authentication..."
|
|
||||||
|
|
||||||
# Use plink with -pw flag to pass password
|
|
||||||
# Accept host key using the fingerprint provided
|
|
||||||
"$PLINK_CMD" -ssh -pw "${REMOTE_PASSWORD}" -batch -hostkey "SHA256:QtU+b4Fx3PSYDUwrgpXcZKZQCe9N8yZWnxY43Wh/bUA" \
|
|
||||||
"${REMOTE_USER}@${REMOTE_HOST}" "${REMOTE_SCRIPT}"
|
|
||||||
|
|
||||||
else
|
|
||||||
echo "Error: plink not found."
|
|
||||||
echo "Please ensure PuTTY is installed or use the manual method below."
|
|
||||||
echo ""
|
|
||||||
echo "Manual method - run these commands:"
|
|
||||||
echo " ssh ${REMOTE_USER}@${REMOTE_HOST}"
|
|
||||||
echo ""
|
|
||||||
echo "Then execute on the remote server:"
|
|
||||||
echo " mkdir -p ~/.ssh"
|
|
||||||
echo " chmod 700 ~/.ssh"
|
|
||||||
echo " echo '${SSH_KEY}' >> ~/.ssh/authorized_keys"
|
|
||||||
echo " chmod 600 ~/.ssh/authorized_keys"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Done!"
|
|
||||||
@ -1,47 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Script to add SSH public key to remote server using plink (PuTTY)
|
|
||||||
# Usage: ./add-ssh-key.sh
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
REMOTE_HOST="155.133.129.88"
|
|
||||||
REMOTE_USER="admin"
|
|
||||||
REMOTE_PASSWORD="GHDKkpNUNuFePQb4KZ4%"
|
|
||||||
SSH_KEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFURI5emj/BtYj6fgO6JnqH8csxJeSlyWkLs1DcPdoVp titouan.tabere@gmail.com"
|
|
||||||
|
|
||||||
echo "Adding SSH key to ${REMOTE_USER}@${REMOTE_HOST} using plink..."
|
|
||||||
|
|
||||||
# Remote script to execute
|
|
||||||
REMOTE_SCRIPT="mkdir -p ~/.ssh && chmod 700 ~/.ssh && AUTH_KEYS_FILE=\$HOME/.ssh/authorized_keys && KEY_TO_ADD='${SSH_KEY}' && if [ -f \"\$AUTH_KEYS_FILE\" ] && grep -qF \"\$KEY_TO_ADD\" \"\$AUTH_KEYS_FILE\"; then echo 'SSH key already exists in authorized_keys'; else echo \"\$KEY_TO_ADD\" >> \"\$AUTH_KEYS_FILE\" && echo 'SSH key added successfully'; fi && chmod 600 \"\$AUTH_KEYS_FILE\" && echo 'SSH key setup completed'"
|
|
||||||
|
|
||||||
# Check if plink is available
|
|
||||||
if command -v plink &> /dev/null || [ -f "/c/Program Files/PuTTY/plink.exe" ]; then
|
|
||||||
PLINK_CMD="plink"
|
|
||||||
if [ -f "/c/Program Files/PuTTY/plink.exe" ]; then
|
|
||||||
PLINK_CMD="/c/Program Files/PuTTY/plink.exe"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Using plink for authentication..."
|
|
||||||
|
|
||||||
# Use plink with -pw flag to pass password
|
|
||||||
# Accept host key using the fingerprint provided
|
|
||||||
"$PLINK_CMD" -ssh -pw "${REMOTE_PASSWORD}" -batch -hostkey "SHA256:QtU+b4Fx3PSYDUwrgpXcZKZQCe9N8yZWnxY43Wh/bUA" \
|
|
||||||
"${REMOTE_USER}@${REMOTE_HOST}" "${REMOTE_SCRIPT}"
|
|
||||||
|
|
||||||
else
|
|
||||||
echo "Error: plink not found."
|
|
||||||
echo "Please ensure PuTTY is installed or use the manual method below."
|
|
||||||
echo ""
|
|
||||||
echo "Manual method - run these commands:"
|
|
||||||
echo " ssh ${REMOTE_USER}@${REMOTE_HOST}"
|
|
||||||
echo ""
|
|
||||||
echo "Then execute on the remote server:"
|
|
||||||
echo " mkdir -p ~/.ssh"
|
|
||||||
echo " chmod 700 ~/.ssh"
|
|
||||||
echo " echo '${SSH_KEY}' >> ~/.ssh/authorized_keys"
|
|
||||||
echo " chmod 600 ~/.ssh/authorized_keys"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Done!"
|
|
||||||
@ -210,7 +210,6 @@ function AuthorFilter({
|
|||||||
<div className="px-3 py-2 text-sm text-cyber-accent/70">Loading authors...</div>
|
<div className="px-3 py-2 text-sm text-cyber-accent/70">Loading authors...</div>
|
||||||
) : (
|
) : (
|
||||||
authors.map((pubkey) => {
|
authors.map((pubkey) => {
|
||||||
const profile = profiles.get(pubkey)
|
|
||||||
const displayName = getDisplayName(pubkey)
|
const displayName = getDisplayName(pubkey)
|
||||||
const picture = getPicture(pubkey)
|
const picture = getPicture(pubkey)
|
||||||
const mnemonicIcons = getMnemonicIcons(pubkey)
|
const mnemonicIcons = getMnemonicIcons(pubkey)
|
||||||
|
|||||||
68
docs/architecture.md
Normal file
68
docs/architecture.md
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
# Architecture technique
|
||||||
|
|
||||||
|
**Auteur** : Équipe 4NK
|
||||||
|
|
||||||
|
## Vue d'ensemble
|
||||||
|
|
||||||
|
Zapwall est une plateforme décentralisée basée sur le protocole Nostr pour la publication et la monétisation de contenu. Le système utilise Lightning Network pour les paiements et Bitcoin mainnet pour le sponsoring.
|
||||||
|
|
||||||
|
## Services principaux
|
||||||
|
|
||||||
|
### Nostr (`lib/nostr.ts`)
|
||||||
|
- Gestion du pool de connexions aux relays
|
||||||
|
- Publication et récupération d'événements
|
||||||
|
- Gestion des profils utilisateurs
|
||||||
|
- Création de zap requests
|
||||||
|
|
||||||
|
### Paiements (`lib/payment.ts`, `lib/paymentPolling.ts`)
|
||||||
|
- Création d'invoices Lightning via Alby/WebLN
|
||||||
|
- Vérification des paiements via zap receipts (NIP-57)
|
||||||
|
- Polling pour confirmation des paiements
|
||||||
|
- Envoi automatique du contenu privé après paiement
|
||||||
|
|
||||||
|
### Commissions (`lib/platformCommissions.ts`)
|
||||||
|
- Configuration centralisée des commissions
|
||||||
|
- Calcul des splits (auteur/plateforme)
|
||||||
|
- Validation des montants
|
||||||
|
|
||||||
|
### Tracking (`lib/platformTracking.ts`, `lib/sponsoringTracking.ts`)
|
||||||
|
- Publication d'événements de tracking sur Nostr
|
||||||
|
- Suivi des livraisons de contenu
|
||||||
|
- Suivi des paiements de sponsoring
|
||||||
|
|
||||||
|
### Intégrations externes
|
||||||
|
- **mempool.space** (`lib/mempoolSpace.ts`) : Vérification des transactions Bitcoin
|
||||||
|
- **Lightning addresses** (`lib/lightningAddress.ts`) : Récupération depuis profils Nostr
|
||||||
|
|
||||||
|
## Flux de paiement article
|
||||||
|
|
||||||
|
1. Lecteur clique sur "Unlock for 800 sats"
|
||||||
|
2. Création d'invoice Lightning (via Alby/WebLN)
|
||||||
|
3. Publication de zap request sur Nostr
|
||||||
|
4. Lecteur paie l'invoice
|
||||||
|
5. Polling pour vérifier le zap receipt
|
||||||
|
6. Envoi automatique du contenu privé (message chiffré NIP-04)
|
||||||
|
7. Tracking de la livraison avec commissions
|
||||||
|
|
||||||
|
## Flux de sponsoring
|
||||||
|
|
||||||
|
1. Utilisateur demande sponsoring (0.046 BTC)
|
||||||
|
2. Service calcule split (0.042/0.004 BTC)
|
||||||
|
3. Retourne deux adresses Bitcoin
|
||||||
|
4. Utilisateur crée transaction avec deux sorties
|
||||||
|
5. Vérification via mempool.space
|
||||||
|
6. Tracking sur Nostr
|
||||||
|
|
||||||
|
## Stockage
|
||||||
|
|
||||||
|
- **IndexedDB** : Contenu privé chiffré (AES-GCM)
|
||||||
|
- **localStorage** : Métadonnées d'articles, invoices
|
||||||
|
- **Nostr** : Tous les contenus publics et événements de tracking
|
||||||
|
|
||||||
|
## Sécurité
|
||||||
|
|
||||||
|
- Chiffrement end-to-end pour contenu privé (NIP-04)
|
||||||
|
- Validation stricte des montants
|
||||||
|
- Tracking complet sur Nostr pour audit
|
||||||
|
- Pas de fallback implicite
|
||||||
|
|
||||||
42
docs/commissions.md
Normal file
42
docs/commissions.md
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# Système de commissions
|
||||||
|
|
||||||
|
**Auteur** : Équipe 4NK
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Les commissions sont centralisées dans `lib/platformCommissions.ts` :
|
||||||
|
|
||||||
|
- **Articles** : 800 sats total (700 auteur, 100 plateforme)
|
||||||
|
- **Avis** : 70 sats total (49 reviewer, 21 plateforme)
|
||||||
|
- **Sponsoring** : 0.046 BTC total (0.042 auteur, 0.004 plateforme)
|
||||||
|
|
||||||
|
## Implémentation
|
||||||
|
|
||||||
|
### Articles
|
||||||
|
- Validation du montant à chaque étape
|
||||||
|
- Tracking avec `author_amount` et `platform_commission`
|
||||||
|
- Récupération automatique de l'adresse Lightning de l'auteur
|
||||||
|
- Transfert automatique déclenché (nécessite nœud Lightning)
|
||||||
|
|
||||||
|
### Sponsoring
|
||||||
|
- Vérification des transactions Bitcoin via mempool.space
|
||||||
|
- Validation des sorties (auteur + plateforme)
|
||||||
|
- Tracking sur Nostr avec confirmations
|
||||||
|
|
||||||
|
### Avis
|
||||||
|
- Mise à jour de l'événement Nostr avec tags `rewarded` et `reward_amount`
|
||||||
|
- Récupération automatique de l'adresse Lightning du reviewer
|
||||||
|
- Transfert automatique déclenché (nécessite nœud Lightning)
|
||||||
|
|
||||||
|
## Tracking
|
||||||
|
|
||||||
|
Tous les paiements sont trackés sur Nostr via des événements personnalisés :
|
||||||
|
- **Kind 30078** : Livraisons de contenu
|
||||||
|
- **Kind 30079** : Paiements de sponsoring
|
||||||
|
|
||||||
|
Ces événements permettent un audit complet et une traçabilité totale.
|
||||||
|
|
||||||
|
## Limitations actuelles
|
||||||
|
|
||||||
|
Les transferts Lightning automatiques nécessitent un nœud Lightning de la plateforme. Actuellement, les transferts sont loggés et peuvent être exécutés manuellement.
|
||||||
|
|
||||||
@ -130,4 +130,3 @@ Les seules limitations sont liées à l'infrastructure :
|
|||||||
- Les transferts sont actuellement loggés et peuvent être exécutés manuellement
|
- Les transferts sont actuellement loggés et peuvent être exécutés manuellement
|
||||||
|
|
||||||
Le système est **prêt pour la production** une fois le nœud Lightning configuré.
|
Le système est **prêt pour la production** une fois le nœud Lightning configuré.
|
||||||
|
|
||||||
@ -1,122 +0,0 @@
|
|||||||
# Résumé du nettoyage et optimisation du code
|
|
||||||
|
|
||||||
**Date** : Décembre 2024
|
|
||||||
|
|
||||||
## Objectifs atteints
|
|
||||||
|
|
||||||
### ✅ 1. Nettoyage des fichiers/dossiers obsolètes
|
|
||||||
- **Supprimé** : Dossier `pages/api/rizful/` (API routes Rizful devenues inutiles)
|
|
||||||
- **Conservé** : Documentation Rizful (`docs/rizful-api-setup.md`, `features/rizful-integration.md`) pour référence historique
|
|
||||||
|
|
||||||
### ✅ 2. Optimisation et division des fichiers > 250 lignes
|
|
||||||
|
|
||||||
#### Fichiers divisés :
|
|
||||||
|
|
||||||
**`lib/nostr.ts`** (était 331 lignes → maintenant 232 lignes)
|
|
||||||
- Créé `lib/nostrEventParsing.ts` : Parsing des événements en articles
|
|
||||||
- Créé `lib/nostrPrivateMessages.ts` : Gestion des messages privés
|
|
||||||
- Créé `lib/nostrZapVerification.ts` : Vérification des zap receipts
|
|
||||||
- Créé `lib/nostrSubscription.ts` : Utilitaires pour les subscriptions avec timeout
|
|
||||||
|
|
||||||
**`lib/payment.ts`** (était 195 lignes → maintenant 196 lignes)
|
|
||||||
- Créé `lib/paymentPolling.ts` : Polling pour vérification des paiements
|
|
||||||
- Créé `lib/invoiceResolver.ts` : Résolution des invoices (tags, localStorage, nouvelle création)
|
|
||||||
|
|
||||||
**`lib/articlePublisher.ts`** (était 237 lignes → maintenant 210 lignes)
|
|
||||||
- Créé `lib/articleStorage.ts` : Gestion du stockage localStorage
|
|
||||||
- Créé `lib/articleInvoice.ts` : Création d'invoices et événements preview
|
|
||||||
|
|
||||||
**`lib/nostrconnect.ts`** (était 156 lignes → maintenant 145 lignes)
|
|
||||||
- Créé `lib/nostrconnectHandler.ts` : Handler pour les messages NostrConnect
|
|
||||||
|
|
||||||
### ✅ 3. Division des fonctions > 40 lignes
|
|
||||||
|
|
||||||
Fonctions refactorisées :
|
|
||||||
- `parseArticleFromEvent` → extraite dans `nostrEventParsing.ts`
|
|
||||||
- `getPrivateContent` → extraite dans `nostrPrivateMessages.ts`
|
|
||||||
- `checkZapReceipt` → simplifiée avec helper dans `nostrZapVerification.ts`
|
|
||||||
- `waitForArticlePayment` → extraite dans `paymentPolling.ts`
|
|
||||||
- `createArticlePayment` → simplifiée avec `invoiceResolver.ts`
|
|
||||||
- `publishArticle` → simplifiée avec `articleInvoice.ts`
|
|
||||||
- Fonctions de stockage → extraites dans `articleStorage.ts`
|
|
||||||
- Handlers de subscription → extraits dans `nostrSubscription.ts`
|
|
||||||
- Handler NostrConnect → extrait dans `nostrconnectHandler.ts`
|
|
||||||
|
|
||||||
### ✅ 4. Correction des erreurs de lint
|
|
||||||
- Aucune erreur de lint détectée
|
|
||||||
- Code TypeScript propre
|
|
||||||
- Imports optimisés
|
|
||||||
|
|
||||||
## Nouveaux fichiers créés
|
|
||||||
|
|
||||||
1. `lib/nostrEventParsing.ts` - Parsing des événements Nostr en articles
|
|
||||||
2. `lib/nostrPrivateMessages.ts` - Gestion des messages privés chiffrés
|
|
||||||
3. `lib/nostrZapVerification.ts` - Vérification des zap receipts
|
|
||||||
4. `lib/nostrSubscription.ts` - Utilitaires pour subscriptions avec timeout
|
|
||||||
5. `lib/paymentPolling.ts` - Polling pour vérification des paiements
|
|
||||||
6. `lib/invoiceResolver.ts` - Résolution intelligente des invoices
|
|
||||||
7. `lib/articleStorage.ts` - Gestion du stockage localStorage
|
|
||||||
8. `lib/articleInvoice.ts` - Création d'invoices et événements preview
|
|
||||||
9. `lib/nostrconnectHandler.ts` - Handler pour messages NostrConnect
|
|
||||||
|
|
||||||
## Avantages de la refactorisation
|
|
||||||
|
|
||||||
### Maintenabilité
|
|
||||||
- Code plus modulaire et réutilisable
|
|
||||||
- Responsabilités mieux séparées (SRP)
|
|
||||||
- Plus facile à tester unitairement
|
|
||||||
|
|
||||||
### Lisibilité
|
|
||||||
- Fichiers plus courts et focalisés
|
|
||||||
- Fonctions plus courtes et plus claires
|
|
||||||
- Imports plus explicites
|
|
||||||
|
|
||||||
### Performance
|
|
||||||
- Pas d'impact négatif sur les performances
|
|
||||||
- Code mieux organisé pour le tree-shaking
|
|
||||||
- Moins de dépendances circulaires
|
|
||||||
|
|
||||||
## Statistiques
|
|
||||||
|
|
||||||
### Avant
|
|
||||||
- `lib/nostr.ts` : 331 lignes
|
|
||||||
- `lib/articlePublisher.ts` : 237 lignes
|
|
||||||
- `lib/payment.ts` : 195 lignes
|
|
||||||
- `lib/nostrconnect.ts` : 156 lignes
|
|
||||||
|
|
||||||
### Après
|
|
||||||
- `lib/nostr.ts` : 232 lignes (-30%)
|
|
||||||
- `lib/articlePublisher.ts` : 210 lignes (-11%)
|
|
||||||
- `lib/payment.ts` : 196 lignes (stable)
|
|
||||||
- `lib/nostrconnect.ts` : 145 lignes (-7%)
|
|
||||||
- 9 nouveaux fichiers modulaires
|
|
||||||
|
|
||||||
## Structure finale
|
|
||||||
|
|
||||||
```
|
|
||||||
lib/
|
|
||||||
├── alby.ts (184 lignes)
|
|
||||||
├── articleInvoice.ts (nouveau, ~60 lignes)
|
|
||||||
├── articlePublisher.ts (210 lignes, optimisé)
|
|
||||||
├── articleStorage.ts (nouveau, ~120 lignes)
|
|
||||||
├── invoiceResolver.ts (nouveau, ~50 lignes)
|
|
||||||
├── nostr.ts (232 lignes, optimisé)
|
|
||||||
├── nostrEventParsing.ts (nouveau, ~55 lignes)
|
|
||||||
├── nostrPrivateMessages.ts (nouveau, ~65 lignes)
|
|
||||||
├── nostrSubscription.ts (nouveau, ~85 lignes)
|
|
||||||
├── nostrZapVerification.ts (nouveau, ~75 lignes)
|
|
||||||
├── nostrconnect.ts (145 lignes, optimisé)
|
|
||||||
├── nostrconnectHandler.ts (nouveau, ~35 lignes)
|
|
||||||
├── nostrRemoteSigner.ts (57 lignes)
|
|
||||||
├── payment.ts (196 lignes, optimisé)
|
|
||||||
├── paymentPolling.ts (nouveau, ~95 lignes)
|
|
||||||
├── retry.ts (91 lignes)
|
|
||||||
└── zapVerification.ts (110 lignes)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
- Tous les fichiers sont maintenant < 250 lignes
|
|
||||||
- Toutes les fonctions sont maintenant < 40 lignes
|
|
||||||
- Aucune erreur de lint
|
|
||||||
- Code optimisé et maintenable
|
|
||||||
@ -1,88 +0,0 @@
|
|||||||
# Corrections complétées - Nostr Paywall
|
|
||||||
|
|
||||||
**Date** : Décembre 2024
|
|
||||||
**Auteur** : Équipe 4NK
|
|
||||||
|
|
||||||
## ✅ Corrections effectuées
|
|
||||||
|
|
||||||
### 1. Bug critique corrigé
|
|
||||||
- ✅ **`components/ArticleCard.tsx`** : `handleUnlockClick` remplacé par `handleUnlock` (ligne 33)
|
|
||||||
- **Impact** : Le bouton "Unlock" fonctionne maintenant correctement
|
|
||||||
|
|
||||||
### 2. Nettoyage des `console.log`
|
|
||||||
Tous les `console.log` ont été supprimés ou remplacés dans :
|
|
||||||
- ✅ `lib/nostrconnect.ts` : 3 `console.log` supprimés
|
|
||||||
- ✅ `lib/nostrconnectMessageHandler.ts` : 4 `console.log` supprimés
|
|
||||||
- ✅ `lib/paymentPolling.ts` : 1 `console.log` remplacé par un commentaire
|
|
||||||
- ✅ `lib/articleInvoice.ts` : 1 `console.log` supprimé
|
|
||||||
|
|
||||||
**Résultat** : Conformité avec la règle ESLint `no-console: warn`
|
|
||||||
|
|
||||||
### 3. Correction des types `any`
|
|
||||||
- ✅ **`lib/alby.ts`** :
|
|
||||||
- Création d'une interface `WebLNProvider` dans `types/alby.ts`
|
|
||||||
- Remplacement de `(window as any).webln` par `window.webln` avec typage strict
|
|
||||||
- Ajout d'une déclaration globale pour `Window.webln`
|
|
||||||
|
|
||||||
**Résultat** : Types stricts pour WebLN, plus de sécurité de type
|
|
||||||
|
|
||||||
### 4. Correction des non-null assertions
|
|
||||||
- ✅ **`lib/storage/indexedDB.ts`** : 4 assertions `this.db!` remplacées par des variables locales avec vérification explicite
|
|
||||||
- ✅ **`lib/nostr.ts`** : 1 assertion `this.privateKey!` remplacée par une variable locale
|
|
||||||
- ✅ **`lib/articleFiltering.ts`** : 2 assertions `filters.minPrice!` et `filters.maxPrice!` remplacées par des variables locales
|
|
||||||
|
|
||||||
**Résultat** : Code plus sûr, pas d'assertions non-null dangereuses
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 État final
|
|
||||||
|
|
||||||
### Code TypeScript
|
|
||||||
- ✅ **0 erreur de lint** dans le code source
|
|
||||||
- ✅ **Conformité** avec toutes les règles ESLint strictes
|
|
||||||
- ✅ **Types stricts** partout où possible
|
|
||||||
- ✅ **Pas d'assertions non-null** dangereuses
|
|
||||||
|
|
||||||
### Exceptions acceptables
|
|
||||||
|
|
||||||
#### 1. `any` dans `lib/storage/indexedDB.ts`
|
|
||||||
**Lignes** : 7, 72, 110
|
|
||||||
**Raison** : Intentionnel - permet de stocker n'importe quel type de données dans IndexedDB
|
|
||||||
```typescript
|
|
||||||
interface DBData {
|
|
||||||
data: any // Acceptable : stockage générique
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 2. `as any` pour `pool.sub` dans plusieurs fichiers
|
|
||||||
**Fichiers** : `lib/nostr.ts`, `lib/notifications.ts`, `lib/nostrSubscription.ts`
|
|
||||||
**Raison** : Problème de typage de la bibliothèque externe `nostr-tools` qui n'expose pas correctement la méthode `sub` dans les types TypeScript
|
|
||||||
```typescript
|
|
||||||
const sub = (this.pool as any).sub([RELAY_URL], filters)
|
|
||||||
```
|
|
||||||
**Note** : C'est un problème connu avec `nostr-tools` v2.3.4. La méthode existe bien à l'exécution mais n'est pas typée.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 Résumé
|
|
||||||
|
|
||||||
### Tâches demandées : ✅ TOUTES COMPLÉTÉES
|
|
||||||
|
|
||||||
1. ✅ Bug critique corrigé
|
|
||||||
2. ✅ `console.log` nettoyés
|
|
||||||
3. ✅ Types `any` corrigés (sauf exceptions acceptables)
|
|
||||||
4. ✅ Non-null assertions corrigées
|
|
||||||
|
|
||||||
### Tâches NON demandées (non faites) :
|
|
||||||
- ❌ Fonctionnalités manquantes (statistiques, édition d'articles, etc.)
|
|
||||||
- ❌ Tests (non planifié)
|
|
||||||
- ❌ Documentation technique
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📝 Notes
|
|
||||||
|
|
||||||
- Le code est maintenant **100% conforme** aux standards stricts du projet
|
|
||||||
- Toutes les corrections demandées ont été effectuées
|
|
||||||
- Les exceptions restantes (`any` pour stockage générique, `as any` pour bibliothèque externe) sont acceptables et documentées
|
|
||||||
- L'application est prête pour la production
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
# Documentation technique à compléter
|
|
||||||
|
|
||||||
## Objectif
|
|
||||||
Formaliser la structure technique (services, hooks, types) et le flux Nostr/stockage, sans ajouter de tests ni d’analytics.
|
|
||||||
|
|
||||||
## Cibles
|
|
||||||
- Services Nostr : `lib/nostr.ts`, `lib/nostrRemoteSigner.ts`, `lib/articleMutations.ts`, `lib/zapVerification.ts`, `lib/nostrconnect.ts`.
|
|
||||||
- Paiement/Alby/WebLN : `lib/alby.ts`, `lib/payment.ts`, `lib/paymentPolling.ts`.
|
|
||||||
- Stockage : `lib/storage/indexedDB.ts`, `lib/storage/cryptoHelpers.ts`, `lib/articleStorage.ts`.
|
|
||||||
- Hooks : `hooks/useArticles.ts`, `hooks/useUserArticles.ts`, `hooks/useArticleEditing.ts`.
|
|
||||||
- Types : `types/nostr.ts`, `types/nostr-tools-extended.ts`, `types/alby.ts`.
|
|
||||||
- UI clés : `components/UserArticles*.tsx`, `components/ArticleEditor*.tsx`, `components/AlbyInstaller.tsx`.
|
|
||||||
|
|
||||||
## Plan
|
|
||||||
1) Cartographie des services/hooks/types (diagramme ou tableau : responsabilités, entrées/sorties, dépendances).
|
|
||||||
2) Guide Nostr : publication, update/delete, zap verification, remote signer.
|
|
||||||
3) Guide stockage : chiffrement IndexedDB, gestion des expirations.
|
|
||||||
4) Guide paiements : création facture, polling, envoi contenu privé.
|
|
||||||
5) Contrib : référencer dans `CONTRIBUTING.md`.
|
|
||||||
|
|
||||||
## Contraintes
|
|
||||||
- Pas de tests, pas d’analytics.
|
|
||||||
- Pas de fallback implicite; erreurs loguées et surfacées.
|
|
||||||
- Respect lint/typage/accessibilité.
|
|
||||||
@ -1,112 +0,0 @@
|
|||||||
# Suppression des fallbacks dans l'application
|
|
||||||
|
|
||||||
**Date** : Décembre 2024
|
|
||||||
**Status** : ✅ Tous les fallbacks supprimés
|
|
||||||
|
|
||||||
## Fallbacks supprimés
|
|
||||||
|
|
||||||
### 1. `components/PaymentModal.tsx` - Fallback vers Lightning URI ✅ SUPPRIMÉ
|
|
||||||
**Lignes** : 71, 75, 81
|
|
||||||
|
|
||||||
**Description** : Si WebLN/Alby échoue, l'application ouvrait le Lightning URI dans le navigateur.
|
|
||||||
|
|
||||||
**Action** : ✅ Supprimé - Affiche maintenant une erreur à la place
|
|
||||||
|
|
||||||
**Modifications** :
|
|
||||||
- Suppression de tous les fallbacks vers `window.location.href = paymentUrl`
|
|
||||||
- Affichage d'une erreur si WebLN n'est pas disponible
|
|
||||||
- Affichage d'une erreur si le paiement échoue (sauf si l'utilisateur a annulé)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2. `lib/invoiceResolver.ts` - Fallback vers storage puis création ✅ SUPPRIMÉ
|
|
||||||
**Ligne** : 26-31
|
|
||||||
|
|
||||||
**Description** : Si l'invoice n'est pas dans les tags de l'événement, essayait le storage, puis créait une nouvelle invoice.
|
|
||||||
|
|
||||||
**Action** : ✅ Supprimé - Utilise uniquement l'invoice des tags de l'événement
|
|
||||||
|
|
||||||
**Modifications** :
|
|
||||||
- Suppression du fallback vers storage
|
|
||||||
- Suppression de la création automatique d'invoice
|
|
||||||
- Lève une erreur si l'article n'a pas d'invoice dans les tags
|
|
||||||
- L'invoice doit être créée par l'auteur lors de la publication
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3. `lib/payment.ts` - Continue même si zap request échoue ✅ SUPPRIMÉ
|
|
||||||
**Ligne** : 39
|
|
||||||
|
|
||||||
**Description** : Si la création du zap request échouait, continuait quand même avec l'invoice.
|
|
||||||
|
|
||||||
**Action** : ✅ Supprimé - Le zap request est maintenant requis
|
|
||||||
|
|
||||||
**Modifications** :
|
|
||||||
- Suppression du try/catch qui ignorait l'erreur
|
|
||||||
- Le zap request doit maintenant réussir, sinon une erreur est levée
|
|
||||||
- Le paiement ne peut pas continuer sans zap request
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 4. `lib/articleInvoice.ts` - Continue sans invoice si création échoue ✅ SUPPRIMÉ
|
|
||||||
**Ligne** : 22-23
|
|
||||||
|
|
||||||
**Description** : Si la création d'invoice via Alby échouait, continuait sans invoice.
|
|
||||||
|
|
||||||
**Action** : ✅ Supprimé - La création d'invoice est maintenant requise
|
|
||||||
|
|
||||||
**Modifications** :
|
|
||||||
- Suppression du try/catch qui retournait `undefined`
|
|
||||||
- La fonction lève maintenant une erreur si la création échoue
|
|
||||||
- L'article ne peut pas être publié sans invoice
|
|
||||||
- `createArticleInvoice` retourne maintenant `Promise<AlbyInvoice>` au lieu de `Promise<AlbyInvoice | undefined>`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 5. `lib/articleStorage.ts` - Commentaire obsolète ✅ CORRIGÉ
|
|
||||||
**Ligne** : 23
|
|
||||||
|
|
||||||
**Description** : Commentaire mentionnait encore localStorage (obsolète).
|
|
||||||
|
|
||||||
**Action** : ✅ Corrigé - Commentaire mis à jour
|
|
||||||
|
|
||||||
**Modifications** :
|
|
||||||
- Commentaire mis à jour pour refléter l'utilisation exclusive d'IndexedDB
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 6. `lib/nostrRemoteSigner.ts` - Commentaire fallback ✅ CORRIGÉ
|
|
||||||
**Ligne** : 35
|
|
||||||
|
|
||||||
**Description** : Commentaire mentionnait "This is a fallback that will throw an error".
|
|
||||||
|
|
||||||
**Action** : ✅ Corrigé - Commentaire mis à jour
|
|
||||||
|
|
||||||
**Modifications** :
|
|
||||||
- Commentaire mis à jour pour refléter que la clé privée est requise
|
|
||||||
- Message d'erreur amélioré
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Résumé des modifications
|
|
||||||
|
|
||||||
Tous les fallbacks ont été supprimés. L'application utilise maintenant une approche "fail-fast" :
|
|
||||||
|
|
||||||
1. ✅ **PaymentModal.tsx** : Affiche une erreur si WebLN échoue (pas de redirection)
|
|
||||||
2. ✅ **invoiceResolver.ts** : Utilise uniquement l'invoice des tags (erreur si absent)
|
|
||||||
3. ✅ **payment.ts** : Le zap request est requis (erreur si échec)
|
|
||||||
4. ✅ **articleInvoice.ts** : La création d'invoice est requise (erreur si échec)
|
|
||||||
5. ✅ **articleStorage.ts** : Commentaire corrigé
|
|
||||||
|
|
||||||
## Impact
|
|
||||||
|
|
||||||
### Comportement avant
|
|
||||||
- L'application essayait plusieurs alternatives en cas d'échec
|
|
||||||
- Continuait même si certaines opérations échouaient
|
|
||||||
- Fallback vers des méthodes alternatives
|
|
||||||
|
|
||||||
### Comportement après
|
|
||||||
- L'application échoue immédiatement si une opération requise échoue
|
|
||||||
- Pas de fallback, pas de continuation silencieuse
|
|
||||||
- Erreurs claires pour l'utilisateur
|
|
||||||
- Code plus prévisible et plus strict
|
|
||||||
@ -1,186 +0,0 @@
|
|||||||
# Résumé des implémentations - Nostr Paywall
|
|
||||||
|
|
||||||
**Date** : Décembre 2025 (mise à jour)
|
|
||||||
|
|
||||||
## ✅ Mises à jour Déc 2025
|
|
||||||
|
|
||||||
- **Séries et critiques** : pages série dédiées (`pages/series/[id].tsx`), agrégats sponsoring/achats/remerciements, filtrage par série sur le profil, affichage des critiques avec formatage auteur/date et total des remerciements.
|
|
||||||
- **NIP-95 médias** : upload images (≤5Mo PNG/JPG/JPEG/WebP) et vidéos (≤45Mo MP4/WebM) via `lib/nip95.ts`, insertion dans markdown et bannière.
|
|
||||||
- **Agrégations zap** : `lib/zapAggregation.ts`, `lib/seriesAggregation.ts`, `lib/reviewAggregation.ts` pour cumuls sponsoring/achats/remerciements par auteur/série/article.
|
|
||||||
- **Tags Nostr enrichis** : `lib/nostrTags.ts`, `lib/articlePublisher.ts`, `lib/articleMutations.ts` intègrent `kind_type`, `seriesId`, bannières, médias, catégories, site/type (science-fiction/research).
|
|
||||||
- **Hooks et subscriptions** : `useArticles` / `useUserArticles` corrigent la gestion des unsub synchro (pas de `.then`), pas de fallback.
|
|
||||||
- **Stockage privé** : contenu chiffré en IndexedDB (WebCrypto AES-GCM) via `lib/storage/indexedDB.ts` + helpers `lib/storage/cryptoHelpers.ts`.
|
|
||||||
- **Qualité stricte** : `exactOptionalPropertyTypes` respecté (props optionnelles typées `| undefined`), fonctions < 40 lignes et fichiers < 250 lignes (refactors multiples).
|
|
||||||
- **Navigation** : liens directs vers page série depuis cartes et liste d’articles, filtrage par série depuis la liste utilisateur.
|
|
||||||
|
|
||||||
## ✅ Implémentations complétées
|
|
||||||
|
|
||||||
### Priorité 1 - Fonctionnalités critiques
|
|
||||||
|
|
||||||
#### 1. Parsing des tags invoice depuis les événements Nostr ✅
|
|
||||||
- **Fichiers modifiés** :
|
|
||||||
- `types/nostr.ts` : Ajout de `invoice` et `paymentHash` à l'interface `Article`
|
|
||||||
- `lib/nostr.ts` : Parsing des tags `invoice` et `payment_hash` dans `parseArticleFromEvent`
|
|
||||||
- `lib/payment.ts` : Utilisation prioritaire de l'invoice depuis les tags de l'événement
|
|
||||||
|
|
||||||
- **Fonctionnement** :
|
|
||||||
- L'invoice créée par l'auteur est stockée dans les tags de l'événement Nostr
|
|
||||||
- Les lecteurs peuvent récupérer l'invoice directement depuis l'événement
|
|
||||||
- Fallback sur localStorage puis création d'une nouvelle invoice si nécessaire
|
|
||||||
|
|
||||||
#### 2. Génération d'invoice côté auteur ✅
|
|
||||||
- **Fichiers modifiés** :
|
|
||||||
- `lib/articlePublisher.ts` : Création d'invoice lors de la publication
|
|
||||||
- `lib/payment.ts` : Vérification de l'invoice de l'auteur avant d'en créer une nouvelle
|
|
||||||
|
|
||||||
- **Fonctionnement** :
|
|
||||||
- L'auteur crée une facture Lightning via Alby/WebLN lors de la publication
|
|
||||||
- L'invoice est stockée dans les tags de l'événement (`invoice`, `payment_hash`)
|
|
||||||
- Stockage également dans localStorage pour récupération rapide
|
|
||||||
|
|
||||||
#### 3. Signature distante améliorée ✅
|
|
||||||
- **Fichiers modifiés** :
|
|
||||||
- `lib/nostrRemoteSigner.ts` : Support amélioré pour la signature
|
|
||||||
- `lib/articlePublisher.ts` : Clé privée optionnelle
|
|
||||||
- `components/ArticleEditor.tsx` : Utilisation améliorée
|
|
||||||
|
|
||||||
- **Note** : Utilise actuellement la signature directe si la clé privée est disponible via NostrConnect
|
|
||||||
|
|
||||||
### Priorité 2 - Améliorations UX/UI
|
|
||||||
|
|
||||||
#### 4. QR Code pour factures Lightning ✅
|
|
||||||
- **Dépendance ajoutée** : `react-qr-code`
|
|
||||||
- **Fichiers modifiés** :
|
|
||||||
- `components/PaymentModal.tsx` : Affichage d'un QR code pour scanner avec un portefeuille mobile
|
|
||||||
- `package.json` : Ajout de `react-qr-code`
|
|
||||||
|
|
||||||
- **Fonctionnement** :
|
|
||||||
- QR code affiché avec l'invoice Lightning
|
|
||||||
- Format `lightning:lnbc...` pour compatibilité universelle
|
|
||||||
- Taille et style adaptés
|
|
||||||
|
|
||||||
#### 5. Gestion de l'expiration des factures ✅
|
|
||||||
- **Fichiers modifiés** :
|
|
||||||
- `components/PaymentModal.tsx` : Timer en temps réel avec compte à rebours
|
|
||||||
|
|
||||||
- **Fonctionnalités** :
|
|
||||||
- Affichage du temps restant en format MM:SS
|
|
||||||
- Indication visuelle (rouge si < 60 secondes)
|
|
||||||
- Message d'expiration si la facture a expiré
|
|
||||||
- Mise à jour toutes les secondes
|
|
||||||
|
|
||||||
#### 6. Retry logic et gestion d'erreurs robuste ✅
|
|
||||||
- **Fichiers créés** :
|
|
||||||
- `lib/retry.ts` : Utilitaire de retry avec backoff exponentiel
|
|
||||||
|
|
||||||
- **Fichiers modifiés** :
|
|
||||||
- `lib/alby.ts` : Intégration du retry pour `createInvoice` et `sendPayment`
|
|
||||||
- `components/PaymentModal.tsx` : Gestion d'erreurs améliorée
|
|
||||||
- `components/ArticleCard.tsx` : Messages d'erreur plus explicites
|
|
||||||
|
|
||||||
- **Fonctionnalités** :
|
|
||||||
- Retry automatique avec backoff exponentiel
|
|
||||||
- Détection des erreurs réseau retryables
|
|
||||||
- Gestion des erreurs utilisateur (rejet, annulation)
|
|
||||||
- Logging structuré des erreurs
|
|
||||||
|
|
||||||
#### 7. Détection et guide d'installation Alby ✅
|
|
||||||
- **Fichiers créés** :
|
|
||||||
- `components/AlbyInstaller.tsx` : Composant pour guider l'installation
|
|
||||||
|
|
||||||
- **Fichiers modifiés** :
|
|
||||||
- `components/PaymentModal.tsx` : Intégration du composant AlbyInstaller
|
|
||||||
|
|
||||||
- **Fonctionnalités** :
|
|
||||||
- Détection automatique de l'extension Alby
|
|
||||||
- Message d'information si non installé
|
|
||||||
- Bouton "Install Alby" avec lien vers getalby.com
|
|
||||||
- Bouton "Already installed? Connect" pour reconnecter
|
|
||||||
- Design responsive et accessible
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
### Flux de paiement
|
|
||||||
|
|
||||||
1. **Publication d'article** :
|
|
||||||
- Auteur crée l'article avec titre, preview, contenu privé, montant
|
|
||||||
- Auteur crée une invoice Lightning via Alby
|
|
||||||
- Publication de l'événement Nostr (kind:1) avec tags `invoice` et `payment_hash`
|
|
||||||
- Stockage du contenu privé dans localStorage
|
|
||||||
|
|
||||||
2. **Lecture d'article** :
|
|
||||||
- Lecteur voit le preview gratuit
|
|
||||||
- Lecteur clique sur "Unlock" pour débloquer
|
|
||||||
- Système récupère l'invoice depuis les tags de l'événement (ou crée une nouvelle)
|
|
||||||
- Affichage de la modal de paiement avec QR code
|
|
||||||
|
|
||||||
3. **Paiement** :
|
|
||||||
- Lecteur paie via Alby/WebLN ou scanne le QR code
|
|
||||||
- Vérification du paiement via zap receipts sur Nostr
|
|
||||||
- Envoi automatique du contenu privé chiffré (kind:4) à l'utilisateur
|
|
||||||
- Déblocage de l'article pour le lecteur
|
|
||||||
|
|
||||||
### Technologies utilisées
|
|
||||||
|
|
||||||
- **Frontend** : Next.js 14, React, TypeScript, Tailwind CSS
|
|
||||||
- **Nostr** : `nostr-tools` 1.17.0 (compat `signEvent`, `verifyEvent`)
|
|
||||||
- **Lightning** : Alby/WebLN
|
|
||||||
- **QR Code** : `react-qr-code`
|
|
||||||
|
|
||||||
## Fichiers créés/modifiés
|
|
||||||
|
|
||||||
### Nouveaux fichiers
|
|
||||||
- `lib/retry.ts` - Utilitaire de retry
|
|
||||||
- `components/AlbyInstaller.tsx` - Composant d'installation Alby
|
|
||||||
- `features/priority1-implementation.md` - Documentation priorité 1
|
|
||||||
- `features/implementation-summary.md` - Ce document
|
|
||||||
|
|
||||||
### Fichiers modifiés
|
|
||||||
- `types/nostr.ts` - Ajout de `invoice` et `paymentHash`
|
|
||||||
- `lib/nostr.ts` - Parsing des tags invoice
|
|
||||||
- `lib/articlePublisher.ts` - Création d'invoice côté auteur
|
|
||||||
- `lib/payment.ts` - Utilisation des invoices depuis les tags
|
|
||||||
- `lib/alby.ts` - Intégration du retry logic
|
|
||||||
- `components/PaymentModal.tsx` - QR code, timer, AlbyInstaller
|
|
||||||
- `components/ArticleCard.tsx` - Gestion d'erreurs améliorée
|
|
||||||
- `lib/nostrRemoteSigner.ts` - Support amélioré
|
|
||||||
- `package.json` - Ajout de `react-qr-code`
|
|
||||||
|
|
||||||
## Prochaines étapes (Priorité 3)
|
|
||||||
|
|
||||||
### Filtrage et recherche d'articles
|
|
||||||
- Barre de recherche par titre/contenu
|
|
||||||
- Filtres (par auteur, date, prix)
|
|
||||||
- Tri (date, popularité)
|
|
||||||
|
|
||||||
### Profil utilisateur et articles de l'utilisateur
|
|
||||||
- Page `/profile` ou `/user/[pubkey]`
|
|
||||||
- Liste des articles publiés
|
|
||||||
- Statistiques (vues, paiements reçus)
|
|
||||||
|
|
||||||
### Système de notifications
|
|
||||||
- Notifications en temps réel via relay Nostr
|
|
||||||
- Badge de notification dans l'UI
|
|
||||||
- Centre de notifications
|
|
||||||
|
|
||||||
### Amélioration du stockage du contenu privé
|
|
||||||
- Utiliser une base de données au lieu de localStorage
|
|
||||||
- Gestion de l'expiration des contenus stockés
|
|
||||||
- Sauvegarde sécurisée des clés privées
|
|
||||||
|
|
||||||
## Notes importantes
|
|
||||||
|
|
||||||
- **Stockage** : Actuellement, le contenu privé est stocké dans localStorage. Pour la production, il faudrait utiliser une base de données.
|
|
||||||
- **Signature distante** : NIP-46 complet non implémenté (nécessite WebSocket relay). Actuellement, utilise la clé privée fournie par NostrConnect.
|
|
||||||
- **Vérification des paiements** : Basée sur les zap receipts (kind:9735) avec vérification de signature complète.
|
|
||||||
|
|
||||||
## Tests et validation
|
|
||||||
|
|
||||||
⚠️ **Aucun test automatisé actuellement** - À implémenter en priorité 4
|
|
||||||
|
|
||||||
Pour tester manuellement :
|
|
||||||
1. Installer l'extension Alby
|
|
||||||
2. Se connecter via NostrConnect (use.nsec.app)
|
|
||||||
3. Publier un article avec invoice
|
|
||||||
4. Ouvrir l'article depuis un autre compte
|
|
||||||
5. Payer et vérifier le déblocage du contenu privé
|
|
||||||
@ -1,244 +0,0 @@
|
|||||||
# Éléments restants à implémenter (Mis à jour après migration Alby)
|
|
||||||
|
|
||||||
**Auteur** : Équipe 4NK
|
|
||||||
|
|
||||||
## ✅ Éléments déjà implémentés
|
|
||||||
|
|
||||||
1. ✅ **Publication d'articles** - Fait
|
|
||||||
- `pages/publish.tsx` existe
|
|
||||||
- `components/ArticleEditor.tsx` existe
|
|
||||||
- `lib/articlePublisher.ts` existe
|
|
||||||
- ⚠️ Limitation : Nécessite la clé privée (à améliorer avec signature distante NIP-46)
|
|
||||||
|
|
||||||
2. ✅ **Envoi de contenu privé après paiement** - Fait
|
|
||||||
- Intégré dans `lib/payment.ts` (méthode `waitForArticlePayment`)
|
|
||||||
- `lib/articlePublisher.ts` a la méthode `sendPrivateContent()`
|
|
||||||
|
|
||||||
3. ✅ **API Routes Rizful** - Plus nécessaire
|
|
||||||
- Remplacé par Alby/WebLN (pas besoin d'API routes)
|
|
||||||
|
|
||||||
4. ✅ **Validation des signatures zap receipts** - Fait
|
|
||||||
- `lib/zapVerification.ts` existe avec vérification complète
|
|
||||||
- Intégré dans `lib/nostr.ts`
|
|
||||||
|
|
||||||
## Priorité 1 - Fonctionnalités critiques ✅ COMPLÉTÉE
|
|
||||||
|
|
||||||
### 1. Signature distante pour publication d'articles (NIP-46) ✅
|
|
||||||
**Status** : Amélioré (utilise clé privée si disponible)
|
|
||||||
|
|
||||||
**Description** : La publication utilise maintenant la clé privée si disponible via NostrConnect. Support amélioré dans `lib/nostrRemoteSigner.ts`.
|
|
||||||
|
|
||||||
**Fichiers modifiés** :
|
|
||||||
- ✅ `lib/nostrRemoteSigner.ts` : Support amélioré
|
|
||||||
- ✅ `components/ArticleEditor.tsx` : Utilisation améliorée
|
|
||||||
- ✅ `lib/articlePublisher.ts` : Clé privée optionnelle
|
|
||||||
|
|
||||||
### 2. Génération d'invoice côté auteur ✅
|
|
||||||
**Status** : Complété
|
|
||||||
|
|
||||||
**Description** : L'auteur crée maintenant l'invoice lors de la publication et la stocke dans les tags de l'événement Nostr.
|
|
||||||
|
|
||||||
**Fichiers modifiés** :
|
|
||||||
- ✅ `lib/articlePublisher.ts` : Création d'invoice lors de la publication
|
|
||||||
- ✅ `lib/payment.ts` : Utilisation prioritaire de l'invoice depuis les tags
|
|
||||||
- ✅ `types/nostr.ts` : Ajout de `invoice` et `paymentHash` à l'article
|
|
||||||
- ✅ `lib/nostr.ts` : Parsing des tags invoice depuis les événements
|
|
||||||
|
|
||||||
### 3. Parsing des tags invoice depuis les événements Nostr ✅
|
|
||||||
**Status** : Complété
|
|
||||||
|
|
||||||
**Description** : Les invoices sont maintenant récupérées directement depuis les tags des événements Nostr.
|
|
||||||
|
|
||||||
**Fichiers modifiés** :
|
|
||||||
- ✅ `lib/nostr.ts` : Parsing des tags `invoice` et `payment_hash`
|
|
||||||
- ✅ `lib/payment.ts` : Utilisation prioritaire des tags avant localStorage
|
|
||||||
|
|
||||||
## Priorité 2 - Améliorations UX/UI ✅ COMPLÉTÉE
|
|
||||||
|
|
||||||
### 3. QR Code pour les factures Lightning ✅
|
|
||||||
**Status** : Complété
|
|
||||||
|
|
||||||
**Description** : QR code ajouté dans la modal de paiement pour faciliter les paiements mobiles.
|
|
||||||
|
|
||||||
**Fichiers modifiés** :
|
|
||||||
- ✅ `components/PaymentModal.tsx` : Composant QR code intégré
|
|
||||||
- ✅ `package.json` : Ajout de `react-qr-code`
|
|
||||||
|
|
||||||
### 4. Gestion de l'expiration des factures ✅
|
|
||||||
**Status** : Complété
|
|
||||||
|
|
||||||
**Description** : Timer en temps réel avec compte à rebours et message d'expiration.
|
|
||||||
|
|
||||||
**Fichiers modifiés** :
|
|
||||||
- ✅ `components/PaymentModal.tsx` : Timer d'expiration avec format MM:SS
|
|
||||||
- ✅ Affichage visuel (rouge si < 60 secondes)
|
|
||||||
- ✅ Message d'expiration si la facture expire
|
|
||||||
|
|
||||||
### 5. Retry logic et gestion d'erreurs robuste ✅
|
|
||||||
**Status** : Complété
|
|
||||||
|
|
||||||
**Description** : Retry automatique avec backoff exponentiel et gestion d'erreurs améliorée.
|
|
||||||
|
|
||||||
**Fichiers créés/modifiés** :
|
|
||||||
- ✅ `lib/retry.ts` : Utilitaire de retry avec backoff exponentiel
|
|
||||||
- ✅ `lib/alby.ts` : Intégration du retry pour `createInvoice` et `sendPayment`
|
|
||||||
- ✅ `lib/payment.ts` : Gestion d'erreurs améliorée
|
|
||||||
- ✅ `components/ArticleCard.tsx` : Messages d'erreur améliorés
|
|
||||||
- ✅ `components/PaymentModal.tsx` : Gestion des erreurs utilisateur
|
|
||||||
|
|
||||||
### 6. Détection et guide d'installation Alby ✅
|
|
||||||
**Status** : Complété
|
|
||||||
|
|
||||||
**Description** : Détection automatique et guide d'installation d'Alby.
|
|
||||||
|
|
||||||
**Fichiers créés/modifiés** :
|
|
||||||
- ✅ `components/AlbyInstaller.tsx` : Composant pour guider l'installation
|
|
||||||
- ✅ `components/PaymentModal.tsx` : Intégration du composant AlbyInstaller
|
|
||||||
|
|
||||||
## Priorité 3 - Fonctionnalités avancées
|
|
||||||
|
|
||||||
### 7. Filtrage et recherche d'articles
|
|
||||||
**Status** : Non implémenté
|
|
||||||
|
|
||||||
**Description** : Permettre aux utilisateurs de rechercher et filtrer les articles.
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Barre de recherche par titre/contenu
|
|
||||||
- Filtres (par auteur, date, prix)
|
|
||||||
- Tri (date, popularité)
|
|
||||||
|
|
||||||
**Fichiers à créer** :
|
|
||||||
- `components/ArticleFilters.tsx`
|
|
||||||
- `components/SearchBar.tsx`
|
|
||||||
|
|
||||||
**Fichiers à modifier** :
|
|
||||||
- `pages/index.tsx` : Ajouter filtres et recherche
|
|
||||||
- `hooks/useArticles.ts` : Ajouter logique de filtrage
|
|
||||||
|
|
||||||
### 8. Profil utilisateur et articles de l'utilisateur
|
|
||||||
**Status** : Non implémenté
|
|
||||||
|
|
||||||
**Description** : Page de profil affichant les articles de l'utilisateur connecté.
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Page `/profile` ou `/user/[pubkey]`
|
|
||||||
- Liste des articles publiés par l'utilisateur
|
|
||||||
- Statistiques (vues, paiements reçus)
|
|
||||||
|
|
||||||
**Fichiers à créer** :
|
|
||||||
- `pages/profile.tsx` ou `pages/user/[pubkey].tsx`
|
|
||||||
- `components/UserProfile.tsx`
|
|
||||||
- `components/UserArticles.tsx`
|
|
||||||
|
|
||||||
### 9. Système de notifications
|
|
||||||
**Status** : Non implémenté
|
|
||||||
|
|
||||||
**Description** : Notifier l'utilisateur des nouveaux paiements, nouveaux articles, etc.
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Notifications en temps réel via relay Nostr
|
|
||||||
- Badge de notification dans l'UI
|
|
||||||
- Centre de notifications
|
|
||||||
|
|
||||||
**Fichiers à créer** :
|
|
||||||
- `components/NotificationCenter.tsx`
|
|
||||||
- `hooks/useNotifications.ts`
|
|
||||||
|
|
||||||
### 10. Amélioration du stockage du contenu privé
|
|
||||||
**Status** : Utilise localStorage (temporaire)
|
|
||||||
|
|
||||||
**Description** : Le contenu privé est actuellement stocké dans localStorage, ce qui n'est pas idéal pour la production.
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Utiliser une base de données ou un service de stockage
|
|
||||||
- Gestion de l'expiration des contenus stockés
|
|
||||||
- Sauvegarde sécurisée des clés privées des auteurs
|
|
||||||
|
|
||||||
**Fichiers à modifier/créer** :
|
|
||||||
- `lib/articlePublisher.ts` : Utiliser un service de stockage
|
|
||||||
- `lib/storage.ts` : Service de stockage (optionnel, peut être DB externe)
|
|
||||||
|
|
||||||
## Priorité 4 - Qualité et maintenance
|
|
||||||
|
|
||||||
### 11. Tests
|
|
||||||
**Status** : Aucun test
|
|
||||||
|
|
||||||
**Description** : Implémenter des tests unitaires, d'intégration et E2E.
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Tests unitaires pour les services (`lib/nostr.ts`, `lib/alby.ts`, `lib/payment.ts`)
|
|
||||||
- Tests de composants React
|
|
||||||
- Tests d'intégration pour le flux de paiement
|
|
||||||
- Tests E2E avec Playwright ou Cypress
|
|
||||||
|
|
||||||
**Fichiers à créer** :
|
|
||||||
- Configuration Jest/Vitest
|
|
||||||
- Tests dans `__tests__/` ou `*.test.ts`
|
|
||||||
- Configuration E2E
|
|
||||||
|
|
||||||
**Dépendances à ajouter** :
|
|
||||||
- Framework de test (Jest, Vitest)
|
|
||||||
- React Testing Library
|
|
||||||
- Playwright ou Cypress
|
|
||||||
|
|
||||||
### 12. Documentation utilisateur
|
|
||||||
**Status** : Documentation technique seulement
|
|
||||||
|
|
||||||
**Description** : Créer une documentation pour les utilisateurs finaux.
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Guide d'utilisation
|
|
||||||
- FAQ
|
|
||||||
- Tutoriel de publication d'articles
|
|
||||||
- Guide de paiement avec Alby
|
|
||||||
|
|
||||||
**Fichiers à créer** :
|
|
||||||
- `docs/user-guide.md`
|
|
||||||
- `docs/faq.md`
|
|
||||||
- Potentiellement une page `/docs` ou `/help`
|
|
||||||
|
|
||||||
### 13. Analytics et monitoring
|
|
||||||
**Status** : Non implémenté
|
|
||||||
|
|
||||||
**Description** : Suivre l'utilisation de l'application et les métriques de performance.
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Tracking des événements (paiements, publications, connexions)
|
|
||||||
- Métriques de performance
|
|
||||||
- Logging structuré
|
|
||||||
- Intégration avec un service d'analytics (optionnel)
|
|
||||||
|
|
||||||
**Fichiers à créer** :
|
|
||||||
- `lib/analytics.ts`
|
|
||||||
|
|
||||||
## Résumé par priorité
|
|
||||||
|
|
||||||
### Priorité 1 (Critique) - ✅ COMPLÉTÉE (3 éléments)
|
|
||||||
1. ✅ Signature distante pour publication (NIP-46) - Amélioré
|
|
||||||
2. ✅ Génération d'invoice côté auteur - Complété
|
|
||||||
3. ✅ Parsing des tags invoice depuis les événements - Complété
|
|
||||||
|
|
||||||
### Priorité 2 (Important) - ✅ COMPLÉTÉE (4 éléments)
|
|
||||||
4. ✅ QR Code pour factures - Complété
|
|
||||||
5. ✅ Gestion expiration factures - Complété
|
|
||||||
6. ✅ Retry logic et gestion d'erreurs - Complété
|
|
||||||
7. ✅ Détection et guide d'installation Alby - Complété
|
|
||||||
|
|
||||||
### Priorité 3 (Améliorations) - En attente (4 éléments)
|
|
||||||
8. Filtrage et recherche
|
|
||||||
9. Profil utilisateur
|
|
||||||
10. Système de notifications
|
|
||||||
11. Amélioration du stockage du contenu privé
|
|
||||||
|
|
||||||
### Priorité 4 (Qualité) - En attente (3 éléments)
|
|
||||||
12. Tests
|
|
||||||
13. Documentation utilisateur
|
|
||||||
14. Analytics et monitoring
|
|
||||||
|
|
||||||
**Total : 7 éléments complétés, 7 éléments restants**
|
|
||||||
|
|
||||||
## Notes importantes
|
|
||||||
|
|
||||||
- Les éléments Rizful (API routes, webhooks) ne sont plus nécessaires avec Alby
|
|
||||||
- La génération d'identités via Rizful n'est plus nécessaire
|
|
||||||
- Webhooks ne sont pas nécessaires avec Alby car on utilise zap receipts pour la vérification
|
|
||||||
@ -1,276 +0,0 @@
|
|||||||
# Éléments restants à implémenter
|
|
||||||
|
|
||||||
**Auteur** : Équipe 4NK
|
|
||||||
|
|
||||||
## Priorité 1 - Fonctionnalités critiques
|
|
||||||
|
|
||||||
### 1. Publication d'articles (côté auteur)
|
|
||||||
**Status** : Non implémenté
|
|
||||||
|
|
||||||
**Description** : Permettre aux auteurs de créer et publier des articles avec aperçus et contenu payant.
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Page/interface pour créer un nouvel article
|
|
||||||
- Formulaire avec titre, aperçu (contenu public), contenu complet (contenu privé)
|
|
||||||
- Publication de la note publique (kind:1) avec tags `title`, `preview`, `zap`
|
|
||||||
- Stockage du contenu privé pour envoi après paiement
|
|
||||||
- Intégration avec le système de paiement
|
|
||||||
|
|
||||||
**Fichiers à créer** :
|
|
||||||
- `pages/create.tsx` ou `pages/publish.tsx` : Page de création d'article
|
|
||||||
- `components/ArticleEditor.tsx` : Composant d'édition d'article
|
|
||||||
- `lib/articlePublisher.ts` : Service pour publier des articles
|
|
||||||
|
|
||||||
### 2. Envoi de contenu privé après paiement
|
|
||||||
**Status** : Partiellement implémenté (réception seulement)
|
|
||||||
|
|
||||||
**Description** : Une fois le paiement confirmé, l'auteur doit automatiquement envoyer le contenu privé chiffré au lecteur.
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Service/worker pour surveiller les paiements confirmés
|
|
||||||
- Envoi automatique de message privé (kind:4) chiffré avec NIP-04
|
|
||||||
- Tag `e` dans le message privé pour lier à l'article
|
|
||||||
- Stockage temporaire du contenu privé jusqu'au paiement
|
|
||||||
|
|
||||||
**Fichiers à modifier/créer** :
|
|
||||||
- `lib/articlePublisher.ts` : Méthode pour envoyer le contenu privé
|
|
||||||
- `lib/payment.ts` : Intégration de l'envoi après paiement confirmé
|
|
||||||
|
|
||||||
### 3. API Routes Next.js pour protéger la clé API Rizful
|
|
||||||
**Status** : Non implémenté (sécurité critique)
|
|
||||||
|
|
||||||
**Description** : La clé API Rizful est actuellement exposée côté client (NEXT_PUBLIC_*). Il faut créer des API routes pour protéger la clé.
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- API route `/api/rizful/invoice` pour créer des factures
|
|
||||||
- API route `/api/rizful/payment/[hash]` pour vérifier les paiements
|
|
||||||
- API route `/api/rizful/identity` pour générer des identités (optionnel)
|
|
||||||
- Stockage sécurisé de la clé API côté serveur
|
|
||||||
- Validation des requêtes côté serveur
|
|
||||||
|
|
||||||
**Fichiers à créer** :
|
|
||||||
- `pages/api/rizful/invoice.ts`
|
|
||||||
- `pages/api/rizful/payment/[hash].ts`
|
|
||||||
- `pages/api/rizful/identity.ts` (optionnel)
|
|
||||||
|
|
||||||
**Fichiers à modifier** :
|
|
||||||
- `lib/rizful.ts` : Utiliser les API routes au lieu d'appels directs
|
|
||||||
- `.env.local` : Changer `NEXT_PUBLIC_RIZFUL_API_KEY` en `RIZFUL_API_KEY` (sans NEXT_PUBLIC)
|
|
||||||
|
|
||||||
### 4. Validation des signatures des zap receipts
|
|
||||||
**Status** : Non implémenté
|
|
||||||
|
|
||||||
**Description** : Actuellement, on vérifie seulement l'existence d'un zap receipt, mais pas sa signature ni l'identité du payeur.
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Vérification de la signature du zap receipt (kind:9735)
|
|
||||||
- Validation que le paiement provient bien de l'utilisateur connecté
|
|
||||||
- Vérification du montant exact du paiement
|
|
||||||
|
|
||||||
**Fichiers à modifier** :
|
|
||||||
- `lib/nostr.ts` : Méthode `checkZapReceipt()` - ajouter validation de signature
|
|
||||||
|
|
||||||
## Priorité 2 - Améliorations UX/UI
|
|
||||||
|
|
||||||
### 5. QR Code pour les factures Lightning
|
|
||||||
**Status** : Non implémenté
|
|
||||||
|
|
||||||
**Description** : Ajouter un QR code dans la modal de paiement pour faciliter les paiements mobiles.
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Bibliothèque de génération de QR code (ex: `qrcode.react` ou `react-qr-code`)
|
|
||||||
- Affichage du QR code dans `PaymentModal`
|
|
||||||
- Taille et style adaptés
|
|
||||||
|
|
||||||
**Fichiers à modifier** :
|
|
||||||
- `components/PaymentModal.tsx` : Ajouter composant QR code
|
|
||||||
- `package.json` : Ajouter dépendance QR code
|
|
||||||
|
|
||||||
### 6. Gestion de l'expiration des factures
|
|
||||||
**Status** : Partiellement implémenté
|
|
||||||
|
|
||||||
**Description** : Les factures expirent mais l'UI ne le montre pas clairement à l'utilisateur.
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Timer/compte à rebours dans la modal
|
|
||||||
- Message d'expiration si la facture expire
|
|
||||||
- Bouton pour régénérer une nouvelle facture
|
|
||||||
|
|
||||||
**Fichiers à modifier** :
|
|
||||||
- `components/PaymentModal.tsx` : Ajouter timer d'expiration
|
|
||||||
|
|
||||||
### 7. Retry logic et gestion d'erreurs robuste
|
|
||||||
**Status** : Basique
|
|
||||||
|
|
||||||
**Description** : Améliorer la gestion des erreurs réseau et des échecs d'API.
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Retry automatique avec backoff exponentiel
|
|
||||||
- Messages d'erreur plus explicites pour l'utilisateur
|
|
||||||
- Gestion des timeouts réseau
|
|
||||||
- Logging structuré des erreurs
|
|
||||||
|
|
||||||
**Fichiers à modifier** :
|
|
||||||
- `lib/rizful.ts` : Ajouter retry logic dans les méthodes fetch
|
|
||||||
- `lib/payment.ts` : Améliorer gestion d'erreurs
|
|
||||||
- `components/ArticleCard.tsx` : Messages d'erreur améliorés
|
|
||||||
|
|
||||||
### 8. Webhooks pour notifications de paiement
|
|
||||||
**Status** : Non implémenté (utilisation de polling actuellement)
|
|
||||||
|
|
||||||
**Description** : Remplacer le polling par des webhooks pour une réactivité en temps réel.
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- API route `/api/webhooks/rizful` pour recevoir les webhooks
|
|
||||||
- Validation de la signature du webhook (si Rizful le supporte)
|
|
||||||
- Mise à jour automatique de l'état de paiement
|
|
||||||
- Alternative au polling actuel
|
|
||||||
|
|
||||||
**Fichiers à créer** :
|
|
||||||
- `pages/api/webhooks/rizful.ts`
|
|
||||||
|
|
||||||
**Fichiers à modifier** :
|
|
||||||
- `lib/payment.ts` : Utiliser webhooks si disponibles, fallback sur polling
|
|
||||||
|
|
||||||
## Priorité 3 - Fonctionnalités avancées
|
|
||||||
|
|
||||||
### 9. Génération d'identités Nostr via Rizful
|
|
||||||
**Status** : Code présent mais non utilisé
|
|
||||||
|
|
||||||
**Description** : La méthode `generateIdentity()` existe mais n'est pas intégrée dans le flux utilisateur.
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Option pour créer une nouvelle identité Nostr lors de l'inscription
|
|
||||||
- Stockage sécurisé des clés privées générées
|
|
||||||
- Intégration avec le système d'authentification
|
|
||||||
|
|
||||||
**Fichiers à créer/modifier** :
|
|
||||||
- `components/IdentityGenerator.tsx` : Composant pour générer des identités
|
|
||||||
- `hooks/useIdentity.ts` : Hook pour gérer les identités
|
|
||||||
|
|
||||||
### 10. Filtrage et recherche d'articles
|
|
||||||
**Status** : Non implémenté
|
|
||||||
|
|
||||||
**Description** : Permettre aux utilisateurs de rechercher et filtrer les articles.
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Barre de recherche par titre/contenu
|
|
||||||
- Filtres (par auteur, date, prix)
|
|
||||||
- Tri (date, popularité)
|
|
||||||
|
|
||||||
**Fichiers à créer** :
|
|
||||||
- `components/ArticleFilters.tsx`
|
|
||||||
- `components/SearchBar.tsx`
|
|
||||||
|
|
||||||
**Fichiers à modifier** :
|
|
||||||
- `pages/index.tsx` : Ajouter filtres et recherche
|
|
||||||
- `hooks/useArticles.ts` : Ajouter logique de filtrage
|
|
||||||
|
|
||||||
### 11. Profil utilisateur et articles de l'utilisateur
|
|
||||||
**Status** : Non implémenté
|
|
||||||
|
|
||||||
**Description** : Page de profil affichant les articles de l'utilisateur connecté.
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Page `/profile` ou `/user/[pubkey]`
|
|
||||||
- Liste des articles publiés par l'utilisateur
|
|
||||||
- Statistiques (vues, paiements reçus)
|
|
||||||
|
|
||||||
**Fichiers à créer** :
|
|
||||||
- `pages/profile.tsx` ou `pages/user/[pubkey].tsx`
|
|
||||||
- `components/UserProfile.tsx`
|
|
||||||
- `components/UserArticles.tsx`
|
|
||||||
|
|
||||||
### 12. Système de notifications
|
|
||||||
**Status** : Non implémenté
|
|
||||||
|
|
||||||
**Description** : Notifier l'utilisateur des nouveaux paiements, nouveaux articles, etc.
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Notifications en temps réel via relay Nostr
|
|
||||||
- Badge de notification dans l'UI
|
|
||||||
- Centre de notifications
|
|
||||||
|
|
||||||
**Fichiers à créer** :
|
|
||||||
- `components/NotificationCenter.tsx`
|
|
||||||
- `hooks/useNotifications.ts`
|
|
||||||
|
|
||||||
## Priorité 4 - Qualité et maintenance
|
|
||||||
|
|
||||||
### 13. Tests
|
|
||||||
**Status** : Aucun test
|
|
||||||
|
|
||||||
**Description** : Implémenter des tests unitaires, d'intégration et E2E.
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Tests unitaires pour les services (`lib/nostr.ts`, `lib/rizful.ts`, `lib/payment.ts`)
|
|
||||||
- Tests de composants React
|
|
||||||
- Tests d'intégration pour le flux de paiement
|
|
||||||
- Tests E2E avec Playwright ou Cypress
|
|
||||||
|
|
||||||
**Fichiers à créer** :
|
|
||||||
- Configuration Jest/Vitest
|
|
||||||
- Tests dans `__tests__/` ou `*.test.ts`
|
|
||||||
- Configuration E2E
|
|
||||||
|
|
||||||
**Dépendances à ajouter** :
|
|
||||||
- Framework de test (Jest, Vitest)
|
|
||||||
- React Testing Library
|
|
||||||
- Playwright ou Cypress
|
|
||||||
|
|
||||||
### 14. Documentation utilisateur
|
|
||||||
**Status** : Documentation technique seulement
|
|
||||||
|
|
||||||
**Description** : Créer une documentation pour les utilisateurs finaux.
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Guide d'utilisation
|
|
||||||
- FAQ
|
|
||||||
- Tutoriel de publication d'articles
|
|
||||||
- Guide de paiement
|
|
||||||
|
|
||||||
**Fichiers à créer** :
|
|
||||||
- `docs/user-guide.md`
|
|
||||||
- `docs/faq.md`
|
|
||||||
- Potentiellement une page `/docs` ou `/help`
|
|
||||||
|
|
||||||
### 15. Analytics et monitoring
|
|
||||||
**Status** : Non implémenté
|
|
||||||
|
|
||||||
**Description** : Suivre l'utilisation de l'application et les métriques de performance.
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Tracking des événements (paiements, publications, connexions)
|
|
||||||
- Métriques de performance
|
|
||||||
- Logging structuré
|
|
||||||
- Intégration avec un service d'analytics (optionnel)
|
|
||||||
|
|
||||||
**Fichiers à créer** :
|
|
||||||
- `lib/analytics.ts`
|
|
||||||
|
|
||||||
## Résumé par priorité
|
|
||||||
|
|
||||||
### Priorité 1 (Critique) - 4 éléments
|
|
||||||
1. Publication d'articles
|
|
||||||
2. Envoi de contenu privé après paiement
|
|
||||||
3. API Routes pour protéger la clé API
|
|
||||||
4. Validation des signatures zap receipts
|
|
||||||
|
|
||||||
### Priorité 2 (Important) - 4 éléments
|
|
||||||
5. QR Code pour factures
|
|
||||||
6. Gestion expiration factures
|
|
||||||
7. Retry logic et gestion d'erreurs
|
|
||||||
8. Webhooks pour paiements
|
|
||||||
|
|
||||||
### Priorité 3 (Améliorations) - 4 éléments
|
|
||||||
9. Génération d'identités
|
|
||||||
10. Filtrage et recherche
|
|
||||||
11. Profil utilisateur
|
|
||||||
12. Système de notifications
|
|
||||||
|
|
||||||
### Priorité 4 (Qualité) - 3 éléments
|
|
||||||
13. Tests
|
|
||||||
14. Documentation utilisateur
|
|
||||||
15. Analytics et monitoring
|
|
||||||
|
|
||||||
**Total : 15 éléments à implémenter**
|
|
||||||
@ -1,295 +0,0 @@
|
|||||||
# Analyse des tâches restantes - Nostr Paywall
|
|
||||||
|
|
||||||
**Date** : Décembre 2024
|
|
||||||
**Auteur** : Équipe 4NK
|
|
||||||
|
|
||||||
## 🔴 Bugs identifiés
|
|
||||||
|
|
||||||
### 1. Bug dans `components/ArticleCard.tsx` - Variable non définie
|
|
||||||
**Ligne** : 33
|
|
||||||
**Problème** : Utilisation de `handleUnlockClick` qui n'existe pas
|
|
||||||
**Correction** : Remplacer par `handleUnlock` (défini dans le hook `useArticlePayment`)
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// ❌ Actuel (ligne 33)
|
|
||||||
onUnlock={handleUnlockClick}
|
|
||||||
|
|
||||||
// ✅ Devrait être
|
|
||||||
onUnlock={handleUnlock}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Impact** : Le bouton "Unlock" ne fonctionne pas sur les articles
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ⚠️ Problèmes de code
|
|
||||||
|
|
||||||
### 2. Utilisation de `console.log` dans le code de production
|
|
||||||
**Fichiers concernés** :
|
|
||||||
- `lib/nostrconnect.ts` : lignes 72, 77, 109
|
|
||||||
- `lib/nostrconnectMessageHandler.ts` : lignes 38, 64, 91, 116
|
|
||||||
- `lib/paymentPolling.ts` : ligne 85
|
|
||||||
- `lib/articleInvoice.ts` : ligne 19
|
|
||||||
- `lib/nostrEventParsing.ts` : ligne 43
|
|
||||||
- `hooks/useArticlePayment.ts` : lignes 39, 70
|
|
||||||
- `pages/profile.tsx` : ligne 57
|
|
||||||
|
|
||||||
**Problème** : Violation de la règle ESLint `no-console: warn` (seuls `console.warn` et `console.error` sont autorisés)
|
|
||||||
|
|
||||||
**Action** : Remplacer tous les `console.log` par `console.error` ou supprimer les logs de debug
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3. Utilisation de `any` dans `lib/alby.ts`
|
|
||||||
**Lignes** : 8, 14, 18
|
|
||||||
**Problème** : Utilisation de `(window as any).webln` et `any` pour le type WebLN
|
|
||||||
|
|
||||||
**Action** : Créer une interface TypeScript pour WebLN ou utiliser un type plus strict
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 4. Non-null assertion dans `lib/storage/indexedDB.ts`
|
|
||||||
**Lignes** : 89, 114, 158
|
|
||||||
**Problème** : Utilisation de `this.db!` (non-null assertion) alors que `this.db` peut être null
|
|
||||||
|
|
||||||
**Action** : Ajouter des vérifications explicites avant utilisation
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📋 Fonctionnalités manquantes (documentées)
|
|
||||||
|
|
||||||
### Priorité 3 - Améliorations du profil utilisateur
|
|
||||||
|
|
||||||
#### 1. Statistiques détaillées (vues, paiements)
|
|
||||||
**Status** : ⏳ À venir
|
|
||||||
**Fichiers concernés** : `components/UserProfile.tsx`, `pages/profile.tsx`
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Compteur de vues par article
|
|
||||||
- Compteur de paiements reçus
|
|
||||||
- Revenus totaux (en sats)
|
|
||||||
- Graphiques de statistiques (optionnel)
|
|
||||||
|
|
||||||
**Complexité** : Moyenne
|
|
||||||
**Dépendances** : Nécessite de suivre les événements de lecture et les zap receipts
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### 2. Édition/suppression d'articles
|
|
||||||
**Status** : ⏳ À venir
|
|
||||||
**Fichiers concernés** : `components/UserArticles.tsx`, `pages/profile.tsx`
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Bouton "Edit" sur chaque article
|
|
||||||
- Formulaire d'édition (pré-rempli avec les données actuelles)
|
|
||||||
- Publication d'un événement de mise à jour (kind:1 avec tag `e` pointant vers l'article original)
|
|
||||||
- Bouton "Delete" (marquer comme supprimé ou supprimer du relay)
|
|
||||||
- Confirmation avant suppression
|
|
||||||
|
|
||||||
**Complexité** : Moyenne à élevée
|
|
||||||
**Dépendances** : Gestion des événements de mise à jour Nostr
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Priorité 3 - Améliorations des notifications
|
|
||||||
|
|
||||||
#### 3. Types supplémentaires de notifications
|
|
||||||
**Status** : ⏳ À venir
|
|
||||||
**Fichiers concernés** : `lib/notifications.ts`, `types/notifications.ts`, `components/NotificationCenter.tsx`
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Notifications de mentions (kind:1 avec tag `p` mentionnant l'utilisateur)
|
|
||||||
- Notifications de commentaires (réponses à des articles)
|
|
||||||
- Notifications de partages (reposts)
|
|
||||||
|
|
||||||
**Complexité** : Moyenne
|
|
||||||
**Dépendances** : Parsing des événements Nostr supplémentaires
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Priorité 3 - Améliorations du stockage
|
|
||||||
|
|
||||||
#### 4. Chiffrement des données sensibles
|
|
||||||
**Status** : ⏳ À venir (optionnel)
|
|
||||||
**Fichiers concernés** : `lib/storage/indexedDB.ts`, `lib/articleStorage.ts`
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Chiffrement des contenus privés stockés dans IndexedDB
|
|
||||||
- Utilisation de Web Crypto API
|
|
||||||
- Gestion des clés de chiffrement
|
|
||||||
|
|
||||||
**Complexité** : Élevée
|
|
||||||
**Dépendances** : Web Crypto API, gestion sécurisée des clés
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🧪 Tests (non planifié mais recommandé)
|
|
||||||
|
|
||||||
### Tests unitaires
|
|
||||||
**Status** : Non planifié
|
|
||||||
**Fichiers à tester** :
|
|
||||||
- `lib/nostr.ts` - Service Nostr
|
|
||||||
- `lib/alby.ts` - Service Alby/WebLN
|
|
||||||
- `lib/payment.ts` - Service de paiement
|
|
||||||
- `lib/articlePublisher.ts` - Publication d'articles
|
|
||||||
- `lib/nostrEventParsing.ts` - Parsing d'événements
|
|
||||||
|
|
||||||
**Framework recommandé** : Jest ou Vitest
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Tests de composants React
|
|
||||||
**Status** : Non planifié
|
|
||||||
**Composants à tester** :
|
|
||||||
- `components/ArticleCard.tsx`
|
|
||||||
- `components/PaymentModal.tsx`
|
|
||||||
- `components/ArticleEditor.tsx`
|
|
||||||
- `components/ConnectButton.tsx`
|
|
||||||
|
|
||||||
**Framework recommandé** : React Testing Library
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Tests d'intégration
|
|
||||||
**Status** : Non planifié
|
|
||||||
**Scénarios à tester** :
|
|
||||||
- Flux complet de publication d'article
|
|
||||||
- Flux complet de paiement et déblocage
|
|
||||||
- Connexion NostrConnect
|
|
||||||
- Recherche et filtrage
|
|
||||||
|
|
||||||
**Framework recommandé** : Playwright ou Cypress
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 Analytics et monitoring (non planifié)
|
|
||||||
|
|
||||||
### Tracking des événements
|
|
||||||
**Status** : Non planifié
|
|
||||||
**Événements à tracker** :
|
|
||||||
- Publications d'articles
|
|
||||||
- Paiements effectués
|
|
||||||
- Connexions utilisateurs
|
|
||||||
- Recherches effectuées
|
|
||||||
- Erreurs rencontrées
|
|
||||||
|
|
||||||
**Fichiers à créer** : `lib/analytics.ts`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔧 Améliorations techniques
|
|
||||||
|
|
||||||
### 1. Gestion d'erreurs améliorée
|
|
||||||
**Fichiers concernés** : Tous les services
|
|
||||||
|
|
||||||
**À implémenter** :
|
|
||||||
- Types d'erreurs personnalisés
|
|
||||||
- Messages d'erreur plus explicites pour l'utilisateur
|
|
||||||
- Logging structuré des erreurs
|
|
||||||
- Retry automatique pour les erreurs réseau
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2. Performance et optimisation
|
|
||||||
**À implémenter** :
|
|
||||||
- Lazy loading des composants
|
|
||||||
- Mémoïsation des calculs coûteux
|
|
||||||
- Optimisation des requêtes relay
|
|
||||||
- Cache des profils utilisateurs
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3. Accessibilité (a11y)
|
|
||||||
**À implémenter** :
|
|
||||||
- Support clavier complet
|
|
||||||
- Attributs ARIA appropriés
|
|
||||||
- Contraste des couleurs
|
|
||||||
- Navigation au clavier
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📝 Documentation technique
|
|
||||||
|
|
||||||
### 1. Documentation API
|
|
||||||
**À créer** :
|
|
||||||
- Documentation des services (`lib/`)
|
|
||||||
- Documentation des hooks (`hooks/`)
|
|
||||||
- Documentation des types (`types/`)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2. Guide de contribution
|
|
||||||
**À créer** :
|
|
||||||
- `CONTRIBUTING.md` - Guide pour les contributeurs
|
|
||||||
- Standards de code
|
|
||||||
- Processus de review
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 Priorités recommandées
|
|
||||||
|
|
||||||
### Priorité 1 (Critique) - Bugs
|
|
||||||
1. ✅ **Corriger le bug `handleUnlockClick`** dans `ArticleCard.tsx`
|
|
||||||
2. ✅ **Remplacer les `console.log`** par `console.error` ou supprimer
|
|
||||||
|
|
||||||
### Priorité 2 (Important) - Qualité de code
|
|
||||||
3. ✅ **Corriger les types `any`** dans `lib/alby.ts`
|
|
||||||
4. ✅ **Corriger les non-null assertions** dans `lib/storage/indexedDB.ts`
|
|
||||||
|
|
||||||
### Priorité 3 (Améliorations) - Fonctionnalités
|
|
||||||
5. ⏳ Statistiques détaillées du profil
|
|
||||||
6. ⏳ Édition/suppression d'articles
|
|
||||||
7. ⏳ Types supplémentaires de notifications
|
|
||||||
8. ⏳ Chiffrement des données sensibles (optionnel)
|
|
||||||
|
|
||||||
### Priorité 4 (Optionnel) - Qualité
|
|
||||||
9. ⏳ Tests unitaires
|
|
||||||
10. ⏳ Tests d'intégration
|
|
||||||
11. ⏳ Analytics et monitoring
|
|
||||||
12. ⏳ Documentation technique
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 Résumé
|
|
||||||
|
|
||||||
### Bugs identifiés : 1
|
|
||||||
- Bug critique dans `ArticleCard.tsx`
|
|
||||||
|
|
||||||
### Problèmes de code : 3
|
|
||||||
- Utilisation de `console.log` (violation ESLint)
|
|
||||||
- Types `any` dans `alby.ts`
|
|
||||||
- Non-null assertions dans `indexedDB.ts`
|
|
||||||
|
|
||||||
### Fonctionnalités manquantes : 4
|
|
||||||
- Statistiques détaillées du profil
|
|
||||||
- Édition/suppression d'articles
|
|
||||||
- Types supplémentaires de notifications
|
|
||||||
- Chiffrement des données sensibles (optionnel)
|
|
||||||
|
|
||||||
### Tests : 0 (non planifié)
|
|
||||||
- Tests unitaires
|
|
||||||
- Tests de composants
|
|
||||||
- Tests d'intégration
|
|
||||||
|
|
||||||
### Documentation : 2
|
|
||||||
- Documentation API
|
|
||||||
- Guide de contribution
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✅ Actions immédiates recommandées
|
|
||||||
|
|
||||||
1. **Corriger le bug `handleUnlockClick`** - Impact critique sur l'utilisation
|
|
||||||
2. **Nettoyer les `console.log`** - Conformité avec les règles ESLint
|
|
||||||
3. **Améliorer les types TypeScript** - Qualité de code
|
|
||||||
4. **Ajouter les statistiques du profil** - Amélioration UX
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📌 Notes
|
|
||||||
|
|
||||||
- L'application est fonctionnelle et prête pour la production
|
|
||||||
- Les bugs identifiés doivent être corrigés avant déploiement
|
|
||||||
- Les fonctionnalités manquantes sont des améliorations, pas des blocages
|
|
||||||
- Les tests peuvent être ajoutés progressivement
|
|
||||||
- La documentation technique facilitera la maintenance
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,4 @@
|
|||||||
import { getAlbyService } from './alby'
|
import { getAlbyService } from './alby'
|
||||||
import { paymentSplitService } from './paymentSplit'
|
|
||||||
import { calculateArticleSplit, PLATFORM_COMMISSIONS } from './platformCommissions'
|
import { calculateArticleSplit, PLATFORM_COMMISSIONS } from './platformCommissions'
|
||||||
import type { AlbyInvoice } from '@/types/alby'
|
import type { AlbyInvoice } from '@/types/alby'
|
||||||
import type { ArticleDraft } from './articlePublisher'
|
import type { ArticleDraft } from './articlePublisher'
|
||||||
|
|||||||
@ -1,7 +1,4 @@
|
|||||||
import { getAlbyService } from './alby'
|
import { calculateArticleSplit, calculateReviewSplit } from './platformCommissions'
|
||||||
import { calculateArticleSplit, calculateReviewSplit, PLATFORM_COMMISSIONS } from './platformCommissions'
|
|
||||||
import { platformTracking } from './platformTracking'
|
|
||||||
import type { AlbyInvoice } from '@/types/alby'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Automatic transfer service
|
* Automatic transfer service
|
||||||
|
|||||||
@ -37,10 +37,16 @@ export async function verifyContentDelivery(
|
|||||||
|
|
||||||
const poolWithSub = pool as SimplePoolWithSub
|
const poolWithSub = pool as SimplePoolWithSub
|
||||||
|
|
||||||
const filters = [
|
const filters: Array<{
|
||||||
|
kinds: number[]
|
||||||
|
ids?: string[]
|
||||||
|
authors: string[]
|
||||||
|
'#p': string[]
|
||||||
|
'#e': string[]
|
||||||
|
limit: number
|
||||||
|
}> = [
|
||||||
{
|
{
|
||||||
kinds: [4],
|
kinds: [4],
|
||||||
ids: messageEventId ? [messageEventId] : undefined,
|
|
||||||
authors: [authorPubkey],
|
authors: [authorPubkey],
|
||||||
'#p': [recipientPubkey],
|
'#p': [recipientPubkey],
|
||||||
'#e': [articleId],
|
'#e': [articleId],
|
||||||
@ -48,6 +54,10 @@ export async function verifyContentDelivery(
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if (messageEventId && filters[0]) {
|
||||||
|
filters[0].ids = [messageEventId]
|
||||||
|
}
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
let resolved = false
|
let resolved = false
|
||||||
const sub = poolWithSub.sub([RELAY_URL], filters)
|
const sub = poolWithSub.sub([RELAY_URL], filters)
|
||||||
|
|||||||
@ -11,7 +11,6 @@ import type { NostrProfile } from '@/types/nostr'
|
|||||||
*/
|
*/
|
||||||
export class LightningAddressService {
|
export class LightningAddressService {
|
||||||
private addressCache: Map<string, string | null> = new Map()
|
private addressCache: Map<string, string | null> = new Map()
|
||||||
private readonly CACHE_TTL = 3600000 // 1 hour
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Lightning address from Nostr profile
|
* Get Lightning address from Nostr profile
|
||||||
@ -100,4 +99,3 @@ export class LightningAddressService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const lightningAddressService = new LightningAddressService()
|
export const lightningAddressService = new LightningAddressService()
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { calculateSponsoringSplit, PLATFORM_BITCOIN_ADDRESS } from './platformCommissions'
|
import { calculateSponsoringSplit } from './platformCommissions'
|
||||||
|
import { PLATFORM_BITCOIN_ADDRESS } from './platformConfig'
|
||||||
|
|
||||||
const MEMPOOL_API_BASE = 'https://mempool.space/api'
|
const MEMPOOL_API_BASE = 'https://mempool.space/api'
|
||||||
|
|
||||||
@ -27,7 +28,7 @@ export interface TransactionVerificationResult {
|
|||||||
address: string
|
address: string
|
||||||
amount: number
|
amount: number
|
||||||
}
|
}
|
||||||
error?: string
|
error?: string | undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -120,24 +121,31 @@ export class MempoolSpaceService {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
const result: TransactionVerificationResult = {
|
||||||
valid,
|
valid,
|
||||||
confirmed,
|
confirmed,
|
||||||
confirmations,
|
confirmations,
|
||||||
authorOutput: authorOutput
|
}
|
||||||
? {
|
|
||||||
|
if (!valid) {
|
||||||
|
result.error = 'Transaction outputs do not match expected split'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authorOutput) {
|
||||||
|
result.authorOutput = {
|
||||||
address: authorOutput.scriptpubkey_address,
|
address: authorOutput.scriptpubkey_address,
|
||||||
amount: authorOutput.value,
|
amount: authorOutput.value,
|
||||||
}
|
}
|
||||||
: undefined,
|
}
|
||||||
platformOutput: platformOutput
|
|
||||||
? {
|
if (platformOutput) {
|
||||||
|
result.platformOutput = {
|
||||||
address: platformOutput.scriptpubkey_address,
|
address: platformOutput.scriptpubkey_address,
|
||||||
amount: platformOutput.value,
|
amount: platformOutput.value,
|
||||||
}
|
}
|
||||||
: undefined,
|
|
||||||
error: valid ? undefined : 'Transaction outputs do not match expected split',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const errorMessage = error instanceof Error ? error.message : 'Unknown error'
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error'
|
||||||
console.error('Error verifying sponsoring transaction', {
|
console.error('Error verifying sponsoring transaction', {
|
||||||
@ -223,4 +231,3 @@ export class MempoolSpaceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const mempoolSpaceService = new MempoolSpaceService()
|
export const mempoolSpaceService = new MempoolSpaceService()
|
||||||
|
|
||||||
|
|||||||
@ -65,6 +65,10 @@ function expandDictionary(): MnemonicIcon[] {
|
|||||||
const variantIndex = Math.floor(i / base) % variants.length
|
const variantIndex = Math.floor(i / base) % variants.length
|
||||||
const baseIcon = ALL_ICONS[baseIndex]
|
const baseIcon = ALL_ICONS[baseIndex]
|
||||||
|
|
||||||
|
if (!baseIcon) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if (variantIndex === 0) {
|
if (variantIndex === 0) {
|
||||||
expanded.push(baseIcon)
|
expanded.push(baseIcon)
|
||||||
} else {
|
} else {
|
||||||
@ -98,7 +102,10 @@ export function generateMnemonicIcons(pubkey: string): string[] {
|
|||||||
const segment = pubkey.slice(i * 8, (i + 1) * 8) || pubkey.slice(-8)
|
const segment = pubkey.slice(i * 8, (i + 1) * 8) || pubkey.slice(-8)
|
||||||
const segmentHash = hashString(segment)
|
const segmentHash = hashString(segment)
|
||||||
const combinedHash = (baseHash + segmentHash + i * 1000) % DICTIONARY.length
|
const combinedHash = (baseHash + segmentHash + i * 1000) % DICTIONARY.length
|
||||||
icons.push(DICTIONARY[combinedHash].emoji)
|
const icon = DICTIONARY[combinedHash]
|
||||||
|
if (icon) {
|
||||||
|
icons.push(icon.emoji)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return icons
|
return icons
|
||||||
|
|||||||
@ -2,10 +2,9 @@ import { nostrService } from './nostr'
|
|||||||
import { articlePublisher } from './articlePublisher'
|
import { articlePublisher } from './articlePublisher'
|
||||||
import { getStoredPrivateContent } from './articleStorage'
|
import { getStoredPrivateContent } from './articleStorage'
|
||||||
import { platformTracking } from './platformTracking'
|
import { platformTracking } from './platformTracking'
|
||||||
import { calculateArticleSplit, PLATFORM_COMMISSIONS } from './platformCommissions'
|
import { calculateArticleSplit } from './platformCommissions'
|
||||||
import { automaticTransferService } from './automaticTransfer'
|
import { automaticTransferService } from './automaticTransfer'
|
||||||
import { lightningAddressService } from './lightningAddress'
|
import { lightningAddressService } from './lightningAddress'
|
||||||
import type { SimplePoolWithSub } from '@/types/nostr-tools-extended'
|
|
||||||
|
|
||||||
const RELAY_URL = process.env.NEXT_PUBLIC_NOSTR_RELAY_URL ?? 'wss://relay.damus.io'
|
const RELAY_URL = process.env.NEXT_PUBLIC_NOSTR_RELAY_URL ?? 'wss://relay.damus.io'
|
||||||
|
|
||||||
@ -171,8 +170,7 @@ async function sendPrivateContentAfterPayment(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Track content delivery with commission information
|
// Track content delivery with commission information
|
||||||
await platformTracking.trackContentDelivery(
|
const trackingData: import('./platformTracking').ContentDeliveryTracking = {
|
||||||
{
|
|
||||||
articleId,
|
articleId,
|
||||||
articlePubkey: storedContent.authorPubkey,
|
articlePubkey: storedContent.authorPubkey,
|
||||||
recipientPubkey,
|
recipientPubkey,
|
||||||
@ -182,10 +180,13 @@ async function sendPrivateContentAfterPayment(
|
|||||||
platformCommission: expectedSplit.platform,
|
platformCommission: expectedSplit.platform,
|
||||||
timestamp,
|
timestamp,
|
||||||
verified: result.verified ?? false,
|
verified: result.verified ?? false,
|
||||||
zapReceiptId,
|
}
|
||||||
},
|
|
||||||
authorPrivateKey
|
if (zapReceiptId) {
|
||||||
)
|
trackingData.zapReceiptId = zapReceiptId
|
||||||
|
}
|
||||||
|
|
||||||
|
await platformTracking.trackContentDelivery(trackingData, authorPrivateKey)
|
||||||
|
|
||||||
// Log commission information for platform tracking
|
// Log commission information for platform tracking
|
||||||
console.log('Article payment processed with commission', {
|
console.log('Article payment processed with commission', {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { getAlbyService } from './alby'
|
import { getAlbyService } from './alby'
|
||||||
import { PLATFORM_LIGHTNING_ADDRESS, calculateArticleSplit, calculateReviewSplit } from './platformCommissions'
|
import { calculateArticleSplit, calculateReviewSplit } from './platformCommissions'
|
||||||
import type { AlbyInvoice } from '@/types/alby'
|
import type { AlbyInvoice } from '@/types/alby'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -18,7 +18,7 @@ export class PaymentSplitService {
|
|||||||
* Returns invoice for full amount (800 sats) that will be split after payment
|
* Returns invoice for full amount (800 sats) that will be split after payment
|
||||||
*/
|
*/
|
||||||
async createArticleInvoiceWithSplit(
|
async createArticleInvoiceWithSplit(
|
||||||
authorLightningAddress: string,
|
_authorLightningAddress: string,
|
||||||
articleTitle: string
|
articleTitle: string
|
||||||
): Promise<{
|
): Promise<{
|
||||||
invoice: AlbyInvoice
|
invoice: AlbyInvoice
|
||||||
@ -45,7 +45,7 @@ export class PaymentSplitService {
|
|||||||
* Returns invoice for full amount (70 sats) that will be split after payment
|
* Returns invoice for full amount (70 sats) that will be split after payment
|
||||||
*/
|
*/
|
||||||
async createReviewRewardInvoiceWithSplit(
|
async createReviewRewardInvoiceWithSplit(
|
||||||
reviewerLightningAddress: string,
|
_reviewerLightningAddress: string,
|
||||||
reviewId: string
|
reviewId: string
|
||||||
): Promise<{
|
): Promise<{
|
||||||
invoice: AlbyInvoice
|
invoice: AlbyInvoice
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { PLATFORM_NPUB, PLATFORM_BITCOIN_ADDRESS } from './platformConfig'
|
// Platform configuration is imported where needed
|
||||||
|
// This file only exports commission-related constants and functions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Platform commission configuration
|
* Platform commission configuration
|
||||||
|
|||||||
@ -157,12 +157,24 @@ export class PlatformTrackingService {
|
|||||||
const zapReceiptTag = event.tags.find((tag) => tag[0] === 'zap_receipt')?.[1]
|
const zapReceiptTag = event.tags.find((tag) => tag[0] === 'zap_receipt')?.[1]
|
||||||
const authorAmountTag = event.tags.find((tag) => tag[0] === 'author_amount')?.[1]
|
const authorAmountTag = event.tags.find((tag) => tag[0] === 'author_amount')?.[1]
|
||||||
const platformCommissionTag = event.tags.find((tag) => tag[0] === 'platform_commission')?.[1]
|
const platformCommissionTag = event.tags.find((tag) => tag[0] === 'platform_commission')?.[1]
|
||||||
deliveries.push({
|
|
||||||
|
const delivery: ContentDeliveryTracking = {
|
||||||
...data,
|
...data,
|
||||||
zapReceiptId: zapReceiptTag,
|
}
|
||||||
authorAmount: authorAmountTag ? parseInt(authorAmountTag, 10) : undefined,
|
|
||||||
platformCommission: platformCommissionTag ? parseInt(platformCommissionTag, 10) : undefined,
|
if (authorAmountTag) {
|
||||||
})
|
delivery.authorAmount = parseInt(authorAmountTag, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (platformCommissionTag) {
|
||||||
|
delivery.platformCommission = parseInt(platformCommissionTag, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zapReceiptTag) {
|
||||||
|
delivery.zapReceiptId = zapReceiptTag
|
||||||
|
}
|
||||||
|
|
||||||
|
deliveries.push(delivery)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error parsing tracking event', {
|
console.error('Error parsing tracking event', {
|
||||||
eventId: event.id,
|
eventId: event.id,
|
||||||
@ -221,10 +233,16 @@ export class PlatformTrackingService {
|
|||||||
try {
|
try {
|
||||||
const data = JSON.parse(event.content) as ContentDeliveryTracking
|
const data = JSON.parse(event.content) as ContentDeliveryTracking
|
||||||
const zapReceiptTag = event.tags.find((tag) => tag[0] === 'zap_receipt')?.[1]
|
const zapReceiptTag = event.tags.find((tag) => tag[0] === 'zap_receipt')?.[1]
|
||||||
deliveries.push({
|
|
||||||
|
const delivery: ContentDeliveryTracking = {
|
||||||
...data,
|
...data,
|
||||||
zapReceiptId: zapReceiptTag,
|
}
|
||||||
})
|
|
||||||
|
if (zapReceiptTag) {
|
||||||
|
delivery.zapReceiptId = zapReceiptTag
|
||||||
|
}
|
||||||
|
|
||||||
|
deliveries.push(delivery)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error parsing tracking event', {
|
console.error('Error parsing tracking event', {
|
||||||
eventId: event.id,
|
eventId: event.id,
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
import { getAlbyService } from './alby'
|
import { getAlbyService } from './alby'
|
||||||
import { calculateReviewSplit, PLATFORM_COMMISSIONS } from './platformCommissions'
|
import { calculateReviewSplit, PLATFORM_COMMISSIONS } from './platformCommissions'
|
||||||
import { automaticTransferService } from './automaticTransfer'
|
import { automaticTransferService } from './automaticTransfer'
|
||||||
import { platformTracking } from './platformTracking'
|
|
||||||
import { nostrService } from './nostr'
|
import { nostrService } from './nostr'
|
||||||
import { lightningAddressService } from './lightningAddress'
|
import { lightningAddressService } from './lightningAddress'
|
||||||
import { getReviewsForArticle } from './reviews'
|
|
||||||
import type { AlbyInvoice } from '@/types/alby'
|
import type { AlbyInvoice } from '@/types/alby'
|
||||||
import type { Event } from 'nostr-tools'
|
import type { Event } from 'nostr-tools'
|
||||||
|
|
||||||
@ -101,9 +99,10 @@ export class ReviewRewardService {
|
|||||||
const split = calculateReviewSplit()
|
const split = calculateReviewSplit()
|
||||||
|
|
||||||
// Get reviewer Lightning address if not provided
|
// Get reviewer Lightning address if not provided
|
||||||
let reviewerLightningAddress = request.reviewerLightningAddress
|
let reviewerLightningAddress: string | undefined = request.reviewerLightningAddress
|
||||||
if (!reviewerLightningAddress) {
|
if (!reviewerLightningAddress) {
|
||||||
reviewerLightningAddress = await lightningAddressService.getLightningAddress(request.reviewerPubkey)
|
const address = await lightningAddressService.getLightningAddress(request.reviewerPubkey)
|
||||||
|
reviewerLightningAddress = address ?? undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transfer reviewer portion
|
// Transfer reviewer portion
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { calculateSponsoringSplit, PLATFORM_COMMISSIONS, PLATFORM_BITCOIN_ADDRESS } from './platformCommissions'
|
import { calculateSponsoringSplit, PLATFORM_COMMISSIONS } from './platformCommissions'
|
||||||
|
import { PLATFORM_BITCOIN_ADDRESS } from './platformConfig'
|
||||||
import { mempoolSpaceService } from './mempoolSpace'
|
import { mempoolSpaceService } from './mempoolSpace'
|
||||||
import { sponsoringTrackingService } from './sponsoringTracking'
|
import { sponsoringTrackingService } from './sponsoringTracking'
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import { Event, EventTemplate, getEventHash, signEvent } from 'nostr-tools'
|
import { Event, EventTemplate, getEventHash, signEvent } from 'nostr-tools'
|
||||||
import { nostrService } from './nostr'
|
import { nostrService } from './nostr'
|
||||||
import { PLATFORM_NPUB } from './platformConfig'
|
import { PLATFORM_NPUB } from './platformConfig'
|
||||||
import { calculateSponsoringSplit } from './platformCommissions'
|
|
||||||
import type { SimplePoolWithSub } from '@/types/nostr-tools-extended'
|
import type { SimplePoolWithSub } from '@/types/nostr-tools-extended'
|
||||||
|
|
||||||
const RELAY_URL = process.env.NEXT_PUBLIC_NOSTR_RELAY_URL ?? 'wss://relay.damus.io'
|
const RELAY_URL = process.env.NEXT_PUBLIC_NOSTR_RELAY_URL ?? 'wss://relay.damus.io'
|
||||||
@ -117,7 +116,7 @@ export class SponsoringTrackingService {
|
|||||||
async updatePresentationSponsoring(
|
async updatePresentationSponsoring(
|
||||||
presentationArticleId: string,
|
presentationArticleId: string,
|
||||||
newTotalSponsoring: number,
|
newTotalSponsoring: number,
|
||||||
authorPrivateKey: string
|
_authorPrivateKey: string
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
// In production, this would:
|
// In production, this would:
|
||||||
@ -144,4 +143,3 @@ export class SponsoringTrackingService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const sponsoringTrackingService = new SponsoringTrackingService()
|
export const sponsoringTrackingService = new SponsoringTrackingService()
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user