@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,7 +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 { AVAILABLE_MODULES, } from "@lastbrain/core/config/modules";
7
+ import { AVAILABLE_MODULES } from "@lastbrain/core/config/modules";
8
8
  const __filename = fileURLToPath(import.meta.url);
9
9
  const __dirname = path.dirname(__filename);
10
10
  export async function initApp(options) {
@@ -86,6 +86,7 @@ export async function initApp(options) {
86
86
  await createGitIgnore(targetDir, force);
87
87
  await createEnvExample(targetDir, force);
88
88
  await createEnvLocal(targetDir, force, isMonorepoProject);
89
+ await createEnvProd(targetDir, force);
89
90
  // 7. Créer la structure Supabase avec migrations (seulement pour projets indépendants)
90
91
  if (!isMonorepoProject) {
91
92
  console.log(chalk.blue("🗄️ Création de la structure Supabase locale...\n"));
@@ -130,16 +131,22 @@ export async function initApp(options) {
130
131
  });
131
132
  console.log(chalk.green("\n✓ Migrations synchronisées\n"));
132
133
  }
133
- catch (error) {
134
+ catch (_error) {
134
135
  console.log(chalk.yellow("\n⚠️ Erreur de synchronisation des migrations\n"));
135
136
  }
136
- console.log(chalk.yellow("🗄️ Initialisation de la base de données...\n"));
137
- try {
138
- execSync("pnpm db:init", { cwd: targetDir, stdio: "inherit" });
139
- console.log(chalk.green("\n✓ Base de données initialisée\n"));
137
+ // Ne pas initialiser la BDD en mode monorepo
138
+ if (!isMonorepoProject) {
139
+ console.log(chalk.yellow("🗄️ Initialisation de la base de données...\n"));
140
+ try {
141
+ execSync("pnpm db:init", { cwd: targetDir, stdio: "inherit" });
142
+ console.log(chalk.green("\n✓ Base de données initialisée\n"));
143
+ }
144
+ catch {
145
+ console.log(chalk.yellow("\n⚠️ Erreur d'initialisation de la DB (normal si Supabase pas configuré)\n"));
146
+ }
140
147
  }
141
- catch {
142
- console.log(chalk.yellow("\n⚠️ Erreur d'initialisation de la DB (normal si Supabase pas configuré)\n"));
148
+ else {
149
+ console.log(chalk.cyan("⏭️ Mode monorepo détecté - BDD centralisée, pas d'initialisation locale requise\n"));
143
150
  }
144
151
  // Détecter le port (par défaut 3000 pour Next.js)
145
152
  const port = 3000;
@@ -148,10 +155,15 @@ export async function initApp(options) {
148
155
  console.log(chalk.cyan(`📱 Ouvrez votre navigateur sur : ${url}\n`));
149
156
  console.log(chalk.blue("\n📋 Prochaines étapes après le démarrage :"));
150
157
  console.log(chalk.white(" 1. Cliquez sur 'Get Started' sur la page d'accueil"));
151
- console.log(chalk.white(" 2. Lancez Docker Desktop"));
152
- console.log(chalk.white(" 3. Installez Supabase CLI si nécessaire : brew install supabase/tap/supabase"));
153
- console.log(chalk.white(" 4. Exécutez : pnpm db:init"));
154
- console.log(chalk.white(" 5. Rechargez la page\n"));
158
+ if (isMonorepoProject) {
159
+ console.log(chalk.white(" 2. La BDD est centralisée dans le monorepo\n"));
160
+ }
161
+ else {
162
+ console.log(chalk.white(" 2. Lancez Docker Desktop"));
163
+ console.log(chalk.white(" 3. Installez Supabase CLI si nécessaire : brew install supabase/tap/supabase"));
164
+ console.log(chalk.white(" 4. Exécutez : pnpm db:init"));
165
+ console.log(chalk.white(" 5. Rechargez la page\n"));
166
+ }
155
167
  // Ouvrir le navigateur
156
168
  const openCommand = process.platform === "darwin"
157
169
  ? "open"
@@ -167,7 +179,7 @@ export async function initApp(options) {
167
179
  }
168
180
  }, 2000);
169
181
  // Lancer pnpm dev
170
- execSync("pnpm dev", { cwd: targetDir, stdio: "inherit" });
182
+ execSync("pnpm dev:local", { cwd: targetDir, stdio: "inherit" });
171
183
  }
172
184
  catch {
173
185
  console.error(chalk.red("\n❌ Erreur lors du lancement\n"));
@@ -176,8 +188,10 @@ export async function initApp(options) {
176
188
  console.log(chalk.white(" pnpm install"));
177
189
  console.log(chalk.white(" pnpm build:modules"));
178
190
  console.log(chalk.white(" pnpm db:migrations:sync"));
179
- console.log(chalk.white(" pnpm db:init"));
180
- console.log(chalk.white(" pnpm dev\n"));
191
+ if (!isMonorepoProject) {
192
+ console.log(chalk.white(" pnpm db:init"));
193
+ }
194
+ console.log(chalk.white(" pnpm dev:local (ou pnpm dev:prod)\n"));
181
195
  }
182
196
  }
183
197
  else {
@@ -187,7 +201,11 @@ export async function initApp(options) {
187
201
  console.log(chalk.white(" 3. pnpm build:modules (générer les routes des modules)"));
188
202
  console.log(chalk.white(" 4. pnpm db:migrations:sync (synchroniser les migrations)"));
189
203
  console.log(chalk.white(" 5. pnpm db:init (initialiser la base de données)"));
190
- console.log(chalk.white(" 6. pnpm dev (lancer le serveur)\n"));
204
+ console.log(chalk.white(" 6. pnpm dev:local (ou pnpm dev:prod)\n"));
205
+ console.log(chalk.cyan("\n💡 Scripts disponibles:"));
206
+ console.log(chalk.white(" • pnpm dev:local - Lance avec .env.local"));
207
+ console.log(chalk.white(" • pnpm dev:prod - Lance avec .env.prod"));
208
+ console.log(chalk.white(" • pnpm dev - Lance avec .env actuel\n"));
191
209
  console.log(chalk.gray("Prérequis pour Supabase :"));
192
210
  console.log(chalk.white(" - Docker Desktop installé et lancé"));
193
211
  console.log(chalk.white(" - Supabase CLI : brew install supabase/tap/supabase\n"));
@@ -283,8 +301,8 @@ function getLastBrainVersions(targetDir) {
283
301
  };
284
302
  }
285
303
  }
286
- catch (error) {
287
- console.warn(chalk.yellow(`⚠️ Impossible de lire les versions locales (${error}), utilisation de 'latest'`));
304
+ catch (_error) {
305
+ console.warn(chalk.yellow(`⚠️ Impossible de lire les versions locales (${_error}), utilisation de 'latest'`));
288
306
  }
289
307
  // Fallback: utiliser "latest"
290
308
  return {
@@ -375,6 +393,7 @@ async function addDependencies(targetDir, useHeroUI, withAuth, selectedModules =
375
393
  requiredDeps["lucide-react"] = "^0.554.0";
376
394
  requiredDeps["framer-motion"] = "^11.18.2";
377
395
  requiredDeps["clsx"] = "^2.1.1";
396
+ requiredDeps["env-cmd"] = "^11.0.0";
378
397
  }
379
398
  // DevDependencies
380
399
  const requiredDevDeps = {
@@ -716,17 +735,56 @@ async function createAppHeader(targetDir, force) {
716
735
  if (!fs.existsSync(headerPath) || force) {
717
736
  const headerContent = `"use client";
718
737
 
719
- import { Header } from "@lastbrain/ui";
738
+ import { Header, type MenuItem } from "@lastbrain/ui";
720
739
  import { menuConfig } from "../config/menu";
721
740
  import { supabaseBrowserClient } from "@lastbrain/core";
722
741
  import { useRouter } from "next/navigation";
723
742
  import { useAuthSession, useNotificationsContext } from "@lastbrain/app";
743
+ import { useState, useEffect } from "react";
744
+
745
+ interface MenuIgnored {
746
+ public: { title: string; path: string }[];
747
+ auth: { title: string; path: string }[];
748
+ }
724
749
 
725
750
  export function AppHeader() {
726
751
  const router = useRouter();
727
752
  const { user, isSuperAdmin } = useAuthSession();
728
753
  const { data, loading, markAsRead, markAllAsRead, deleteNotification } =
729
754
  useNotificationsContext();
755
+ const [menuIgnored, setMenuIgnored] = useState<MenuIgnored | undefined>();
756
+ const [menuCustom, setMenuCustom] = useState<MenuItem[] | undefined>();
757
+ const [isLoading, setIsLoading] = useState(true);
758
+
759
+ // Charger menuIgnored et menuCustom s'ils existent
760
+ useEffect(() => {
761
+ let loadedIgnored = false;
762
+ let loadedCustom = false;
763
+
764
+ // Charger menu-ignored
765
+ import("../config/menu-ignored")
766
+ .then((mod) => setMenuIgnored(mod.menuIgnored))
767
+ .catch(() => setMenuIgnored(undefined))
768
+ .finally(() => {
769
+ loadedIgnored = true;
770
+ if (loadedIgnored && loadedCustom) setIsLoading(false);
771
+ });
772
+
773
+ // Charger menu-custom
774
+ import("../config/menu-custom")
775
+ .then((mod) => {
776
+ // Combiner les menus custom publics et auth
777
+ const customMenus: MenuItem[] = [];
778
+ if (mod.menuCustom?.public) customMenus.push(...mod.menuCustom.public);
779
+ if (mod.menuCustom?.auth) customMenus.push(...mod.menuCustom.auth);
780
+ setMenuCustom(customMenus.length > 0 ? customMenus : undefined);
781
+ })
782
+ .catch(() => setMenuCustom(undefined))
783
+ .finally(() => {
784
+ loadedCustom = true;
785
+ if (loadedIgnored && loadedCustom) setIsLoading(false);
786
+ });
787
+ }, []);
730
788
 
731
789
  const handleLogout = async () => {
732
790
  await supabaseBrowserClient.auth.signOut();
@@ -749,6 +807,9 @@ export function AppHeader() {
749
807
  onMarkAsRead={markAsRead}
750
808
  onMarkAllAsRead={markAllAsRead}
751
809
  onDeleteNotification={deleteNotification}
810
+ {...(menuIgnored ? { menuIgnored } : {})}
811
+ {...(menuCustom ? { menuCustom } : {})}
812
+ {...{ isLoadingMenus: isLoading }}
752
813
  />
753
814
  );
754
815
  }
@@ -826,7 +887,58 @@ async function createConfigFiles(targetDir, force, useHeroUI, projectName) {
826
887
  const middlewarePath = path.join(targetDir, "middleware.ts");
827
888
  if (!fs.existsSync(middlewarePath) || force) {
828
889
  const middleware = `import { type NextRequest, NextResponse } from "next/server";
829
- import { createMiddlewareClient } from "@lastbrain/core/server";
890
+ import { createServerClient, type CookieOptions } from "@supabase/ssr";
891
+
892
+ /**
893
+ * Crée un client Supabase pour le middleware
894
+ */
895
+ function createMiddlewareClient(request: NextRequest) {
896
+ let response = NextResponse.next({
897
+ request: {
898
+ headers: request.headers,
899
+ },
900
+ });
901
+
902
+ const supabase = createServerClient(
903
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
904
+ process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
905
+ {
906
+ cookies: {
907
+ get(name: string) {
908
+ return request.cookies.get(name)?.value;
909
+ },
910
+ set(name: string, value: string, options: CookieOptions) {
911
+ request.cookies.set({
912
+ name,
913
+ value,
914
+ ...options,
915
+ });
916
+ response = NextResponse.next({
917
+ request: {
918
+ headers: request.headers,
919
+ },
920
+ });
921
+ response.cookies.set({
922
+ name,
923
+ value,
924
+ ...options,
925
+ });
926
+ },
927
+ remove(name: string, options: CookieOptions) {
928
+ request.cookies.delete(name);
929
+ response = NextResponse.next({
930
+ request: {
931
+ headers: request.headers,
932
+ },
933
+ });
934
+ response.cookies.delete(name);
935
+ },
936
+ },
937
+ }
938
+ );
939
+
940
+ return { supabase, response };
941
+ }
830
942
 
831
943
  export async function middleware(request: NextRequest) {
832
944
  const { pathname } = request.nextUrl;
@@ -969,9 +1081,9 @@ export const config = {
969
1081
  const nextConfig = `/** @type {import('next').NextConfig} */
970
1082
  const nextConfig = {
971
1083
  reactStrictMode: true,
972
- devIndicators: {
1084
+ devIndicators: {
973
1085
  position: 'bottom-right',
974
- },
1086
+ }
975
1087
  };
976
1088
 
977
1089
  export default nextConfig;
@@ -984,7 +1096,7 @@ export default nextConfig;
984
1096
  if (!fs.existsSync(tailwindConfigPath) || force) {
985
1097
  let tailwindConfig = "";
986
1098
  if (useHeroUI) {
987
- // Configuration avec HeroUI
1099
+ // Configuration avec HeroUI - complète avec thèmes
988
1100
  tailwindConfig = `import { heroui } from "@heroui/theme";
989
1101
 
990
1102
  /** @type {import('tailwindcss').Config} */
@@ -996,8 +1108,195 @@ const config = {
996
1108
  "./node_modules/@heroui/theme/dist/**/*.{js,mjs}",
997
1109
  ],
998
1110
  darkMode: "class",
999
- plugins: [heroui()],
1000
- }
1111
+ plugins: [
1112
+ heroui({
1113
+ themes: {
1114
+ light: {
1115
+ colors: {
1116
+ default: {
1117
+ 950: "#0d0d0e",
1118
+ 900: "#19191c",
1119
+ 800: "#26262a",
1120
+ 700: "#323238",
1121
+ 600: "#3f3f46",
1122
+ 500: "#65656b",
1123
+ 400: "#8c8c90",
1124
+ 300: "#b2b2b5",
1125
+ 200: "#d9d9da",
1126
+ 100: "#ffffff",
1127
+ foreground: "#000000",
1128
+ DEFAULT: "#d4d4d8",
1129
+ },
1130
+ primary: {
1131
+ 50: "#eef2ff",
1132
+ 100: "#e0e7ff",
1133
+ 200: "#c7d2fe",
1134
+ 300: "#a5b4fc",
1135
+ 400: "#818cf8",
1136
+ 500: "#6366f1",
1137
+ 600: "#4f46e5",
1138
+ 700: "#4338ca",
1139
+ 800: "#3730a3",
1140
+ 900: "#312e81",
1141
+ foreground: "#ffffff",
1142
+ DEFAULT: "#6366f1",
1143
+ },
1144
+ secondary: {
1145
+ 50: "#f5e8ff",
1146
+ 100: "#e8ccff",
1147
+ 200: "#d7a6ff",
1148
+ 300: "#c57fff",
1149
+ 400: "#b359ff",
1150
+ 500: "#9b37ff",
1151
+ 600: "#7d1fcc",
1152
+ 700: "#5f1799",
1153
+ 800: "#410f66",
1154
+ 900: "#240833",
1155
+ foreground: "#ffffff",
1156
+ DEFAULT: "#9b37ff",
1157
+ },
1158
+ success: {
1159
+ 50: "#e7fff7",
1160
+ 100: "#c3ffec",
1161
+ 200: "#9affdf",
1162
+ 300: "#70ffd2",
1163
+ 400: "#4bffca",
1164
+ 500: "#22e6b0",
1165
+ 600: "#18b38a",
1166
+ 700: "#108066",
1167
+ 800: "#074d40",
1168
+ 900: "#012b22",
1169
+ foreground: "#000",
1170
+ DEFAULT: "#22e6b0",
1171
+ },
1172
+ warning: {
1173
+ 50: "#fff8e1",
1174
+ 100: "#ffecb3",
1175
+ 200: "#ffe082",
1176
+ 300: "#ffd54f",
1177
+ 400: "#ffca28",
1178
+ 500: "#ffc107",
1179
+ 600: "#ffb300",
1180
+ 700: "#ffa000",
1181
+ 800: "#ff8f00",
1182
+ 900: "#ff6f00",
1183
+ foreground: "#000",
1184
+ DEFAULT: "#ffca28",
1185
+ },
1186
+ danger: {
1187
+ 50: "#ffe6e9",
1188
+ 100: "#ffbac1",
1189
+ 200: "#ff8f99",
1190
+ 300: "#ff6471",
1191
+ 400: "#ff3949",
1192
+ 500: "#ff112a",
1193
+ 600: "#d80c22",
1194
+ 700: "#b1081b",
1195
+ 800: "#890514",
1196
+ 900: "#62020d",
1197
+ foreground: "#fff",
1198
+ DEFAULT: "#ff112a",
1199
+ },
1200
+ background: "#f7f8fc",
1201
+ foreground: "#0e0e10",
1202
+ content1: "#ffffff",
1203
+ },
1204
+ },
1205
+ dark: {
1206
+ colors: {
1207
+ default: {
1208
+ 50: "#1a1c1f",
1209
+ 100: "#232529",
1210
+ 200: "#2c2f34",
1211
+ 300: "#363940",
1212
+ 400: "#40444d",
1213
+ 500: "#4b4f59",
1214
+ 600: "#6c707b",
1215
+ 700: "#8d919b",
1216
+ 800: "#afb2bb",
1217
+ 900: "#d1d3d9",
1218
+ foreground: "#ffffff",
1219
+ DEFAULT: "#363940",
1220
+ },
1221
+ primary: {
1222
+ 50: "#312e81",
1223
+ 100: "#3730a3",
1224
+ 200: "#4338ca",
1225
+ 300: "#4f46e5",
1226
+ 400: "#6366f1",
1227
+ 500: "#818cf8",
1228
+ 600: "#a5b4fc",
1229
+ 700: "#c7d2fe",
1230
+ 800: "#e0e7ff",
1231
+ 900: "#eef2ff",
1232
+ foreground: "#ffffff",
1233
+ DEFAULT: "#6366f1",
1234
+ },
1235
+ secondary: {
1236
+ 50: "#240833",
1237
+ 100: "#410f66",
1238
+ 200: "#5f1799",
1239
+ 300: "#7d1fcc",
1240
+ 400: "#9b37ff",
1241
+ 500: "#b359ff",
1242
+ 600: "#c57fff",
1243
+ 700: "#d7a6ff",
1244
+ 800: "#e8ccff",
1245
+ 900: "#f5e8ff",
1246
+ foreground: "#ffffff",
1247
+ DEFAULT: "#9b37ff",
1248
+ },
1249
+ success: {
1250
+ 50: "#012b22",
1251
+ 100: "#074d40",
1252
+ 200: "#108066",
1253
+ 300: "#18b38a",
1254
+ 400: "#22e6b0",
1255
+ 500: "#4bffca",
1256
+ 600: "#70ffd2",
1257
+ 700: "#9affdf",
1258
+ 800: "#c3ffec",
1259
+ 900: "#e7fff7",
1260
+ foreground: "#0e0e0e",
1261
+ DEFAULT: "#22e6b0",
1262
+ },
1263
+ warning: {
1264
+ 50: "#3a2c00",
1265
+ 100: "#5e4700",
1266
+ 200: "#836300",
1267
+ 300: "#a77e00",
1268
+ 400: "#cc9900",
1269
+ 500: "#ffc107",
1270
+ 600: "#ffd54f",
1271
+ 700: "#ffe082",
1272
+ 800: "#ffecb3",
1273
+ 900: "#fff8e1",
1274
+ foreground: "#000",
1275
+ DEFAULT: "#ffc107",
1276
+ },
1277
+ danger: {
1278
+ 50: "#4a000a",
1279
+ 100: "#6e000f",
1280
+ 200: "#920014",
1281
+ 300: "#b60019",
1282
+ 400: "#da001f",
1283
+ 500: "#ff112a",
1284
+ 600: "#ff3949",
1285
+ 700: "#ff6471",
1286
+ 800: "#ff8f99",
1287
+ 900: "#ffbac1",
1288
+ foreground: "#ffffff",
1289
+ DEFAULT: "#ff112a",
1290
+ },
1291
+ background: "#0f1114",
1292
+ foreground: "#f8f8f8",
1293
+ content1: "#15181d",
1294
+ },
1295
+ },
1296
+ },
1297
+ }),
1298
+ ],
1299
+ };
1001
1300
 
1002
1301
  export default config;
1003
1302
  `;
@@ -1054,8 +1353,51 @@ export default config;
1054
1353
  // tsconfig.json
1055
1354
  const tsconfigPath = path.join(targetDir, "tsconfig.json");
1056
1355
  if (!fs.existsSync(tsconfigPath) || force) {
1356
+ // Détecter si le projet cible est dans un monorepo
1357
+ const targetIsInMonorepo = fs.existsSync(path.join(targetDir, "../../../packages/core/package.json")) ||
1358
+ fs.existsSync(path.join(targetDir, "../../packages/core/package.json"));
1359
+ // Générer les chemins en fonction du contexte
1360
+ const paths = {
1361
+ "@/*": ["./*"],
1362
+ };
1363
+ if (targetIsInMonorepo) {
1364
+ // En monorepo, pointer sur les sources locales
1365
+ paths["@lastbrain/ui"] = ["../../packages/ui/src/index.ts"];
1366
+ paths["@lastbrain/ui/*"] = ["../../packages/ui/src/*"];
1367
+ paths["@lastbrain/core"] = ["../../packages/core/src/index.ts"];
1368
+ paths["@lastbrain/core/*"] = ["../../packages/core/src/*"];
1369
+ paths["@lastbrain/app"] = ["../../packages/app/src/index.ts"];
1370
+ paths["@lastbrain/app/*"] = ["../../packages/app/src/*"];
1371
+ paths["@lastbrain/module-auth"] = [
1372
+ "../../packages/module-auth/src/index.ts",
1373
+ ];
1374
+ paths["@lastbrain/module-auth/*"] = ["../../packages/module-auth/src/*"];
1375
+ paths["@lastbrain/module-ai"] = ["../../packages/module-ai/src/index.ts"];
1376
+ paths["@lastbrain/module-ai/*"] = ["../../packages/module-ai/src/*"];
1377
+ paths["@lastbrain/module-legal"] = [
1378
+ "../../packages/module-legal/src/index.ts",
1379
+ ];
1380
+ paths["@lastbrain/module-legal/*"] = [
1381
+ "../../packages/module-legal/src/*",
1382
+ ];
1383
+ paths["@lastbrain/module-project-board"] = [
1384
+ "../../packages/module-project-board/src/index.ts",
1385
+ ];
1386
+ paths["@lastbrain/module-project-board/*"] = [
1387
+ "../../packages/module-project-board/src/*",
1388
+ ];
1389
+ paths["@lastbrain/module-tasks"] = [
1390
+ "../../packages/module-tasks/src/index.ts",
1391
+ ];
1392
+ paths["@lastbrain/module-tasks/*"] = [
1393
+ "../../packages/module-tasks/src/*",
1394
+ ];
1395
+ }
1396
+ else {
1397
+ // Hors monorepo (npm install), ne pas utiliser de paths aliases
1398
+ delete paths["@/*"];
1399
+ }
1057
1400
  const tsconfig = {
1058
- extends: "../../tsconfig.base.json",
1059
1401
  compilerOptions: {
1060
1402
  target: "ES2020",
1061
1403
  lib: ["ES2020", "DOM", "DOM.Iterable"],
@@ -1072,14 +1414,16 @@ export default config;
1072
1414
  incremental: true,
1073
1415
  isolatedModules: true,
1074
1416
  plugins: [{ name: "next" }],
1075
- paths: {
1076
- "@/*": ["./*"],
1077
- },
1417
+ paths,
1078
1418
  types: [],
1079
1419
  },
1080
1420
  include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
1081
1421
  exclude: ["node_modules", "dist", ".next", "out"],
1082
1422
  };
1423
+ // Ajouter extends seulement en monorepo
1424
+ if (targetIsInMonorepo) {
1425
+ tsconfig.extends = "../../tsconfig.base.json";
1426
+ }
1083
1427
  await fs.writeJson(tsconfigPath, tsconfig, { spaces: 2 });
1084
1428
  console.log(chalk.green("✓ tsconfig.json créé"));
1085
1429
  }
@@ -1108,6 +1452,67 @@ export const menuConfig: MenuConfig = {
1108
1452
  await fs.writeFile(menuConfigPath, menuConfig);
1109
1453
  console.log(chalk.green("✓ config/menu.ts créé"));
1110
1454
  }
1455
+ // config/menu-ignored.ts - Optional file to hide menus and block routes
1456
+ const menuIgnoredPath = path.join(configDir, "menu-ignored.ts");
1457
+ if (!fs.existsSync(menuIgnoredPath) || force) {
1458
+ const menuIgnored = `import type { MenuIgnored } from "@lastbrain/app";
1459
+
1460
+ /**
1461
+ * Menu items to hide and routes to block
1462
+ * This file is optional - if it doesn't exist, all menus are shown
1463
+ *
1464
+ * Example:
1465
+ * export const menuIgnored: MenuIgnored = {
1466
+ * public: [
1467
+ * { title: "Documentation", path: "/docs" }
1468
+ * ],
1469
+ * auth: [
1470
+ * { title: "Profile", path: "/auth/profile" }
1471
+ * ]
1472
+ * };
1473
+ */
1474
+
1475
+ export const menuIgnored: MenuIgnored = {
1476
+ public: [],
1477
+ auth: [],
1478
+ };
1479
+ `;
1480
+ await fs.writeFile(menuIgnoredPath, menuIgnored);
1481
+ console.log(chalk.green("✓ config/menu-ignored.ts créé"));
1482
+ }
1483
+ // config/menu-custom.ts - Optional file to add custom menus
1484
+ const menuCustomPath = path.join(configDir, "menu-custom.ts");
1485
+ if (!fs.existsSync(menuCustomPath) || force) {
1486
+ const menuCustom = `import type { MenuCustom } from "@lastbrain/app";
1487
+
1488
+ /**
1489
+ * Custom menu items to add without creating a module
1490
+ * This file is optional - if it doesn't exist, no custom menus are added
1491
+ *
1492
+ * Example:
1493
+ * export const menuCustom: MenuCustom = {
1494
+ * public: [
1495
+ * { label: "Blog", href: "/blog" },
1496
+ * { label: "Pricing", href: "/pricing" }
1497
+ * ],
1498
+ * auth: [
1499
+ * { label: "Invoices", href: "/auth/invoices" }
1500
+ * ],
1501
+ * admin: [
1502
+ * { label: "Reports", href: "/admin/reports" }
1503
+ * ]
1504
+ * };
1505
+ */
1506
+
1507
+ export const menuCustom: MenuCustom = {
1508
+ public: [],
1509
+ auth: [],
1510
+ admin: [],
1511
+ };
1512
+ `;
1513
+ await fs.writeFile(menuCustomPath, menuCustom);
1514
+ console.log(chalk.green("✓ config/menu-custom.ts créé"));
1515
+ }
1111
1516
  // config/footer.ts
1112
1517
  const footerConfigPath = path.join(configDir, "footer.ts");
1113
1518
  if (!fs.existsSync(footerConfigPath) || force) {
@@ -1127,6 +1532,28 @@ export const footerConfig: FooterConfig = {
1127
1532
  await fs.writeFile(footerConfigPath, footerConfig);
1128
1533
  console.log(chalk.green("✓ config/footer.ts créé"));
1129
1534
  }
1535
+ // config/user-tabs.ts - User detail page tabs configuration
1536
+ const userTabsConfigPath = path.join(configDir, "user-tabs.ts");
1537
+ if (!fs.existsSync(userTabsConfigPath) || force) {
1538
+ const userTabsConfig = `// User tabs configuration
1539
+ // This file is generated and can be regenerated by running: pnpm build:modules
1540
+ "use client";
1541
+
1542
+ import type React from "react";
1543
+
1544
+ export interface ModuleUserTab {
1545
+ id: string;
1546
+ label: string;
1547
+ component: React.ComponentType<{ userId: string }>;
1548
+ }
1549
+
1550
+ // Module user tabs - dynamically imported from active modules
1551
+ // To add tabs from modules, import them here and add to the array below
1552
+ export const moduleUserTabs: ModuleUserTab[] = [];
1553
+ `;
1554
+ await fs.writeFile(userTabsConfigPath, userTabsConfig);
1555
+ console.log(chalk.green("✓ config/user-tabs.ts créé"));
1556
+ }
1130
1557
  // Créer les hooks
1131
1558
  await createHooksDirectory(targetDir, force);
1132
1559
  }
@@ -1286,16 +1713,7 @@ tmp/
1286
1713
  coverage/
1287
1714
  *.lcov
1288
1715
 
1289
- # Generated by module-build
1290
- app/navigation.generated.ts
1291
- app/routes.generated.ts
1292
- app/menu.generated.ts
1293
1716
 
1294
- # Generated app-shell overrides
1295
- app/(public)/
1296
- app/(auth)/
1297
- app/(admin)/
1298
- app/layout.tsx
1299
1717
  `;
1300
1718
  await fs.writeFile(gitignorePath, gitignoreContent);
1301
1719
  }
@@ -1357,6 +1775,27 @@ OPENAI_API_KEY=sk-fake-openai-key-for-development-replace-with-real-key
1357
1775
  console.log(chalk.green("✓ .env.local créé"));
1358
1776
  }
1359
1777
  }
1778
+ async function createEnvProd(targetDir, force) {
1779
+ const envProdPath = path.join(targetDir, ".env.prod");
1780
+ if (!fs.existsSync(envProdPath) || force) {
1781
+ console.log(chalk.yellow("\n🔐 Création de .env.prod..."));
1782
+ const envContent = `# Production Environment Configuration
1783
+ # Copy your production values here
1784
+
1785
+ # Supabase Production
1786
+ NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
1787
+ NEXT_PUBLIC_SUPABASE_ANON_KEY=your-prod-anon-key
1788
+ SUPABASE_SERVICE_ROLE_KEY=your-prod-service-role-key
1789
+
1790
+ # OpenAI Production
1791
+ OPENAI_API_KEY=sk-proj-your-prod-api-key
1792
+
1793
+ # Note: Update these values with your actual production credentials
1794
+ `;
1795
+ await fs.writeFile(envProdPath, envContent);
1796
+ console.log(chalk.green("✓ .env.prod créé"));
1797
+ }
1798
+ }
1360
1799
  async function createSupabaseStructure(targetDir, force) {
1361
1800
  console.log(chalk.yellow("\n🗄️ Création de la structure Supabase..."));
1362
1801
  const supabaseDir = path.join(targetDir, "supabase");
@@ -1377,8 +1816,8 @@ async function createSupabaseStructure(targetDir, force) {
1377
1816
  console.log(chalk.green("✓ supabase/migrations/20201010100000_app_base.sql créé (vide)"));
1378
1817
  }
1379
1818
  }
1380
- catch (error) {
1381
- console.error(chalk.red("✗ Erreur lors de la création de la migration:"), error);
1819
+ catch (_error) {
1820
+ console.error(chalk.red("✗ Erreur lors de la création de la migration:"), _error);
1382
1821
  }
1383
1822
  }
1384
1823
  else {
@@ -1392,22 +1831,21 @@ async function addScriptsToPackageJson(targetDir) {
1392
1831
  // Détecter si le projet cible est dans un workspace
1393
1832
  const targetIsInMonorepo = fs.existsSync(path.join(targetDir, "../../../packages/core/package.json")) ||
1394
1833
  fs.existsSync(path.join(targetDir, "../../packages/core/package.json"));
1395
- let scriptsPrefix = "lastbrain";
1396
- if (!targetIsInMonorepo) {
1397
- // Hors monorepo, utiliser le chemin direct vers le CLI
1398
- scriptsPrefix = "node node_modules/@lastbrain/app/dist/cli.js";
1399
- }
1834
+ // Utiliser le CLI depuis le monorepo si présent, sinon depuis node_modules
1835
+ const scriptsPrefix = targetIsInMonorepo
1836
+ ? "node ../../packages/app/dist/cli.js"
1837
+ : "node node_modules/@lastbrain/app/dist/cli.js";
1400
1838
  const scripts = {
1401
1839
  predev: targetIsInMonorepo
1402
- ? "pnpm --filter @lastbrain/core build && pnpm --filter @lastbrain/ui build && pnpm --filter @lastbrain/module-auth build && pnpm --filter @lastbrain/module-ai build"
1403
- : "echo 'No prebuild needed outside monorepo'",
1840
+ ? "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"
1841
+ : "echo 'No prebuild needed'",
1404
1842
  dev: "next dev",
1843
+ "dev:local": "env-cmd -f .env.local next dev",
1844
+ "dev:prod": "env-cmd -f .env.prod next dev",
1405
1845
  build: "next build",
1406
1846
  start: "next start",
1407
1847
  lint: "next lint",
1408
- lastbrain: targetIsInMonorepo
1409
- ? "lastbrain"
1410
- : "node node_modules/@lastbrain/app/dist/cli.js",
1848
+ lastbrain: scriptsPrefix,
1411
1849
  "build:modules": `${scriptsPrefix} module:build`,
1412
1850
  "db:migrations:sync": `${scriptsPrefix} db:migrations:sync`,
1413
1851
  "db:init": `${scriptsPrefix} db:init`,