lint fix wip
This commit is contained in:
parent
790b8f6e25
commit
ff7b83d829
61
docs/features-consolidated.md
Normal file
61
docs/features-consolidated.md
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# Fonctionnalités implémentées - Documentation consolidée
|
||||||
|
|
||||||
|
**Auteur** : Équipe 4NK
|
||||||
|
**Date** : 2025-01-27
|
||||||
|
|
||||||
|
## Vue d'ensemble
|
||||||
|
|
||||||
|
Ce document consolide toutes les fonctionnalités documentées dans `features/` pour référence future.
|
||||||
|
|
||||||
|
## Architecture et refactoring
|
||||||
|
|
||||||
|
### zapwall4science Refactoring
|
||||||
|
- Refactoring complet depuis Nostr Paywall
|
||||||
|
- Publication d'articles avec aperçus gratuits et contenu payant
|
||||||
|
- Paiement Lightning via Alby/WebLN
|
||||||
|
- Interface TypeScript/Next.js
|
||||||
|
- Services : Nostr pool, paiements Lightning, stockage IndexedDB avec chiffrement
|
||||||
|
|
||||||
|
## Fonctionnalités utilisateur
|
||||||
|
|
||||||
|
### Séries et média
|
||||||
|
- Système de séries avec cover images
|
||||||
|
- Support NIP-95 pour images/vidéos
|
||||||
|
- Hiérarchie : catégorie → auteur → série → articles → article
|
||||||
|
- Agrégations financières (sponsoring, paiements, tips)
|
||||||
|
|
||||||
|
### Notifications
|
||||||
|
- Surveillance des paiements en temps réel
|
||||||
|
- Badge de notification avec compteur non lus
|
||||||
|
- Centre de notifications avec tri par date
|
||||||
|
- Gestion : marquer comme lu, supprimer
|
||||||
|
- Stockage persistant dans IndexedDB
|
||||||
|
|
||||||
|
### Préférences de langue
|
||||||
|
- Stockage dans IndexedDB (migré depuis localStorage)
|
||||||
|
- Support français/anglais
|
||||||
|
- Migration automatique depuis localStorage
|
||||||
|
- Service dédié : `localeStorage`
|
||||||
|
|
||||||
|
### Gestion des clés
|
||||||
|
- Import/export de clés Nostr
|
||||||
|
- Configuration de clés dans les paramètres
|
||||||
|
- Séparation des boutons de création de compte
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### NIP-95 Endpoints
|
||||||
|
- Configuration des endpoints NIP-95
|
||||||
|
- Gestion des URLs d'upload
|
||||||
|
- Validation des uploads
|
||||||
|
|
||||||
|
### NIP-98 Authentication
|
||||||
|
- Authentification via NostrCheck
|
||||||
|
- Intégration avec les endpoints NIP-95
|
||||||
|
|
||||||
|
## Open Source
|
||||||
|
|
||||||
|
- Configuration pour contributions externes
|
||||||
|
- Templates d'issues et PR
|
||||||
|
- Code of Conduct
|
||||||
|
- Documentation des contributions
|
||||||
@ -1,150 +0,0 @@
|
|||||||
# Analyse : Note non synchronisée
|
|
||||||
|
|
||||||
## Note concernée
|
|
||||||
|
|
||||||
- **ID** : `527d83e0af20bf23c3e104974090ccc21536ece72c24eb784b3642890f63b763`
|
|
||||||
- **Pubkey** : `3c1f1844a9e9df8caa71c6f6f16f3190337c1d57d7da58180f8f33206e2d7d11`
|
|
||||||
- **Created_at** : `1767681622` (6 janvier 2026)
|
|
||||||
- **Kind** : `1`
|
|
||||||
- **Tag service** : `["service", "zapwall.fr"]`
|
|
||||||
|
|
||||||
## Filtre utilisé
|
|
||||||
|
|
||||||
Le système envoie aux relais le filtre suivant :
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"kinds": [1],
|
|
||||||
"#service": ["zapwall.fr"],
|
|
||||||
"since": 1767571200,
|
|
||||||
"limit": 1000
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- `kinds: [1]` : Notes (kind 1)
|
|
||||||
- `#service: ["zapwall.fr"]` : Tag `service` avec valeur `zapwall.fr`
|
|
||||||
- `since: 1767571200` : À partir du 5 janvier 2026 00:00:00 UTC
|
|
||||||
- `limit: 1000` : Maximum 1000 événements par relai
|
|
||||||
|
|
||||||
## Vérification de correspondance
|
|
||||||
|
|
||||||
La note **devrait** correspondre au filtre :
|
|
||||||
|
|
||||||
- ✅ **Kind** : La note est de kind `1`, correspond au filtre `kinds: [1]`
|
|
||||||
- ✅ **Tag service** : La note a le tag `["service", "zapwall.fr"]`, correspond au filtre `#service: ["zapwall.fr"]`
|
|
||||||
- ✅ **Date** : `created_at: 1767681622` (6 jan 2026) > `since: 1767571200` (5 jan 2026)
|
|
||||||
|
|
||||||
## Constat des logs
|
|
||||||
|
|
||||||
D'après les logs de synchronisation :
|
|
||||||
|
|
||||||
- **Aucun événement reçu** : Tous les relais retournent `received 0 total events, 0 with service='zapwall.fr'`
|
|
||||||
- **EOSE immédiat** : La plupart des relais envoient un signal EOSE (End of Stored Events) immédiatement après la connexion
|
|
||||||
- **Timeouts** : Certains relais timeout après 60 secondes sans retourner d'événements
|
|
||||||
|
|
||||||
## Causes possibles
|
|
||||||
|
|
||||||
### 1. Propagation limitée sur les relais
|
|
||||||
|
|
||||||
**Problème** : La note n'est peut-être pas propagée sur les relais utilisés par l'application.
|
|
||||||
|
|
||||||
**Solution** : Vérifier manuellement si la note est présente sur les relais :
|
|
||||||
- Utiliser un client Nostr (Amethyst, Damus, etc.)
|
|
||||||
- Interroger directement les relais avec le même filtre
|
|
||||||
- Vérifier si la note est visible sur d'autres plateformes
|
|
||||||
|
|
||||||
### 2. Support limité du filtre `#service`
|
|
||||||
|
|
||||||
**Problème** : Certains relais peuvent ne pas supporter correctement le filtre `#service` ou l'interpréter différemment.
|
|
||||||
|
|
||||||
**Solution** : Tester le filtre sur différents relais et vérifier si certains retournent des résultats.
|
|
||||||
|
|
||||||
### 3. Limitations des relais
|
|
||||||
|
|
||||||
**Problème** : Les relais peuvent avoir des limitations :
|
|
||||||
- Limite de temps pour les requêtes
|
|
||||||
- Limite de résultats même avec `limit: 1000`
|
|
||||||
- Indexation incomplète des tags
|
|
||||||
|
|
||||||
**Solution** : Réduire la fenêtre temporelle ou diviser les requêtes par période.
|
|
||||||
|
|
||||||
### 4. Timing de publication
|
|
||||||
|
|
||||||
**Problème** : Si la note a été publiée récemment, elle peut ne pas encore être indexée par tous les relais.
|
|
||||||
|
|
||||||
**Solution** : Attendre quelques minutes/hours et relancer la synchronisation.
|
|
||||||
|
|
||||||
### 5. Filtre trop restrictif
|
|
||||||
|
|
||||||
**Problème** : Le filtre `#service` peut être trop restrictif. Certains relais peuvent ne pas indexer ce tag correctement.
|
|
||||||
|
|
||||||
**Solution** : Envisager une approche alternative :
|
|
||||||
- Ne pas filtrer par `#service` dans la requête aux relais
|
|
||||||
- Filtrer côté client après réception des événements
|
|
||||||
- Utiliser un filtre par `pubkey` si la note provient d'un auteur connu
|
|
||||||
|
|
||||||
## Recommandations
|
|
||||||
|
|
||||||
### Court terme
|
|
||||||
|
|
||||||
1. **Vérifier la propagation** : Tester manuellement si la note est présente sur les relais principaux (relay.damus.io, relay.nostr.band, etc.)
|
|
||||||
2. **Augmenter les logs** : Ajouter plus de logs pour voir les événements reçus avant filtrage
|
|
||||||
3. **Tester sans filtre service** : Essayer une requête sans le filtre `#service` pour voir si des événements sont retournés
|
|
||||||
|
|
||||||
### Moyen terme
|
|
||||||
|
|
||||||
1. **Approche hybride** : Ne pas filtrer par `#service` côté relais, filtrer après réception
|
|
||||||
2. **Relais spécialisés** : Utiliser des relais spécialisés pour zapwall.fr si disponibles
|
|
||||||
3. **Indexation locale** : Mettre en place un cache/IndexedDB pour les événements déjà reçus
|
|
||||||
|
|
||||||
### Long terme
|
|
||||||
|
|
||||||
1. **Relai dédié** : Opérer un relai Nostr dédié pour la plateforme
|
|
||||||
2. **Propagation garantie** : S'assurer que toutes les notes publiées sont propagées sur plusieurs relais
|
|
||||||
|
|
||||||
## Code de debug
|
|
||||||
|
|
||||||
Pour tester manuellement si la note est présente sur un relai :
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Tester avec un client Nostr
|
|
||||||
const filter = {
|
|
||||||
ids: ['527d83e0af20bf23c3e104974090ccc21536ece72c24eb784b3642890f63b763']
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ou avec le filtre service
|
|
||||||
const filterService = {
|
|
||||||
kinds: [1],
|
|
||||||
'#service': ['zapwall.fr'],
|
|
||||||
since: 1767571200,
|
|
||||||
limit: 1000
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Solution appliquée
|
|
||||||
|
|
||||||
### Problème identifié
|
|
||||||
|
|
||||||
Le filtre `#service` n'est pas correctement supporté par certains relais (notamment relay.damus.io). Même si la note est présente sur le relai et correspond au filtre, le relai ne la retourne pas quand on filtre par `#service`.
|
|
||||||
|
|
||||||
### Correction
|
|
||||||
|
|
||||||
Modification de `lib/platformSync.ts` pour :
|
|
||||||
1. **Ne plus filtrer par `#service` côté relai** : Le filtre envoyé aux relais ne contient plus `"#service": ["zapwall.fr"]`
|
|
||||||
2. **Récupérer tous les kind 1** depuis `MIN_EVENT_DATE` avec le filtre `{ kinds: [1], since: 1767571200, limit: 1000 }`
|
|
||||||
3. **Filtrer côté client** : Après réception des événements, filtrer ceux qui ont `service='zapwall.fr'` avant de les traiter
|
|
||||||
|
|
||||||
Cette approche permet de :
|
|
||||||
- Récupérer la note même si le relai ne supporte pas bien le filtre `#service`
|
|
||||||
- Voir tous les événements reçus dans les logs pour debug
|
|
||||||
- Maintenir la même logique de filtrage, mais appliquée après réception
|
|
||||||
|
|
||||||
### Impact
|
|
||||||
|
|
||||||
- **Plus d'événements reçus** : Les relais retourneront plus d'événements (tous les kind 1 depuis la date)
|
|
||||||
- **Traitement côté client** : Le filtrage se fait maintenant dans le code JavaScript, ce qui est plus fiable
|
|
||||||
- **Meilleure visibilité** : Les logs montreront tous les événements reçus, permettant de confirmer si la note est bien présente
|
|
||||||
|
|
||||||
## Conclusion
|
|
||||||
|
|
||||||
Le problème était lié au support limité du filtre `#service` par certains relais. En ne filtrant plus côté relai et en filtrant après réception, la note devrait maintenant être correctement récupérée si elle est présente sur les relais utilisés.
|
|
||||||
@ -1,296 +0,0 @@
|
|||||||
# Session Summary - 2026-01-05
|
|
||||||
|
|
||||||
**Author**: Équipe 4NK
|
|
||||||
**Date**: 2026-01-05
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
This document summarizes all modifications and implementations completed during this development session, focusing on object identification, caching, payment systems, A5 pages, and payment notes.
|
|
||||||
|
|
||||||
## Major Features Implemented
|
|
||||||
|
|
||||||
### 1. Object Identification System
|
|
||||||
|
|
||||||
**Objective**: Implement a comprehensive object identification system with `id`, `hash`, `version`, and `index` fields for all objects.
|
|
||||||
|
|
||||||
**Implementation**:
|
|
||||||
- ID format: `<hash>_<index=0>_<version=0>`
|
|
||||||
- All objects now have: `id`, `hash`, `version`, `index`
|
|
||||||
- Hash generation using SHA-256 from canonical object representation
|
|
||||||
- Index management for duplicate hash handling
|
|
||||||
- Version management for object updates
|
|
||||||
|
|
||||||
**Files Modified**:
|
|
||||||
- `types/nostr.ts`: Added fields to all object interfaces
|
|
||||||
- `lib/urlGenerator.ts`: Added `buildObjectId` and `parseObjectId` functions
|
|
||||||
- `lib/hashIdGenerator.ts`: Hash generation for all object types
|
|
||||||
- `lib/nostrEventParsing.ts`: Updated to extract and construct new ID fields
|
|
||||||
- `lib/objectCache.ts`: Updated IndexedDB cache to support new ID structure
|
|
||||||
|
|
||||||
**Routes**: All object routes now use the new ID format: `https://zapwall.fr/<type>/<id>`
|
|
||||||
|
|
||||||
### 2. IndexedDB Caching System
|
|
||||||
|
|
||||||
**Objective**: Implement per-object-type caching in IndexedDB with settings storage and last sync date tracking.
|
|
||||||
|
|
||||||
**Implementation**:
|
|
||||||
- Separate IndexedDB stores for each object type (author, series, publication, review, purchase, sponsoring, review_tip)
|
|
||||||
- Settings store (excluding keys) for platform configuration
|
|
||||||
- Last synchronized day tracking for background sync resumption
|
|
||||||
- Database migration system (DB_VERSION incremented to 2)
|
|
||||||
- New indexes: `hash`, `index` for efficient lookups
|
|
||||||
|
|
||||||
**Files Modified**:
|
|
||||||
- `lib/objectCache.ts`: Complete rewrite with new structure
|
|
||||||
- `components/CacheUpdateManager.tsx`: User-facing cache update button
|
|
||||||
|
|
||||||
**Features**:
|
|
||||||
- Cache per object type
|
|
||||||
- Settings cache (excluding sensitive keys)
|
|
||||||
- Last sync date tracking
|
|
||||||
- Cache clearing and re-synchronization
|
|
||||||
|
|
||||||
### 3. Payment Objects Extension
|
|
||||||
|
|
||||||
**Objective**: Extend object/route/cache system to include article payments, sponsoring, and review acknowledgements.
|
|
||||||
|
|
||||||
**Implementation**:
|
|
||||||
- New object types: `Purchase`, `Sponsoring`, `ReviewTip`
|
|
||||||
- Routes: `/purchase/[id]`, `/sponsoring/[id]`, `/review-tip/[id]`
|
|
||||||
- Query functions: `purchaseQueries.ts`, `sponsoringQueries.ts`, `reviewTipQueries.ts`
|
|
||||||
- Cache support for all new object types
|
|
||||||
- Parsing from zap receipts (kind 9735)
|
|
||||||
|
|
||||||
**Files Created**:
|
|
||||||
- `lib/purchaseQueries.ts`
|
|
||||||
- `lib/sponsoringQueries.ts`
|
|
||||||
- `lib/reviewTipQueries.ts`
|
|
||||||
- `pages/purchase/[id].tsx`
|
|
||||||
- `pages/sponsoring/[id].tsx`
|
|
||||||
- `pages/review-tip/[id].tsx`
|
|
||||||
|
|
||||||
**Files Modified**:
|
|
||||||
- `types/nostr.ts`: Added new interfaces
|
|
||||||
- `lib/objectCache.ts`: Added cache support
|
|
||||||
- `lib/nostrEventParsing.ts`: Added parsing functions
|
|
||||||
- `lib/userContentSync.ts`: Added sync functions
|
|
||||||
|
|
||||||
### 4. A5 Page System for Publications
|
|
||||||
|
|
||||||
**Objective**: Implement A5-sized pages within series publications, supporting both Markdown and image content.
|
|
||||||
|
|
||||||
**Implementation**:
|
|
||||||
- New `Page` interface: `number`, `type: 'markdown' | 'image'`, `content`
|
|
||||||
- Pages stored in article `pages` array
|
|
||||||
- Two-column Markdown editor with live preview
|
|
||||||
- Page management: add, remove, edit pages
|
|
||||||
- Image upload similar to profile photos
|
|
||||||
- Serialization in Nostr events (JSON tag)
|
|
||||||
- Display component for published articles
|
|
||||||
|
|
||||||
**Files Created**:
|
|
||||||
- `components/MarkdownEditorTwoColumns.tsx`: Two-column editor with page management
|
|
||||||
- `components/ArticlePages.tsx`: Display component for A5 pages
|
|
||||||
|
|
||||||
**Files Modified**:
|
|
||||||
- `types/nostr.ts`: Added `Page` interface and `pages` to `Article`
|
|
||||||
- `lib/articlePublisherTypes.ts`: Added `pages` to `ArticleDraft`
|
|
||||||
- `lib/articleInvoice.ts`: Updated to include pages in JSON metadata
|
|
||||||
- `lib/metadataExtractor.ts`: Updated to extract pages from events
|
|
||||||
- `components/ArticleEditorForm.tsx`: Integrated two-column editor
|
|
||||||
- `components/ArticlePreview.tsx`: Integrated page display
|
|
||||||
|
|
||||||
### 5. Optional Text Fields
|
|
||||||
|
|
||||||
**Objective**: Add optional plain text messages to reviews, review tips, and sponsoring.
|
|
||||||
|
|
||||||
**Implementation**:
|
|
||||||
- Added `text?: string` to `Review`, `ReviewTip`, `Sponsoring` interfaces
|
|
||||||
- Parsing from Nostr event tags
|
|
||||||
- Display in UI components
|
|
||||||
- Included in zap request tags
|
|
||||||
|
|
||||||
**Files Modified**:
|
|
||||||
- `types/nostr.ts`: Added `text` field
|
|
||||||
- `lib/articleMutations.ts`: Updated `buildReviewEvent` to include text
|
|
||||||
- `lib/nostrEventParsing.ts`: Updated parsing to extract text
|
|
||||||
- `lib/zapRequestBuilder.ts`: Updated to include text in zap requests
|
|
||||||
|
|
||||||
### 6. Review, Review Tip, and Sponsoring Forms
|
|
||||||
|
|
||||||
**Objective**: Create user-facing forms for creating reviews, sending review tips, and sponsoring authors.
|
|
||||||
|
|
||||||
**Implementation**:
|
|
||||||
- `ReviewForm`: Create reviews with optional title, required content, optional text
|
|
||||||
- `ReviewTipForm`: Send tips to reviewers with optional text message
|
|
||||||
- `SponsoringForm`: Sponsor authors with optional text message (Bitcoin mainnet)
|
|
||||||
|
|
||||||
**Files Created**:
|
|
||||||
- `components/ReviewForm.tsx`
|
|
||||||
- `components/ReviewTipForm.tsx`
|
|
||||||
- `components/SponsoringForm.tsx`
|
|
||||||
|
|
||||||
**Files Modified**:
|
|
||||||
- `components/ArticleReviews.tsx`: Integrated review and tip forms
|
|
||||||
- `pages/series/[id].tsx`: Integrated review display
|
|
||||||
- `pages/author/[pubkey].tsx`: Integrated sponsoring form
|
|
||||||
- `public/locales/fr.txt` and `public/locales/en.txt`: Added translations
|
|
||||||
|
|
||||||
### 7. Full-Width Layout
|
|
||||||
|
|
||||||
**Objective**: Allow the site to take up the full screen width.
|
|
||||||
|
|
||||||
**Implementation**:
|
|
||||||
- Removed `max-w-*` constraints from all pages
|
|
||||||
- Updated layout classes across the application
|
|
||||||
|
|
||||||
**Files Modified**:
|
|
||||||
- All page components (`pages/*.tsx`)
|
|
||||||
- `components/HomeView.tsx`
|
|
||||||
|
|
||||||
### 8. Funding Gauge Priorities
|
|
||||||
|
|
||||||
**Objective**: Set priorities for funding gauges: Priority 1 for AI, Priority 2 for Anchoring.
|
|
||||||
|
|
||||||
**Implementation**:
|
|
||||||
- Updated `components/FundingGauge.tsx` to display two gauges with priorities
|
|
||||||
- Added translations for certification gauge
|
|
||||||
|
|
||||||
**Files Modified**:
|
|
||||||
- `components/FundingGauge.tsx`
|
|
||||||
- `public/locales/fr.txt` and `public/locales/en.txt`
|
|
||||||
|
|
||||||
### 9. Payment Notes System
|
|
||||||
|
|
||||||
**Objective**: Create explicit payment notes (kind 1) for all confirmed payments with project tags.
|
|
||||||
|
|
||||||
**Implementation**:
|
|
||||||
- Extended tag system with `'payment'` type
|
|
||||||
- Created `PaymentTags` interface
|
|
||||||
- Three publication functions: `publishPurchaseNote`, `publishReviewTipNote`, `publishSponsoringNote`
|
|
||||||
- Integration with payment confirmation flows
|
|
||||||
- Zap receipt query utilities
|
|
||||||
|
|
||||||
**Files Created**:
|
|
||||||
- `lib/paymentNotes.ts`: Payment note publication functions
|
|
||||||
- `lib/zapReceiptQueries.ts`: Zap receipt query utilities
|
|
||||||
|
|
||||||
**Files Modified**:
|
|
||||||
- `lib/nostrTagSystemTypes.ts`: Added `PaymentTags`
|
|
||||||
- `lib/nostrTagSystemBuild.ts`: Added `buildPaymentTags`
|
|
||||||
- `lib/paymentPollingMain.ts`: Integrated purchase note publication
|
|
||||||
|
|
||||||
**Documentation**: See `docs/payment-notes-system.md` for detailed documentation.
|
|
||||||
|
|
||||||
## Tag System Verification
|
|
||||||
|
|
||||||
Verified that all note creation functions use the `buildTags` helper:
|
|
||||||
- `buildSeriesEvent`: ✅ Uses `buildTags`
|
|
||||||
- `buildReviewEvent`: ✅ Uses `buildTags`
|
|
||||||
- `buildAuthorPresentationEvent`: ✅ Uses `buildTags`
|
|
||||||
- `buildPreviewTags`: ✅ Uses `buildTags`
|
|
||||||
- Zap requests: ✅ Include `kind_type` and relevant tags
|
|
||||||
|
|
||||||
## Technical Details
|
|
||||||
|
|
||||||
### Object ID Format
|
|
||||||
|
|
||||||
```
|
|
||||||
id: <hash>_<index>_<version>
|
|
||||||
```
|
|
||||||
|
|
||||||
- `hash`: SHA-256 hash of canonical object representation
|
|
||||||
- `index`: Index for duplicate hashes (default: 0)
|
|
||||||
- `version`: Version number for updates (default: 0)
|
|
||||||
|
|
||||||
### IndexedDB Schema
|
|
||||||
|
|
||||||
- Stores: `author`, `series`, `publication`, `review`, `purchase`, `sponsoring`, `review_tip`, `settings`
|
|
||||||
- Indexes: `hash`, `index`, `version`, `hidden`
|
|
||||||
- Version: 2 (migrated from 1)
|
|
||||||
|
|
||||||
### Payment Flow Integration
|
|
||||||
|
|
||||||
1. **Purchase**: Zap receipt → Content delivery → Payment note publication
|
|
||||||
2. **Review Tip**: Zap request → Zap receipt (via Alby) → Payment note publication (to be integrated)
|
|
||||||
3. **Sponsoring**: Bitcoin transaction → Verification → Tracking → Payment note publication (to be integrated)
|
|
||||||
|
|
||||||
## Internationalization
|
|
||||||
|
|
||||||
Added translations for:
|
|
||||||
- A5 pages (`page.*`)
|
|
||||||
- Reviews (`review.*`)
|
|
||||||
- Review tips (`reviewTip.*`)
|
|
||||||
- Sponsoring (`sponsoring.*`)
|
|
||||||
- Funding gauge priorities
|
|
||||||
- Common optional field label
|
|
||||||
|
|
||||||
## Testing Considerations
|
|
||||||
|
|
||||||
- All new code compiles without TypeScript errors
|
|
||||||
- Linter checks pass
|
|
||||||
- No fallback mechanisms (as per project rules)
|
|
||||||
- Error handling with logging
|
|
||||||
- Non-blocking payment note publication
|
|
||||||
|
|
||||||
## Known Limitations
|
|
||||||
|
|
||||||
1. **Review Tip Notes**: Automatic publication after zap receipt confirmation not yet fully integrated
|
|
||||||
2. **Sponsoring Notes**: Requires payer information at transaction submission time (currently not captured)
|
|
||||||
3. **Payment History UI**: Not yet implemented (payment notes are published but not displayed in UI)
|
|
||||||
|
|
||||||
## Next Steps
|
|
||||||
|
|
||||||
1. Complete review tip note publication integration
|
|
||||||
2. Improve sponsoring note publication with payer information capture
|
|
||||||
3. Implement payment history UI
|
|
||||||
4. Add payment aggregation queries
|
|
||||||
5. Create payment search functionality
|
|
||||||
|
|
||||||
## Files Summary
|
|
||||||
|
|
||||||
### Created Files
|
|
||||||
- `lib/purchaseQueries.ts`
|
|
||||||
- `lib/sponsoringQueries.ts`
|
|
||||||
- `lib/reviewTipQueries.ts`
|
|
||||||
- `lib/paymentNotes.ts`
|
|
||||||
- `lib/zapReceiptQueries.ts`
|
|
||||||
- `lib/zapRequestBuilder.ts`
|
|
||||||
- `components/MarkdownEditorTwoColumns.tsx`
|
|
||||||
- `components/ArticlePages.tsx`
|
|
||||||
- `components/ReviewForm.tsx`
|
|
||||||
- `components/ReviewTipForm.tsx`
|
|
||||||
- `components/SponsoringForm.tsx`
|
|
||||||
- `pages/purchase/[id].tsx`
|
|
||||||
- `pages/sponsoring/[id].tsx`
|
|
||||||
- `pages/review-tip/[id].tsx`
|
|
||||||
|
|
||||||
### Modified Files
|
|
||||||
- `types/nostr.ts`
|
|
||||||
- `lib/urlGenerator.ts`
|
|
||||||
- `lib/objectCache.ts`
|
|
||||||
- `lib/nostrEventParsing.ts`
|
|
||||||
- `lib/nostrTagSystemTypes.ts`
|
|
||||||
- `lib/nostrTagSystemBuild.ts`
|
|
||||||
- `lib/articlePublisherTypes.ts`
|
|
||||||
- `lib/articleInvoice.ts`
|
|
||||||
- `lib/metadataExtractor.ts`
|
|
||||||
- `lib/articleMutations.ts`
|
|
||||||
- `lib/paymentPollingMain.ts`
|
|
||||||
- `lib/userContentSync.ts`
|
|
||||||
- `components/ArticleEditorForm.tsx`
|
|
||||||
- `components/ArticlePreview.tsx`
|
|
||||||
- `components/ArticleReviews.tsx`
|
|
||||||
- `components/CacheUpdateManager.tsx`
|
|
||||||
- `components/FundingGauge.tsx`
|
|
||||||
- `pages/series/[id].tsx`
|
|
||||||
- `pages/author/[pubkey].tsx`
|
|
||||||
- All page layout files (removed max-w constraints)
|
|
||||||
- `public/locales/fr.txt`
|
|
||||||
- `public/locales/en.txt`
|
|
||||||
|
|
||||||
## Related Documentation
|
|
||||||
|
|
||||||
- `docs/payment-notes-system.md`: Detailed payment notes system documentation
|
|
||||||
- `docs/object-identification-system.md`: Object ID system (if exists)
|
|
||||||
- `docs/tag-system.md`: Tag system documentation (if exists)
|
|
||||||
62
docs/troubleshooting-consolidated.md
Normal file
62
docs/troubleshooting-consolidated.md
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# Résolution de problèmes - Documentation consolidée
|
||||||
|
|
||||||
|
**Auteur** : Équipe 4NK
|
||||||
|
**Date** : 2025-01-27
|
||||||
|
|
||||||
|
## Vue d'ensemble
|
||||||
|
|
||||||
|
Ce document consolide toutes les connaissances de résolution de problèmes documentées dans `fixKnowledge/` pour référence future.
|
||||||
|
|
||||||
|
## Problèmes de déploiement
|
||||||
|
|
||||||
|
### SSH Connection Errors
|
||||||
|
- **Problème** : Erreurs de connexion SSH pendant le déploiement
|
||||||
|
- **Cause** : SSH ControlMaster multiplexing connection fermée prématurément
|
||||||
|
- **Solution** : Amélioration de la gestion des erreurs SSH dans les scripts de déploiement
|
||||||
|
- **Fichiers** : `deploy.sh`
|
||||||
|
|
||||||
|
### Let's Encrypt Certificates
|
||||||
|
- **Problème** : Configuration des certificats Let's Encrypt
|
||||||
|
- **Solution** : Documentation de la configuration et du renouvellement automatique
|
||||||
|
- **Fichiers** : Configuration Nginx
|
||||||
|
|
||||||
|
### Nginx conf.d Not Loaded
|
||||||
|
- **Problème** : Configuration Nginx dans `conf.d/` non chargée
|
||||||
|
- **Solution** : Vérification de la configuration principale Nginx
|
||||||
|
|
||||||
|
## Problèmes NIP-95
|
||||||
|
|
||||||
|
### Upload 500 Error
|
||||||
|
- **Problème** : Erreur 500 lors de l'upload via NIP-95
|
||||||
|
- **Cause** : Problèmes de configuration ou d'authentification
|
||||||
|
- **Solution** : Vérification de l'authentification NIP-98 et de la configuration des endpoints
|
||||||
|
|
||||||
|
### DNS Resolution Error
|
||||||
|
- **Problème** : Erreur de résolution DNS lors de l'upload
|
||||||
|
- **Cause** : Configuration DNS incorrecte ou endpoints inaccessibles
|
||||||
|
- **Solution** : Vérification de la configuration DNS et des endpoints
|
||||||
|
|
||||||
|
## Problèmes NostrImg
|
||||||
|
|
||||||
|
### 500 Error Diagnosis
|
||||||
|
- **Problème** : Erreur 500 de NostrImg
|
||||||
|
- **Cause** : Problèmes d'authentification ou de configuration
|
||||||
|
- **Solution** : Diagnostic des erreurs et vérification de l'authentification
|
||||||
|
|
||||||
|
### HTML Response Error
|
||||||
|
- **Problème** : NostrImg retourne du HTML au lieu de JSON
|
||||||
|
- **Cause** : Problème de configuration ou de requête
|
||||||
|
- **Solution** : Vérification des en-têtes et de la configuration
|
||||||
|
|
||||||
|
## Problèmes d'authentification
|
||||||
|
|
||||||
|
### NostrCheck.me Authentication
|
||||||
|
- **Problème** : Problèmes d'authentification avec NostrCheck
|
||||||
|
- **Cause** : Configuration incorrecte ou clés invalides
|
||||||
|
- **Solution** : Vérification de la configuration NIP-98 et des clés
|
||||||
|
|
||||||
|
## Problèmes mineurs
|
||||||
|
|
||||||
|
### Favicon 404 Error
|
||||||
|
- **Problème** : Erreur 404 pour le favicon
|
||||||
|
- **Solution** : Ajout du favicon dans le répertoire public
|
||||||
@ -1,57 +0,0 @@
|
|||||||
# Account Creation Buttons Separation
|
|
||||||
|
|
||||||
**Date**: December 2024
|
|
||||||
**Auteur**: Équipe 4NK
|
|
||||||
|
|
||||||
## Objectif
|
|
||||||
|
|
||||||
Remplacer le bouton unique "Créer un compte ou importer une clé" par deux boutons distincts "Générer un nouveau compte" et "Importer une clé existante" pour améliorer la clarté de l'interface utilisateur.
|
|
||||||
|
|
||||||
## Motivations
|
|
||||||
|
|
||||||
- Améliorer la clarté de l'interface utilisateur
|
|
||||||
- Permettre aux utilisateurs de choisir directement l'action souhaitée sans étape intermédiaire
|
|
||||||
- Réduire le nombre de clics nécessaires pour accéder à la fonctionnalité d'import
|
|
||||||
|
|
||||||
## Modifications
|
|
||||||
|
|
||||||
### Composants modifiés
|
|
||||||
|
|
||||||
1. **components/CreateAccountModal.tsx** :
|
|
||||||
- Ajout d'une prop optionnelle `initialStep` pour permettre d'initialiser la modal directement au step 'import' ou 'choose'
|
|
||||||
- Modification du hook `useAccountCreation` pour accepter un paramètre `initialStep` avec valeur par défaut 'choose'
|
|
||||||
|
|
||||||
2. **components/AuthorPresentationEditor.tsx** :
|
|
||||||
- Refactorisation du composant `NoAccountView` pour afficher deux boutons distincts
|
|
||||||
- Extraction des boutons dans un composant séparé `NoAccountActionButtons` pour respecter la limite de lignes de fonction (max-lines-per-function)
|
|
||||||
- Ajout de la gestion d'état pour déterminer quel step de la modal afficher
|
|
||||||
- Suppression du paramètre `connected` inutilisé dans `AuthorPresentationFormView`
|
|
||||||
|
|
||||||
### Structure du code
|
|
||||||
|
|
||||||
- `NoAccountActionButtons` : Composant réutilisable pour les boutons d'action
|
|
||||||
- `NoAccountView` : Gère l'état de la modal et détermine quel step afficher
|
|
||||||
|
|
||||||
## Modalités de déploiement
|
|
||||||
|
|
||||||
Aucun déploiement spécial nécessaire. Les modifications sont purement frontend et seront déployées avec la prochaine version de l'application.
|
|
||||||
|
|
||||||
## Modalités d'analyse
|
|
||||||
|
|
||||||
### Vérifications à effectuer
|
|
||||||
|
|
||||||
1. Tester que le bouton "Générer un nouveau compte" ouvre la modal avec le step 'choose'
|
|
||||||
2. Tester que le bouton "Importer une clé existante" ouvre directement la modal avec le step 'import'
|
|
||||||
3. Vérifier que le comportement de la modal reste inchangé une fois ouverte
|
|
||||||
4. Vérifier que les autres usages de `CreateAccountModal` (dans `ConnectButton.tsx`) fonctionnent correctement avec la prop optionnelle
|
|
||||||
|
|
||||||
### Points d'attention
|
|
||||||
|
|
||||||
- La prop `initialStep` est optionnelle et rétrocompatible
|
|
||||||
- Le composant `NoAccountActionButtons` respecte la limite de lignes de fonction
|
|
||||||
- La fonction `NoAccountView` respecte la limite de 40 lignes après refactorisation
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,148 +0,0 @@
|
|||||||
# Fonctionnalités implémentées
|
|
||||||
|
|
||||||
**Auteur** : Équipe 4NK
|
|
||||||
|
|
||||||
## Architecture de base
|
|
||||||
|
|
||||||
### Nostr Paywall → zapwall4Science
|
|
||||||
- Publication d'articles avec aperçus gratuits et contenu payant
|
|
||||||
- Paiement Lightning via Alby/WebLN (remplacement de Rizful)
|
|
||||||
- Connexion via Alby extension (NIP-07) pour l'authentification Nostr et les paiements Lightning
|
|
||||||
- Interface TypeScript/Next.js
|
|
||||||
|
|
||||||
### Services principaux
|
|
||||||
- **Nostr** : Pool de connexions, publication/récupération d'événements, profils
|
|
||||||
- **Paiements** : Invoices Lightning, vérification zap receipts (NIP-57), envoi automatique contenu privé
|
|
||||||
- **Stockage** : IndexedDB avec chiffrement AES-GCM pour contenu privé
|
|
||||||
- **Notifications** : Surveillance des paiements en temps réel (zap receipts)
|
|
||||||
|
|
||||||
## Fonctionnalités utilisateur
|
|
||||||
|
|
||||||
### Profil et articles
|
|
||||||
- Page profil (`/profile`) avec informations utilisateur
|
|
||||||
- Liste des articles publiés par l'utilisateur
|
|
||||||
- Recherche et filtres (auteur, prix, texte)
|
|
||||||
- Tri (date, prix)
|
|
||||||
|
|
||||||
### Édition et suppression
|
|
||||||
- Édition d'articles via événements Nostr (kind 1 avec tag `replace`)
|
|
||||||
- Suppression d'articles via événements Nostr (kind 5)
|
|
||||||
- Confirmation avant suppression
|
|
||||||
- Ré-encryptage du contenu privé lors de l'édition
|
|
||||||
|
|
||||||
### Notifications
|
|
||||||
- Surveillance automatique des zap receipts (kind:9735) destinés à l'utilisateur
|
|
||||||
- Badge avec nombre de notifications non lues dans le header
|
|
||||||
- Centre de notifications (panneau latéral) avec liste des paiements
|
|
||||||
- Formatage du temps relatif (il y a X minutes/heures/jours)
|
|
||||||
- Marquer comme lu / marquer tout comme lu
|
|
||||||
- Tri par date (plus récentes en premier)
|
|
||||||
|
|
||||||
**Scope** : Uniquement notifications de paiements. Pas de mentions, reposts, likes. Si commentaires demandés plus tard, approbation explicite requise.
|
|
||||||
|
|
||||||
## Stockage
|
|
||||||
|
|
||||||
### IndexedDB avec chiffrement
|
|
||||||
- Remplacement de localStorage par IndexedDB
|
|
||||||
- Chiffrement AES-GCM du contenu privé
|
|
||||||
- Clé maître générée une fois et stockée en localStorage
|
|
||||||
- Secret par article : `<masterKey>:<articleId>`
|
|
||||||
- Expiration automatique (30 jours)
|
|
||||||
- Pas de fallback : échec si IndexedDB ou Web Crypto indisponible
|
|
||||||
|
|
||||||
### Fichiers
|
|
||||||
- `lib/storage/indexedDB.ts` : Service IndexedDB
|
|
||||||
- `lib/storage/cryptoHelpers.ts` : Helpers AES-GCM
|
|
||||||
- `lib/articleStorage.ts` : Gestion du stockage avec chiffrement
|
|
||||||
|
|
||||||
## Hiérarchie de contenu
|
|
||||||
|
|
||||||
### Structure
|
|
||||||
- **Page auteur** : Publication publique et gratuite (obligatoire avant de publier)
|
|
||||||
- **Séries** : Publications publiques et gratuites organisées par auteur
|
|
||||||
- **Publications** : Contenu confidentiel et gratuit pour l'auteur, payant pour l'accès (800 sats)
|
|
||||||
|
|
||||||
### Navigation
|
|
||||||
- Home : Bouton "Créer page auteur" si pas de présentation, sinon "Publier une publication"
|
|
||||||
- Page auteur : Résumé du sponsoring et liste des séries
|
|
||||||
- Page série : Résumé de la série, illustration de couverture et liste des publications
|
|
||||||
|
|
||||||
## Système de tags Nostr
|
|
||||||
|
|
||||||
### Nouveau système (tous en anglais)
|
|
||||||
- **Type** : `#author`, `#series`, `#publication`, `#quote` (tags simples)
|
|
||||||
- **Catégorie** : `#sciencefiction` ou `#research` (tags simples)
|
|
||||||
- **ID** : `#id_<id>` (tag avec valeur)
|
|
||||||
- **Paywall** : `#paywall` (pour les publications payantes)
|
|
||||||
- **Payment** : `#payment` (optionnel, pour les notes de paiement)
|
|
||||||
|
|
||||||
### Utilitaires
|
|
||||||
- `lib/nostrTagSystem.ts` : `buildTags()`, `extractTagsFromEvent()`, `buildTagFilter()`
|
|
||||||
- Migration complète depuis l'ancien système (`kind_type`, `site`, etc.)
|
|
||||||
|
|
||||||
## Séries et médias (NIP-95)
|
|
||||||
|
|
||||||
### Séries
|
|
||||||
- Événements kind 1 avec tag `#series`
|
|
||||||
- Tags : `#sciencefiction` ou `#research`, `#id_<id>`, `title`, `description`, `cover`, `preview`
|
|
||||||
- Agrégation du sponsoring et des paiements par série
|
|
||||||
|
|
||||||
### Médias
|
|
||||||
- Upload d'images (≤5Mo) et vidéos (≤45Mo) via NIP-95
|
|
||||||
- Tags `banner` et `media` dans les événements
|
|
||||||
- Validations de taille et type
|
|
||||||
- Support dans les articles et séries
|
|
||||||
|
|
||||||
### Avis (reviews)
|
|
||||||
- Événements kind 1 avec tag `#quote`
|
|
||||||
- Tags : `#sciencefiction` ou `#research`, `#id_<id>`, `#article`, `reviewer`, `title`
|
|
||||||
- Rémunération possible avec tags `rewarded` et `reward_amount`
|
|
||||||
|
|
||||||
## Optimisations et nettoyage
|
|
||||||
|
|
||||||
### Refactoring
|
|
||||||
- Division des fichiers > 250 lignes
|
|
||||||
- Extraction des fonctions > 40 lignes
|
|
||||||
- Modules dédiés : parsing, messages privés, vérification zap, subscriptions, polling, résolution invoices, stockage, handlers
|
|
||||||
|
|
||||||
### Code quality
|
|
||||||
- Respect strict `exactOptionalPropertyTypes`
|
|
||||||
- Fonctions < 40 lignes, fichiers < 250 lignes
|
|
||||||
- Pas de fallback implicite
|
|
||||||
- Logs structurés
|
|
||||||
- Pas d'analytics
|
|
||||||
|
|
||||||
## Intégrations
|
|
||||||
|
|
||||||
### Alby/WebLN
|
|
||||||
- Remplacement de Rizful par Alby/WebLN
|
|
||||||
- Standard WebLN compatible avec tous les portefeuilles
|
|
||||||
- Pas d'API backend nécessaire
|
|
||||||
- Service `AlbyService` pour enable, makeInvoice, sendPayment
|
|
||||||
|
|
||||||
### Priorité 1 (implémenté)
|
|
||||||
- Génération d'invoice côté auteur lors de la publication
|
|
||||||
- Invoice stockée dans tags Nostr et localStorage
|
|
||||||
- Vérification de l'invoice avant création d'une nouvelle
|
|
||||||
- Signature distante (NIP-46) préparée
|
|
||||||
|
|
||||||
## Internationalisation (i18n)
|
|
||||||
|
|
||||||
### Système de traduction
|
|
||||||
- Fichiers texte plats : `public/locales/fr.txt`, `public/locales/en.txt`
|
|
||||||
- Format : `key=value` avec paramètres `{{param}}`
|
|
||||||
- Hook `useI18n` pour charger et utiliser les traductions
|
|
||||||
- Initialisation dans `_app.tsx` avec locale par défaut (fr)
|
|
||||||
|
|
||||||
### Langues supportées
|
|
||||||
- Français (fr) : langue par défaut
|
|
||||||
- Anglais (en) : disponible
|
|
||||||
- Extensible : ajout de nouvelles langues via fichiers de traduction
|
|
||||||
|
|
||||||
## Financement IA
|
|
||||||
|
|
||||||
### Jauge de financement
|
|
||||||
- Composant `FundingGauge` sur la page d'accueil
|
|
||||||
- Affiche montant collecté, cible (0.27 BTC) et pourcentage
|
|
||||||
- Calcul via `lib/fundingCalculation.ts`
|
|
||||||
- Description de l'usage des fonds pour le développement IA (développement et matériel)
|
|
||||||
@ -1,123 +0,0 @@
|
|||||||
# Key Management Configuration Page
|
|
||||||
|
|
||||||
**Auteur** : Équipe 4NK
|
|
||||||
|
|
||||||
## Objectif
|
|
||||||
|
|
||||||
Créer une page de configuration permettant de :
|
|
||||||
- Consulter les clés publiques (npub et hex)
|
|
||||||
- Importer une clé privée sous forme d'URL (nostr://nsec1...) ou de texte (nsec1... ou hex)
|
|
||||||
- Respecter le système de stockage et de sécurisation à deux niveaux existant
|
|
||||||
|
|
||||||
## Impacts
|
|
||||||
|
|
||||||
### Utilisateurs
|
|
||||||
- Interface dédiée pour gérer les clés Nostr
|
|
||||||
- Consultation facile des clés publiques
|
|
||||||
- Import de clés via URL ou texte
|
|
||||||
- Affichage des mots de récupération après import
|
|
||||||
|
|
||||||
### Technique
|
|
||||||
- Nouveau composant `KeyManagementManager` dans `components/`
|
|
||||||
- Intégration dans la page `/settings`
|
|
||||||
- Utilisation des services existants (`nostrAuthService`, `keyManagementService`)
|
|
||||||
- Respect du système de chiffrement à deux niveaux (KEK + phrase de récupération)
|
|
||||||
|
|
||||||
## Modifications
|
|
||||||
|
|
||||||
### Fichiers créés
|
|
||||||
- `components/KeyManagementManager.tsx` : Composant de gestion des clés
|
|
||||||
- Affichage des clés publiques (npub et hex)
|
|
||||||
- Formulaire d'import de clé privée
|
|
||||||
- Support des formats : nsec URL (nostr://nsec1...), nsec texte (nsec1...), hex (64 caractères)
|
|
||||||
- Extraction automatique de la clé depuis une URL
|
|
||||||
- Avertissement et confirmation avant remplacement d'un compte existant
|
|
||||||
- Affichage des mots de récupération après import
|
|
||||||
|
|
||||||
### Fichiers modifiés
|
|
||||||
- `pages/settings.tsx` : Ajout du composant `KeyManagementManager` dans la page settings
|
|
||||||
|
|
||||||
## Fonctionnalités
|
|
||||||
|
|
||||||
### Consultation des clés publiques
|
|
||||||
- Affichage du npub (format NIP-19)
|
|
||||||
- Affichage de la clé publique hexadécimale
|
|
||||||
- Boutons de copie pour chaque format
|
|
||||||
|
|
||||||
### Import de clé privée
|
|
||||||
- Support de plusieurs formats :
|
|
||||||
- URL nostr:// avec nsec : `nostr://nsec1...`
|
|
||||||
- Texte nsec : `nsec1...`
|
|
||||||
- Clé hexadécimale : `64 caractères hex`
|
|
||||||
- Extraction automatique de la clé depuis une URL
|
|
||||||
- Validation du format avant import
|
|
||||||
- Gestion du remplacement d'un compte existant :
|
|
||||||
- Avertissement si un compte existe déjà
|
|
||||||
- Confirmation avant remplacement
|
|
||||||
- Suppression de l'ancien compte avant création du nouveau
|
|
||||||
|
|
||||||
### Sécurité
|
|
||||||
- Respect du système de chiffrement à deux niveaux :
|
|
||||||
- KEK (Key Encryption Key) chiffré avec la phrase de récupération
|
|
||||||
- Clé privée chiffrée avec le KEK
|
|
||||||
- KEK stocké dans Credentials API
|
|
||||||
- Clé privée chiffrée stockée dans IndexedDB
|
|
||||||
- Affichage unique des mots de récupération après import
|
|
||||||
- Avertissements clairs sur l'importance de sauvegarder la phrase de récupération
|
|
||||||
|
|
||||||
## Modalités de déploiement
|
|
||||||
|
|
||||||
1. Vérifier que le composant compile sans erreur :
|
|
||||||
```bash
|
|
||||||
npm run type-check
|
|
||||||
npm run lint
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Tester l'interface :
|
|
||||||
- Accéder à `/settings`
|
|
||||||
- Vérifier l'affichage des clés publiques si un compte existe
|
|
||||||
- Tester l'import d'une clé privée (nsec ou hex)
|
|
||||||
- Vérifier l'affichage des mots de récupération
|
|
||||||
- Tester le remplacement d'un compte existant
|
|
||||||
|
|
||||||
3. Déployer avec le script de déploiement standard
|
|
||||||
|
|
||||||
## Modalités d'analyse
|
|
||||||
|
|
||||||
### Logs à surveiller
|
|
||||||
- Erreurs lors du chargement des clés publiques
|
|
||||||
- Erreurs lors de l'import de clé privée
|
|
||||||
- Erreurs lors de la validation du format de clé
|
|
||||||
- Erreurs lors du remplacement d'un compte
|
|
||||||
|
|
||||||
### Points de contrôle
|
|
||||||
- Affichage correct des clés publiques (npub et hex)
|
|
||||||
- Extraction correcte de la clé depuis une URL
|
|
||||||
- Validation correcte des formats (nsec, hex)
|
|
||||||
- Gestion correcte du remplacement de compte
|
|
||||||
- Affichage correct des mots de récupération
|
|
||||||
- Copie correcte des clés et mots de récupération
|
|
||||||
|
|
||||||
### Tests à effectuer
|
|
||||||
1. **Consultation des clés publiques** :
|
|
||||||
- Vérifier l'affichage du npub
|
|
||||||
- Vérifier l'affichage de la clé hex
|
|
||||||
- Tester la copie de chaque format
|
|
||||||
|
|
||||||
2. **Import de clé privée** :
|
|
||||||
- Tester l'import avec une URL nostr://
|
|
||||||
- Tester l'import avec un nsec texte
|
|
||||||
- Tester l'import avec une clé hex
|
|
||||||
- Vérifier la validation des formats invalides
|
|
||||||
|
|
||||||
3. **Remplacement de compte** :
|
|
||||||
- Créer un compte
|
|
||||||
- Importer une nouvelle clé
|
|
||||||
- Vérifier l'avertissement et la confirmation
|
|
||||||
- Vérifier que l'ancien compte est supprimé
|
|
||||||
- Vérifier que le nouveau compte est créé
|
|
||||||
|
|
||||||
4. **Sécurité** :
|
|
||||||
- Vérifier que les mots de récupération sont affichés une seule fois
|
|
||||||
- Vérifier que la clé privée n'est jamais affichée
|
|
||||||
- Vérifier que le système de chiffrement à deux niveaux est respecté
|
|
||||||
@ -1,76 +0,0 @@
|
|||||||
# Language preference selector in settings
|
|
||||||
|
|
||||||
## Date
|
|
||||||
2025-01-27
|
|
||||||
|
|
||||||
## Objectif
|
|
||||||
Permettre aux utilisateurs de configurer leur langue de préférence (fr/en) dans la page des paramètres, avec chargement automatique au démarrage de l'application depuis localStorage.
|
|
||||||
|
|
||||||
## Motivations
|
|
||||||
- Centraliser la gestion de la langue dans la page des paramètres
|
|
||||||
- Permettre aux utilisateurs de changer facilement leur langue préférée
|
|
||||||
- Charger automatiquement la préférence de langue au démarrage pour configurer l'application
|
|
||||||
- Utiliser localStorage pour un accès plus rapide et synchrone
|
|
||||||
|
|
||||||
## Impacts
|
|
||||||
- **Utilisateurs** : Peuvent maintenant configurer leur langue préférée dans les paramètres
|
|
||||||
- **Performance** : Chargement synchrone depuis localStorage au démarrage (plus rapide qu'IndexedDB)
|
|
||||||
- **Cohérence** : Tous les composants utilisent maintenant localStorage pour la langue
|
|
||||||
|
|
||||||
## Modifications
|
|
||||||
|
|
||||||
### Fichiers créés
|
|
||||||
- **`components/LanguageSettingsManager.tsx`** : Composant de gestion de la langue dans les paramètres avec sélection fr/en
|
|
||||||
|
|
||||||
### Fichiers modifiés
|
|
||||||
- **`pages/settings.tsx`** : Ajout du composant LanguageSettingsManager en première position
|
|
||||||
- **`pages/_app.tsx`** : Modification pour charger la langue depuis localStorage de manière synchrone au démarrage
|
|
||||||
- **`hooks/useI18n.ts`** : Migration de IndexedDB vers localStorage pour la langue
|
|
||||||
- **`components/LanguageSelector.tsx`** : Migration de IndexedDB vers localStorage pour la cohérence
|
|
||||||
- **`locales/fr.txt`** : Ajout des traductions pour les paramètres de langue
|
|
||||||
- **`locales/en.txt`** : Ajout des traductions pour les paramètres de langue
|
|
||||||
|
|
||||||
### Fonctionnalités implémentées
|
|
||||||
|
|
||||||
#### Composant LanguageSettingsManager
|
|
||||||
- Affichage de la langue actuelle
|
|
||||||
- Boutons pour sélectionner français ou anglais
|
|
||||||
- Sauvegarde automatique dans localStorage
|
|
||||||
- Rechargement de la page après changement pour appliquer les traductions
|
|
||||||
|
|
||||||
#### Chargement au démarrage
|
|
||||||
- Lecture synchrone depuis localStorage dans `_app.tsx`
|
|
||||||
- Détection de la langue du navigateur en fallback
|
|
||||||
- Configuration de la locale avant le chargement des traductions
|
|
||||||
|
|
||||||
#### Migration vers localStorage
|
|
||||||
- Remplacement de IndexedDB par localStorage pour la langue
|
|
||||||
- Accès synchrone plus rapide
|
|
||||||
- Compatibilité avec tous les navigateurs
|
|
||||||
|
|
||||||
## Traductions ajoutées
|
|
||||||
|
|
||||||
### Français (fr.txt)
|
|
||||||
- `settings.language.title` : Langue de préférence
|
|
||||||
- `settings.language.description` : Choisissez votre langue préférée pour l'interface
|
|
||||||
- `settings.language.loading` : Chargement...
|
|
||||||
- `settings.language.french` : Français
|
|
||||||
- `settings.language.english` : Anglais
|
|
||||||
|
|
||||||
### Anglais (en.txt)
|
|
||||||
- `settings.language.title` : Preferred Language
|
|
||||||
- `settings.language.description` : Choose your preferred language for the interface
|
|
||||||
- `settings.language.loading` : Loading...
|
|
||||||
- `settings.language.french` : French
|
|
||||||
- `settings.language.english` : English
|
|
||||||
|
|
||||||
## Modalités de déploiement
|
|
||||||
1. Les modifications sont rétrocompatibles
|
|
||||||
2. Les utilisateurs existants avec une préférence dans IndexedDB devront la reconfigurer (migration automatique possible si nécessaire)
|
|
||||||
3. Aucune action spéciale requise, déploiement standard
|
|
||||||
|
|
||||||
## Modalités d'analyse
|
|
||||||
- Vérifier que la langue est bien chargée au démarrage dans localStorage
|
|
||||||
- Tester le changement de langue depuis les paramètres
|
|
||||||
- Vérifier que le sélecteur dans le header fonctionne toujours correctement
|
|
||||||
- Confirmer que les traductions sont appliquées après changement de langue
|
|
||||||
@ -1,92 +0,0 @@
|
|||||||
# Configuration des endpoints NIP-95
|
|
||||||
|
|
||||||
## Date
|
|
||||||
2025-01-27
|
|
||||||
|
|
||||||
## Objectif
|
|
||||||
Permettre aux utilisateurs de configurer les endpoints NIP-95 pour l'upload de médias via une interface utilisateur, avec la possibilité d'ajouter, modifier, activer/désactiver et supprimer des endpoints.
|
|
||||||
|
|
||||||
## Motivations
|
|
||||||
- Résoudre les problèmes de DNS/connectivité en permettant d'utiliser plusieurs endpoints
|
|
||||||
- Donner aux utilisateurs le contrôle sur les endpoints utilisés
|
|
||||||
- Faciliter l'ajout de nouveaux endpoints sans modifier le code
|
|
||||||
- Permettre l'activation/désactivation d'endpoints selon les besoins
|
|
||||||
|
|
||||||
## Impacts
|
|
||||||
- **Utilisateurs** : Peuvent configurer leurs propres endpoints NIP-95 via l'interface
|
|
||||||
- **Développeurs** : Plus besoin de modifier le code pour ajouter des endpoints
|
|
||||||
- **Fiabilité** : Possibilité d'avoir plusieurs endpoints de secours activés
|
|
||||||
|
|
||||||
## Modifications
|
|
||||||
|
|
||||||
### Fichiers créés
|
|
||||||
- **`pages/settings.tsx`** : Page de configuration des paramètres de l'application
|
|
||||||
- **`components/Nip95ConfigManager.tsx`** : Composant de gestion des endpoints NIP-95 avec interface complète
|
|
||||||
|
|
||||||
### Fichiers modifiés
|
|
||||||
- **`lib/configStorageTypes.ts`** : Ajout d'un endpoint supplémentaire (`nostrimg.com`) dans `DEFAULT_NIP95_APIS`
|
|
||||||
- **`components/PageHeader.tsx`** : Ajout d'un lien vers la page Settings dans la navigation
|
|
||||||
|
|
||||||
### Fonctionnalités implémentées
|
|
||||||
|
|
||||||
#### Interface de gestion des endpoints
|
|
||||||
- **Affichage de la liste** : Tous les endpoints configurés sont affichés avec leur statut (activé/désactivé), priorité et URL
|
|
||||||
- **Ajout d'endpoints** : Formulaire pour ajouter de nouveaux endpoints avec validation d'URL
|
|
||||||
- **Modification d'URL** : Clic sur l'URL pour la modifier directement
|
|
||||||
- **Activation/Désactivation** : Checkbox pour activer ou désactiver chaque endpoint
|
|
||||||
- **Gestion de la priorité** : Champ numérique pour définir l'ordre de tentative (plus bas = priorité plus haute)
|
|
||||||
- **Suppression** : Bouton pour supprimer un endpoint avec confirmation
|
|
||||||
|
|
||||||
#### Endpoints par défaut
|
|
||||||
Les endpoints suivants sont maintenant disponibles par défaut :
|
|
||||||
1. `https://void.cat/upload` (activé, priorité 1)
|
|
||||||
2. `https://nostr.build/api/v2/upload` (désactivé, priorité 2)
|
|
||||||
3. `https://picstr.build/api/v1/upload` (désactivé, priorité 3)
|
|
||||||
4. `https://nostrcheck.me/api/v1/media` (désactivé, priorité 4)
|
|
||||||
5. `https://nostrimg.com/api/upload` (désactivé, priorité 5) - **Nouveau**
|
|
||||||
|
|
||||||
## Modalités de déploiement
|
|
||||||
1. Les modifications sont dans le code source
|
|
||||||
2. Rebuild de l'application : `npm run build`
|
|
||||||
3. Redémarrage du service Next.js
|
|
||||||
4. Aucune migration de données nécessaire (les endpoints par défaut sont créés automatiquement)
|
|
||||||
|
|
||||||
## Modalités d'analyse
|
|
||||||
Pour vérifier que la fonctionnalité fonctionne :
|
|
||||||
|
|
||||||
1. **Accéder à la page Settings** :
|
|
||||||
- Naviguer vers `/settings` depuis le menu de navigation
|
|
||||||
- Vérifier que la liste des endpoints s'affiche
|
|
||||||
|
|
||||||
2. **Tester l'ajout d'un endpoint** :
|
|
||||||
- Cliquer sur "+ Add Endpoint"
|
|
||||||
- Entrer une URL valide (ex: `https://example.com/upload`)
|
|
||||||
- Vérifier que l'endpoint apparaît dans la liste
|
|
||||||
|
|
||||||
3. **Tester l'activation/désactivation** :
|
|
||||||
- Cocher/décocher la checkbox d'un endpoint
|
|
||||||
- Vérifier que le statut change
|
|
||||||
- Tester un upload pour vérifier que seuls les endpoints activés sont utilisés
|
|
||||||
|
|
||||||
4. **Tester la modification de priorité** :
|
|
||||||
- Modifier la priorité d'un endpoint
|
|
||||||
- Vérifier que l'ordre dans la liste change
|
|
||||||
- Tester un upload pour vérifier l'ordre de tentative
|
|
||||||
|
|
||||||
5. **Tester la modification d'URL** :
|
|
||||||
- Cliquer sur une URL pour la modifier
|
|
||||||
- Entrer une nouvelle URL et appuyer sur Enter
|
|
||||||
- Vérifier que l'URL est mise à jour
|
|
||||||
|
|
||||||
6. **Tester la suppression** :
|
|
||||||
- Cliquer sur "Remove" d'un endpoint
|
|
||||||
- Confirmer la suppression
|
|
||||||
- Vérifier que l'endpoint disparaît de la liste
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
- Les endpoints sont stockés dans IndexedDB (côté client)
|
|
||||||
- Les modifications sont persistantes et survivent aux rechargements de page
|
|
||||||
- Les endpoints sont essayés dans l'ordre de priorité (plus bas = priorité plus haute)
|
|
||||||
- Seuls les endpoints activés sont utilisés pour les uploads
|
|
||||||
- Si tous les endpoints activés échouent, une erreur est retournée à l'utilisateur
|
|
||||||
- La validation d'URL vérifie le format mais pas la disponibilité du service
|
|
||||||
@ -1,90 +0,0 @@
|
|||||||
# Implémentation NIP-98 pour authentification nostrcheck.me
|
|
||||||
|
|
||||||
## Date
|
|
||||||
2025-01-27
|
|
||||||
|
|
||||||
## Objectif
|
|
||||||
Implémenter l'authentification NIP-98 pour permettre l'upload de médias vers nostrcheck.me qui nécessite une authentification.
|
|
||||||
|
|
||||||
## Motivations
|
|
||||||
- nostrcheck.me retourne 401 Unauthorized sans authentification
|
|
||||||
- NIP-98 est le standard d'authentification HTTP pour Nostr
|
|
||||||
- Permettre l'utilisation de nostrcheck.me comme endpoint NIP-95
|
|
||||||
|
|
||||||
## Impacts
|
|
||||||
- **Utilisateurs** : Peuvent maintenant uploader vers nostrcheck.me s'ils sont connectés avec une extension Nostr (Alby, nos2x, etc.)
|
|
||||||
- **Fonctionnalité** : Un endpoint supplémentaire disponible pour les uploads
|
|
||||||
- **Sécurité** : L'authentification utilise la signature Nostr standard
|
|
||||||
|
|
||||||
## Modifications
|
|
||||||
|
|
||||||
### Fichiers créés
|
|
||||||
- **`lib/nip98.ts`** : Implémentation de NIP-98 pour générer des tokens d'authentification HTTP
|
|
||||||
|
|
||||||
### Fichiers modifiés
|
|
||||||
- **`lib/nip95.ts`** : Détection automatique de nostrcheck.me et génération du token NIP-98
|
|
||||||
- **`pages/api/nip95-upload.ts`** : Ajout du header Authorization avec le token NIP-98
|
|
||||||
|
|
||||||
### Fonctionnalités implémentées
|
|
||||||
|
|
||||||
#### Génération du token NIP-98 (`lib/nip98.ts`)
|
|
||||||
- Création d'un événement Nostr de type 27235 (NIP-98 HTTP Auth)
|
|
||||||
- Tags requis :
|
|
||||||
- `u` : URL complète de la requête
|
|
||||||
- `method` : Méthode HTTP (POST)
|
|
||||||
- `payload` : Hash SHA256 du body (optionnel, non implémenté pour l'instant)
|
|
||||||
- Signature de l'événement via `nostrRemoteSigner` (support Alby/nos2x)
|
|
||||||
- Encodage base64 de l'événement signé
|
|
||||||
|
|
||||||
#### Intégration dans le flux d'upload (`lib/nip95.ts`)
|
|
||||||
- Détection automatique si l'endpoint est nostrcheck.me
|
|
||||||
- Vérification de la disponibilité de NIP-98 (utilisateur connecté)
|
|
||||||
- Génération du token pour l'URL finale (nostrcheck.me)
|
|
||||||
- Passage du token à l'API proxy via paramètre de requête
|
|
||||||
|
|
||||||
#### Support dans l'API proxy (`pages/api/nip95-upload.ts`)
|
|
||||||
- Récupération du token depuis les paramètres de requête
|
|
||||||
- Ajout du header `Authorization: Nostr <token>` aux requêtes HTTP
|
|
||||||
- Préservation du token lors des redirections HTTP
|
|
||||||
|
|
||||||
## Modalités de déploiement
|
|
||||||
1. Les modifications sont dans le code source
|
|
||||||
2. Rebuild de l'application : `npm run build`
|
|
||||||
3. Redémarrage du service Next.js
|
|
||||||
4. Aucune migration de données nécessaire
|
|
||||||
|
|
||||||
## Modalités d'analyse
|
|
||||||
Pour vérifier que l'authentification fonctionne :
|
|
||||||
|
|
||||||
1. **Vérifier la connexion Nostr** :
|
|
||||||
- L'utilisateur doit être connecté avec Alby, nos2x ou une autre extension NIP-07
|
|
||||||
- Vérifier que `nostrRemoteSigner.isAvailable()` retourne true
|
|
||||||
|
|
||||||
2. **Tester l'upload vers nostrcheck.me** :
|
|
||||||
- Activer nostrcheck.me dans les settings
|
|
||||||
- Tenter un upload d'image/vidéo
|
|
||||||
- Vérifier que le token NIP-98 est généré (logs console)
|
|
||||||
- Vérifier que le header Authorization est présent dans la requête
|
|
||||||
|
|
||||||
3. **Vérifier les logs serveur** :
|
|
||||||
- Chercher les logs de redirection si applicable
|
|
||||||
- Vérifier que le header Authorization est transmis
|
|
||||||
- Vérifier la réponse de nostrcheck.me (devrait être 200 au lieu de 401)
|
|
||||||
|
|
||||||
4. **En cas d'erreur** :
|
|
||||||
- Vérifier que l'utilisateur est bien connecté
|
|
||||||
- Vérifier que le compte nostrcheck.me est créé avec la même clé
|
|
||||||
- Vérifier les logs pour les erreurs de signature
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
- Le token NIP-98 est généré côté client (navigateur) car il nécessite la clé privée
|
|
||||||
- Le token est passé à l'API proxy via paramètre de requête (sécurisé car HTTPS)
|
|
||||||
- Le token est valide uniquement pour l'URL et la méthode spécifiées
|
|
||||||
- Le token inclut un timestamp et expire après un certain temps (selon la politique de nostrcheck.me)
|
|
||||||
- Pour l'instant, le hash du payload n'est pas calculé (peut être ajouté plus tard si nécessaire)
|
|
||||||
- Le kind 27235 est le kind standard pour NIP-98 HTTP Auth
|
|
||||||
|
|
||||||
## Références
|
|
||||||
- NIP-98 : https://github.com/nostr-protocol/nips/blob/master/98.md
|
|
||||||
- nostrcheck.me : https://nostrcheck.me/
|
|
||||||
- NIP-07 : https://github.com/nostr-protocol/nips/blob/master/07.md
|
|
||||||
@ -1,179 +0,0 @@
|
|||||||
# Implémentation du système de notifications
|
|
||||||
|
|
||||||
**Date** : Décembre 2024
|
|
||||||
**Status** : ✅ Complété
|
|
||||||
|
|
||||||
## Objectif
|
|
||||||
|
|
||||||
Permettre aux utilisateurs de recevoir des notifications en temps réel lorsque leurs articles sont achetés (paiements reçus via zap receipts).
|
|
||||||
|
|
||||||
## Fonctionnalités implémentées
|
|
||||||
|
|
||||||
### 1. Surveillance des paiements
|
|
||||||
- Subscription automatique aux zap receipts (kind:9735) destinés à l'utilisateur connecté
|
|
||||||
- Détection en temps réel des nouveaux paiements
|
|
||||||
- Extraction des informations de paiement (montant, article, auteur du paiement)
|
|
||||||
|
|
||||||
### 2. Badge de notification
|
|
||||||
- Badge avec le nombre de notifications non lues
|
|
||||||
- Affiché dans le header à côté du profil utilisateur
|
|
||||||
- Masqué si aucune notification non lue
|
|
||||||
|
|
||||||
### 3. Centre de notifications
|
|
||||||
- Panneau latéral/dropdown avec liste de toutes les notifications
|
|
||||||
- Notifications triées par date (plus récentes en premier)
|
|
||||||
- Indicateur visuel pour les notifications non lues (fond bleu clair + point bleu)
|
|
||||||
- Formatage du temps relatif (il y a X minutes/heures/jours)
|
|
||||||
|
|
||||||
### 4. Gestion des notifications
|
|
||||||
- Marquer une notification comme lue en cliquant dessus
|
|
||||||
- Marquer toutes les notifications comme lues
|
|
||||||
- Supprimer une notification
|
|
||||||
- Stockage persistant dans localStorage (par utilisateur)
|
|
||||||
- Limite de 100 notifications stockées
|
|
||||||
|
|
||||||
### 5. Navigation
|
|
||||||
- Clic sur une notification pour la marquer comme lue et fermer le panneau
|
|
||||||
- Lien vers l'article associé (si disponible)
|
|
||||||
|
|
||||||
## Fichiers créés
|
|
||||||
|
|
||||||
### `types/notifications.ts`
|
|
||||||
Types TypeScript pour les notifications :
|
|
||||||
- `NotificationType` : Types de notifications (payment, mention, comment)
|
|
||||||
- `Notification` : Interface pour une notification
|
|
||||||
- `NotificationState` : État des notifications
|
|
||||||
|
|
||||||
### `lib/notifications.ts`
|
|
||||||
Service de notifications :
|
|
||||||
- `NotificationService` : Classe pour surveiller les zap receipts
|
|
||||||
- `subscribeToPayments()` : S'abonne aux paiements pour un utilisateur
|
|
||||||
- `loadStoredNotifications()` : Charge les notifications depuis localStorage
|
|
||||||
- `saveNotifications()` : Sauvegarde les notifications dans localStorage
|
|
||||||
- `markNotificationAsRead()` : Marque une notification comme lue
|
|
||||||
- `markAllAsRead()` : Marque toutes les notifications comme lues
|
|
||||||
- `deleteNotification()` : Supprime une notification
|
|
||||||
|
|
||||||
### `hooks/useNotifications.ts`
|
|
||||||
Hook React pour gérer les notifications :
|
|
||||||
- Charge les notifications stockées au montage
|
|
||||||
- S'abonne aux nouvelles notifications en temps réel
|
|
||||||
- Calcule le nombre de notifications non lues
|
|
||||||
- Méthodes pour marquer comme lue et supprimer
|
|
||||||
|
|
||||||
**Signature** :
|
|
||||||
```typescript
|
|
||||||
export function useNotifications(userPubkey: string | null)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Retour** :
|
|
||||||
```typescript
|
|
||||||
{
|
|
||||||
notifications: Notification[]
|
|
||||||
unreadCount: number
|
|
||||||
loading: boolean
|
|
||||||
markAsRead: (notificationId: string) => void
|
|
||||||
markAllAsRead: () => void
|
|
||||||
deleteNotification: (notificationId: string) => void
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### `components/NotificationBadge.tsx`
|
|
||||||
Badge de notification simple :
|
|
||||||
- Affiche une icône de cloche
|
|
||||||
- Badge avec le nombre de notifications non lues
|
|
||||||
- Masqué si aucune notification non lue
|
|
||||||
- Cliquable pour ouvrir le centre de notifications
|
|
||||||
|
|
||||||
### `components/NotificationCenter.tsx`
|
|
||||||
Centre de notifications complet :
|
|
||||||
- Panneau dropdown avec liste des notifications
|
|
||||||
- Header avec bouton "Mark all as read" et fermeture
|
|
||||||
- Liste scrollable des notifications
|
|
||||||
- Chaque notification affiche :
|
|
||||||
- Titre et message
|
|
||||||
- Temps relatif
|
|
||||||
- Indicateur de non-lu
|
|
||||||
- Bouton de suppression
|
|
||||||
- Lien vers l'article (si disponible)
|
|
||||||
- Backdrop pour fermer en cliquant à l'extérieur
|
|
||||||
|
|
||||||
## Fichiers modifiés
|
|
||||||
|
|
||||||
### `lib/nostr.ts`
|
|
||||||
- Ajout de `getPool()` : Méthode publique pour obtenir l'instance du pool (nécessaire pour le service de notifications)
|
|
||||||
|
|
||||||
### `components/ConnectButton.tsx`
|
|
||||||
- Intégration de `NotificationCenter` dans le header
|
|
||||||
- Le badge de notification apparaît à côté du nom de l'utilisateur
|
|
||||||
|
|
||||||
## Flux utilisateur
|
|
||||||
|
|
||||||
1. **Réception d'un paiement** :
|
|
||||||
- Un utilisateur achète un article de l'auteur connecté
|
|
||||||
- Un zap receipt est publié sur Nostr
|
|
||||||
- Le service de notifications détecte le zap receipt
|
|
||||||
- Une notification est créée et ajoutée à la liste
|
|
||||||
|
|
||||||
2. **Visualisation des notifications** :
|
|
||||||
- Le badge affiche le nombre de notifications non lues
|
|
||||||
- L'utilisateur clique sur le badge pour ouvrir le centre de notifications
|
|
||||||
- La liste des notifications s'affiche avec les plus récentes en premier
|
|
||||||
|
|
||||||
3. **Gestion des notifications** :
|
|
||||||
- Clic sur une notification pour la marquer comme lue
|
|
||||||
- Bouton "Mark all as read" pour tout marquer comme lu
|
|
||||||
- Bouton de suppression pour supprimer une notification
|
|
||||||
- Clic sur "View article" pour voir l'article associé
|
|
||||||
|
|
||||||
## Stockage
|
|
||||||
|
|
||||||
Les notifications sont stockées dans `localStorage` avec la clé `notifications_{userPubkey}`. Cela permet :
|
|
||||||
- Persistance entre les sessions
|
|
||||||
- Notifications par utilisateur (si plusieurs comptes)
|
|
||||||
- Limite de 100 notifications (les plus anciennes sont supprimées)
|
|
||||||
|
|
||||||
## Limitations et améliorations futures
|
|
||||||
|
|
||||||
### Limitations actuelles
|
|
||||||
- Seulement les notifications de paiement (pas de mentions, commentaires, etc.)
|
|
||||||
- Pas de notifications push (navigateur)
|
|
||||||
- Stockage limité à localStorage (100 notifications max)
|
|
||||||
- Pas de filtrage par type de notification
|
|
||||||
- Pas de recherche dans les notifications
|
|
||||||
|
|
||||||
### Améliorations possibles
|
|
||||||
- **Notifications push** : Utiliser l'API Notifications du navigateur
|
|
||||||
- **Base de données** : Remplacer localStorage par IndexedDB ou une DB externe
|
|
||||||
- **Types de notifications** : Ajouter mentions, commentaires, réactions
|
|
||||||
- **Filtres** : Filtrer par type, date, statut (lu/non-lu)
|
|
||||||
- **Recherche** : Rechercher dans les notifications
|
|
||||||
- **Notifications groupées** : Grouper les notifications similaires
|
|
||||||
- **Paramètres** : Permettre à l'utilisateur de configurer quelles notifications recevoir
|
|
||||||
|
|
||||||
## Tests recommandés
|
|
||||||
|
|
||||||
1. **Réception de notifications** :
|
|
||||||
- Publier un article
|
|
||||||
- Faire un paiement pour cet article (depuis un autre compte)
|
|
||||||
- Vérifier que la notification apparaît
|
|
||||||
|
|
||||||
2. **Badge** :
|
|
||||||
- Vérifier que le badge affiche le bon nombre
|
|
||||||
- Vérifier que le badge disparaît quand toutes les notifications sont lues
|
|
||||||
|
|
||||||
3. **Centre de notifications** :
|
|
||||||
- Ouvrir/fermer le panneau
|
|
||||||
- Marquer une notification comme lue
|
|
||||||
- Marquer toutes comme lues
|
|
||||||
- Supprimer une notification
|
|
||||||
|
|
||||||
4. **Persistance** :
|
|
||||||
- Recevoir des notifications
|
|
||||||
- Recharger la page
|
|
||||||
- Vérifier que les notifications sont toujours là
|
|
||||||
|
|
||||||
5. **Performance** :
|
|
||||||
- Tester avec un grand nombre de notifications
|
|
||||||
- Vérifier que le scroll fonctionne bien
|
|
||||||
- Vérifier que les nouvelles notifications arrivent rapidement
|
|
||||||
@ -1,170 +0,0 @@
|
|||||||
# Open Source Setup
|
|
||||||
|
|
||||||
**Date**: December 2024
|
|
||||||
**Auteur**: Équipe 4NK
|
|
||||||
|
|
||||||
## Objectif
|
|
||||||
|
|
||||||
Mise en place complète du projet en open source avec documentation des contributions, code de conduite, politique de sécurité et templates pour issues et pull requests.
|
|
||||||
|
|
||||||
## Motivations
|
|
||||||
|
|
||||||
- Faciliter les contributions externes au projet
|
|
||||||
- Standardiser le processus de contribution
|
|
||||||
- Assurer la sécurité et la qualité du code
|
|
||||||
- Créer un environnement accueillant pour les contributeurs
|
|
||||||
- Documenter les bonnes pratiques et les guidelines
|
|
||||||
|
|
||||||
## Modifications
|
|
||||||
|
|
||||||
### Fichiers créés
|
|
||||||
|
|
||||||
1. **LICENSE** : Licence MIT pour le projet
|
|
||||||
- Permet l'utilisation, modification et distribution libre
|
|
||||||
- Standard pour les projets open source
|
|
||||||
|
|
||||||
2. **README.md** : Amélioration avec sections open source
|
|
||||||
- Badges (License, TypeScript, Next.js)
|
|
||||||
- Table of contents
|
|
||||||
- Section Contributing avec workflow
|
|
||||||
- Section Documentation
|
|
||||||
- Section License
|
|
||||||
|
|
||||||
3. **CONTRIBUTING.md** : Guide complet de contribution
|
|
||||||
- Code of Conduct
|
|
||||||
- Getting Started
|
|
||||||
- Development Setup
|
|
||||||
- Coding Guidelines détaillées
|
|
||||||
- Workflow complet (branches, commits, PRs)
|
|
||||||
- Commit Guidelines avec format structuré
|
|
||||||
- Checklist avant soumission
|
|
||||||
- What Not to Do
|
|
||||||
|
|
||||||
4. **CODE_OF_CONDUCT.md** : Code de conduite
|
|
||||||
- Basé sur Contributor Covenant v2.0
|
|
||||||
- Standards de comportement
|
|
||||||
- Processus d'enforcement
|
|
||||||
- Guidelines d'impact communautaire
|
|
||||||
|
|
||||||
5. **SECURITY.md** : Politique de sécurité
|
|
||||||
- Processus de reporting des vulnérabilités
|
|
||||||
- Timeline de réponse
|
|
||||||
- Best practices de sécurité
|
|
||||||
- Considérations de sécurité spécifiques au projet
|
|
||||||
- Checklist de sécurité pour les PRs
|
|
||||||
|
|
||||||
6. **.gitea/ISSUE_TEMPLATE/** : Templates pour issues (Gitea)
|
|
||||||
- `bug_report.md` : Template pour rapports de bugs
|
|
||||||
- `feature_request.md` : Template pour demandes de fonctionnalités
|
|
||||||
- `question.md` : Template pour questions
|
|
||||||
|
|
||||||
7. **.gitea/PULL_REQUEST_TEMPLATE.md** : Template pour pull requests (Gitea)
|
|
||||||
- Format structuré avec sections Motivations, Root causes, Correctifs, Evolutions, Pages affectées
|
|
||||||
- Checklist de validation
|
|
||||||
- Sections de testing et documentation
|
|
||||||
|
|
||||||
## Structure des templates
|
|
||||||
|
|
||||||
### Issue Templates
|
|
||||||
|
|
||||||
- **Bug Report** : Sections pour description, étapes de reproduction, environnement, erreurs console
|
|
||||||
- **Feature Request** : Sections pour description, use cases, considérations techniques
|
|
||||||
- **Question** : Format simple pour questions et contexte
|
|
||||||
|
|
||||||
### Pull Request Template
|
|
||||||
|
|
||||||
- Format aligné avec les guidelines de commit du projet
|
|
||||||
- Sections structurées (Motivations, Root causes, Correctifs, Evolutions, Pages affectées)
|
|
||||||
- Checklist complète de validation
|
|
||||||
- Sections pour testing et documentation
|
|
||||||
|
|
||||||
## Guidelines de contribution
|
|
||||||
|
|
||||||
### Principes fondamentaux
|
|
||||||
|
|
||||||
- Pas de fallbacks ou échecs silencieux
|
|
||||||
- Pas d'analytics
|
|
||||||
- Pas de tests ad-hoc (sauf demande explicite)
|
|
||||||
- TypeScript strict (pas de `any`, pas de `ts-ignore`)
|
|
||||||
- Gestion d'erreurs explicite
|
|
||||||
- Accessibilité (ARIA, clavier, contraste)
|
|
||||||
|
|
||||||
### Workflow standardisé
|
|
||||||
|
|
||||||
1. Fork du repository
|
|
||||||
2. Création de branche feature/fix
|
|
||||||
3. Développement suivant les guidelines
|
|
||||||
4. Lint et type-check
|
|
||||||
5. Commit avec format structuré
|
|
||||||
6. Pull Request avec template
|
|
||||||
7. Review et merge
|
|
||||||
|
|
||||||
### Format de commit
|
|
||||||
|
|
||||||
Commits exhaustifs et synthétiques avec :
|
|
||||||
- **Motivations**
|
|
||||||
- **Root causes**
|
|
||||||
- **Correctifs**
|
|
||||||
- **Evolutions**
|
|
||||||
- **Pages affectées**
|
|
||||||
|
|
||||||
## Sécurité
|
|
||||||
|
|
||||||
### Processus de reporting
|
|
||||||
|
|
||||||
- Utilisation d'issues privées sur Gitea (préfixées [SECURITY])
|
|
||||||
- Reporting privé (pas d'issues publiques)
|
|
||||||
- Timeline de réponse définie
|
|
||||||
- Crédit des chercheurs en sécurité
|
|
||||||
|
|
||||||
### Considérations spécifiques
|
|
||||||
|
|
||||||
- Authentification Nostr (NIP-07 via Alby)
|
|
||||||
- Paiements Lightning (WebLN)
|
|
||||||
- Stockage chiffré (IndexedDB avec AES-GCM)
|
|
||||||
- Pas de secrets en clair
|
|
||||||
|
|
||||||
## Accessibilité
|
|
||||||
|
|
||||||
- Respect ARIA
|
|
||||||
- Navigation clavier
|
|
||||||
- Contraste WCAG
|
|
||||||
- Pas de régressions
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
- Documentation des fixes dans `fixKnowledge/`
|
|
||||||
- Documentation des features dans `features/`
|
|
||||||
- Format structuré avec sections claires
|
|
||||||
- Attribution (Équipe 4NK)
|
|
||||||
|
|
||||||
## Modalités de déploiement
|
|
||||||
|
|
||||||
Aucun déploiement nécessaire. Les fichiers sont directement dans le repository et seront visibles sur Gitea lors du push.
|
|
||||||
|
|
||||||
**Repository Gitea** : https://git.4nkweb.com/4nk/story-research-zapwall
|
|
||||||
|
|
||||||
## Modalités d'analyse
|
|
||||||
|
|
||||||
### Vérifications à effectuer
|
|
||||||
|
|
||||||
1. **LICENSE** : Vérifier que la licence MIT est appropriée
|
|
||||||
2. **README.md** : Vérifier les liens et badges
|
|
||||||
3. **CONTRIBUTING.md** : Vérifier la cohérence avec les règles du projet et les URLs Gitea
|
|
||||||
4. **Templates** : Tester la création d'issues et PRs sur Gitea
|
|
||||||
5. **SECURITY.md** : Vérifier les références Gitea
|
|
||||||
|
|
||||||
### Points d'attention
|
|
||||||
|
|
||||||
- Les URLs dans CONTRIBUTING.md pointent vers git.4nkweb.com
|
|
||||||
- Les templates sont dans `.gitea/` pour compatibilité Gitea
|
|
||||||
- Les références GitHub ont été remplacées par Gitea
|
|
||||||
- Le repository est : https://git.4nkweb.com/4nk/story-research-zapwall
|
|
||||||
|
|
||||||
## Prochaines étapes
|
|
||||||
|
|
||||||
1. Tester la création d'issues et PRs sur Gitea avec les templates
|
|
||||||
2. Vérifier que Gitea reconnaît les templates dans `.gitea/`
|
|
||||||
3. Ajouter des labels Gitea si nécessaire (bug, enhancement, question, etc.)
|
|
||||||
4. Configurer les branch protection rules sur Gitea si nécessaire
|
|
||||||
5. Vérifier que les permissions du repository permettent le fork et les contributions
|
|
||||||
@ -1,69 +0,0 @@
|
|||||||
# Séries, média NIP-95 et événements Nostr (spec v1, Jan 2026)
|
|
||||||
|
|
||||||
## 1) Événements et tags (rien en local)
|
|
||||||
|
|
||||||
Namespace tag communs (tous les events) :
|
|
||||||
- `site`: `zapwall4science`
|
|
||||||
- `category`: `science-fiction` | `scientific-research`
|
|
||||||
- `author`: pubkey auteur
|
|
||||||
- `series`: id série (event id de la série)
|
|
||||||
- `article`: id article (event id de l’article)
|
|
||||||
|
|
||||||
Kinds proposés (réutilisation kind 1 pour compat) :
|
|
||||||
- Série : kind `1` avec tag `kind_type: series`
|
|
||||||
- tags : `site`, `category`, `author`, `series` (self id), `title`, `description`, `cover` (URL NIP-95), `preview`
|
|
||||||
- Article : kind `1` avec tag `kind_type: article`
|
|
||||||
- tags : `site`, `category`, `author`, `series`, `article` (self id), `title`, `preview`, `banner` (URL NIP-95), `media` (0..n URLs NIP-95)
|
|
||||||
- contenu markdown public (preview) ; privé chiffré inchangé côté storage
|
|
||||||
- Avis (critique) : kind `1` avec tag `kind_type: review`
|
|
||||||
- tags : `site`, `category`, `author`, `series`, `article`, `reviewer` (pubkey), `title`, `created_at`
|
|
||||||
- contenu = avis en clair
|
|
||||||
- Achat article (zap receipt) : kind `9735` (zap) avec tags standard `p`, `e`, plus `site`, `category`, `author`, `series`, `article`, `kind_type: purchase`
|
|
||||||
- amount = millisats, hors frais site gérés off-chain
|
|
||||||
- Paiement remerciement avis : kind `9735` zap avec `kind_type: review_tip`, tags `site`, `category`, `author`, `series`, `article`, `reviewer`, `review_id`
|
|
||||||
- Paiement sponsoring : kind `9735` zap avec `kind_type: sponsoring`, tags `site`, `category`, `author`, `series` (optionnel), `article` (présentation si ciblé)
|
|
||||||
|
|
||||||
Notes :
|
|
||||||
- Tous les cumuls (sponsoring, paiements article, remerciements avis) calculés via zap receipts filtrés par `kind_type`.
|
|
||||||
- Séries sans sponsoring autorisées (0).
|
|
||||||
|
|
||||||
## 2) Média NIP-95 (images/vidéos)
|
|
||||||
|
|
||||||
- Upload via NIP-95 (encrypted file events). Contraintes :
|
|
||||||
- Images/photos : max 5 Mo, png/jpg/jpeg/webp.
|
|
||||||
- Vidéos : max 45 Mo.
|
|
||||||
- Stockage chiffré (même logique qu’articles) ; URL NIP-95 insérée dans markdown et bannière.
|
|
||||||
- Validation côté client : type MIME, taille, échec → erreur surfacée (pas de fallback).
|
|
||||||
|
|
||||||
## 3) Pages / navigation
|
|
||||||
|
|
||||||
Hiérarchie : site → catégorie (SF/Recherche) → auteurs → auteur → série → articles → article.
|
|
||||||
|
|
||||||
- Page auteur : liste des séries (cover type “livre”, titre, desc, preview, cumul sponsoring/paiements agrégés via zap receipts). Profil Nostr affiché.
|
|
||||||
- Page série : détails série (cover, desc, preview), cumul sponsoring série + paiements articles de la série, liste d’articles de la série.
|
|
||||||
- Article : preview public, contenu privé chiffré inchangé, bannière NIP-95, média insérés dans markdown.
|
|
||||||
- Rédaction : éditeur markdown + preview live, upload/paste NIP-95 pour images/vidéos, champs bannière (URL NIP-95), sélection série.
|
|
||||||
|
|
||||||
## 4) Agrégations financières (hors frais/site)
|
|
||||||
|
|
||||||
- Sponsoring : zap receipts `kind_type: sponsoring`, filtres `site`, `author`, option `series`.
|
|
||||||
- Paiements articles : zap receipts `kind_type: purchase`.
|
|
||||||
- Remerciements avis : zap receipts `kind_type: review_tip`.
|
|
||||||
- Cumuls par auteur et par série ; pas de détail de lecteurs (sauf auteur du zap pour avis si nécessaire au wording minimal).
|
|
||||||
|
|
||||||
## 5) Wording “critiques”
|
|
||||||
|
|
||||||
- Affichage des avis en tant que “critiques”.
|
|
||||||
- Liste des critiques : afficher contenu + auteur (pubkey→profil) ; pas de liste distincte “critiques” séparée des avis (juste les avis).
|
|
||||||
|
|
||||||
## 6) TODO d’implémentation (proposé)
|
|
||||||
|
|
||||||
- Types : étendre `types/nostr.ts` avec Series, Review, media refs; enum `KindType`.
|
|
||||||
- Upload NIP-95 : service dédié (validation taille/type, retour URL).
|
|
||||||
- Publisher : ajouter création série (event), article avec tags série/media/banner.
|
|
||||||
- Parsing : `nostrEventParsing` pour séries/articles/avis avec tags `kind_type`.
|
|
||||||
- Aggregation : service zap pour cumuls (sponsoring/purchase/review_tip) par auteur/série.
|
|
||||||
- UI :
|
|
||||||
- Form auteur/série/article (cover/banner, sélection série, markdown+preview, upload media).
|
|
||||||
- Pages auteur/série avec stats cumulées.
|
|
||||||
- Pas de stockage local pour méta (tout via events).
|
|
||||||
@ -1,427 +0,0 @@
|
|||||||
# Refonte zapwall4Science - Spécifications
|
|
||||||
|
|
||||||
**Date** : Décembre 2024
|
|
||||||
**Auteur** : Équipe 4NK
|
|
||||||
|
|
||||||
## 🎯 Objectif
|
|
||||||
|
|
||||||
Transformation de Nostr Paywall en **zapwall4Science** : plateforme de publication d'articles scientifiques et de science-fiction avec système de sponsoring, commissions et rémunération des avis.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📝 Wording et terminologie
|
|
||||||
|
|
||||||
### Acteurs
|
|
||||||
|
|
||||||
- **Auteur** : Utilisateur qui publie des articles (science-fiction ou recherche scientifique)
|
|
||||||
- **Lecteur** : Utilisateur qui lit les articles et peut poster des avis
|
|
||||||
- **Site** : La plateforme zapwall4Science (recevant les commissions)
|
|
||||||
|
|
||||||
### Contenus
|
|
||||||
|
|
||||||
- **Article** : Publication d'un auteur (science-fiction ou recherche scientifique)
|
|
||||||
- **Article de présentation** : Article obligatoire créé par chaque auteur lors de son inscription, contenant sa présentation, description de son contenu et adresse de sponsoring mainnet
|
|
||||||
- **Avis** : Commentaire/évaluation d'un article par un lecteur qui a acheté l'article
|
|
||||||
- **Message d'envoi de l'article** : Message privé chiffré (kind:4) envoyé automatiquement après paiement d'un article
|
|
||||||
|
|
||||||
### Paiements
|
|
||||||
|
|
||||||
- **Paiement** : Transaction Bitcoin/Lightning pour accéder à un article ou sponsoriser un auteur
|
|
||||||
- **Sponsoring** : Paiement unique de 0.05 BTC pour sponsoriser un auteur (0.004 BTC au site, 0.046 BTC à l'auteur)
|
|
||||||
- **Commission pour le site sur la vente d'un article** : 100 sats sur chaque achat d'article (800 sats total, 700 à l'auteur)
|
|
||||||
- **Commission pour le site sur le remerciement d'un avis** : 21 sats sur chaque rémunération d'avis (70 sats au lecteur, 21 sats au site)
|
|
||||||
- **Remerciement pour l'avis** : Paiement de 70 sats (21 sats commission site) par l'auteur à un lecteur pour son avis
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🏗️ Architecture fonctionnelle
|
|
||||||
|
|
||||||
### 1. Article de présentation obligatoire
|
|
||||||
|
|
||||||
**Description** : Chaque auteur doit créer un article de présentation lors de sa première connexion.
|
|
||||||
|
|
||||||
**Contenu obligatoire** :
|
|
||||||
- Titre : "Présentation de [Nom auteur]"
|
|
||||||
- Présentation personnelle de l'auteur
|
|
||||||
- Description/aperçu du type de contenu qu'il publie
|
|
||||||
- Adresse Bitcoin mainnet pour le sponsoring (obligatoire)
|
|
||||||
|
|
||||||
**Caractéristiques** :
|
|
||||||
- Article gratuit (pas de paiement requis)
|
|
||||||
- Visible par tous
|
|
||||||
- Tag spécial : `presentation: true`
|
|
||||||
- Tag : `category: author-presentation`
|
|
||||||
- Tag : `mainnet_address: [adresse]`
|
|
||||||
- Non supprimable (peut être édité)
|
|
||||||
- Un seul par auteur
|
|
||||||
|
|
||||||
**Fichiers à créer/modifier** :
|
|
||||||
- `components/AuthorPresentationEditor.tsx` : Éditeur d'article de présentation
|
|
||||||
- `lib/articlePublisher.ts` : Vérification de l'existence d'un article de présentation
|
|
||||||
- `hooks/useAuthorPresentation.ts` : Hook pour gérer l'article de présentation
|
|
||||||
- `types/nostr.ts` : Ajout du type `AuthorPresentationArticle`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2. Division en 2 catégories
|
|
||||||
|
|
||||||
**Catégories** :
|
|
||||||
1. **Science-fiction** (`category: science-fiction`)
|
|
||||||
2. **Recherche scientifique** (`category: scientific-research`)
|
|
||||||
|
|
||||||
**Fonctionnalités** :
|
|
||||||
- Les auteurs peuvent publier dans les 2 catégories
|
|
||||||
- Filtrage par catégorie sur la page d'accueil
|
|
||||||
- Onglets ou sections distinctes pour chaque catégorie
|
|
||||||
- Tag obligatoire `category` sur chaque article (sauf article de présentation)
|
|
||||||
|
|
||||||
**Fichiers à créer/modifier** :
|
|
||||||
- `components/CategoryFilter.tsx` : Filtre par catégorie
|
|
||||||
- `pages/index.tsx` : Affichage par catégories
|
|
||||||
- `lib/articleFiltering.ts` : Filtrage par catégorie
|
|
||||||
- `types/nostr.ts` : Ajout de `ArticleCategory`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3. Tri des articles
|
|
||||||
|
|
||||||
**Ordre de tri** :
|
|
||||||
1. **Par sponsoring** : Auteurs les plus sponsorisés en premier
|
|
||||||
2. **Par date** : Articles les plus récents en premier (parmi les auteurs de même niveau de sponsoring)
|
|
||||||
|
|
||||||
**Calcul du sponsoring** :
|
|
||||||
- Somme totale des paiements de sponsoring reçus par l'auteur
|
|
||||||
- Stocké dans un tag sur l'article de présentation : `total_sponsoring: [montant en sats]`
|
|
||||||
- Mis à jour à chaque nouveau sponsoring
|
|
||||||
|
|
||||||
**Fichiers à créer/modifier** :
|
|
||||||
- `lib/articleFiltering.ts` : Tri par sponsoring puis date
|
|
||||||
- `lib/sponsoring.ts` : Service de gestion du sponsoring
|
|
||||||
- `types/nostr.ts` : Ajout de `totalSponsoring` dans `Article`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 4. Système de sponsoring
|
|
||||||
|
|
||||||
**Montant** : 0.05 BTC (5 000 000 sats)
|
|
||||||
|
|
||||||
**Répartition** :
|
|
||||||
- **Site** : 0.004 BTC (400 000 sats) - frais de transaction payés par l'auteur
|
|
||||||
- **Auteur** : 0.046 BTC (4 600 000 sats) - frais de transaction payés par l'auteur
|
|
||||||
|
|
||||||
**Fonctionnement** :
|
|
||||||
- Paiement unique vers l'adresse mainnet de l'auteur (depuis l'article de présentation)
|
|
||||||
- Transaction Bitcoin mainnet (pas Lightning)
|
|
||||||
- Mise à jour du tag `total_sponsoring` sur l'article de présentation
|
|
||||||
- Affichage du montant total sponsorisé sur le profil de l'auteur
|
|
||||||
|
|
||||||
**Fichiers à créer/modifier** :
|
|
||||||
- `components/SponsorButton.tsx` : Bouton de sponsoring
|
|
||||||
- `lib/sponsoring.ts` : Service de sponsoring
|
|
||||||
- `lib/bitcoinMainnet.ts` : Service pour les paiements mainnet
|
|
||||||
- `types/sponsoring.ts` : Types pour le sponsoring
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 5. Paiement d'article modifié (BOLT12)
|
|
||||||
|
|
||||||
**Montant** : 800 sats
|
|
||||||
|
|
||||||
**Répartition** :
|
|
||||||
- **Auteur** : 700 sats - frais de transaction payés par l'auteur
|
|
||||||
- **Site** : 100 sats - frais de transaction payés par l'auteur
|
|
||||||
|
|
||||||
**Technologie** : BOLT12 (offers) pour diviser automatiquement le paiement
|
|
||||||
|
|
||||||
**Fonctionnement** :
|
|
||||||
- Création d'une offre BOLT12 avec split automatique
|
|
||||||
- 700 sats vers l'adresse Lightning de l'auteur
|
|
||||||
- 100 sats vers l'adresse Lightning du site
|
|
||||||
- Frais de transaction payés par l'auteur (déduits de sa part)
|
|
||||||
|
|
||||||
**Fichiers à créer/modifier** :
|
|
||||||
- `lib/bolt12.ts` : Service BOLT12 pour les offres avec split
|
|
||||||
- `lib/payment.ts` : Modification pour utiliser BOLT12
|
|
||||||
- `types/payment.ts` : Types pour BOLT12
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 6. Système de rémunération des avis
|
|
||||||
|
|
||||||
**Conditions** :
|
|
||||||
- Seuls les lecteurs qui ont acheté l'article peuvent poster un avis
|
|
||||||
- L'auteur peut rémunérer un avis avec 70 sats
|
|
||||||
|
|
||||||
**Répartition** :
|
|
||||||
- **Lecteur (auteur de l'avis)** : 70 sats - frais de transaction payés par l'auteur
|
|
||||||
- **Site** : 21 sats - frais de transaction payés par l'auteur
|
|
||||||
|
|
||||||
**Fonctionnement** :
|
|
||||||
- Bouton "Remercier" sur chaque avis (visible uniquement par l'auteur de l'article)
|
|
||||||
- Paiement Lightning avec split automatique (BOLT12)
|
|
||||||
- Tag sur l'avis : `rewarded: true`, `reward_amount: 70`
|
|
||||||
|
|
||||||
**Fichiers à créer/modifier** :
|
|
||||||
- `components/ArticleReview.tsx` : Composant d'avis avec bouton de rémunération
|
|
||||||
- `components/ReviewRewardButton.tsx` : Bouton de rémunération d'avis
|
|
||||||
- `lib/reviewReward.ts` : Service de rémunération des avis
|
|
||||||
- `types/reviews.ts` : Types pour les avis
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔧 Modifications techniques
|
|
||||||
|
|
||||||
### Structure de données
|
|
||||||
|
|
||||||
#### Article de présentation
|
|
||||||
```typescript
|
|
||||||
interface AuthorPresentationArticle extends Article {
|
|
||||||
category: 'author-presentation'
|
|
||||||
mainnetAddress: string
|
|
||||||
totalSponsoring: number // en sats
|
|
||||||
isPresentation: true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Article standard
|
|
||||||
```typescript
|
|
||||||
interface StandardArticle extends Article {
|
|
||||||
category: 'science-fiction' | 'scientific-research'
|
|
||||||
authorPresentationId: string // ID de l'article de présentation
|
|
||||||
lightningAddress: string // Adresse Lightning de l'auteur
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Avis
|
|
||||||
```typescript
|
|
||||||
interface Review {
|
|
||||||
id: string
|
|
||||||
articleId: string
|
|
||||||
authorPubkey: string // Auteur de l'article
|
|
||||||
reviewerPubkey: string // Lecteur qui a écrit l'avis
|
|
||||||
content: string
|
|
||||||
rating?: number // 1-5 étoiles
|
|
||||||
createdAt: number
|
|
||||||
rewarded: boolean
|
|
||||||
rewardAmount?: number // 70 sats si rémunéré
|
|
||||||
rewardTransactionId?: string
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Tags Nostr
|
|
||||||
|
|
||||||
#### Article de présentation
|
|
||||||
```
|
|
||||||
- title: "Présentation de [Nom]"
|
|
||||||
- category: "author-presentation"
|
|
||||||
- presentation: "true"
|
|
||||||
- mainnet_address: "[adresse Bitcoin]"
|
|
||||||
- total_sponsoring: "[montant en sats]"
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Article standard
|
|
||||||
```
|
|
||||||
- title: "[Titre]"
|
|
||||||
- category: "science-fiction" | "scientific-research"
|
|
||||||
- preview: "[Aperçu]"
|
|
||||||
- zap: "800"
|
|
||||||
- author_presentation_id: "[ID article présentation]"
|
|
||||||
- lightning_address: "[adresse Lightning auteur]"
|
|
||||||
- invoice: "[BOLT12 offer]"
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Avis (kind:1 avec tag spécial)
|
|
||||||
```
|
|
||||||
- review: "true"
|
|
||||||
- e: "[ID article]"
|
|
||||||
- p: "[pubkey auteur]"
|
|
||||||
- rating: "[1-5]"
|
|
||||||
- rewarded: "true" | "false"
|
|
||||||
- reward_amount: "70" (si rémunéré)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📁 Fichiers à créer
|
|
||||||
|
|
||||||
### Nouveaux composants
|
|
||||||
- `components/AuthorPresentationEditor.tsx`
|
|
||||||
- `components/CategoryFilter.tsx`
|
|
||||||
- `components/CategoryTabs.tsx`
|
|
||||||
- `components/SponsorButton.tsx`
|
|
||||||
- `components/ArticleReview.tsx`
|
|
||||||
- `components/ReviewRewardButton.tsx`
|
|
||||||
- `components/ReviewForm.tsx`
|
|
||||||
|
|
||||||
### Nouveaux services
|
|
||||||
- `lib/sponsoring.ts`
|
|
||||||
- `lib/bitcoinMainnet.ts`
|
|
||||||
- `lib/bolt12.ts`
|
|
||||||
- `lib/reviewReward.ts`
|
|
||||||
- `lib/reviews.ts`
|
|
||||||
|
|
||||||
### Nouveaux hooks
|
|
||||||
- `hooks/useAuthorPresentation.ts`
|
|
||||||
- `hooks/useSponsoring.ts`
|
|
||||||
- `hooks/useReviews.ts`
|
|
||||||
- `hooks/useReviewReward.ts`
|
|
||||||
|
|
||||||
### Nouveaux types
|
|
||||||
- `types/sponsoring.ts`
|
|
||||||
- `types/reviews.ts`
|
|
||||||
- `types/bolt12.ts`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📁 Fichiers à modifier
|
|
||||||
|
|
||||||
### Pages
|
|
||||||
- `pages/index.tsx` : Ajout des catégories et tri par sponsoring
|
|
||||||
- `pages/publish.tsx` : Sélection de catégorie obligatoire
|
|
||||||
- `pages/profile.tsx` : Affichage de l'article de présentation et sponsoring
|
|
||||||
|
|
||||||
### Composants existants
|
|
||||||
- `components/ArticleCard.tsx` : Affichage catégorie et sponsoring
|
|
||||||
- `components/ArticleEditor.tsx` : Sélection de catégorie
|
|
||||||
- `components/UserProfile.tsx` : Affichage sponsoring total
|
|
||||||
|
|
||||||
### Services existants
|
|
||||||
- `lib/articlePublisher.ts` : Vérification article de présentation
|
|
||||||
- `lib/payment.ts` : Migration vers BOLT12
|
|
||||||
- `lib/articleFiltering.ts` : Tri par sponsoring
|
|
||||||
- `lib/nostr.ts` : Parsing des nouveaux tags
|
|
||||||
|
|
||||||
### Types existants
|
|
||||||
- `types/nostr.ts` : Ajout des nouveaux types
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔄 Flux utilisateur
|
|
||||||
|
|
||||||
### Inscription d'un auteur
|
|
||||||
1. Connexion avec Nostr
|
|
||||||
2. Redirection vers création d'article de présentation (obligatoire)
|
|
||||||
3. Remplissage : présentation, description, adresse mainnet
|
|
||||||
4. Publication de l'article de présentation
|
|
||||||
5. Accès à la plateforme
|
|
||||||
|
|
||||||
### Publication d'un article
|
|
||||||
1. Sélection de la catégorie (science-fiction ou recherche)
|
|
||||||
2. Remplissage du formulaire (titre, preview, contenu)
|
|
||||||
3. Création de l'offre BOLT12 avec split (700/100)
|
|
||||||
4. Publication avec tags appropriés
|
|
||||||
|
|
||||||
### Achat d'un article
|
|
||||||
1. Clic sur "Unlock for 800 sats"
|
|
||||||
2. Affichage de l'offre BOLT12
|
|
||||||
3. Paiement Lightning
|
|
||||||
4. Réception automatique du contenu (message privé)
|
|
||||||
5. Possibilité de poster un avis
|
|
||||||
|
|
||||||
### Sponsoring d'un auteur
|
|
||||||
1. Clic sur "Sponsor" sur l'article de présentation
|
|
||||||
2. Affichage de l'adresse mainnet
|
|
||||||
3. Paiement Bitcoin mainnet de 0.05 BTC
|
|
||||||
4. Mise à jour du sponsoring total
|
|
||||||
5. Tri mis à jour
|
|
||||||
|
|
||||||
### Rémunération d'un avis
|
|
||||||
1. Auteur voit l'avis d'un lecteur qui a acheté
|
|
||||||
2. Clic sur "Remercier (70 sats)"
|
|
||||||
3. Paiement Lightning avec split (70/21)
|
|
||||||
4. Tag `rewarded: true` sur l'avis
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ⚠️ Points d'attention
|
|
||||||
|
|
||||||
### BOLT12
|
|
||||||
- Vérifier la compatibilité avec Alby/WebLN pour BOLT12
|
|
||||||
- Implémenter le split automatique dans l'offre
|
|
||||||
- Gérer les frais de transaction
|
|
||||||
|
|
||||||
### Bitcoin Mainnet
|
|
||||||
- Intégration avec un service de paiement mainnet (ou QR code)
|
|
||||||
- Vérification des paiements mainnet
|
|
||||||
- Gestion des confirmations
|
|
||||||
|
|
||||||
### Sécurité
|
|
||||||
- Vérifier que seuls les acheteurs peuvent poster des avis
|
|
||||||
- Vérifier que seul l'auteur peut rémunérer les avis
|
|
||||||
- Vérifier l'authenticité des paiements
|
|
||||||
|
|
||||||
### Performance
|
|
||||||
- Indexer les articles par catégorie
|
|
||||||
- Indexer les auteurs par sponsoring total
|
|
||||||
- Cache des calculs de tri
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 Priorités d'implémentation
|
|
||||||
|
|
||||||
### Phase 1 - Fondations
|
|
||||||
1. ✅ Wording et terminologie (documentation)
|
|
||||||
2. ⏳ Article de présentation obligatoire
|
|
||||||
3. ⏳ Division en catégories
|
|
||||||
4. ⏳ Tri par sponsoring puis date
|
|
||||||
|
|
||||||
### Phase 2 - Paiements
|
|
||||||
5. ⏳ Système de sponsoring (Bitcoin mainnet)
|
|
||||||
6. ⏳ Migration vers BOLT12 pour les articles
|
|
||||||
7. ⏳ Split automatique des paiements
|
|
||||||
|
|
||||||
### Phase 3 - Avis et rémunération
|
|
||||||
8. ⏳ Système d'avis (seulement pour acheteurs)
|
|
||||||
9. ⏳ Rémunération des avis par l'auteur
|
|
||||||
|
|
||||||
### Phase 4 - UI/UX
|
|
||||||
10. ⏳ Interface par catégories
|
|
||||||
11. ⏳ Affichage du sponsoring
|
|
||||||
12. ⏳ Interface de rémunération des avis
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎨 Renommage
|
|
||||||
|
|
||||||
- **Nom du site** : zapwall4Science
|
|
||||||
- **Titre** : "zapwall4Science - Science Fiction & Scientific Research"
|
|
||||||
- **Description** : "Plateforme de publication d'articles scientifiques et de science-fiction avec sponsoring et rémunération des avis"
|
|
||||||
|
|
||||||
**Fichiers à modifier** :
|
|
||||||
- `pages/index.tsx` : Titre et description
|
|
||||||
- `pages/_app.tsx` : Titre par défaut
|
|
||||||
- `README.md` : Nom et description
|
|
||||||
- Tous les composants avec "Nostr Paywall" → "zapwall4Science"
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📝 Notes techniques
|
|
||||||
|
|
||||||
### BOLT12 Offers
|
|
||||||
- Utiliser `lightning:lno1...` pour les offres
|
|
||||||
- Split automatique via les métadonnées de l'offre
|
|
||||||
- Vérifier la compatibilité avec les wallets Lightning
|
|
||||||
|
|
||||||
### Bitcoin Mainnet
|
|
||||||
- Utiliser une API de vérification de transactions (blockchain.info, blockstream, etc.)
|
|
||||||
- QR code pour faciliter les paiements
|
|
||||||
- Affichage clair de l'adresse et du montant
|
|
||||||
|
|
||||||
### Stockage
|
|
||||||
- Stocker les montants de sponsoring dans IndexedDB
|
|
||||||
- Cache des calculs de tri
|
|
||||||
- Synchronisation avec les événements Nostr
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✅ Checklist de validation
|
|
||||||
|
|
||||||
- [ ] Article de présentation créé pour chaque auteur
|
|
||||||
- [ ] Catégories fonctionnelles (science-fiction / recherche)
|
|
||||||
- [ ] Tri par sponsoring puis date opérationnel
|
|
||||||
- [ ] Sponsoring Bitcoin mainnet fonctionnel
|
|
||||||
- [ ] Paiements articles avec BOLT12 et split
|
|
||||||
- [ ] Avis uniquement pour les acheteurs
|
|
||||||
- [ ] Rémunération des avis fonctionnelle
|
|
||||||
- [ ] Wording cohérent partout
|
|
||||||
- [ ] Renommage complet en zapwall4Science
|
|
||||||
@ -1,58 +0,0 @@
|
|||||||
# Problème : favicon.ico retourne 404
|
|
||||||
|
|
||||||
## Date
|
|
||||||
2025-01-27
|
|
||||||
|
|
||||||
## Problème
|
|
||||||
Le navigateur demandait automatiquement `/favicon.ico` mais le fichier n'existait pas dans le dossier `public/`, causant une erreur 404.
|
|
||||||
|
|
||||||
## Symptômes
|
|
||||||
- Console navigateur : `Failed to load resource: the server responded with a status of 404 ()`
|
|
||||||
- Erreur répétée sur toutes les pages : `favicon.ico:1 Failed to load resource: the server responded with a status of 404 ()`
|
|
||||||
- Aucun favicon affiché dans les onglets du navigateur
|
|
||||||
|
|
||||||
## Root cause
|
|
||||||
Le fichier `favicon.ico` n'existait pas dans le dossier `public/`, mais plusieurs pages référençaient `/favicon.ico` dans leur balise `<Head>` :
|
|
||||||
- `components/HomeView.tsx`
|
|
||||||
- `pages/presentation.tsx`
|
|
||||||
- `pages/docs.tsx`
|
|
||||||
|
|
||||||
Les navigateurs demandent automatiquement `/favicon.ico` même si une autre icône est spécifiée, ce qui causait l'erreur 404.
|
|
||||||
|
|
||||||
## Impact
|
|
||||||
- Erreurs 404 répétées dans les logs du serveur
|
|
||||||
- Aucun favicon affiché dans les onglets du navigateur
|
|
||||||
- Expérience utilisateur dégradée
|
|
||||||
|
|
||||||
## Correctifs
|
|
||||||
1. Création d'un fichier `favicon.svg` minimal dans `public/`
|
|
||||||
2. Mise à jour des références dans les fichiers pour pointer vers `/favicon.svg` au lieu de `/favicon.ico`
|
|
||||||
3. Ajout du type MIME `image/svg+xml` dans les balises `<link>`
|
|
||||||
|
|
||||||
## Modifications
|
|
||||||
- **Fichier créé** : `public/favicon.svg` (SVG minimal avec un rectangle cyan)
|
|
||||||
- **Fichiers modifiés** :
|
|
||||||
- `components/HomeView.tsx` : `<link rel="icon" href="/favicon.svg" type="image/svg+xml" />`
|
|
||||||
- `pages/presentation.tsx` : `<link rel="icon" href="/favicon.svg" type="image/svg+xml" />`
|
|
||||||
- `pages/docs.tsx` : `<link rel="icon" href="/favicon.svg" type="image/svg+xml" />`
|
|
||||||
|
|
||||||
## Modalités de déploiement
|
|
||||||
1. Les modifications sont dans le code source
|
|
||||||
2. Le fichier `favicon.svg` est servi automatiquement par Next.js depuis le dossier `public/`
|
|
||||||
3. Rebuild de l'application : `npm run build`
|
|
||||||
4. Redémarrage du service Next.js si nécessaire
|
|
||||||
5. Aucune configuration supplémentaire nécessaire
|
|
||||||
|
|
||||||
## Modalités d'analyse
|
|
||||||
Pour vérifier si le problème existe :
|
|
||||||
1. Vérifier la présence du fichier `public/favicon.svg`
|
|
||||||
2. Vérifier les références dans les fichiers HTML (balises `<link rel="icon">`)
|
|
||||||
3. Tester dans le navigateur : accéder à `/favicon.svg` et vérifier qu'il est servi
|
|
||||||
4. Vérifier les logs du serveur pour les erreurs 404 sur `/favicon.ico`
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
- Les navigateurs modernes supportent les SVG comme favicon
|
|
||||||
- SVG est plus léger et plus flexible qu'un fichier .ico
|
|
||||||
- Si nécessaire, on peut créer un fichier `.ico` en plus pour la compatibilité avec les anciens navigateurs
|
|
||||||
- Le favicon SVG actuel est minimal (rectangle cyan) et peut être remplacé par un design plus élaboré si nécessaire
|
|
||||||
|
|
||||||
@ -1,60 +0,0 @@
|
|||||||
# Configuration des certificats Let's Encrypt pour zapwall.fr
|
|
||||||
|
|
||||||
## Date
|
|
||||||
2025-12-28
|
|
||||||
|
|
||||||
## Problème
|
|
||||||
Le site https://zapwall.fr/ utilisait des certificats auto-signés, ce qui provoquait des avertissements de sécurité dans les navigateurs.
|
|
||||||
|
|
||||||
## Solution
|
|
||||||
Configuration de certificats Let's Encrypt valides via certbot snap.
|
|
||||||
|
|
||||||
## Motivations
|
|
||||||
- Éliminer les avertissements de sécurité dans les navigateurs
|
|
||||||
- Obtenir des certificats SSL valides et reconnus
|
|
||||||
- Utiliser certbot snap pour éviter le bug avec certbot et Python 3.11
|
|
||||||
|
|
||||||
## Root causes
|
|
||||||
- Certificats auto-signés utilisés initialement
|
|
||||||
- Certbot classique présentait un bug `AttributeError: can't set attribute` avec Python 3.11
|
|
||||||
- Solution : utiliser certbot via snap qui utilise son propre environnement Python
|
|
||||||
|
|
||||||
## Correctifs
|
|
||||||
1. Installation de certbot via snap : `sudo snap install certbot --classic`
|
|
||||||
2. Obtention des certificats en mode standalone (nginx arrêté) : `sudo certbot certonly --standalone -d zapwall.fr`
|
|
||||||
3. Copie des certificats dans le volume monté Docker pour nginx
|
|
||||||
4. Mise à jour de la configuration nginx pour utiliser les certificats Let's Encrypt
|
|
||||||
|
|
||||||
## Modifications
|
|
||||||
- **Certificats obtenus** : `/etc/letsencrypt/live/zapwall.fr/` (sur l'hôte)
|
|
||||||
- **Volume monté** : `/home/debian/sites/test-lecoffreio.4nkweb.com/deploy/nginx/certbot/conf-test/` → `/etc/letsencrypt` (dans le conteneur, en lecture seule)
|
|
||||||
- **Configuration nginx** :
|
|
||||||
- `ssl_certificate /etc/letsencrypt/live/zapwall.fr/fullchain.pem;`
|
|
||||||
- `ssl_certificate_key /etc/letsencrypt/live/zapwall.fr/privkey.pem;`
|
|
||||||
|
|
||||||
## Modalités de déploiement
|
|
||||||
1. Installer snap si nécessaire : `sudo apt-get install -y snapd`
|
|
||||||
2. Installer certbot via snap : `sudo snap install certbot --classic`
|
|
||||||
3. Arrêter nginx : `sudo docker stop lecoffre_nginx_test`
|
|
||||||
4. Obtenir les certificats : `sudo certbot certonly --standalone -d zapwall.fr --non-interactive --agree-tos --email admin@zapwall.fr`
|
|
||||||
5. Copier les certificats dans le volume monté :
|
|
||||||
- Créer la structure : `sudo mkdir -p /home/debian/sites/test-lecoffreio.4nkweb.com/deploy/nginx/certbot/conf-test/{live,archive}/zapwall.fr`
|
|
||||||
- Copier les fichiers : `sudo cp /etc/letsencrypt/archive/zapwall.fr/* /home/debian/sites/test-lecoffreio.4nkweb.com/deploy/nginx/certbot/conf-test/archive/zapwall.fr/`
|
|
||||||
- Créer les liens symboliques dans `live/zapwall.fr/`
|
|
||||||
6. Redémarrer nginx : `sudo docker start lecoffre_nginx_test`
|
|
||||||
7. Mettre à jour la configuration nginx pour pointer vers les certificats Let's Encrypt
|
|
||||||
8. Recharger nginx : `sudo docker exec lecoffre_nginx_test nginx -s reload`
|
|
||||||
|
|
||||||
## Modalités d'analyse
|
|
||||||
Pour vérifier l'état des certificats :
|
|
||||||
1. Vérifier les certificats sur l'hôte : `sudo ls -la /etc/letsencrypt/live/zapwall.fr/`
|
|
||||||
2. Vérifier dans le conteneur : `sudo docker exec lecoffre_nginx_test ls -la /etc/letsencrypt/live/zapwall.fr/`
|
|
||||||
3. Vérifier la configuration nginx : `sudo docker exec lecoffre_nginx_test grep ssl_certificate /etc/nginx/conf.d/zapwall.fr.conf`
|
|
||||||
4. Tester la connexion SSL : `openssl s_client -connect zapwall.fr:443 -servername zapwall.fr`
|
|
||||||
|
|
||||||
## Notes importantes
|
|
||||||
- Les certificats sont valides uniquement pour `zapwall.fr` (pas pour `www.zapwall.fr`)
|
|
||||||
- Pour ajouter `www.zapwall.fr`, configurer d'abord le DNS, puis relancer certbot avec `-d zapwall.fr -d www.zapwall.fr`
|
|
||||||
- Les certificats expirent après 90 jours, mais certbot snap configure automatiquement le renouvellement
|
|
||||||
- Le volume `/etc/letsencrypt` est monté en lecture seule dans le conteneur, donc les certificats doivent être copiés sur l'hôte dans le répertoire monté
|
|
||||||
- Certbot snap utilise son propre environnement Python, évitant le bug avec Python 3.11
|
|
||||||
@ -1,57 +0,0 @@
|
|||||||
# Problème : nginx ne charge pas les configurations dans conf.d
|
|
||||||
|
|
||||||
## Date
|
|
||||||
2025-12-28
|
|
||||||
|
|
||||||
## Problème
|
|
||||||
Le site https://zapwall.fr/ pointait vers le mauvais site (LEcoffre au lieu de Zapwall) malgré une configuration correcte dans `/etc/nginx/conf.d/zapwall.fr.conf`.
|
|
||||||
|
|
||||||
## Symptômes
|
|
||||||
- https://zapwall.fr/ servait le site LEcoffre (test-lecoffreio.4nkweb.com)
|
|
||||||
- La configuration `zapwall.fr.conf` existait et était correcte
|
|
||||||
- Le service zapwall fonctionnait correctement sur le port 3001
|
|
||||||
- Nginx ne chargeait pas les configurations dans `conf.d/`
|
|
||||||
|
|
||||||
## Root cause
|
|
||||||
La configuration principale nginx (`/etc/nginx/nginx.conf` dans le conteneur Docker `lecoffre_nginx_test`) ne contenait pas la directive `include /etc/nginx/conf.d/*.conf;` pour charger les configurations des sites dans le répertoire `conf.d/`.
|
|
||||||
|
|
||||||
Le fichier nginx.conf était monté depuis l'hôte (`/home/debian/sites/test-lecoffreio.4nkweb.com/deploy/nginx/nginx-test.conf`) et ne chargeait que la configuration pour `test-lecoffreio.4nkweb.com`.
|
|
||||||
|
|
||||||
## Impact
|
|
||||||
- Le site zapwall.fr n'était pas accessible correctement
|
|
||||||
- Les utilisateurs voyaient le mauvais site
|
|
||||||
- La configuration zapwall.fr.conf était ignorée par nginx
|
|
||||||
|
|
||||||
## Correctifs
|
|
||||||
1. Ajout de la directive `include /etc/nginx/conf.d/*.conf;` dans le bloc `http` de nginx.conf, avant la fermeture du bloc
|
|
||||||
2. Modification du fichier sur l'hôte : `/home/debian/sites/test-lecoffreio.4nkweb.com/deploy/nginx/nginx-test.conf`
|
|
||||||
3. Redémarrage du conteneur nginx pour prendre en compte la modification
|
|
||||||
|
|
||||||
## Modifications
|
|
||||||
- **Fichier modifié** : `/home/debian/sites/test-lecoffreio.4nkweb.com/deploy/nginx/nginx-test.conf` (sur l'hôte)
|
|
||||||
- **Ajout** :
|
|
||||||
```nginx
|
|
||||||
# Include site configurations
|
|
||||||
include /etc/nginx/conf.d/*.conf;
|
|
||||||
```
|
|
||||||
Avant la fermeture du bloc `http` (avant `}`)
|
|
||||||
|
|
||||||
## Modalités de déploiement
|
|
||||||
1. Arrêter le conteneur nginx : `sudo docker stop lecoffre_nginx_test`
|
|
||||||
2. Modifier le fichier sur l'hôte : `/home/debian/sites/test-lecoffreio.4nkweb.com/deploy/nginx/nginx-test.conf`
|
|
||||||
3. Ajouter l'inclusion avant la fermeture du bloc `http`
|
|
||||||
4. Démarrer le conteneur : `sudo docker start lecoffre_nginx_test`
|
|
||||||
5. Vérifier la configuration : `sudo docker exec lecoffre_nginx_test nginx -t`
|
|
||||||
6. Vérifier que zapwall.fr est chargé : `sudo docker exec lecoffre_nginx_test nginx -T | grep "server_name zapwall.fr"`
|
|
||||||
|
|
||||||
## Modalités d'analyse
|
|
||||||
Pour vérifier si le problème existe :
|
|
||||||
1. Vérifier si l'inclusion existe : `sudo docker exec lecoffre_nginx_test cat /etc/nginx/nginx.conf | grep "include.*conf.d"`
|
|
||||||
2. Vérifier si zapwall.fr est chargé : `sudo docker exec lecoffre_nginx_test nginx -T | grep "server_name zapwall.fr"`
|
|
||||||
3. Tester avec curl : `sudo docker exec lecoffre_nginx_test curl -s -k -H "Host: zapwall.fr" https://localhost | head -5`
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
- Le fichier nginx.conf est monté en lecture seule depuis l'hôte dans le conteneur Docker
|
|
||||||
- Les modifications doivent être faites sur l'hôte, pas dans le conteneur
|
|
||||||
- Le conteneur doit être redémarré pour prendre en compte les modifications du fichier monté
|
|
||||||
- L'inclusion doit être dans le bloc `http`, pas après sa fermeture
|
|
||||||
@ -1,64 +0,0 @@
|
|||||||
# Problème : API NIP-95 upload retourne 500
|
|
||||||
|
|
||||||
## Date
|
|
||||||
2025-01-27
|
|
||||||
|
|
||||||
## Problème
|
|
||||||
L'endpoint API `/api/nip95-upload` retournait une erreur 500 lors des tentatives d'upload de fichiers via NIP-95.
|
|
||||||
|
|
||||||
## Symptômes
|
|
||||||
- Erreur 500 lors des appels à `/api/nip95-upload?endpoint=https://void.cat/upload`
|
|
||||||
- Console navigateur : `Failed to load resource: the server responded with a status of 500 ()`
|
|
||||||
- Console navigateur : `NIP-95 upload endpoint error: Object`
|
|
||||||
- Les uploads NIP-95 échouaient systématiquement
|
|
||||||
|
|
||||||
## Root cause
|
|
||||||
Le package npm `form-data` n'est pas compatible avec `fetch()` natif de Node.js (Node 18+). L'API utilisait `form-data` de npm avec `fetch()` natif, ce qui causait une incompatibilité car :
|
|
||||||
- `form-data` (npm) utilise des streams Node.js natifs et l'API `getHeaders()` pour obtenir les headers avec le boundary
|
|
||||||
- `fetch()` natif de Node.js attend le FormData du web standard (disponible dans le navigateur), pas le package npm `form-data`
|
|
||||||
- Cette incompatibilité provoquait une erreur lors de l'exécution de la requête HTTP
|
|
||||||
|
|
||||||
## Impact
|
|
||||||
- Impossible d'uploader des fichiers via NIP-95
|
|
||||||
- Les utilisateurs ne pouvaient pas publier d'articles avec des médias
|
|
||||||
- Fonctionnalité d'upload complètement non fonctionnelle
|
|
||||||
|
|
||||||
## Correctifs
|
|
||||||
1. Remplacement de `fetch()` natif par les modules natifs `https` et `http` de Node.js
|
|
||||||
2. Utilisation de `form-data.pipe()` pour envoyer les données via les modules natifs
|
|
||||||
3. Gestion correcte des erreurs et nettoyage des fichiers temporaires dans tous les cas
|
|
||||||
|
|
||||||
## Modifications
|
|
||||||
- **Fichier modifié** : `pages/api/nip95-upload.ts`
|
|
||||||
- **Imports ajoutés** :
|
|
||||||
```typescript
|
|
||||||
import https from 'https'
|
|
||||||
import http from 'http'
|
|
||||||
import { URL } from 'url'
|
|
||||||
```
|
|
||||||
- **Imports supprimés** :
|
|
||||||
```typescript
|
|
||||||
import { Readable } from 'stream' // Non utilisé
|
|
||||||
```
|
|
||||||
- **Remplacement de fetch()** : Utilisation de `https.request()` ou `http.request()` selon le protocole de l'URL cible
|
|
||||||
- **Gestion des erreurs améliorée** : Nettoyage des fichiers temporaires même en cas d'erreur de requête
|
|
||||||
- **Gestion des streams** : Utilisation de `formData.pipe(proxyRequest)` pour envoyer les données
|
|
||||||
|
|
||||||
## Modalités de déploiement
|
|
||||||
1. Les modifications sont dans le code source
|
|
||||||
2. Rebuild de l'application : `npm run build`
|
|
||||||
3. Redémarrage du service Next.js
|
|
||||||
4. Aucune dépendance supplémentaire nécessaire (utilisation des modules natifs Node.js)
|
|
||||||
|
|
||||||
## Modalités d'analyse
|
|
||||||
Pour vérifier si le problème existe :
|
|
||||||
1. Vérifier les logs du serveur pour les erreurs liées à `form-data` ou `fetch`
|
|
||||||
2. Tester l'upload via l'interface utilisateur
|
|
||||||
3. Vérifier les logs de la console navigateur pour les erreurs 500
|
|
||||||
4. Vérifier que `form-data` (npm) est utilisé avec `https`/`http` natif, pas avec `fetch()`
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
- Le package `form-data` (npm) doit être utilisé avec les modules `https`/`http` natifs de Node.js, pas avec `fetch()`
|
|
||||||
- `fetch()` natif de Node.js est compatible avec FormData du web standard (disponible dans le navigateur), pas avec le package npm `form-data`
|
|
||||||
- Les fichiers temporaires créés par formidable doivent être nettoyés même en cas d'erreur pour éviter l'accumulation de fichiers
|
|
||||||
|
|
||||||
@ -1,107 +0,0 @@
|
|||||||
# Problème : Erreur DNS resolution pour NIP-95 upload
|
|
||||||
|
|
||||||
## Date
|
|
||||||
2025-01-27
|
|
||||||
|
|
||||||
## Problème
|
|
||||||
L'API NIP-95 upload retourne une erreur `getaddrinfo ENOTFOUND void.cat` lors des tentatives d'upload, indiquant que le serveur Node.js ne peut pas résoudre le nom de domaine.
|
|
||||||
|
|
||||||
## Symptômes
|
|
||||||
- Erreur : `Failed to upload to all endpoints: {"error":"Failed to connect to upload endpoint: getaddrinfo ENOTFOUND void.cat"}`
|
|
||||||
- Code d'erreur Node.js : `ENOTFOUND` ou `EAI_AGAIN`
|
|
||||||
- Les uploads NIP-95 échouent avec une erreur de résolution DNS
|
|
||||||
|
|
||||||
## Root cause
|
|
||||||
Le serveur Node.js qui exécute l'API Next.js ne peut pas résoudre le nom de domaine `void.cat` (ou d'autres endpoints NIP-95). Cela peut être dû à :
|
|
||||||
|
|
||||||
1. **Problème de DNS sur le serveur** : Le serveur n'a pas accès à un serveur DNS fonctionnel
|
|
||||||
2. **Pas d'accès Internet** : Le serveur n'a pas de connexion Internet ou est derrière un pare-feu qui bloque les requêtes sortantes
|
|
||||||
3. **Configuration réseau incorrecte** : Les paramètres réseau du serveur sont mal configurés
|
|
||||||
4. **Problème de résolution DNS temporaire** : Problème temporaire avec le serveur DNS
|
|
||||||
|
|
||||||
## Impact
|
|
||||||
- Impossible d'uploader des fichiers via NIP-95
|
|
||||||
- Les utilisateurs ne peuvent pas publier d'articles avec des médias
|
|
||||||
- Fonctionnalité d'upload complètement non fonctionnelle
|
|
||||||
|
|
||||||
## Correctifs
|
|
||||||
1. **Amélioration de la gestion d'erreur DNS** : Détection spécifique des erreurs DNS avec messages d'erreur plus clairs
|
|
||||||
2. **Ajout d'un timeout** : Timeout de 30 secondes pour éviter que les requêtes restent bloquées indéfiniment
|
|
||||||
3. **Amélioration des logs** : Logs plus détaillés pour diagnostiquer les problèmes DNS
|
|
||||||
|
|
||||||
## Modifications
|
|
||||||
- **Fichier modifié** : `pages/api/nip95-upload.ts`
|
|
||||||
- **Ajout de timeout** : `timeout: 30000` dans les options de requête
|
|
||||||
- **Détection spécifique des erreurs DNS** : Vérification des codes d'erreur `ENOTFOUND` et `EAI_AGAIN`
|
|
||||||
- **Messages d'erreur améliorés** : Messages plus clairs pour les erreurs DNS avec suggestions de diagnostic
|
|
||||||
- **Logs améliorés** : Logs incluant le hostname, le code d'erreur et des suggestions
|
|
||||||
|
|
||||||
## Modalités de déploiement
|
|
||||||
1. Les modifications sont dans le code source
|
|
||||||
2. Rebuild de l'application : `npm run build`
|
|
||||||
3. Redémarrage du service Next.js
|
|
||||||
4. Aucune dépendance supplémentaire nécessaire
|
|
||||||
|
|
||||||
## Modalités d'analyse
|
|
||||||
Pour diagnostiquer le problème DNS :
|
|
||||||
|
|
||||||
1. **Vérifier la résolution DNS depuis le serveur** :
|
|
||||||
```bash
|
|
||||||
# Depuis le serveur
|
|
||||||
nslookup void.cat
|
|
||||||
# ou
|
|
||||||
dig void.cat
|
|
||||||
# ou
|
|
||||||
host void.cat
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Vérifier la connectivité réseau** :
|
|
||||||
```bash
|
|
||||||
# Tester la connexion HTTPS
|
|
||||||
curl -v https://void.cat/upload
|
|
||||||
# ou
|
|
||||||
wget --spider https://void.cat/upload
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Vérifier les logs du serveur Node.js** :
|
|
||||||
- Chercher les erreurs `ENOTFOUND` ou `EAI_AGAIN`
|
|
||||||
- Vérifier les logs avec le hostname et les suggestions
|
|
||||||
|
|
||||||
4. **Vérifier la configuration DNS du serveur** :
|
|
||||||
```bash
|
|
||||||
# Vérifier les serveurs DNS configurés
|
|
||||||
cat /etc/resolv.conf
|
|
||||||
# ou sur systemd
|
|
||||||
systemd-resolve --status
|
|
||||||
```
|
|
||||||
|
|
||||||
5. **Tester depuis le conteneur/service** :
|
|
||||||
```bash
|
|
||||||
# Si le service tourne dans un conteneur Docker
|
|
||||||
docker exec <container_name> nslookup void.cat
|
|
||||||
docker exec <container_name> curl -v https://void.cat/upload
|
|
||||||
```
|
|
||||||
|
|
||||||
## Solutions possibles
|
|
||||||
|
|
||||||
### Si le problème est la résolution DNS
|
|
||||||
1. Vérifier que le serveur a accès à un serveur DNS fonctionnel
|
|
||||||
2. Configurer des serveurs DNS fiables (par exemple 8.8.8.8, 1.1.1.1)
|
|
||||||
3. Vérifier que `/etc/resolv.conf` contient des serveurs DNS valides
|
|
||||||
|
|
||||||
### Si le problème est l'accès Internet
|
|
||||||
1. Vérifier que le serveur a une connexion Internet fonctionnelle
|
|
||||||
2. Vérifier les règles de pare-feu qui pourraient bloquer les requêtes sortantes HTTPS
|
|
||||||
3. Vérifier les proxies si le serveur est derrière un proxy
|
|
||||||
|
|
||||||
### Si le problème est temporaire
|
|
||||||
1. Attendre quelques minutes et réessayer
|
|
||||||
2. Vérifier si d'autres services ont des problèmes de connectivité
|
|
||||||
3. Vérifier les statuts des endpoints NIP-95 (void.cat, etc.)
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
- L'erreur `ENOTFOUND` signifie que le nom de domaine n'a pas pu être résolu en adresse IP
|
|
||||||
- L'erreur `EAI_AGAIN` signifie que la résolution DNS a échoué temporairement (peut être réessayé)
|
|
||||||
- Le timeout de 30 secondes évite que les requêtes restent bloquées indéfiniment
|
|
||||||
- Les messages d'erreur améliorés aident à diagnostiquer rapidement le problème
|
|
||||||
- Si le problème persiste, vérifier la configuration réseau du serveur et l'accès à Internet
|
|
||||||
@ -1,128 +0,0 @@
|
|||||||
# Authentification pour nostrcheck.me API
|
|
||||||
|
|
||||||
## Date
|
|
||||||
2025-01-27
|
|
||||||
|
|
||||||
## Problème
|
|
||||||
L'endpoint `https://nostrcheck.me/api/v1/media` retourne une erreur 401 Unauthorized lors des tentatives d'upload, indiquant qu'une authentification est requise.
|
|
||||||
|
|
||||||
## Symptômes
|
|
||||||
- Erreur 401 lors des appels à `/api/nip95-upload?endpoint=https://nostrcheck.me/api/v1/media`
|
|
||||||
- Message d'erreur : `{"result":false,"description":"Authorization header not found"}`
|
|
||||||
- Les uploads vers nostrcheck.me échouent systématiquement
|
|
||||||
|
|
||||||
## Recherche effectuée
|
|
||||||
|
|
||||||
### Informations trouvées sur nostrcheck.me
|
|
||||||
|
|
||||||
1. **Authentification du site web** :
|
|
||||||
- Support de NIP-07 (extensions de navigateur comme Alby)
|
|
||||||
- Code à usage unique envoyé via message direct Nostr lors de l'inscription
|
|
||||||
- Nécessite la création d'un compte sur nostrcheck.me
|
|
||||||
|
|
||||||
2. **Services offerts** :
|
|
||||||
- Enregistrement d'adresses Nostr (NIP-05)
|
|
||||||
- Hébergement de médias
|
|
||||||
- Galeries privées et publiques
|
|
||||||
- Relais privé
|
|
||||||
|
|
||||||
3. **API d'upload** :
|
|
||||||
- Endpoint : `https://nostrcheck.me/api/v1/media`
|
|
||||||
- Nécessite un header `Authorization`
|
|
||||||
- Format du header non documenté publiquement
|
|
||||||
|
|
||||||
### NIP-98 (HTTP Auth pour Nostr)
|
|
||||||
|
|
||||||
NIP-98 est le standard d'authentification HTTP pour Nostr. Il permet d'authentifier des requêtes HTTP en signant un événement Nostr qui contient :
|
|
||||||
- La méthode HTTP (POST)
|
|
||||||
- L'URL de la requête
|
|
||||||
- Le hash du body (optionnel)
|
|
||||||
- Un timestamp
|
|
||||||
|
|
||||||
Le header `Authorization` devrait contenir un token au format NIP-98, généralement :
|
|
||||||
```
|
|
||||||
Authorization: Nostr <base64-encoded-event>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Hypothèses
|
|
||||||
|
|
||||||
1. **NIP-98 requis** : nostrcheck.me utilise probablement NIP-98 pour l'authentification de l'API
|
|
||||||
2. **Compte requis** : Un compte doit être créé sur nostrcheck.me avant d'utiliser l'API
|
|
||||||
3. **Signature d'événement** : Il faut probablement signer un événement Nostr avec la clé privée de l'utilisateur pour générer le token d'authentification
|
|
||||||
|
|
||||||
## À explorer
|
|
||||||
|
|
||||||
### 1. Documentation de l'API nostrcheck.me
|
|
||||||
- Vérifier s'il existe une documentation publique de l'API
|
|
||||||
- Contacter le support de nostrcheck.me pour obtenir les spécifications
|
|
||||||
- Examiner le code source si disponible
|
|
||||||
|
|
||||||
### 2. Implémentation de NIP-98
|
|
||||||
Si NIP-98 est requis, il faut :
|
|
||||||
- Créer une fonction pour générer un événement d'authentification NIP-98
|
|
||||||
- Signer cet événement avec la clé privée de l'utilisateur (via Alby ou clé locale)
|
|
||||||
- Encoder l'événement signé en base64
|
|
||||||
- Ajouter le header `Authorization: Nostr <token>` aux requêtes
|
|
||||||
|
|
||||||
### 3. Format de l'événement NIP-98
|
|
||||||
L'événement devrait contenir :
|
|
||||||
- `kind`: Probablement un kind spécifique pour l'authentification HTTP
|
|
||||||
- `tags`: Tags avec la méthode HTTP, l'URL, etc.
|
|
||||||
- `content`: Vide ou contenant des métadonnées
|
|
||||||
- `created_at`: Timestamp actuel
|
|
||||||
- `pubkey`: Clé publique de l'utilisateur
|
|
||||||
- `sig`: Signature de l'événement
|
|
||||||
|
|
||||||
### 4. Intégration dans l'API proxy
|
|
||||||
Modifier `pages/api/nip95-upload.ts` pour :
|
|
||||||
- Détecter si l'endpoint est nostrcheck.me
|
|
||||||
- Générer un token NIP-98 si l'utilisateur est authentifié
|
|
||||||
- Ajouter le header Authorization à la requête
|
|
||||||
|
|
||||||
## Code existant disponible
|
|
||||||
|
|
||||||
Le projet dispose déjà de :
|
|
||||||
- `lib/nostrRemoteSigner.ts` : Service de signature d'événements Nostr
|
|
||||||
- `lib/nostrAuth.ts` : Service d'authentification Nostr
|
|
||||||
- Support de NIP-07 via Alby extension
|
|
||||||
- Gestion des clés privées (stockage chiffré)
|
|
||||||
|
|
||||||
## Implémentation réalisée
|
|
||||||
|
|
||||||
✅ **NIP-98 implémenté** (2025-01-27)
|
|
||||||
|
|
||||||
1. **Création de `lib/nip98.ts`** :
|
|
||||||
- Fonction `generateNip98Token()` pour générer le token d'authentification
|
|
||||||
- Support de la signature via `nostrRemoteSigner` (Alby/nos2x)
|
|
||||||
- Encodage base64 de l'événement signé
|
|
||||||
|
|
||||||
2. **Intégration dans `lib/nip95.ts`** :
|
|
||||||
- Détection automatique de nostrcheck.me
|
|
||||||
- Génération du token NIP-98 avant l'upload
|
|
||||||
- Passage du token à l'API proxy
|
|
||||||
|
|
||||||
3. **Support dans `pages/api/nip95-upload.ts`** :
|
|
||||||
- Récupération du token depuis les paramètres de requête
|
|
||||||
- Ajout du header `Authorization: Nostr <token>`
|
|
||||||
- Préservation du token lors des redirections
|
|
||||||
|
|
||||||
## Utilisation
|
|
||||||
|
|
||||||
Pour utiliser nostrcheck.me :
|
|
||||||
1. Créer un compte sur nostrcheck.me avec la même clé Nostr (via nos2x, Alby, etc.)
|
|
||||||
2. Se connecter à l'application avec la même extension/clé
|
|
||||||
3. Activer nostrcheck.me dans les settings (`/settings`)
|
|
||||||
4. L'upload vers nostrcheck.me fonctionnera automatiquement avec l'authentification NIP-98
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
- L'authentification NIP-98 nécessite que l'utilisateur soit connecté avec Alby ou ait une clé privée disponible
|
|
||||||
- Le token doit être généré côté client (navigateur) car il nécessite la clé privée
|
|
||||||
- L'API proxy côté serveur ne peut pas générer le token sans avoir accès à la clé privée de l'utilisateur
|
|
||||||
- Solution possible : Générer le token côté client et le passer en paramètre à l'API proxy
|
|
||||||
|
|
||||||
## Références
|
|
||||||
|
|
||||||
- nostrcheck.me : https://nostrcheck.me/
|
|
||||||
- NIP-07 : https://github.com/nostr-protocol/nips/blob/master/07.md
|
|
||||||
- NIP-98 : À rechercher dans le repository des NIPs
|
|
||||||
@ -1,116 +0,0 @@
|
|||||||
# Diagnostic : Erreurs 500 avec nostrimg.com
|
|
||||||
|
|
||||||
## Date
|
|
||||||
2025-01-27
|
|
||||||
|
|
||||||
## Problème
|
|
||||||
L'endpoint `https://nostrimg.com/api/upload` retourne systématiquement des erreurs 500 lors des tentatives d'upload.
|
|
||||||
|
|
||||||
## Vérifications effectuées du code
|
|
||||||
|
|
||||||
### 1. Format de la requête ✅
|
|
||||||
- **FormData** : Utilisation correcte du package `form-data` npm
|
|
||||||
- **Champ de fichier** : Nom de champ `'file'` (standard NIP-95)
|
|
||||||
- **Stream** : Utilisation de `fs.createReadStream()` pour lire le fichier
|
|
||||||
- **Filename** : Transmission du nom de fichier original ou généré
|
|
||||||
- **Content-Type** : Transmission du type MIME du fichier
|
|
||||||
|
|
||||||
### 2. Headers HTTP ✅
|
|
||||||
- **Content-Type** : Généré automatiquement par `form-data` avec le boundary correct
|
|
||||||
- Format : `multipart/form-data; boundary=...`
|
|
||||||
- **Accept** : `application/json` (ajouté)
|
|
||||||
- **User-Agent** : `zapwall.fr/1.0` (ajouté)
|
|
||||||
- **Authorization** : Ajouté uniquement si token NIP-98 fourni (non requis pour nostrimg.com)
|
|
||||||
|
|
||||||
### 3. Configuration de la requête ✅
|
|
||||||
- **Méthode** : `POST` (correct)
|
|
||||||
- **URL** : `https://nostrimg.com/api/upload` (correcte)
|
|
||||||
- **Timeout** : 30 secondes (raisonnable)
|
|
||||||
- **Gestion des redirections** : Support des 301, 302, 307, 308
|
|
||||||
|
|
||||||
### 4. Gestion des erreurs ✅
|
|
||||||
- Détection des réponses HTML
|
|
||||||
- Classification des erreurs (404, 403, 500)
|
|
||||||
- Messages d'erreur clairs
|
|
||||||
- Logging amélioré
|
|
||||||
|
|
||||||
## Points à vérifier (non confirmés)
|
|
||||||
|
|
||||||
### 1. Nom du champ de fichier
|
|
||||||
- **Actuel** : `'file'`
|
|
||||||
- **Possible problème** : Certains endpoints NIP-95 utilisent `'image'`, `'upload'`, ou d'autres noms
|
|
||||||
- **Action** : Le code utilise `'file'` qui est le standard NIP-95, mais nostrimg.com pourrait attendre un autre nom
|
|
||||||
|
|
||||||
### 2. Format de la réponse attendue
|
|
||||||
- **Actuel** : Le code attend du JSON
|
|
||||||
- **Possible problème** : nostrimg.com pourrait retourner un format différent ou nécessiter des paramètres spécifiques
|
|
||||||
|
|
||||||
### 3. Authentification
|
|
||||||
- **Actuel** : Pas d'authentification pour nostrimg.com
|
|
||||||
- **Possible problème** : nostrimg.com pourrait nécessiter une authentification (NIP-98 ou autre)
|
|
||||||
|
|
||||||
### 4. Taille de fichier
|
|
||||||
- **Actuel** : Limite de 50MB côté proxy
|
|
||||||
- **Possible problème** : nostrimg.com pourrait avoir une limite différente
|
|
||||||
|
|
||||||
## Logging ajouté
|
|
||||||
|
|
||||||
Pour diagnostiquer le problème, un logging détaillé a été ajouté spécifiquement pour nostrimg.com :
|
|
||||||
|
|
||||||
### Logs de requête
|
|
||||||
- URL complète
|
|
||||||
- Méthode HTTP
|
|
||||||
- Nom du champ de fichier
|
|
||||||
- Nom du fichier
|
|
||||||
- Type MIME
|
|
||||||
- Taille du fichier
|
|
||||||
- Tous les headers (Content-Type, Accept, User-Agent, Authorization)
|
|
||||||
|
|
||||||
### Logs de réponse
|
|
||||||
- Code de statut HTTP
|
|
||||||
- Message de statut
|
|
||||||
- Headers de réponse (Content-Type, Content-Length)
|
|
||||||
- Aperçu du corps de la réponse (500 premiers caractères)
|
|
||||||
- Longueur du corps
|
|
||||||
- Détection HTML
|
|
||||||
|
|
||||||
## Prochaines étapes
|
|
||||||
|
|
||||||
1. **Activer nostrimg.com temporairement** et vérifier les logs serveur pour voir :
|
|
||||||
- Les détails exacts de la requête envoyée
|
|
||||||
- La réponse exacte du serveur nostrimg.com
|
|
||||||
- Le code de statut et les headers de réponse
|
|
||||||
|
|
||||||
2. **Tester avec curl** pour comparer :
|
|
||||||
```bash
|
|
||||||
curl -X POST https://nostrimg.com/api/upload \
|
|
||||||
-H "Accept: application/json" \
|
|
||||||
-H "User-Agent: zapwall.fr/1.0" \
|
|
||||||
-F "file=@test.jpg"
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Vérifier la documentation** de nostrimg.com si disponible :
|
|
||||||
- Nom de champ attendu
|
|
||||||
- Headers requis
|
|
||||||
- Format de réponse
|
|
||||||
- Limites de taille
|
|
||||||
|
|
||||||
4. **Tester avec un nom de champ différent** si les logs indiquent un problème :
|
|
||||||
- `'image'` au lieu de `'file'`
|
|
||||||
- `'upload'` au lieu de `'file'`
|
|
||||||
|
|
||||||
## Conclusion
|
|
||||||
|
|
||||||
Le code semble correct selon les standards NIP-95 :
|
|
||||||
- ✅ Format multipart/form-data correct
|
|
||||||
- ✅ Headers HTTP appropriés
|
|
||||||
- ✅ Gestion des erreurs robuste
|
|
||||||
- ✅ Logging détaillé pour diagnostic
|
|
||||||
|
|
||||||
**Hypothèse principale** : Le problème semble être côté serveur nostrimg.com plutôt que dans notre code. Les logs détaillés permettront de confirmer ou d'infirmer cette hypothèse.
|
|
||||||
|
|
||||||
## Modifications
|
|
||||||
|
|
||||||
- **Fichier modifié** : `pages/api/nip95-upload.ts`
|
|
||||||
- **Logging ajouté** : Logs détaillés pour les requêtes et réponses vers nostrimg.com
|
|
||||||
- **Commentaire ajouté** : Note sur le nom de champ 'file' et alternatives possibles
|
|
||||||
@ -1,125 +0,0 @@
|
|||||||
# Problème : nostrimg.com retourne du HTML au lieu de JSON
|
|
||||||
|
|
||||||
## Date
|
|
||||||
2025-01-27
|
|
||||||
|
|
||||||
## Problème
|
|
||||||
L'endpoint `https://nostrimg.com/api/upload` retourne une page HTML au lieu d'une réponse JSON lors des tentatives d'upload.
|
|
||||||
|
|
||||||
## Symptômes
|
|
||||||
- Erreur 500 lors des appels à `/api/nip95-upload?endpoint=https://nostrimg.com/api/upload`
|
|
||||||
- Message d'erreur : `"Invalid upload response: Unexpected token '<', \"\n<!DOCTYPE \"... is not valid JSON"`
|
|
||||||
- Les uploads vers nostrimg.com échouent systématiquement
|
|
||||||
- La réponse contient du HTML (page d'erreur) au lieu de JSON
|
|
||||||
|
|
||||||
## Causes possibles identifiées
|
|
||||||
|
|
||||||
### 1. Headers HTTP manquants
|
|
||||||
**Problème** : Certains serveurs nécessitent des headers spécifiques pour retourner du JSON au lieu de HTML.
|
|
||||||
|
|
||||||
**Solution appliquée** :
|
|
||||||
- Ajout du header `Accept: application/json` pour indiquer au serveur qu'on attend du JSON
|
|
||||||
- Ajout du header `User-Agent: zapwall.fr/1.0` car certains serveurs bloquent les requêtes sans User-Agent
|
|
||||||
|
|
||||||
### 2. URL d'endpoint incorrecte
|
|
||||||
**Problème** : L'URL `https://nostrimg.com/api/upload` pourrait ne pas être la bonne.
|
|
||||||
|
|
||||||
**Vérifications à faire** :
|
|
||||||
- Vérifier la documentation de nostrimg.com
|
|
||||||
- Tester l'endpoint directement avec curl ou Postman
|
|
||||||
- Vérifier si l'endpoint nécessite un chemin différent (ex: `/upload` vs `/api/upload`)
|
|
||||||
|
|
||||||
### 3. Authentification requise
|
|
||||||
**Problème** : L'endpoint pourrait nécessiter une authentification (NIP-98 ou autre).
|
|
||||||
|
|
||||||
**Vérifications à faire** :
|
|
||||||
- Vérifier si nostrimg.com nécessite une authentification
|
|
||||||
- Tester avec un token d'authentification si disponible
|
|
||||||
- Vérifier la documentation pour les exigences d'authentification
|
|
||||||
|
|
||||||
### 4. Endpoint non disponible ou modifié
|
|
||||||
**Problème** : L'endpoint pourrait ne plus être disponible, avoir changé d'URL, ou être temporairement indisponible.
|
|
||||||
|
|
||||||
**Vérifications à faire** :
|
|
||||||
- Vérifier le statut du service nostrimg.com
|
|
||||||
- Tester l'endpoint directement dans un navigateur
|
|
||||||
- Vérifier les logs serveur pour voir le code de statut exact (404, 403, 500, etc.)
|
|
||||||
|
|
||||||
### 5. Configuration serveur
|
|
||||||
**Problème** : Le serveur nostrimg.com pourrait avoir une configuration qui retourne du HTML par défaut pour certaines requêtes.
|
|
||||||
|
|
||||||
**Vérifications à faire** :
|
|
||||||
- Vérifier le Content-Type de la réponse
|
|
||||||
- Vérifier si le serveur redirige vers une page d'erreur
|
|
||||||
- Vérifier les logs pour voir exactement ce qui est retourné
|
|
||||||
|
|
||||||
## Correctifs appliqués
|
|
||||||
|
|
||||||
### 1. Ajout de headers HTTP
|
|
||||||
```typescript
|
|
||||||
headers['Accept'] = 'application/json'
|
|
||||||
headers['User-Agent'] = 'zapwall.fr/1.0'
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Amélioration de la détection des erreurs HTML
|
|
||||||
- Détection automatique des réponses HTML (commence par `<!DOCTYPE`, `<html`, ou `<!`)
|
|
||||||
- Classification des erreurs (404, 403, 500)
|
|
||||||
- Extraction du message d'erreur depuis le HTML (title, h1)
|
|
||||||
- Messages d'erreur plus clairs avec suggestions
|
|
||||||
|
|
||||||
### 3. Logging amélioré
|
|
||||||
- Aperçu du corps de la réponse HTML (500 caractères)
|
|
||||||
- Classification de l'erreur (404, 403, 500)
|
|
||||||
- Suggestions basées sur le type d'erreur détecté
|
|
||||||
|
|
||||||
## Diagnostic
|
|
||||||
|
|
||||||
Pour diagnostiquer le problème avec nostrimg.com :
|
|
||||||
|
|
||||||
1. **Vérifier les logs serveur** :
|
|
||||||
- Regarder les logs de l'API pour voir le code de statut exact
|
|
||||||
- Vérifier le contenu de la réponse HTML retournée
|
|
||||||
- Identifier le type d'erreur (404, 403, 500, etc.)
|
|
||||||
|
|
||||||
2. **Tester l'endpoint directement** :
|
|
||||||
```bash
|
|
||||||
curl -X POST https://nostrimg.com/api/upload \
|
|
||||||
-H "Accept: application/json" \
|
|
||||||
-H "User-Agent: zapwall.fr/1.0" \
|
|
||||||
-F "file=@test.jpg"
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Vérifier la documentation** :
|
|
||||||
- Consulter la documentation de nostrimg.com si disponible
|
|
||||||
- Vérifier les exemples d'utilisation
|
|
||||||
- Vérifier les exigences d'authentification
|
|
||||||
|
|
||||||
4. **Vérifier le statut du service** :
|
|
||||||
- Tester si le site nostrimg.com est accessible
|
|
||||||
- Vérifier si l'endpoint `/api/upload` existe
|
|
||||||
- Vérifier s'il y a des annonces de maintenance ou de changements
|
|
||||||
|
|
||||||
## Recommandations
|
|
||||||
|
|
||||||
1. **Désactiver temporairement nostrimg.com** :
|
|
||||||
- Si le problème persiste, désactiver l'endpoint dans les paramètres
|
|
||||||
- Utiliser d'autres endpoints fonctionnels (nostrcheck.me avec auth, etc.)
|
|
||||||
|
|
||||||
2. **Vérifier périodiquement** :
|
|
||||||
- Tester l'endpoint périodiquement pour voir s'il redevient fonctionnel
|
|
||||||
- Surveiller les mises à jour de nostrimg.com
|
|
||||||
|
|
||||||
3. **Alternative** :
|
|
||||||
- Utiliser d'autres endpoints NIP-95 qui fonctionnent correctement
|
|
||||||
- Configurer nostrcheck.me avec authentification NIP-98
|
|
||||||
|
|
||||||
## Modifications
|
|
||||||
|
|
||||||
- **Fichier modifié** : `pages/api/nip95-upload.ts`
|
|
||||||
- **Headers ajoutés** :
|
|
||||||
- `Accept: application/json`
|
|
||||||
- `User-Agent: zapwall.fr/1.0`
|
|
||||||
- **Détection HTML améliorée** :
|
|
||||||
- Classification des erreurs (404, 403, 500)
|
|
||||||
- Messages d'erreur plus clairs
|
|
||||||
- Logging amélioré avec aperçu du HTML
|
|
||||||
@ -1,210 +0,0 @@
|
|||||||
# SSH Connection Errors During Deployment
|
|
||||||
|
|
||||||
**Date**: 2024-12-19
|
|
||||||
**Auteur**: Équipe 4NK
|
|
||||||
|
|
||||||
## Problem Description
|
|
||||||
|
|
||||||
During deployment, SSH connection errors occurred when verifying the Git repository on the server. The errors were:
|
|
||||||
|
|
||||||
```
|
|
||||||
mux_client_request_session: read from master failed: Connection reset by peer
|
|
||||||
Failed to connect to new control master
|
|
||||||
mm_send_fd: sendmsg(2): Broken pipe
|
|
||||||
mux_client_request_session: send fds failed
|
|
||||||
```
|
|
||||||
|
|
||||||
These errors appeared at step 5 of the deployment script when checking if Git is initialized on the server.
|
|
||||||
|
|
||||||
Additionally, the script could hang indefinitely at step 5 due to command substitution blocking when SSH connections failed or timed out.
|
|
||||||
|
|
||||||
## Impact
|
|
||||||
|
|
||||||
- **Severity**: Medium
|
|
||||||
- **Scope**: Deployment script reliability
|
|
||||||
- **User Impact**: Deployment could fail or continue with errors, potentially leaving the server in an inconsistent state
|
|
||||||
- **Frequency**: Intermittent, occurring when SSH ControlMaster connection is interrupted
|
|
||||||
|
|
||||||
## Root Cause
|
|
||||||
|
|
||||||
The SSH ControlMaster multiplexing connection was being closed prematurely or becoming stale, causing subsequent SSH commands to fail. The original `ssh_exec` function did not handle connection failures robustly:
|
|
||||||
|
|
||||||
1. **No connection validation**: The function did not check if the ControlMaster socket was still valid before use
|
|
||||||
2. **No retry mechanism**: Failed connections were not retried after cleanup
|
|
||||||
3. **No dead connection cleanup**: Stale connections were not detected and cleaned up before reuse
|
|
||||||
4. **Silent failures**: Connection errors in conditional checks could be misinterpreted as command failures
|
|
||||||
|
|
||||||
## Root Cause Analysis
|
|
||||||
|
|
||||||
The SSH ControlMaster feature creates a persistent connection to avoid multiple SSH handshakes. However:
|
|
||||||
|
|
||||||
- Network interruptions can close the master connection
|
|
||||||
- The ControlMaster socket file can become stale if the connection dies
|
|
||||||
- The script did not detect or handle these cases, leading to cascading failures
|
|
||||||
- Command substitution `$()` with SSH commands can block indefinitely if the connection hangs
|
|
||||||
- The original logic used `grep` on command output, which required capturing all output and could hang
|
|
||||||
|
|
||||||
### Deep Root Cause: ControlSocket Already Exists
|
|
||||||
|
|
||||||
The fundamental issue is that:
|
|
||||||
|
|
||||||
1. **Socket can become invalid between check and execution**: The socket file can exist on the filesystem, but the underlying connection can die between the validation check and the actual command execution.
|
|
||||||
|
|
||||||
2. **ControlMaster=auto behavior**: When SSH detects that a ControlMaster socket exists but is invalid, it does NOT remove the socket. Instead, it:
|
|
||||||
- Disables multiplexing for that command
|
|
||||||
- Creates a new connection without multiplexing
|
|
||||||
- Leaves the dead socket file in place
|
|
||||||
|
|
||||||
3. **Dead socket accumulation**: The dead socket remains and causes subsequent commands to fail with "ControlSocket already exists, disabling multiplexing" errors.
|
|
||||||
|
|
||||||
4. **Insufficient cleanup**: Previous cleanup attempts only removed the socket file, but if a process was still holding it, the socket could remain. Removing the entire directory ensures complete cleanup.
|
|
||||||
|
|
||||||
The solution is to:
|
|
||||||
- Test actual connection usability (not just socket existence)
|
|
||||||
- Aggressively remove the entire socket directory when invalid
|
|
||||||
- Recreate the directory for fresh connections
|
|
||||||
|
|
||||||
## Corrections Applied
|
|
||||||
|
|
||||||
### 1. Enhanced SSH Connection Management
|
|
||||||
|
|
||||||
**File**: `deploy.sh`
|
|
||||||
|
|
||||||
**Changes**:
|
|
||||||
- Added `cleanup_dead_ssh()` function to properly clean up dead SSH connections
|
|
||||||
- Added `check_ssh_connection()` function to validate ControlMaster connection before use
|
|
||||||
- Enhanced `ssh_exec()` function with:
|
|
||||||
- Connection validation before each command
|
|
||||||
- Automatic cleanup of dead connections
|
|
||||||
- Additional SSH options for better connection stability:
|
|
||||||
- `ConnectTimeout=10`: Fail fast if connection cannot be established
|
|
||||||
- `ServerAliveInterval=60`: Keep connection alive
|
|
||||||
- `ServerAliveCountMax=3`: Detect dead connections quickly
|
|
||||||
|
|
||||||
**Latest improvements (root cause fix)**:
|
|
||||||
- `check_ssh_connection()` now tests actual connection usability with `ssh ... true` instead of just `ssh -O check`
|
|
||||||
- `cleanup_dead_ssh()` now removes entire socket directory instead of just socket file
|
|
||||||
- This ensures socket is truly removed even if process is still holding it
|
|
||||||
- Directory is recreated after cleanup for fresh connections
|
|
||||||
|
|
||||||
### 2. Improved Error Handling at Step 5
|
|
||||||
|
|
||||||
**File**: `deploy.sh`
|
|
||||||
|
|
||||||
**Changes**:
|
|
||||||
- Enhanced Git repository verification to properly handle SSH connection errors
|
|
||||||
- Added explicit error detection and recovery mechanism
|
|
||||||
- Added automatic retry after connection cleanup
|
|
||||||
- Better error messages to distinguish between connection errors and Git initialization needs
|
|
||||||
- **Fixed blocking issue**: Removed command substitution `$()` that could hang indefinitely
|
|
||||||
- Simplified logic to use direct exit code checking instead of parsing output
|
|
||||||
- Improved timeout handling to prevent script from hanging
|
|
||||||
|
|
||||||
## Modifications
|
|
||||||
|
|
||||||
### Files Modified
|
|
||||||
|
|
||||||
- `deploy.sh`:
|
|
||||||
- Enhanced `ssh_exec()` function with retry logic and connection validation
|
|
||||||
- Added `cleanup_dead_ssh()` and `check_ssh_connection()` helper functions
|
|
||||||
- Improved error handling in Git repository verification step
|
|
||||||
|
|
||||||
### Code Changes
|
|
||||||
|
|
||||||
**Before**:
|
|
||||||
```bash
|
|
||||||
ssh_exec() {
|
|
||||||
ssh -o ControlMaster=auto -o ControlPath="${SSH_CONTROL_PATH}" -o ControlPersist=300 ${SERVER} "$@"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**After**:
|
|
||||||
```bash
|
|
||||||
ssh_exec() {
|
|
||||||
# Validates connection, cleans up dead connections, retries on failure
|
|
||||||
# Includes connection stability options
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Deployment Procedures
|
|
||||||
|
|
||||||
### Automatic Deployment
|
|
||||||
|
|
||||||
The fix is automatically applied when using the deployment script:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./deploy.sh "commit message"
|
|
||||||
```
|
|
||||||
|
|
||||||
No manual intervention required. The script now handles SSH connection errors automatically.
|
|
||||||
|
|
||||||
### Verification
|
|
||||||
|
|
||||||
After deployment, verify that SSH connections are stable:
|
|
||||||
|
|
||||||
1. Check that deployment completes without SSH errors
|
|
||||||
2. Monitor for connection errors in subsequent deployments
|
|
||||||
3. Verify that retry mechanism works correctly
|
|
||||||
|
|
||||||
## Analysis Procedures
|
|
||||||
|
|
||||||
### Monitoring SSH Connection Issues
|
|
||||||
|
|
||||||
1. **Check deployment logs** for SSH connection errors:
|
|
||||||
```bash
|
|
||||||
# Review recent deployment output
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Verify SSH ControlMaster socket**:
|
|
||||||
```bash
|
|
||||||
# On the deployment machine
|
|
||||||
ls -la /tmp/ssh_control_*/
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Test SSH connection manually**:
|
|
||||||
```bash
|
|
||||||
ssh -O check -o ControlPath="/tmp/ssh_control_*/debian_92.243.27.35_22" debian@92.243.27.35
|
|
||||||
```
|
|
||||||
|
|
||||||
### Debugging Steps
|
|
||||||
|
|
||||||
If SSH connection errors persist:
|
|
||||||
|
|
||||||
1. Check network connectivity to the server
|
|
||||||
2. Verify SSH server configuration allows ControlMaster
|
|
||||||
3. Check for firewall or network issues
|
|
||||||
4. Review SSH server logs on the remote machine
|
|
||||||
5. Verify SSH key authentication is working
|
|
||||||
|
|
||||||
### Logs to Review
|
|
||||||
|
|
||||||
- Deployment script output (stdout/stderr)
|
|
||||||
- SSH client logs (if verbose mode enabled)
|
|
||||||
- Remote SSH server logs: `/var/log/auth.log` or similar
|
|
||||||
|
|
||||||
## Prevention
|
|
||||||
|
|
||||||
### Best Practices
|
|
||||||
|
|
||||||
1. **Connection validation**: Always validate SSH connections before use
|
|
||||||
2. **Retry logic**: Implement retry mechanisms for network operations
|
|
||||||
3. **Cleanup**: Properly clean up stale connections
|
|
||||||
4. **Error handling**: Distinguish between different types of failures
|
|
||||||
5. **Monitoring**: Monitor connection stability over time
|
|
||||||
|
|
||||||
### Future Improvements
|
|
||||||
|
|
||||||
- Add connection health metrics
|
|
||||||
- Implement exponential backoff for retries
|
|
||||||
- Add connection pooling if needed
|
|
||||||
- Consider alternative connection methods if ControlMaster proves unreliable
|
|
||||||
|
|
||||||
## Related Issues
|
|
||||||
|
|
||||||
None identified at this time.
|
|
||||||
|
|
||||||
## References
|
|
||||||
|
|
||||||
- SSH ControlMaster documentation
|
|
||||||
- Deployment script: `deploy.sh`
|
|
||||||
- Related documentation: `docs/deployment.md`
|
|
||||||
@ -324,9 +324,6 @@ export async function publishReview(params: {
|
|||||||
const {category} = params
|
const {category} = params
|
||||||
requireCategory(category)
|
requireCategory(category)
|
||||||
|
|
||||||
// Map category to new system
|
|
||||||
const newCategory = category === 'science-fiction' ? 'sciencefiction' : 'research'
|
|
||||||
|
|
||||||
// Generate hash ID from review data
|
// Generate hash ID from review data
|
||||||
const { generateReviewHashId } = await import('./hashIdGenerator')
|
const { generateReviewHashId } = await import('./hashIdGenerator')
|
||||||
const hashId = await generateReviewHashId({
|
const hashId = await generateReviewHashId({
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user