532 lines
12 KiB
Markdown
532 lines
12 KiB
Markdown
# SocioWire Frontend
|
|
|
|
Interface utilisateur de SocioWire - plateforme sociale géolocalisée. Application React moderne avec cartes 3D, authentification Keycloak, et fonctionnalités temps réel.
|
|
|
|
## Description
|
|
|
|
Le frontend SocioWire est une Single Page Application (SPA) construite avec React 19 et Vite. Elle offre une expérience utilisateur riche avec:
|
|
- Authentification OAuth2 via Keycloak
|
|
- Feed de posts géolocalisés avec cartes interactives
|
|
- Recherche intelligente avec autocomplete
|
|
- Visualisation 3D des "Islands" utilisateurs
|
|
- Engagement temps réel (likes, comments, shares)
|
|
- Interface responsive et moderne
|
|
|
|
## Technologies
|
|
|
|
- **Framework**: React 19
|
|
- **Build Tool**: Vite (rolldown-vite)
|
|
- **Routing**: React Router DOM v7
|
|
- **Auth**: Keycloak.js (OAuth2/OIDC)
|
|
- **Maps**: MapLibre GL
|
|
- **HTTP Client**: Axios
|
|
- **Icons**: Font Awesome
|
|
- **Styling**: CSS modules + custom themes
|
|
|
|
## Structure du projet
|
|
|
|
```
|
|
sociowire-frontend/
|
|
├── src/
|
|
│ ├── main.jsx # Entry point
|
|
│ ├── App.jsx # App router
|
|
│ ├── api/
|
|
│ │ ├── client.js # Axios client avec auth
|
|
│ │ └── templates.js # API templates
|
|
│ ├── auth/
|
|
│ │ ├── AuthContext.jsx # Auth provider
|
|
│ │ ├── authStorage.js # Token storage
|
|
│ │ └── emailVerified.js # Email verification
|
|
│ ├── components/
|
|
│ │ ├── Posts/ # Post components
|
|
│ │ │ ├── PostCard.jsx
|
|
│ │ │ ├── PostList.jsx
|
|
│ │ │ └── PostCardTemplate.jsx
|
|
│ │ ├── Search/ # Search components
|
|
│ │ │ └── SmartSearchBar.jsx
|
|
│ │ ├── Filters/ # Filter components
|
|
│ │ │ ├── FilterButtons.jsx
|
|
│ │ │ └── TimeFilterButtons.jsx
|
|
│ │ ├── Profile/ # User profile
|
|
│ │ │ └── UserProfile.jsx
|
|
│ │ ├── Island/ # Island visualization
|
|
│ │ │ ├── IslandViewer.jsx
|
|
│ │ │ └── IslandUniverse.jsx
|
|
│ │ ├── Map/ # Map components
|
|
│ │ │ ├── MapView.jsx
|
|
│ │ │ ├── MapControls.jsx
|
|
│ │ │ └── TemplateMarkerCard.jsx
|
|
│ │ ├── Auth/ # Auth components
|
|
│ │ │ ├── AuthToast.jsx
|
|
│ │ │ └── AuthPill.jsx
|
|
│ │ └── ui/ # UI primitives
|
|
│ │ └── ToastHost.jsx
|
|
│ ├── services/
|
|
│ │ └── recoSearch.js # Reco service client
|
|
│ ├── theme/
|
|
│ │ └── cardTokens.js # Design tokens
|
|
│ └── index.css # Global styles
|
|
├── public/ # Static assets
|
|
├── package.json
|
|
├── vite.config.js
|
|
└── eslint.config.js
|
|
```
|
|
|
|
## Prérequis
|
|
|
|
- Node.js 18+ (recommandé: 20+)
|
|
- npm ou yarn
|
|
- Backend SocioWire en cours d'exécution (port 8081)
|
|
- Keycloak configuré
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
cd /home/swire/sociowire-frontend
|
|
npm install
|
|
```
|
|
|
|
## Configuration
|
|
|
|
Les URLs des services sont configurées dans le code:
|
|
|
|
**Backend API**: `http://localhost:8081`
|
|
**Keycloak**: `https://auth.sociowire.com`
|
|
|
|
Pour changer ces URLs, modifier:
|
|
- `src/api/client.js` - Backend URL
|
|
- `src/auth/AuthContext.jsx` - Keycloak URL
|
|
|
|
### Variables d'environnement (optionnel)
|
|
|
|
Créer un fichier `.env.local`:
|
|
|
|
```env
|
|
VITE_API_URL=http://localhost:8081
|
|
VITE_KEYCLOAK_URL=https://auth.sociowire.com
|
|
VITE_KEYCLOAK_REALM=sociowire
|
|
VITE_KEYCLOAK_CLIENT_ID=sociowire-frontend
|
|
```
|
|
|
|
## Démarrage
|
|
|
|
### Mode développement
|
|
|
|
```bash
|
|
npm run dev
|
|
```
|
|
|
|
L'application démarre sur `http://localhost:5173` (ou autre port si occupé).
|
|
|
|
### Build production
|
|
|
|
```bash
|
|
npm run build
|
|
```
|
|
|
|
Les fichiers sont générés dans `dist/`.
|
|
|
|
### Preview production
|
|
|
|
```bash
|
|
npm run preview
|
|
```
|
|
|
|
Teste le build production localement.
|
|
|
|
## Fonctionnalités principales
|
|
|
|
### 1. Authentification
|
|
|
|
- **Login**: Email/password via Keycloak
|
|
- **Signup**: Création de compte avec vérification email
|
|
- **OAuth**: Login social (Google, GitHub, etc.)
|
|
- **Refresh tokens**: Gestion automatique de l'expiration
|
|
- **Logout**: Déconnexion complète (Keycloak + local)
|
|
|
|
**Composants**:
|
|
- `AuthContext` - Provider global d'auth
|
|
- `AuthPill` - Widget utilisateur
|
|
- `AuthToast` - Notifications auth
|
|
|
|
### 2. Feed de posts
|
|
|
|
- **Posts géolocalisés**: Affichage avec lat/lon
|
|
- **Catégories**: NEWS, EVENT, DISCUSSION, QUESTION
|
|
- **Filtres**: Par catégorie, temps, géolocalisation
|
|
- **Pagination**: Chargement progressif
|
|
- **Templates**: Posts avec templates visuels
|
|
|
|
**Composants**:
|
|
- `PostList` - Liste de posts
|
|
- `PostCard` - Carte de post individuelle
|
|
- `PostCardTemplate` - Post avec template
|
|
|
|
### 3. Recherche
|
|
|
|
- **Smart Search**: Recherche full-text via reco-service
|
|
- **Autocomplete**: Suggestions en temps réel (posts, profils, lieux)
|
|
- **Filtres avancés**: Catégorie, temps, géo
|
|
- **Unified Search**: Posts + profils + places
|
|
|
|
**Composants**:
|
|
- `SmartSearchBar` - Barre de recherche avec autocomplete
|
|
- `FilterButtons` - Filtres de catégorie
|
|
- `TimeFilterButtons` - Filtres temporels
|
|
|
|
### 4. Cartes interactives
|
|
|
|
- **MapLibre GL**: Cartes vectorielles performantes
|
|
- **Markers**: Posts géolocalisés sur la carte
|
|
- **Clustering**: Regroupement de markers
|
|
- **3D**: Visualisation 3D optionnelle
|
|
- **Controls**: Zoom, rotation, pitch
|
|
|
|
**Composants**:
|
|
- `MapView` - Carte principale
|
|
- `MapControls` - Contrôles de carte
|
|
- `TemplateMarkerCard` - Popup de marker
|
|
|
|
### 5. Islands (Univers utilisateurs)
|
|
|
|
- **Island Universe**: Visualisation 3D des utilisateurs
|
|
- **Island Viewer**: Détails d'une island
|
|
- **Génération procédurale**: Islands uniques par utilisateur
|
|
- **Navigation**: Exploration de l'univers
|
|
|
|
**Composants**:
|
|
- `IslandUniverse` - Univers 3D
|
|
- `IslandViewer` - Vue détaillée d'island
|
|
|
|
### 6. Profils utilisateurs
|
|
|
|
- **User Profile**: Profil complet avec posts
|
|
- **Avatar**: Upload et affichage
|
|
- **Stats**: Posts, followers, etc.
|
|
- **Bio**: Description personnalisée
|
|
|
|
**Composants**:
|
|
- `UserProfile` - Page de profil
|
|
|
|
### 7. Engagement
|
|
|
|
- **Likes**: Like/unlike de posts
|
|
- **Comments**: Commentaires hiérarchiques
|
|
- **Shares**: Partage de posts
|
|
- **Truth Voting**: Vote de vérité (fact-checking)
|
|
|
|
Intégré dans `PostCard`.
|
|
|
|
## Appels API
|
|
|
|
Le frontend communique avec:
|
|
|
|
### 1. sociowire-backend (`http://localhost:8081`)
|
|
|
|
**Authentification**:
|
|
- `POST /api/signup-email`
|
|
- `POST /api/signup`
|
|
- `POST /api/login`
|
|
- `POST /api/refresh`
|
|
- `GET /api/me`
|
|
|
|
**Posts**:
|
|
- `GET /api/posts` - Feed
|
|
- `POST /api/post` - Créer
|
|
- `GET /api/post?id=...` - Get
|
|
- `POST /api/post/like` - Like
|
|
- `GET /api/post/comments` - Comments
|
|
- `POST /api/post/comment` - Ajouter comment
|
|
|
|
**Recherche**:
|
|
- `GET /api/search?q=...` - Recherche full-text
|
|
- `GET /api/suggestions?q=...` - Autocomplete
|
|
- `GET /api/smart-feed` - Feed personnalisé
|
|
- `GET /api/unified-search` - Search combinée
|
|
|
|
**Profils**:
|
|
- `GET /api/profile` - Mon profil
|
|
- `PATCH /api/profile/username` - Update username
|
|
- `POST /api/profile/avatar` - Upload avatar
|
|
|
|
**Assets**:
|
|
- `POST /api/assets/upload` - Upload image
|
|
- `GET /api/assets/url?id=...` - Get asset URL
|
|
|
|
**Islands**:
|
|
- `GET /api/islands/nearby` - Islands à proximité
|
|
- `GET /api/islands/by-username/{username}` - Island par username
|
|
|
|
**Utilitaires**:
|
|
- `GET /api/templates` - Templates de posts
|
|
- `GET /api/ip-location` - Géolocalisation IP
|
|
|
|
---
|
|
|
|
### 2. Keycloak (`https://auth.sociowire.com`)
|
|
|
|
Le frontend utilise `keycloak-js` pour communiquer avec Keycloak:
|
|
|
|
- **Init**: `keycloak.init({ onLoad: 'check-sso' })`
|
|
- **Login**: `keycloak.login()`
|
|
- **Logout**: `keycloak.logout()`
|
|
- **Token**: Rafraîchissement automatique via `keycloak.updateToken()`
|
|
|
|
**Realm**: `sociowire`
|
|
**Client ID**: `sociowire-frontend`
|
|
|
|
---
|
|
|
|
## Gestion d'état
|
|
|
|
### AuthContext
|
|
|
|
Provider global pour l'authentification:
|
|
|
|
```jsx
|
|
import { useAuth } from './auth/AuthContext';
|
|
|
|
function Component() {
|
|
const { keycloak, isAuthenticated, username, login, logout } = useAuth();
|
|
// ...
|
|
}
|
|
```
|
|
|
|
**État**:
|
|
- `keycloak` - Instance Keycloak
|
|
- `isAuthenticated` - Boolean
|
|
- `username` - String
|
|
- `emailVerified` - Boolean
|
|
- `login()` - Fonction login
|
|
- `logout()` - Fonction logout
|
|
|
|
---
|
|
|
|
## Axios Client
|
|
|
|
Client HTTP configuré avec intercepteurs pour auth:
|
|
|
|
```javascript
|
|
// src/api/client.js
|
|
import axios from 'axios';
|
|
|
|
const client = axios.create({
|
|
baseURL: 'http://localhost:8081',
|
|
headers: { 'Content-Type': 'application/json' }
|
|
});
|
|
|
|
// Request interceptor: ajoute Bearer token
|
|
client.interceptors.request.use(config => {
|
|
const token = localStorage.getItem('keycloak_token');
|
|
if (token) {
|
|
config.headers.Authorization = `Bearer ${token}`;
|
|
}
|
|
return config;
|
|
});
|
|
|
|
// Response interceptor: refresh token si 401
|
|
client.interceptors.response.use(
|
|
response => response,
|
|
async error => {
|
|
if (error.response?.status === 401) {
|
|
// Refresh token logic
|
|
}
|
|
return Promise.reject(error);
|
|
}
|
|
);
|
|
```
|
|
|
|
---
|
|
|
|
## Routing
|
|
|
|
Routes principales:
|
|
|
|
```jsx
|
|
<BrowserRouter>
|
|
<Routes>
|
|
<Route path="/" element={<Home />} />
|
|
<Route path="/feed" element={<Feed />} />
|
|
<Route path="/search" element={<Search />} />
|
|
<Route path="/profile/:username" element={<Profile />} />
|
|
<Route path="/islands" element={<Islands />} />
|
|
<Route path="/post/:id" element={<PostDetail />} />
|
|
<Route path="/login" element={<Login />} />
|
|
<Route path="/signup" element={<Signup />} />
|
|
</Routes>
|
|
</BrowserRouter>
|
|
```
|
|
|
|
---
|
|
|
|
## Thème et Styling
|
|
|
|
Le projet utilise CSS modules + variables CSS:
|
|
|
|
**Design Tokens** (`theme/cardTokens.js`):
|
|
- Couleurs de catégories
|
|
- Spacing
|
|
- Border radius
|
|
- Shadows
|
|
|
|
**CSS Variables**:
|
|
```css
|
|
:root {
|
|
--primary-color: #007bff;
|
|
--secondary-color: #6c757d;
|
|
--success-color: #28a745;
|
|
--danger-color: #dc3545;
|
|
--warning-color: #ffc107;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Icônes (Font Awesome)
|
|
|
|
```jsx
|
|
import '@fortawesome/fontawesome-free/css/all.min.css';
|
|
|
|
<i className="fas fa-heart"></i>
|
|
<i className="fas fa-comment"></i>
|
|
<i className="fas fa-share"></i>
|
|
```
|
|
|
|
---
|
|
|
|
## MapLibre GL
|
|
|
|
Configuration de la carte:
|
|
|
|
```jsx
|
|
import maplibregl from 'maplibre-gl';
|
|
import 'maplibre-gl/dist/maplibre-gl.css';
|
|
|
|
const map = new maplibregl.Map({
|
|
container: 'map',
|
|
style: 'https://demotiles.maplibre.org/style.json',
|
|
center: [-73.5, 45.5],
|
|
zoom: 10
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## Build et Déploiement
|
|
|
|
### Build optimisé
|
|
|
|
```bash
|
|
npm run build
|
|
```
|
|
|
|
Génère:
|
|
- `dist/index.html` - HTML principal
|
|
- `dist/assets/*.js` - Bundles JavaScript
|
|
- `dist/assets/*.css` - Styles
|
|
- `dist/assets/*` - Assets (images, fonts)
|
|
|
|
### Déploiement
|
|
|
|
Le build peut être déployé sur:
|
|
- **Nginx**: Servir `dist/` avec fallback vers `index.html`
|
|
- **Vercel**: Détection automatique de Vite
|
|
- **Netlify**: Build command `npm run build`, publish dir `dist`
|
|
- **Docker**: Nginx container avec `dist/`
|
|
|
|
**Nginx config**:
|
|
```nginx
|
|
server {
|
|
listen 80;
|
|
root /var/www/sociowire-frontend/dist;
|
|
index index.html;
|
|
|
|
location / {
|
|
try_files $uri $uri/ /index.html;
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Développement
|
|
|
|
### Hot Module Replacement (HMR)
|
|
|
|
Vite supporte HMR out-of-the-box:
|
|
- Modifications CSS: Rechargement instantané
|
|
- Modifications JSX: Preserve state
|
|
- Modifications API: Reload complet
|
|
|
|
### ESLint
|
|
|
|
```bash
|
|
npm run lint
|
|
```
|
|
|
|
Configuration dans `eslint.config.js`.
|
|
|
|
---
|
|
|
|
## Tests
|
|
|
|
Tests à ajouter avec Vitest + React Testing Library:
|
|
|
|
```bash
|
|
npm install -D vitest @testing-library/react @testing-library/jest-dom
|
|
```
|
|
|
|
---
|
|
|
|
## Performance
|
|
|
|
Optimisations:
|
|
- **Code splitting**: Routes lazy-loaded
|
|
- **Tree shaking**: Vite optimise automatiquement
|
|
- **Asset optimization**: Images optimisées
|
|
- **Caching**: Service Worker (à ajouter)
|
|
- **Bundle size**: Analysé avec rollup-plugin-visualizer
|
|
|
|
---
|
|
|
|
## Sécurité
|
|
|
|
- Tokens stockés en localStorage (préférer httpOnly cookies en prod)
|
|
- Validation input côté client + serveur
|
|
- CORS configuré sur backend
|
|
- CSP headers recommandés
|
|
- Sanitisation des URLs externes
|
|
|
|
---
|
|
|
|
## Debugging
|
|
|
|
### React DevTools
|
|
|
|
Installer l'extension browser React DevTools.
|
|
|
|
### Vite DevTools
|
|
|
|
Console affiche:
|
|
- HMR updates
|
|
- Build errors
|
|
- Network requests (via browser)
|
|
|
|
### Logs
|
|
|
|
```javascript
|
|
console.log('Debug:', data);
|
|
```
|
|
|
|
En production, utiliser un service de logging (Sentry, LogRocket).
|
|
|
|
---
|
|
|
|
## Notes de développement
|
|
|
|
- Le frontend assume que le backend est sur `localhost:8081`
|
|
- Keycloak doit être configuré avec le client `sociowire-frontend`
|
|
- Les tokens JWT sont stockés en localStorage
|
|
- MapLibre nécessite une clé API pour certains styles (optionnel)
|
|
- L'upload d'images passe par le backend, qui proxy vers asset-service
|