@lastbrain/app 0.1.46 → 1.0.1

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.
Files changed (50) hide show
  1. package/dist/app-shell/layout.d.ts +1 -1
  2. package/dist/app-shell/layout.d.ts.map +1 -1
  3. package/dist/app-shell/layout.js +1 -1
  4. package/dist/components/NotificationContainer.js +1 -1
  5. package/dist/index.d.ts +19 -19
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +19 -19
  8. package/dist/layouts/AdminLayoutWithSidebar.d.ts +3 -2
  9. package/dist/layouts/AdminLayoutWithSidebar.d.ts.map +1 -1
  10. package/dist/layouts/AdminLayoutWithSidebar.js +5 -5
  11. package/dist/layouts/AppProviders.d.ts +1 -1
  12. package/dist/layouts/AppProviders.d.ts.map +1 -1
  13. package/dist/layouts/AppProviders.js +3 -3
  14. package/dist/layouts/AuthLayoutWithSidebar.d.ts +7 -4
  15. package/dist/layouts/AuthLayoutWithSidebar.d.ts.map +1 -1
  16. package/dist/layouts/AuthLayoutWithSidebar.js +5 -5
  17. package/dist/layouts/PublicLayoutWithSidebar.js +2 -2
  18. package/dist/layouts/RootLayout.js +1 -1
  19. package/dist/scripts/init-app.d.ts.map +1 -1
  20. package/dist/scripts/init-app.js +488 -50
  21. package/dist/scripts/module-add.js +1 -1
  22. package/dist/scripts/module-build.d.ts.map +1 -1
  23. package/dist/scripts/module-build.js +36 -15
  24. package/dist/scripts/module-create.js +8 -8
  25. package/dist/scripts/module-delete.d.ts.map +1 -1
  26. package/dist/scripts/module-delete.js +1 -1
  27. package/dist/templates/DefaultDoc.js +2 -2
  28. package/dist/templates/DocPage.js +1 -1
  29. package/dist/templates/DocsPageWithModules.js +1 -1
  30. package/dist/types/menu.d.ts +23 -0
  31. package/dist/types/menu.d.ts.map +1 -0
  32. package/dist/types/menu.js +1 -0
  33. package/package.json +11 -3
  34. package/src/app-shell/layout.tsx +1 -1
  35. package/src/components/NotificationContainer.tsx +1 -1
  36. package/src/index.ts +24 -19
  37. package/src/layouts/AdminLayoutWithSidebar.tsx +11 -3
  38. package/src/layouts/AppProviders.tsx +4 -4
  39. package/src/layouts/AuthLayoutWithSidebar.tsx +18 -4
  40. package/src/layouts/PublicLayoutWithSidebar.tsx +2 -2
  41. package/src/layouts/RootLayout.tsx +1 -1
  42. package/src/scripts/init-app.ts +514 -60
  43. package/src/scripts/module-add.ts +1 -1
  44. package/src/scripts/module-build.ts +46 -22
  45. package/src/scripts/module-create.ts +8 -8
  46. package/src/scripts/module-delete.ts +1 -4
  47. package/src/templates/DefaultDoc.tsx +2 -2
  48. package/src/templates/DocPage.tsx +1 -1
  49. package/src/templates/DocsPageWithModules.tsx +1 -1
  50. package/src/types/menu.ts +18 -0
@@ -4,10 +4,7 @@ import { fileURLToPath } from "url";
4
4
  import chalk from "chalk";
5
5
  import inquirer from "inquirer";
6
6
  import { execSync } from "child_process";
7
- import {
8
- AVAILABLE_MODULES,
9
- type ModuleMetadata,
10
- } from "@lastbrain/core/config/modules";
7
+ import { AVAILABLE_MODULES } from "@lastbrain/core/config/modules";
11
8
 
12
9
  const __filename = fileURLToPath(import.meta.url);
13
10
  const __dirname = path.dirname(__filename);
@@ -131,6 +128,7 @@ export async function initApp(options: InitAppOptions) {
131
128
  await createGitIgnore(targetDir, force);
132
129
  await createEnvExample(targetDir, force);
133
130
  await createEnvLocal(targetDir, force, isMonorepoProject);
131
+ await createEnvProd(targetDir, force);
134
132
 
135
133
  // 7. Créer la structure Supabase avec migrations (seulement pour projets indépendants)
136
134
  if (!isMonorepoProject) {
@@ -195,20 +193,31 @@ export async function initApp(options: InitAppOptions) {
195
193
  stdio: "inherit",
196
194
  });
197
195
  console.log(chalk.green("\n✓ Migrations synchronisées\n"));
198
- } catch (error) {
196
+ } catch (_error) {
199
197
  console.log(
200
198
  chalk.yellow("\n⚠️ Erreur de synchronisation des migrations\n")
201
199
  );
202
200
  }
203
201
 
204
- console.log(chalk.yellow("🗄️ Initialisation de la base de données...\n"));
205
- try {
206
- execSync("pnpm db:init", { cwd: targetDir, stdio: "inherit" });
207
- console.log(chalk.green("\n✓ Base de données initialisée\n"));
208
- } catch {
202
+ // Ne pas initialiser la BDD en mode monorepo
203
+ if (!isMonorepoProject) {
209
204
  console.log(
210
- chalk.yellow(
211
- "\n⚠️ Erreur d'initialisation de la DB (normal si Supabase pas configuré)\n"
205
+ chalk.yellow("🗄️ Initialisation de la base de données...\n")
206
+ );
207
+ try {
208
+ execSync("pnpm db:init", { cwd: targetDir, stdio: "inherit" });
209
+ console.log(chalk.green("\n✓ Base de données initialisée\n"));
210
+ } catch {
211
+ console.log(
212
+ chalk.yellow(
213
+ "\n⚠️ Erreur d'initialisation de la DB (normal si Supabase pas configuré)\n"
214
+ )
215
+ );
216
+ }
217
+ } else {
218
+ console.log(
219
+ chalk.cyan(
220
+ "⏭️ Mode monorepo détecté - BDD centralisée, pas d'initialisation locale requise\n"
212
221
  )
213
222
  );
214
223
  }
@@ -226,14 +235,20 @@ export async function initApp(options: InitAppOptions) {
226
235
  console.log(
227
236
  chalk.white(" 1. Cliquez sur 'Get Started' sur la page d'accueil")
228
237
  );
229
- console.log(chalk.white(" 2. Lancez Docker Desktop"));
230
- console.log(
231
- chalk.white(
232
- " 3. Installez Supabase CLI si nécessaire : brew install supabase/tap/supabase"
233
- )
234
- );
235
- console.log(chalk.white(" 4. Exécutez : pnpm db:init"));
236
- console.log(chalk.white(" 5. Rechargez la page\n"));
238
+ if (isMonorepoProject) {
239
+ console.log(
240
+ chalk.white(" 2. La BDD est centralisée dans le monorepo\n")
241
+ );
242
+ } else {
243
+ console.log(chalk.white(" 2. Lancez Docker Desktop"));
244
+ console.log(
245
+ chalk.white(
246
+ " 3. Installez Supabase CLI si nécessaire : brew install supabase/tap/supabase"
247
+ )
248
+ );
249
+ console.log(chalk.white(" 4. Exécutez : pnpm db:init"));
250
+ console.log(chalk.white(" 5. Rechargez la page\n"));
251
+ }
237
252
 
238
253
  // Ouvrir le navigateur
239
254
  const openCommand =
@@ -251,7 +266,7 @@ export async function initApp(options: InitAppOptions) {
251
266
  }, 2000);
252
267
 
253
268
  // Lancer pnpm dev
254
- execSync("pnpm dev", { cwd: targetDir, stdio: "inherit" });
269
+ execSync("pnpm dev:local", { cwd: targetDir, stdio: "inherit" });
255
270
  } catch {
256
271
  console.error(chalk.red("\n❌ Erreur lors du lancement\n"));
257
272
  console.log(chalk.cyan("\nVous pouvez lancer manuellement avec :"));
@@ -259,8 +274,10 @@ export async function initApp(options: InitAppOptions) {
259
274
  console.log(chalk.white(" pnpm install"));
260
275
  console.log(chalk.white(" pnpm build:modules"));
261
276
  console.log(chalk.white(" pnpm db:migrations:sync"));
262
- console.log(chalk.white(" pnpm db:init"));
263
- console.log(chalk.white(" pnpm dev\n"));
277
+ if (!isMonorepoProject) {
278
+ console.log(chalk.white(" pnpm db:init"));
279
+ }
280
+ console.log(chalk.white(" pnpm dev:local (ou pnpm dev:prod)\n"));
264
281
  }
265
282
  } else {
266
283
  console.log(chalk.cyan("\n📋 Prochaines étapes:"));
@@ -275,7 +292,12 @@ export async function initApp(options: InitAppOptions) {
275
292
  console.log(
276
293
  chalk.white(" 5. pnpm db:init (initialiser la base de données)")
277
294
  );
278
- console.log(chalk.white(" 6. pnpm dev (lancer le serveur)\n"));
295
+ console.log(chalk.white(" 6. pnpm dev:local (ou pnpm dev:prod)\n"));
296
+
297
+ console.log(chalk.cyan("\n💡 Scripts disponibles:"));
298
+ console.log(chalk.white(" • pnpm dev:local - Lance avec .env.local"));
299
+ console.log(chalk.white(" • pnpm dev:prod - Lance avec .env.prod"));
300
+ console.log(chalk.white(" • pnpm dev - Lance avec .env actuel\n"));
279
301
 
280
302
  console.log(chalk.gray("Prérequis pour Supabase :"));
281
303
  console.log(chalk.white(" - Docker Desktop installé et lancé"));
@@ -405,10 +427,10 @@ function getLastBrainVersions(targetDir: string): {
405
427
  moduleAi: moduleAiVersion,
406
428
  };
407
429
  }
408
- } catch (error) {
430
+ } catch (_error) {
409
431
  console.warn(
410
432
  chalk.yellow(
411
- `⚠️ Impossible de lire les versions locales (${error}), utilisation de 'latest'`
433
+ `⚠️ Impossible de lire les versions locales (${_error}), utilisation de 'latest'`
412
434
  )
413
435
  );
414
436
  }
@@ -514,6 +536,7 @@ async function addDependencies(
514
536
  requiredDeps["lucide-react"] = "^0.554.0";
515
537
  requiredDeps["framer-motion"] = "^11.18.2";
516
538
  requiredDeps["clsx"] = "^2.1.1";
539
+ requiredDeps["env-cmd"] = "^11.0.0";
517
540
  }
518
541
 
519
542
  // DevDependencies
@@ -910,17 +933,56 @@ async function createAppHeader(targetDir: string, force: boolean) {
910
933
  if (!fs.existsSync(headerPath) || force) {
911
934
  const headerContent = `"use client";
912
935
 
913
- import { Header } from "@lastbrain/ui";
936
+ import { Header, type MenuItem } from "@lastbrain/ui";
914
937
  import { menuConfig } from "../config/menu";
915
938
  import { supabaseBrowserClient } from "@lastbrain/core";
916
939
  import { useRouter } from "next/navigation";
917
940
  import { useAuthSession, useNotificationsContext } from "@lastbrain/app";
941
+ import { useState, useEffect } from "react";
942
+
943
+ interface MenuIgnored {
944
+ public: { title: string; path: string }[];
945
+ auth: { title: string; path: string }[];
946
+ }
918
947
 
919
948
  export function AppHeader() {
920
949
  const router = useRouter();
921
950
  const { user, isSuperAdmin } = useAuthSession();
922
951
  const { data, loading, markAsRead, markAllAsRead, deleteNotification } =
923
952
  useNotificationsContext();
953
+ const [menuIgnored, setMenuIgnored] = useState<MenuIgnored | undefined>();
954
+ const [menuCustom, setMenuCustom] = useState<MenuItem[] | undefined>();
955
+ const [isLoading, setIsLoading] = useState(true);
956
+
957
+ // Charger menuIgnored et menuCustom s'ils existent
958
+ useEffect(() => {
959
+ let loadedIgnored = false;
960
+ let loadedCustom = false;
961
+
962
+ // Charger menu-ignored
963
+ import("../config/menu-ignored")
964
+ .then((mod) => setMenuIgnored(mod.menuIgnored))
965
+ .catch(() => setMenuIgnored(undefined))
966
+ .finally(() => {
967
+ loadedIgnored = true;
968
+ if (loadedIgnored && loadedCustom) setIsLoading(false);
969
+ });
970
+
971
+ // Charger menu-custom
972
+ import("../config/menu-custom")
973
+ .then((mod) => {
974
+ // Combiner les menus custom publics et auth
975
+ const customMenus: MenuItem[] = [];
976
+ if (mod.menuCustom?.public) customMenus.push(...mod.menuCustom.public);
977
+ if (mod.menuCustom?.auth) customMenus.push(...mod.menuCustom.auth);
978
+ setMenuCustom(customMenus.length > 0 ? customMenus : undefined);
979
+ })
980
+ .catch(() => setMenuCustom(undefined))
981
+ .finally(() => {
982
+ loadedCustom = true;
983
+ if (loadedIgnored && loadedCustom) setIsLoading(false);
984
+ });
985
+ }, []);
924
986
 
925
987
  const handleLogout = async () => {
926
988
  await supabaseBrowserClient.auth.signOut();
@@ -943,6 +1005,9 @@ export function AppHeader() {
943
1005
  onMarkAsRead={markAsRead}
944
1006
  onMarkAllAsRead={markAllAsRead}
945
1007
  onDeleteNotification={deleteNotification}
1008
+ {...(menuIgnored ? { menuIgnored } : {})}
1009
+ {...(menuCustom ? { menuCustom } : {})}
1010
+ {...{ isLoadingMenus: isLoading }}
946
1011
  />
947
1012
  );
948
1013
  }
@@ -1040,7 +1105,58 @@ async function createConfigFiles(
1040
1105
  const middlewarePath = path.join(targetDir, "middleware.ts");
1041
1106
  if (!fs.existsSync(middlewarePath) || force) {
1042
1107
  const middleware = `import { type NextRequest, NextResponse } from "next/server";
1043
- import { createMiddlewareClient } from "@lastbrain/core/server";
1108
+ import { createServerClient, type CookieOptions } from "@supabase/ssr";
1109
+
1110
+ /**
1111
+ * Crée un client Supabase pour le middleware
1112
+ */
1113
+ function createMiddlewareClient(request: NextRequest) {
1114
+ let response = NextResponse.next({
1115
+ request: {
1116
+ headers: request.headers,
1117
+ },
1118
+ });
1119
+
1120
+ const supabase = createServerClient(
1121
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
1122
+ process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
1123
+ {
1124
+ cookies: {
1125
+ get(name: string) {
1126
+ return request.cookies.get(name)?.value;
1127
+ },
1128
+ set(name: string, value: string, options: CookieOptions) {
1129
+ request.cookies.set({
1130
+ name,
1131
+ value,
1132
+ ...options,
1133
+ });
1134
+ response = NextResponse.next({
1135
+ request: {
1136
+ headers: request.headers,
1137
+ },
1138
+ });
1139
+ response.cookies.set({
1140
+ name,
1141
+ value,
1142
+ ...options,
1143
+ });
1144
+ },
1145
+ remove(name: string, options: CookieOptions) {
1146
+ request.cookies.delete(name);
1147
+ response = NextResponse.next({
1148
+ request: {
1149
+ headers: request.headers,
1150
+ },
1151
+ });
1152
+ response.cookies.delete(name);
1153
+ },
1154
+ },
1155
+ }
1156
+ );
1157
+
1158
+ return { supabase, response };
1159
+ }
1044
1160
 
1045
1161
  export async function middleware(request: NextRequest) {
1046
1162
  const { pathname } = request.nextUrl;
@@ -1188,9 +1304,9 @@ export const config = {
1188
1304
  const nextConfig = `/** @type {import('next').NextConfig} */
1189
1305
  const nextConfig = {
1190
1306
  reactStrictMode: true,
1191
- devIndicators: {
1307
+ devIndicators: {
1192
1308
  position: 'bottom-right',
1193
- },
1309
+ }
1194
1310
  };
1195
1311
 
1196
1312
  export default nextConfig;
@@ -1205,7 +1321,7 @@ export default nextConfig;
1205
1321
  let tailwindConfig = "";
1206
1322
 
1207
1323
  if (useHeroUI) {
1208
- // Configuration avec HeroUI
1324
+ // Configuration avec HeroUI - complète avec thèmes
1209
1325
  tailwindConfig = `import { heroui } from "@heroui/theme";
1210
1326
 
1211
1327
  /** @type {import('tailwindcss').Config} */
@@ -1217,8 +1333,195 @@ const config = {
1217
1333
  "./node_modules/@heroui/theme/dist/**/*.{js,mjs}",
1218
1334
  ],
1219
1335
  darkMode: "class",
1220
- plugins: [heroui()],
1221
- }
1336
+ plugins: [
1337
+ heroui({
1338
+ themes: {
1339
+ light: {
1340
+ colors: {
1341
+ default: {
1342
+ 950: "#0d0d0e",
1343
+ 900: "#19191c",
1344
+ 800: "#26262a",
1345
+ 700: "#323238",
1346
+ 600: "#3f3f46",
1347
+ 500: "#65656b",
1348
+ 400: "#8c8c90",
1349
+ 300: "#b2b2b5",
1350
+ 200: "#d9d9da",
1351
+ 100: "#ffffff",
1352
+ foreground: "#000000",
1353
+ DEFAULT: "#d4d4d8",
1354
+ },
1355
+ primary: {
1356
+ 50: "#eef2ff",
1357
+ 100: "#e0e7ff",
1358
+ 200: "#c7d2fe",
1359
+ 300: "#a5b4fc",
1360
+ 400: "#818cf8",
1361
+ 500: "#6366f1",
1362
+ 600: "#4f46e5",
1363
+ 700: "#4338ca",
1364
+ 800: "#3730a3",
1365
+ 900: "#312e81",
1366
+ foreground: "#ffffff",
1367
+ DEFAULT: "#6366f1",
1368
+ },
1369
+ secondary: {
1370
+ 50: "#f5e8ff",
1371
+ 100: "#e8ccff",
1372
+ 200: "#d7a6ff",
1373
+ 300: "#c57fff",
1374
+ 400: "#b359ff",
1375
+ 500: "#9b37ff",
1376
+ 600: "#7d1fcc",
1377
+ 700: "#5f1799",
1378
+ 800: "#410f66",
1379
+ 900: "#240833",
1380
+ foreground: "#ffffff",
1381
+ DEFAULT: "#9b37ff",
1382
+ },
1383
+ success: {
1384
+ 50: "#e7fff7",
1385
+ 100: "#c3ffec",
1386
+ 200: "#9affdf",
1387
+ 300: "#70ffd2",
1388
+ 400: "#4bffca",
1389
+ 500: "#22e6b0",
1390
+ 600: "#18b38a",
1391
+ 700: "#108066",
1392
+ 800: "#074d40",
1393
+ 900: "#012b22",
1394
+ foreground: "#000",
1395
+ DEFAULT: "#22e6b0",
1396
+ },
1397
+ warning: {
1398
+ 50: "#fff8e1",
1399
+ 100: "#ffecb3",
1400
+ 200: "#ffe082",
1401
+ 300: "#ffd54f",
1402
+ 400: "#ffca28",
1403
+ 500: "#ffc107",
1404
+ 600: "#ffb300",
1405
+ 700: "#ffa000",
1406
+ 800: "#ff8f00",
1407
+ 900: "#ff6f00",
1408
+ foreground: "#000",
1409
+ DEFAULT: "#ffca28",
1410
+ },
1411
+ danger: {
1412
+ 50: "#ffe6e9",
1413
+ 100: "#ffbac1",
1414
+ 200: "#ff8f99",
1415
+ 300: "#ff6471",
1416
+ 400: "#ff3949",
1417
+ 500: "#ff112a",
1418
+ 600: "#d80c22",
1419
+ 700: "#b1081b",
1420
+ 800: "#890514",
1421
+ 900: "#62020d",
1422
+ foreground: "#fff",
1423
+ DEFAULT: "#ff112a",
1424
+ },
1425
+ background: "#f7f8fc",
1426
+ foreground: "#0e0e10",
1427
+ content1: "#ffffff",
1428
+ },
1429
+ },
1430
+ dark: {
1431
+ colors: {
1432
+ default: {
1433
+ 50: "#1a1c1f",
1434
+ 100: "#232529",
1435
+ 200: "#2c2f34",
1436
+ 300: "#363940",
1437
+ 400: "#40444d",
1438
+ 500: "#4b4f59",
1439
+ 600: "#6c707b",
1440
+ 700: "#8d919b",
1441
+ 800: "#afb2bb",
1442
+ 900: "#d1d3d9",
1443
+ foreground: "#ffffff",
1444
+ DEFAULT: "#363940",
1445
+ },
1446
+ primary: {
1447
+ 50: "#312e81",
1448
+ 100: "#3730a3",
1449
+ 200: "#4338ca",
1450
+ 300: "#4f46e5",
1451
+ 400: "#6366f1",
1452
+ 500: "#818cf8",
1453
+ 600: "#a5b4fc",
1454
+ 700: "#c7d2fe",
1455
+ 800: "#e0e7ff",
1456
+ 900: "#eef2ff",
1457
+ foreground: "#ffffff",
1458
+ DEFAULT: "#6366f1",
1459
+ },
1460
+ secondary: {
1461
+ 50: "#240833",
1462
+ 100: "#410f66",
1463
+ 200: "#5f1799",
1464
+ 300: "#7d1fcc",
1465
+ 400: "#9b37ff",
1466
+ 500: "#b359ff",
1467
+ 600: "#c57fff",
1468
+ 700: "#d7a6ff",
1469
+ 800: "#e8ccff",
1470
+ 900: "#f5e8ff",
1471
+ foreground: "#ffffff",
1472
+ DEFAULT: "#9b37ff",
1473
+ },
1474
+ success: {
1475
+ 50: "#012b22",
1476
+ 100: "#074d40",
1477
+ 200: "#108066",
1478
+ 300: "#18b38a",
1479
+ 400: "#22e6b0",
1480
+ 500: "#4bffca",
1481
+ 600: "#70ffd2",
1482
+ 700: "#9affdf",
1483
+ 800: "#c3ffec",
1484
+ 900: "#e7fff7",
1485
+ foreground: "#0e0e0e",
1486
+ DEFAULT: "#22e6b0",
1487
+ },
1488
+ warning: {
1489
+ 50: "#3a2c00",
1490
+ 100: "#5e4700",
1491
+ 200: "#836300",
1492
+ 300: "#a77e00",
1493
+ 400: "#cc9900",
1494
+ 500: "#ffc107",
1495
+ 600: "#ffd54f",
1496
+ 700: "#ffe082",
1497
+ 800: "#ffecb3",
1498
+ 900: "#fff8e1",
1499
+ foreground: "#000",
1500
+ DEFAULT: "#ffc107",
1501
+ },
1502
+ danger: {
1503
+ 50: "#4a000a",
1504
+ 100: "#6e000f",
1505
+ 200: "#920014",
1506
+ 300: "#b60019",
1507
+ 400: "#da001f",
1508
+ 500: "#ff112a",
1509
+ 600: "#ff3949",
1510
+ 700: "#ff6471",
1511
+ 800: "#ff8f99",
1512
+ 900: "#ffbac1",
1513
+ foreground: "#ffffff",
1514
+ DEFAULT: "#ff112a",
1515
+ },
1516
+ background: "#0f1114",
1517
+ foreground: "#f8f8f8",
1518
+ content1: "#15181d",
1519
+ },
1520
+ },
1521
+ },
1522
+ }),
1523
+ ],
1524
+ };
1222
1525
 
1223
1526
  export default config;
1224
1527
  `;
@@ -1277,8 +1580,56 @@ export default config;
1277
1580
  // tsconfig.json
1278
1581
  const tsconfigPath = path.join(targetDir, "tsconfig.json");
1279
1582
  if (!fs.existsSync(tsconfigPath) || force) {
1280
- const tsconfig = {
1281
- extends: "../../tsconfig.base.json",
1583
+ // Détecter si le projet cible est dans un monorepo
1584
+ const targetIsInMonorepo =
1585
+ fs.existsSync(
1586
+ path.join(targetDir, "../../../packages/core/package.json")
1587
+ ) ||
1588
+ fs.existsSync(path.join(targetDir, "../../packages/core/package.json"));
1589
+
1590
+ // Générer les chemins en fonction du contexte
1591
+ const paths: Record<string, string[]> = {
1592
+ "@/*": ["./*"],
1593
+ };
1594
+
1595
+ if (targetIsInMonorepo) {
1596
+ // En monorepo, pointer sur les sources locales
1597
+ paths["@lastbrain/ui"] = ["../../packages/ui/src/index.ts"];
1598
+ paths["@lastbrain/ui/*"] = ["../../packages/ui/src/*"];
1599
+ paths["@lastbrain/core"] = ["../../packages/core/src/index.ts"];
1600
+ paths["@lastbrain/core/*"] = ["../../packages/core/src/*"];
1601
+ paths["@lastbrain/app"] = ["../../packages/app/src/index.ts"];
1602
+ paths["@lastbrain/app/*"] = ["../../packages/app/src/*"];
1603
+ paths["@lastbrain/module-auth"] = [
1604
+ "../../packages/module-auth/src/index.ts",
1605
+ ];
1606
+ paths["@lastbrain/module-auth/*"] = ["../../packages/module-auth/src/*"];
1607
+ paths["@lastbrain/module-ai"] = ["../../packages/module-ai/src/index.ts"];
1608
+ paths["@lastbrain/module-ai/*"] = ["../../packages/module-ai/src/*"];
1609
+ paths["@lastbrain/module-legal"] = [
1610
+ "../../packages/module-legal/src/index.ts",
1611
+ ];
1612
+ paths["@lastbrain/module-legal/*"] = [
1613
+ "../../packages/module-legal/src/*",
1614
+ ];
1615
+ paths["@lastbrain/module-project-board"] = [
1616
+ "../../packages/module-project-board/src/index.ts",
1617
+ ];
1618
+ paths["@lastbrain/module-project-board/*"] = [
1619
+ "../../packages/module-project-board/src/*",
1620
+ ];
1621
+ paths["@lastbrain/module-tasks"] = [
1622
+ "../../packages/module-tasks/src/index.ts",
1623
+ ];
1624
+ paths["@lastbrain/module-tasks/*"] = [
1625
+ "../../packages/module-tasks/src/*",
1626
+ ];
1627
+ } else {
1628
+ // Hors monorepo (npm install), ne pas utiliser de paths aliases
1629
+ delete paths["@/*"];
1630
+ }
1631
+
1632
+ const tsconfig: any = {
1282
1633
  compilerOptions: {
1283
1634
  target: "ES2020",
1284
1635
  lib: ["ES2020", "DOM", "DOM.Iterable"],
@@ -1295,14 +1646,18 @@ export default config;
1295
1646
  incremental: true,
1296
1647
  isolatedModules: true,
1297
1648
  plugins: [{ name: "next" }],
1298
- paths: {
1299
- "@/*": ["./*"],
1300
- },
1649
+ paths,
1301
1650
  types: [],
1302
1651
  },
1303
1652
  include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
1304
1653
  exclude: ["node_modules", "dist", ".next", "out"],
1305
1654
  };
1655
+
1656
+ // Ajouter extends seulement en monorepo
1657
+ if (targetIsInMonorepo) {
1658
+ tsconfig.extends = "../../tsconfig.base.json";
1659
+ }
1660
+
1306
1661
  await fs.writeJson(tsconfigPath, tsconfig, { spaces: 2 });
1307
1662
  console.log(chalk.green("✓ tsconfig.json créé"));
1308
1663
  }
@@ -1333,6 +1688,69 @@ export const menuConfig: MenuConfig = {
1333
1688
  console.log(chalk.green("✓ config/menu.ts créé"));
1334
1689
  }
1335
1690
 
1691
+ // config/menu-ignored.ts - Optional file to hide menus and block routes
1692
+ const menuIgnoredPath = path.join(configDir, "menu-ignored.ts");
1693
+ if (!fs.existsSync(menuIgnoredPath) || force) {
1694
+ const menuIgnored = `import type { MenuIgnored } from "@lastbrain/app";
1695
+
1696
+ /**
1697
+ * Menu items to hide and routes to block
1698
+ * This file is optional - if it doesn't exist, all menus are shown
1699
+ *
1700
+ * Example:
1701
+ * export const menuIgnored: MenuIgnored = {
1702
+ * public: [
1703
+ * { title: "Documentation", path: "/docs" }
1704
+ * ],
1705
+ * auth: [
1706
+ * { title: "Profile", path: "/auth/profile" }
1707
+ * ]
1708
+ * };
1709
+ */
1710
+
1711
+ export const menuIgnored: MenuIgnored = {
1712
+ public: [],
1713
+ auth: [],
1714
+ };
1715
+ `;
1716
+ await fs.writeFile(menuIgnoredPath, menuIgnored);
1717
+ console.log(chalk.green("✓ config/menu-ignored.ts créé"));
1718
+ }
1719
+
1720
+ // config/menu-custom.ts - Optional file to add custom menus
1721
+ const menuCustomPath = path.join(configDir, "menu-custom.ts");
1722
+ if (!fs.existsSync(menuCustomPath) || force) {
1723
+ const menuCustom = `import type { MenuCustom } from "@lastbrain/app";
1724
+
1725
+ /**
1726
+ * Custom menu items to add without creating a module
1727
+ * This file is optional - if it doesn't exist, no custom menus are added
1728
+ *
1729
+ * Example:
1730
+ * export const menuCustom: MenuCustom = {
1731
+ * public: [
1732
+ * { label: "Blog", href: "/blog" },
1733
+ * { label: "Pricing", href: "/pricing" }
1734
+ * ],
1735
+ * auth: [
1736
+ * { label: "Invoices", href: "/auth/invoices" }
1737
+ * ],
1738
+ * admin: [
1739
+ * { label: "Reports", href: "/admin/reports" }
1740
+ * ]
1741
+ * };
1742
+ */
1743
+
1744
+ export const menuCustom: MenuCustom = {
1745
+ public: [],
1746
+ auth: [],
1747
+ admin: [],
1748
+ };
1749
+ `;
1750
+ await fs.writeFile(menuCustomPath, menuCustom);
1751
+ console.log(chalk.green("✓ config/menu-custom.ts créé"));
1752
+ }
1753
+
1336
1754
  // config/footer.ts
1337
1755
  const footerConfigPath = path.join(configDir, "footer.ts");
1338
1756
  if (!fs.existsSync(footerConfigPath) || force) {
@@ -1353,6 +1771,29 @@ export const footerConfig: FooterConfig = {
1353
1771
  console.log(chalk.green("✓ config/footer.ts créé"));
1354
1772
  }
1355
1773
 
1774
+ // config/user-tabs.ts - User detail page tabs configuration
1775
+ const userTabsConfigPath = path.join(configDir, "user-tabs.ts");
1776
+ if (!fs.existsSync(userTabsConfigPath) || force) {
1777
+ const userTabsConfig = `// User tabs configuration
1778
+ // This file is generated and can be regenerated by running: pnpm build:modules
1779
+ "use client";
1780
+
1781
+ import type React from "react";
1782
+
1783
+ export interface ModuleUserTab {
1784
+ id: string;
1785
+ label: string;
1786
+ component: React.ComponentType<{ userId: string }>;
1787
+ }
1788
+
1789
+ // Module user tabs - dynamically imported from active modules
1790
+ // To add tabs from modules, import them here and add to the array below
1791
+ export const moduleUserTabs: ModuleUserTab[] = [];
1792
+ `;
1793
+ await fs.writeFile(userTabsConfigPath, userTabsConfig);
1794
+ console.log(chalk.green("✓ config/user-tabs.ts créé"));
1795
+ }
1796
+
1356
1797
  // Créer les hooks
1357
1798
  await createHooksDirectory(targetDir, force);
1358
1799
  }
@@ -1521,16 +1962,7 @@ tmp/
1521
1962
  coverage/
1522
1963
  *.lcov
1523
1964
 
1524
- # Generated by module-build
1525
- app/navigation.generated.ts
1526
- app/routes.generated.ts
1527
- app/menu.generated.ts
1528
1965
 
1529
- # Generated app-shell overrides
1530
- app/(public)/
1531
- app/(auth)/
1532
- app/(admin)/
1533
- app/layout.tsx
1534
1966
  `;
1535
1967
  await fs.writeFile(gitignorePath, gitignoreContent);
1536
1968
  }
@@ -1604,6 +2036,30 @@ OPENAI_API_KEY=sk-fake-openai-key-for-development-replace-with-real-key
1604
2036
  }
1605
2037
  }
1606
2038
 
2039
+ async function createEnvProd(targetDir: string, force: boolean) {
2040
+ const envProdPath = path.join(targetDir, ".env.prod");
2041
+
2042
+ if (!fs.existsSync(envProdPath) || force) {
2043
+ console.log(chalk.yellow("\n🔐 Création de .env.prod..."));
2044
+
2045
+ const envContent = `# Production Environment Configuration
2046
+ # Copy your production values here
2047
+
2048
+ # Supabase Production
2049
+ NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
2050
+ NEXT_PUBLIC_SUPABASE_ANON_KEY=your-prod-anon-key
2051
+ SUPABASE_SERVICE_ROLE_KEY=your-prod-service-role-key
2052
+
2053
+ # OpenAI Production
2054
+ OPENAI_API_KEY=sk-proj-your-prod-api-key
2055
+
2056
+ # Note: Update these values with your actual production credentials
2057
+ `;
2058
+ await fs.writeFile(envProdPath, envContent);
2059
+ console.log(chalk.green("✓ .env.prod créé"));
2060
+ }
2061
+ }
2062
+
1607
2063
  async function createSupabaseStructure(targetDir: string, force: boolean) {
1608
2064
  console.log(chalk.yellow("\n🗄️ Création de la structure Supabase..."));
1609
2065
 
@@ -1644,10 +2100,10 @@ async function createSupabaseStructure(targetDir: string, force: boolean) {
1644
2100
  )
1645
2101
  );
1646
2102
  }
1647
- } catch (error) {
2103
+ } catch (_error) {
1648
2104
  console.error(
1649
2105
  chalk.red("✗ Erreur lors de la création de la migration:"),
1650
- error
2106
+ _error
1651
2107
  );
1652
2108
  }
1653
2109
  } else {
@@ -1672,24 +2128,22 @@ async function addScriptsToPackageJson(targetDir: string) {
1672
2128
  ) ||
1673
2129
  fs.existsSync(path.join(targetDir, "../../packages/core/package.json"));
1674
2130
 
1675
- let scriptsPrefix = "lastbrain";
1676
-
1677
- if (!targetIsInMonorepo) {
1678
- // Hors monorepo, utiliser le chemin direct vers le CLI
1679
- scriptsPrefix = "node node_modules/@lastbrain/app/dist/cli.js";
1680
- }
2131
+ // Utiliser le CLI depuis le monorepo si présent, sinon depuis node_modules
2132
+ const scriptsPrefix = targetIsInMonorepo
2133
+ ? "node ../../packages/app/dist/cli.js"
2134
+ : "node node_modules/@lastbrain/app/dist/cli.js";
1681
2135
 
1682
2136
  const scripts = {
1683
2137
  predev: targetIsInMonorepo
1684
- ? "pnpm --filter @lastbrain/core build && pnpm --filter @lastbrain/ui build && pnpm --filter @lastbrain/module-auth build && pnpm --filter @lastbrain/module-ai build"
1685
- : "echo 'No prebuild needed outside monorepo'",
2138
+ ? "pnpm --filter @lastbrain/core build && pnpm --filter @lastbrain/ui build && pnpm --filter @lastbrain/app build && pnpm --filter @lastbrain/module-auth build && pnpm --filter @lastbrain/module-ai build"
2139
+ : "echo 'No prebuild needed'",
1686
2140
  dev: "next dev",
2141
+ "dev:local": "env-cmd -f .env.local next dev",
2142
+ "dev:prod": "env-cmd -f .env.prod next dev",
1687
2143
  build: "next build",
1688
2144
  start: "next start",
1689
2145
  lint: "next lint",
1690
- lastbrain: targetIsInMonorepo
1691
- ? "lastbrain"
1692
- : "node node_modules/@lastbrain/app/dist/cli.js",
2146
+ lastbrain: scriptsPrefix,
1693
2147
  "build:modules": `${scriptsPrefix} module:build`,
1694
2148
  "db:migrations:sync": `${scriptsPrefix} db:migrations:sync`,
1695
2149
  "db:init": `${scriptsPrefix} db:init`,