@lastbrain/module-auth 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +533 -0
- package/dist/api/admin/users.d.ts +9 -0
- package/dist/api/admin/users.d.ts.map +1 -0
- package/dist/api/admin/users.js +38 -0
- package/dist/api/auth/me.d.ts +17 -0
- package/dist/api/auth/me.d.ts.map +1 -0
- package/dist/api/auth/me.js +32 -0
- package/dist/api/auth/profile.d.ts +32 -0
- package/dist/api/auth/profile.d.ts.map +1 -0
- package/dist/api/auth/profile.js +104 -0
- package/dist/api/public/signin.js +3 -3
- package/dist/api/storage.d.ts +13 -0
- package/dist/api/storage.d.ts.map +1 -0
- package/dist/api/storage.js +47 -0
- package/dist/auth.build.config.d.ts.map +1 -1
- package/dist/auth.build.config.js +42 -2
- package/dist/web/admin/users.d.ts.map +1 -1
- package/dist/web/admin/users.js +94 -2
- package/dist/web/auth/dashboard.d.ts +1 -1
- package/dist/web/auth/dashboard.d.ts.map +1 -1
- package/dist/web/auth/dashboard.js +42 -2
- package/dist/web/auth/profile.d.ts.map +1 -1
- package/dist/web/auth/profile.js +191 -2
- package/dist/web/auth/reglage.d.ts.map +1 -1
- package/dist/web/auth/reglage.js +98 -2
- package/dist/web/public/SignInPage.d.ts.map +1 -1
- package/dist/web/public/SignInPage.js +1 -1
- package/dist/web/public/SignUpPage.js +1 -1
- package/package.json +8 -7
- package/src/api/admin/users.ts +51 -0
- package/src/api/auth/me.ts +39 -0
- package/src/api/auth/profile.ts +142 -0
- package/src/api/public/signin.ts +3 -3
- package/src/api/storage.ts +66 -0
- package/src/auth.build.config.ts +42 -2
- package/src/web/admin/users.tsx +290 -1
- package/src/web/auth/dashboard.tsx +207 -1
- package/src/web/auth/profile.tsx +420 -1
- package/src/web/auth/reglage.tsx +284 -1
- package/src/web/public/SignInPage.tsx +1 -2
- package/src/web/public/SignUpPage.tsx +2 -2
- package/supabase/.temp/cli-latest +1 -0
- package/supabase/migrations/20251112000000_user_init.sql +1 -1
- package/supabase/migrations/20251112000001_auto_profile_and_admin_view.sql +206 -0
- package/supabase/migrations/20251112000002_sync_avatars.sql +54 -0
- package/supabase/migrations-down/20251112000000_user_init.down.sql +2 -0
- package/supabase/migrations-down/20251112000001_auto_profile_and_admin_view.down.sql +23 -0
- package/supabase/migrations-down/20251112000002_sync_avatars.down.sql +9 -0
package/README.md
ADDED
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
# Module Auth (@lastbrain/module-auth)
|
|
2
|
+
|
|
3
|
+
Module d'authentification complet pour LastBrain avec Supabase. Ce module fournit des pages web, des API routes et une gestion complète de l'authentification utilisateur, du profil et de l'administration.
|
|
4
|
+
|
|
5
|
+
## Table des matières
|
|
6
|
+
|
|
7
|
+
- [Installation](#installation)
|
|
8
|
+
- [Configuration](#configuration)
|
|
9
|
+
- [Pages Web Fournies](#pages-web-fournies)
|
|
10
|
+
- [Routes API](#routes-api)
|
|
11
|
+
- [Schéma de Base de Données](#schéma-de-base-de-données)
|
|
12
|
+
- [Intégration dans une Application](#intégration-dans-une-application)
|
|
13
|
+
- [Sécurité](#sécurité)
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @lastbrain/module-auth
|
|
19
|
+
# or
|
|
20
|
+
pnpm add @lastbrain/module-auth
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Configuration
|
|
24
|
+
|
|
25
|
+
### Prérequis
|
|
26
|
+
|
|
27
|
+
1. **Supabase configuré** : Vous devez avoir un projet Supabase avec les variables d'environnement suivantes :
|
|
28
|
+
|
|
29
|
+
```env
|
|
30
|
+
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
|
|
31
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
2. **Migrations appliquées** : Appliquez la migration fournie dans `supabase/migrations/20251112000000_user_init.sql` pour créer les tables nécessaires.
|
|
35
|
+
|
|
36
|
+
3. **Fonction RPC is_superadmin** : Assurez-vous que la fonction `is_superadmin` est disponible (généralement fournie par la migration de base de l'app).
|
|
37
|
+
|
|
38
|
+
### Configuration de la fonction is_superadmin
|
|
39
|
+
|
|
40
|
+
La fonction `is_superadmin` vérifie si un utilisateur a le rôle d'administrateur. Elle est définie dans la migration de base et examine les métadonnées utilisateur :
|
|
41
|
+
|
|
42
|
+
```sql
|
|
43
|
+
CREATE OR REPLACE FUNCTION public.is_superadmin(user_id uuid)
|
|
44
|
+
RETURNS boolean
|
|
45
|
+
LANGUAGE sql
|
|
46
|
+
STABLE
|
|
47
|
+
SECURITY DEFINER
|
|
48
|
+
SET search_path = public, auth
|
|
49
|
+
AS $function$
|
|
50
|
+
SELECT COALESCE((
|
|
51
|
+
SELECT
|
|
52
|
+
COALESCE((raw_app_meta_data ->> 'is_super_admin')::boolean, FALSE)
|
|
53
|
+
OR COALESCE((raw_user_meta_data ->> 'is_super_admin')::boolean, FALSE)
|
|
54
|
+
OR COALESCE((raw_app_meta_data -> 'roles') ? 'admin', FALSE)
|
|
55
|
+
OR COALESCE((raw_user_meta_data -> 'roles') ? 'admin', FALSE)
|
|
56
|
+
FROM auth.users
|
|
57
|
+
WHERE id = user_id
|
|
58
|
+
), FALSE);
|
|
59
|
+
$function$;
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Pages Web Fournies
|
|
63
|
+
|
|
64
|
+
Le module fournit plusieurs composants React prêts à l'emploi utilisant HeroUI :
|
|
65
|
+
|
|
66
|
+
### Pages Utilisateur Authentifié
|
|
67
|
+
|
|
68
|
+
#### 1. Dashboard (`/auth/dashboard`)
|
|
69
|
+
|
|
70
|
+
**Component**: `DashboardPage`
|
|
71
|
+
|
|
72
|
+
Tableau de bord utilisateur affichant :
|
|
73
|
+
|
|
74
|
+
- Résumé du profil avec avatar
|
|
75
|
+
- Email et date de création du compte
|
|
76
|
+
- Statut du compte
|
|
77
|
+
- Statistiques rapides (projets, tâches, etc.)
|
|
78
|
+
|
|
79
|
+
**Usage** :
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
import { DashboardPage } from "@lastbrain/module-auth";
|
|
83
|
+
|
|
84
|
+
export default function Dashboard() {
|
|
85
|
+
return <DashboardPage />;
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
#### 2. Profil (`/auth/profile`)
|
|
90
|
+
|
|
91
|
+
**Component**: `ProfilePage`
|
|
92
|
+
|
|
93
|
+
Page de modification du profil utilisateur permettant de mettre à jour :
|
|
94
|
+
|
|
95
|
+
- Informations personnelles (nom, prénom, téléphone, bio)
|
|
96
|
+
- Informations professionnelles (entreprise, site web, localisation)
|
|
97
|
+
- Préférences (langue, timezone, avatar)
|
|
98
|
+
|
|
99
|
+
**Usage** :
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
import { ProfilePage } from "@lastbrain/module-auth";
|
|
103
|
+
|
|
104
|
+
export default function Profile() {
|
|
105
|
+
return <ProfilePage />;
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
#### 3. Paramètres (`/auth/settings`)
|
|
110
|
+
|
|
111
|
+
**Component**: `ReglagePage`
|
|
112
|
+
|
|
113
|
+
Page de configuration du compte avec :
|
|
114
|
+
|
|
115
|
+
- Notifications (email, push, marketing)
|
|
116
|
+
- Apparence (thème)
|
|
117
|
+
- Langue et région (langue, timezone)
|
|
118
|
+
|
|
119
|
+
**Usage** :
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
import { ReglagePage } from "@lastbrain/module-auth";
|
|
123
|
+
|
|
124
|
+
export default function Settings() {
|
|
125
|
+
return <ReglagePage />;
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Pages Publiques
|
|
130
|
+
|
|
131
|
+
#### 4. Connexion (`/signin`)
|
|
132
|
+
|
|
133
|
+
**Component**: `SignInPage`
|
|
134
|
+
|
|
135
|
+
Page de connexion avec gestion des erreurs et redirection.
|
|
136
|
+
|
|
137
|
+
**Usage** :
|
|
138
|
+
|
|
139
|
+
```tsx
|
|
140
|
+
import { SignInPage } from "@lastbrain/module-auth";
|
|
141
|
+
|
|
142
|
+
export default function SignIn() {
|
|
143
|
+
return <SignInPage />;
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
#### 5. Inscription (`/signup`)
|
|
148
|
+
|
|
149
|
+
**Component**: `SignUpPage`
|
|
150
|
+
|
|
151
|
+
Page d'inscription avec validation des champs.
|
|
152
|
+
|
|
153
|
+
**Usage** :
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
import { SignUpPage } from "@lastbrain/module-auth";
|
|
157
|
+
|
|
158
|
+
export default function SignUp() {
|
|
159
|
+
return <SignUpPage />;
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Pages Administration
|
|
164
|
+
|
|
165
|
+
#### 6. Gestion des Utilisateurs (`/admin/users`)
|
|
166
|
+
|
|
167
|
+
**Component**: `AdminUsersPage`
|
|
168
|
+
|
|
169
|
+
Page d'administration pour lister et gérer tous les utilisateurs.
|
|
170
|
+
**Accès réservé aux super admins uniquement.**
|
|
171
|
+
|
|
172
|
+
Fonctionnalités :
|
|
173
|
+
|
|
174
|
+
- Liste de tous les utilisateurs
|
|
175
|
+
- Recherche par email ou nom
|
|
176
|
+
- Pagination
|
|
177
|
+
- Affichage des informations (email, rôle, date de création)
|
|
178
|
+
|
|
179
|
+
**Usage** :
|
|
180
|
+
|
|
181
|
+
```tsx
|
|
182
|
+
import { AdminUsersPage } from "@lastbrain/module-auth";
|
|
183
|
+
|
|
184
|
+
export default function AdminUsers() {
|
|
185
|
+
return <AdminUsersPage />;
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Routes API
|
|
190
|
+
|
|
191
|
+
Le module expose plusieurs routes API pour la gestion des utilisateurs et profils.
|
|
192
|
+
|
|
193
|
+
### API Authentification (`/api/auth/*`)
|
|
194
|
+
|
|
195
|
+
#### GET `/api/auth/me`
|
|
196
|
+
|
|
197
|
+
Récupère les informations de l'utilisateur connecté et son profil.
|
|
198
|
+
|
|
199
|
+
**Réponse** :
|
|
200
|
+
|
|
201
|
+
```json
|
|
202
|
+
{
|
|
203
|
+
"data": {
|
|
204
|
+
"id": "uuid",
|
|
205
|
+
"email": "user@example.com",
|
|
206
|
+
"created_at": "2024-01-01T00:00:00Z",
|
|
207
|
+
"profile": {
|
|
208
|
+
"first_name": "John",
|
|
209
|
+
"last_name": "Doe",
|
|
210
|
+
"avatar_url": "https://...",
|
|
211
|
+
"bio": "...",
|
|
212
|
+
"phone": "...",
|
|
213
|
+
"company": "...",
|
|
214
|
+
"website": "...",
|
|
215
|
+
"location": "...",
|
|
216
|
+
"language": "en",
|
|
217
|
+
"timezone": "UTC",
|
|
218
|
+
"preferences": {}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**Erreurs** :
|
|
225
|
+
|
|
226
|
+
- `401` : Utilisateur non authentifié
|
|
227
|
+
|
|
228
|
+
#### GET `/api/auth/profile`
|
|
229
|
+
|
|
230
|
+
Récupère le profil de l'utilisateur connecté.
|
|
231
|
+
|
|
232
|
+
**Réponse** :
|
|
233
|
+
|
|
234
|
+
```json
|
|
235
|
+
{
|
|
236
|
+
"data": {
|
|
237
|
+
"id": "uuid",
|
|
238
|
+
"owner_id": "uuid",
|
|
239
|
+
"first_name": "John",
|
|
240
|
+
"last_name": "Doe",
|
|
241
|
+
...
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
#### PUT/PATCH `/api/auth/profile`
|
|
247
|
+
|
|
248
|
+
Met à jour le profil de l'utilisateur. Crée le profil s'il n'existe pas.
|
|
249
|
+
|
|
250
|
+
**Body** :
|
|
251
|
+
|
|
252
|
+
```json
|
|
253
|
+
{
|
|
254
|
+
"first_name": "John",
|
|
255
|
+
"last_name": "Doe",
|
|
256
|
+
"avatar_url": "https://...",
|
|
257
|
+
"bio": "...",
|
|
258
|
+
"phone": "...",
|
|
259
|
+
"company": "...",
|
|
260
|
+
"website": "...",
|
|
261
|
+
"location": "...",
|
|
262
|
+
"language": "fr",
|
|
263
|
+
"timezone": "Europe/Paris",
|
|
264
|
+
"preferences": {
|
|
265
|
+
"email_notifications": true,
|
|
266
|
+
"theme": "dark"
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**Réponse** :
|
|
272
|
+
|
|
273
|
+
```json
|
|
274
|
+
{
|
|
275
|
+
"data": {
|
|
276
|
+
"id": "uuid",
|
|
277
|
+
"owner_id": "uuid",
|
|
278
|
+
"first_name": "John",
|
|
279
|
+
...
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### API Administration (`/api/admin/*`)
|
|
285
|
+
|
|
286
|
+
⚠️ **Toutes les routes admin nécessitent un accès super admin.**
|
|
287
|
+
|
|
288
|
+
#### GET `/api/admin/users`
|
|
289
|
+
|
|
290
|
+
Liste tous les utilisateurs (paginé).
|
|
291
|
+
|
|
292
|
+
**Query Parameters** :
|
|
293
|
+
|
|
294
|
+
- `page` (optionnel, défaut: 1) : Numéro de page
|
|
295
|
+
- `per_page` (optionnel, défaut: 20) : Nombre d'éléments par page
|
|
296
|
+
- `search` (optionnel) : Recherche par email ou nom
|
|
297
|
+
|
|
298
|
+
**Réponse** :
|
|
299
|
+
|
|
300
|
+
```json
|
|
301
|
+
{
|
|
302
|
+
"data": [
|
|
303
|
+
{
|
|
304
|
+
"id": "uuid",
|
|
305
|
+
"email": "user@example.com",
|
|
306
|
+
"created_at": "2024-01-01T00:00:00Z",
|
|
307
|
+
"profile": {
|
|
308
|
+
"first_name": "John",
|
|
309
|
+
"last_name": "Doe",
|
|
310
|
+
...
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
],
|
|
314
|
+
"pagination": {
|
|
315
|
+
"page": 1,
|
|
316
|
+
"per_page": 20,
|
|
317
|
+
"total": 100,
|
|
318
|
+
"total_pages": 5
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
**Erreurs** :
|
|
324
|
+
|
|
325
|
+
- `401` : Utilisateur non authentifié
|
|
326
|
+
- `403` : Accès refusé (non super admin)
|
|
327
|
+
|
|
328
|
+
### Utilisation dans une API Route Next.js
|
|
329
|
+
|
|
330
|
+
```typescript
|
|
331
|
+
// app/api/auth/me/route.ts
|
|
332
|
+
export { GET } from "@lastbrain/module-auth/api/auth/me";
|
|
333
|
+
|
|
334
|
+
// app/api/auth/profile/route.ts
|
|
335
|
+
export { GET, PUT, PATCH } from "@lastbrain/module-auth/api/auth/profile";
|
|
336
|
+
|
|
337
|
+
// app/api/admin/users/route.ts
|
|
338
|
+
export { GET } from "@lastbrain/module-auth/api/admin/users";
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
## Schéma de Base de Données
|
|
342
|
+
|
|
343
|
+
Le module utilise les tables suivantes (créées par la migration `20251112000000_user_init.sql`) :
|
|
344
|
+
|
|
345
|
+
### Table `user_profil`
|
|
346
|
+
|
|
347
|
+
Stocke les informations de profil utilisateur.
|
|
348
|
+
|
|
349
|
+
```sql
|
|
350
|
+
CREATE TABLE public.user_profil (
|
|
351
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
352
|
+
owner_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
353
|
+
first_name TEXT,
|
|
354
|
+
last_name TEXT,
|
|
355
|
+
avatar_url TEXT,
|
|
356
|
+
bio TEXT,
|
|
357
|
+
phone TEXT,
|
|
358
|
+
company TEXT,
|
|
359
|
+
website TEXT,
|
|
360
|
+
location TEXT,
|
|
361
|
+
language TEXT DEFAULT 'en',
|
|
362
|
+
timezone TEXT,
|
|
363
|
+
preferences JSONB DEFAULT '{}'::jsonb,
|
|
364
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
365
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
366
|
+
);
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
**Index** :
|
|
370
|
+
|
|
371
|
+
- `idx_user_profil_owner_id` sur `owner_id`
|
|
372
|
+
|
|
373
|
+
**RLS (Row Level Security)** :
|
|
374
|
+
|
|
375
|
+
- Les utilisateurs peuvent lire, créer, modifier et supprimer leur propre profil
|
|
376
|
+
- Les super admins ont accès à tous les profils
|
|
377
|
+
|
|
378
|
+
### Table `user_address`
|
|
379
|
+
|
|
380
|
+
Stocke les adresses des utilisateurs.
|
|
381
|
+
|
|
382
|
+
```sql
|
|
383
|
+
CREATE TABLE public.user_address (
|
|
384
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
385
|
+
owner_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
386
|
+
street TEXT NOT NULL,
|
|
387
|
+
street2 TEXT,
|
|
388
|
+
city TEXT NOT NULL,
|
|
389
|
+
state TEXT,
|
|
390
|
+
postal_code TEXT,
|
|
391
|
+
country TEXT NOT NULL,
|
|
392
|
+
is_default BOOLEAN DEFAULT false,
|
|
393
|
+
address_type TEXT DEFAULT 'billing',
|
|
394
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
395
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
396
|
+
);
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### Table `user_notifications`
|
|
400
|
+
|
|
401
|
+
Stocke les notifications des utilisateurs.
|
|
402
|
+
|
|
403
|
+
```sql
|
|
404
|
+
CREATE TABLE public.user_notifications (
|
|
405
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
406
|
+
owner_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
407
|
+
title TEXT NOT NULL,
|
|
408
|
+
body TEXT,
|
|
409
|
+
type TEXT NOT NULL DEFAULT 'primary',
|
|
410
|
+
read BOOLEAN NOT NULL DEFAULT false,
|
|
411
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
412
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
413
|
+
);
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
## Intégration dans une Application
|
|
417
|
+
|
|
418
|
+
### 1. Installer les dépendances
|
|
419
|
+
|
|
420
|
+
```bash
|
|
421
|
+
pnpm add @lastbrain/module-auth @lastbrain/core @lastbrain/ui
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
### 2. Appliquer les migrations Supabase
|
|
425
|
+
|
|
426
|
+
Copiez les migrations du module dans votre projet Supabase et appliquez-les :
|
|
427
|
+
|
|
428
|
+
```bash
|
|
429
|
+
cp node_modules/@lastbrain/module-auth/supabase/migrations/* supabase/migrations/
|
|
430
|
+
supabase db push
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### 3. Créer les pages Next.js
|
|
434
|
+
|
|
435
|
+
Créez les pages dans votre application Next.js :
|
|
436
|
+
|
|
437
|
+
```typescript
|
|
438
|
+
// app/auth/dashboard/page.tsx
|
|
439
|
+
import { DashboardPage } from "@lastbrain/module-auth";
|
|
440
|
+
export default DashboardPage;
|
|
441
|
+
|
|
442
|
+
// app/auth/profile/page.tsx
|
|
443
|
+
import { ProfilePage } from "@lastbrain/module-auth";
|
|
444
|
+
export default ProfilePage;
|
|
445
|
+
|
|
446
|
+
// app/auth/settings/page.tsx
|
|
447
|
+
import { ReglagePage } from "@lastbrain/module-auth";
|
|
448
|
+
export default ReglagePage;
|
|
449
|
+
|
|
450
|
+
// app/admin/users/page.tsx
|
|
451
|
+
import { AdminUsersPage } from "@lastbrain/module-auth";
|
|
452
|
+
export default AdminUsersPage;
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
### 4. Créer les routes API
|
|
456
|
+
|
|
457
|
+
```typescript
|
|
458
|
+
// app/api/auth/me/route.ts
|
|
459
|
+
export { GET } from "@lastbrain/module-auth/api/auth/me";
|
|
460
|
+
|
|
461
|
+
// app/api/auth/profile/route.ts
|
|
462
|
+
export { GET, PUT, PATCH } from "@lastbrain/module-auth/api/auth/profile";
|
|
463
|
+
|
|
464
|
+
// app/api/admin/users/route.ts
|
|
465
|
+
export { GET } from "@lastbrain/module-auth/api/admin/users";
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### 5. Configurer les variables d'environnement
|
|
469
|
+
|
|
470
|
+
```env
|
|
471
|
+
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
|
|
472
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
## Sécurité
|
|
476
|
+
|
|
477
|
+
### Row Level Security (RLS)
|
|
478
|
+
|
|
479
|
+
Toutes les tables sont protégées par RLS :
|
|
480
|
+
|
|
481
|
+
- Les utilisateurs ne peuvent accéder qu'à leurs propres données
|
|
482
|
+
- Les super admins ont accès à toutes les données
|
|
483
|
+
|
|
484
|
+
### Vérification Super Admin
|
|
485
|
+
|
|
486
|
+
Les routes admin vérifient l'accès super admin via la RPC Supabase :
|
|
487
|
+
|
|
488
|
+
```typescript
|
|
489
|
+
const { data: isSuperAdmin } = await supabase.rpc("is_superadmin", {
|
|
490
|
+
user_id: user.id,
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
if (!isSuperAdmin) {
|
|
494
|
+
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
|
495
|
+
}
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
### Authentification
|
|
499
|
+
|
|
500
|
+
Les routes API vérifient l'authentification :
|
|
501
|
+
|
|
502
|
+
```typescript
|
|
503
|
+
const {
|
|
504
|
+
data: { user },
|
|
505
|
+
error,
|
|
506
|
+
} = await supabase.auth.getUser();
|
|
507
|
+
|
|
508
|
+
if (error || !user) {
|
|
509
|
+
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
510
|
+
}
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
## Développement
|
|
514
|
+
|
|
515
|
+
### Build
|
|
516
|
+
|
|
517
|
+
```bash
|
|
518
|
+
pnpm build
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
### Watch mode
|
|
522
|
+
|
|
523
|
+
```bash
|
|
524
|
+
pnpm dev
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
## Support
|
|
528
|
+
|
|
529
|
+
Pour des questions ou des problèmes, ouvrez une issue sur [GitHub](https://github.com/lastpublication/starter).
|
|
530
|
+
|
|
531
|
+
## Licence
|
|
532
|
+
|
|
533
|
+
MIT
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
2
|
+
/**
|
|
3
|
+
* GET /api/admin/users
|
|
4
|
+
* Returns all users (superadmin only)
|
|
5
|
+
* Supports pagination via query params: page, per_page
|
|
6
|
+
* Supports search via query param: search (email)
|
|
7
|
+
*/
|
|
8
|
+
export declare function GET(request: NextRequest): Promise<NextResponse<any>>;
|
|
9
|
+
//# sourceMappingURL=users.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../../src/api/admin/users.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGxD;;;;;GAKG;AACH,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW,8BAyC7C"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { getSupabaseServerClient } from "@lastbrain/core/server";
|
|
3
|
+
/**
|
|
4
|
+
* GET /api/admin/users
|
|
5
|
+
* Returns all users (superadmin only)
|
|
6
|
+
* Supports pagination via query params: page, per_page
|
|
7
|
+
* Supports search via query param: search (email)
|
|
8
|
+
*/
|
|
9
|
+
export async function GET(request) {
|
|
10
|
+
try {
|
|
11
|
+
const supabase = await getSupabaseServerClient();
|
|
12
|
+
// L'authentification et les droits superadmin sont déjà vérifiés par le middleware
|
|
13
|
+
// Get query parameters
|
|
14
|
+
const searchParams = request.nextUrl.searchParams;
|
|
15
|
+
const page = parseInt(searchParams.get("page") || "1");
|
|
16
|
+
const perPage = parseInt(searchParams.get("per_page") || "20");
|
|
17
|
+
const search = searchParams.get("search") || "";
|
|
18
|
+
// Use RPC function to get users with emails
|
|
19
|
+
const { data: result, error: usersError } = await supabase.rpc("get_admin_users", {
|
|
20
|
+
page_number: page,
|
|
21
|
+
page_size: perPage,
|
|
22
|
+
search_term: search,
|
|
23
|
+
});
|
|
24
|
+
if (usersError) {
|
|
25
|
+
console.error("Error fetching users:", usersError);
|
|
26
|
+
return NextResponse.json({ error: "Database Error", message: usersError.message }, { status: 500 });
|
|
27
|
+
}
|
|
28
|
+
// The RPC function returns the complete response with data and pagination
|
|
29
|
+
return NextResponse.json(result || { data: [], pagination: { page, per_page: perPage, total: 0, total_pages: 0 } });
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
console.error("Error in admin users endpoint:", error);
|
|
33
|
+
return NextResponse.json({
|
|
34
|
+
error: "Internal Server Error",
|
|
35
|
+
message: "Failed to fetch users",
|
|
36
|
+
}, { status: 500 });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
/**
|
|
3
|
+
* GET /api/auth/me
|
|
4
|
+
* Returns the current authenticated user and their profile
|
|
5
|
+
*/
|
|
6
|
+
export declare function GET(): Promise<NextResponse<{
|
|
7
|
+
data: {
|
|
8
|
+
id: string;
|
|
9
|
+
email: string | undefined;
|
|
10
|
+
created_at: string;
|
|
11
|
+
profile: any;
|
|
12
|
+
};
|
|
13
|
+
}> | NextResponse<{
|
|
14
|
+
error: string;
|
|
15
|
+
message: string;
|
|
16
|
+
}>>;
|
|
17
|
+
//# sourceMappingURL=me.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"me.d.ts","sourceRoot":"","sources":["../../../src/api/auth/me.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C;;;GAGG;AACH,wBAAsB,GAAG;;;;;;;;;;IA+BxB"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { getSupabaseServerClient } from "@lastbrain/core/server";
|
|
3
|
+
/**
|
|
4
|
+
* GET /api/auth/me
|
|
5
|
+
* Returns the current authenticated user and their profile
|
|
6
|
+
*/
|
|
7
|
+
export async function GET() {
|
|
8
|
+
try {
|
|
9
|
+
const supabase = await getSupabaseServerClient();
|
|
10
|
+
// Get the authenticated user
|
|
11
|
+
const { data: { user } } = await supabase.auth.getUser();
|
|
12
|
+
// L'utilisateur est déjà authentifié grâce au middleware
|
|
13
|
+
// Get user profile
|
|
14
|
+
const { data: profile } = await supabase
|
|
15
|
+
.from("user_profil")
|
|
16
|
+
.select("*")
|
|
17
|
+
.eq("owner_id", user.id)
|
|
18
|
+
.single();
|
|
19
|
+
// Profile might not exist yet, that's OK
|
|
20
|
+
const userData = {
|
|
21
|
+
id: user.id,
|
|
22
|
+
email: user.email,
|
|
23
|
+
created_at: user.created_at,
|
|
24
|
+
profile: profile || null,
|
|
25
|
+
};
|
|
26
|
+
return NextResponse.json({ data: userData });
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
console.error("Error fetching user:", error);
|
|
30
|
+
return NextResponse.json({ error: "Internal Server Error", message: "Failed to fetch user data" }, { status: 500 });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
2
|
+
/**
|
|
3
|
+
* GET /api/auth/profile
|
|
4
|
+
* Returns the user's profile
|
|
5
|
+
*/
|
|
6
|
+
export declare function GET(): Promise<NextResponse<{
|
|
7
|
+
error: string;
|
|
8
|
+
message: string;
|
|
9
|
+
}> | NextResponse<{
|
|
10
|
+
data: any;
|
|
11
|
+
}>>;
|
|
12
|
+
/**
|
|
13
|
+
* PUT /api/auth/profile
|
|
14
|
+
* Updates the user's profile
|
|
15
|
+
*/
|
|
16
|
+
export declare function PUT(request: NextRequest): Promise<NextResponse<{
|
|
17
|
+
error: string;
|
|
18
|
+
message: string;
|
|
19
|
+
}> | NextResponse<{
|
|
20
|
+
data: any;
|
|
21
|
+
}>>;
|
|
22
|
+
/**
|
|
23
|
+
* PATCH /api/auth/profile
|
|
24
|
+
* Partially updates the user's profile
|
|
25
|
+
*/
|
|
26
|
+
export declare function PATCH(request: NextRequest): Promise<NextResponse<{
|
|
27
|
+
error: string;
|
|
28
|
+
message: string;
|
|
29
|
+
}> | NextResponse<{
|
|
30
|
+
data: any;
|
|
31
|
+
}>>;
|
|
32
|
+
//# sourceMappingURL=profile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../../../src/api/auth/profile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGxD;;;GAGG;AACH,wBAAsB,GAAG;;;;;IA+BxB;AAED;;;GAGG;AACH,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW;;;;;IAyF7C;AAED;;;GAGG;AACH,wBAAsB,KAAK,CAAC,OAAO,EAAE,WAAW;;;;;IAE/C"}
|