feat: add base44 entity schemas reference

feat: add issue template
feat: add labels.yml with platform:admin label
feat: add setup_admin_console.sh script and update Makefile

This commit introduces several new features and files to the
repository:

- Adds a reference document for Base44 entity schemas to
 ensure data integrity during the migration to the new
 GCP/Firebase backend.
- Adds an issue template to standardize issue reporting and
 ensure all necessary information is included.
- Adds a new label to `labels.yml` for tasks specific to the
 Admin Console web app.
- Adds a shell script to automate the setup of the Admin
 Console web application, including scaffolding,
 dependency installation, and configuration. Also updates
 the Makefile to include new targets for managing the Admin
 Console application.
- Adds issues to create markdown file.
This commit is contained in:
bwnyasse
2025-11-14 18:50:24 -05:00
parent 07626dd340
commit edf3dc4042
5 changed files with 655 additions and 0 deletions

View File

@@ -0,0 +1,80 @@
# Base44 Entity Schemas Reference
This document serves as a developer reference for the original data schemas from the Base44 backend. It is used to ensure feature parity and data integrity during the migration to the new GCP/Firebase backend.
---
## User Schema
```
role (text, required)
- The role of the user in the app
- Options: admin, user
email (text, required)
- The email of the user
full_name (text, required)
- Full name of the user
user_role (text)
- User's role in the system
- Options: admin, procurement, operator, sector, client, vendor, workforce
company_name (text)
- Company or organization name
profile_picture (text)
- URL to profile picture
phone (text)
- Phone number
address (text)
- Address
preferred_vendor_id (text)
- ID of the client's preferred/default vendor
preferred_vendor_name (text)
- Name of the client's preferred vendor
backup_vendor_ids (array)
- List of backup vendor IDs
dashboard_layout (object)
- User's customized dashboard layout preferences (legacy, kept for backward compatibility)
- widgets (array): Ordered list of visible widgets
- hidden_widgets (array): List of hidden widgets
- layout_version (text): Layout version for migration
dashboard_layout_client (object)
- Client dashboard layout
- widgets (array)
- hidden_widgets (array)
- layout_version (text)
dashboard_layout_vendor (object)
- Vendor dashboard layout
- widgets (array)
- hidden_widgets (array)
- layout_version (text)
dashboard_layout_operator (object)
- Operator dashboard layout
- widgets (array)
- hidden_widgets (array)
- layout_version (text)
dashboard_layout_workforce (object)
- Workforce dashboard layout
- widgets (array)
- hidden_widgets (array)
- layout_version (text)
preferences (object)
- User preferences and settings
- theme (text): Default: "light", Options: light, dark
- notifications_enabled (boolean): Default: true
- email_notifications (boolean): Default: true
```

200
docs/issues/template.md Normal file
View File

@@ -0,0 +1,200 @@
# [Auth] Implement Firebase Authentication via krowSDK Facade
Labels: feature, infra, platform:web, platform:backend, priority:high, sred-eligible
Milestone: Foundation & Dev Environment Setup
### 🎯 Objective
Replace the Base44 authentication client with a new internal SDK module, `krowSDK.auth`, backed by Firebase Authentication. This foundational task will unblock all future backend development and align the web application with the new GCP-based architecture.
### 🔬 SR&ED Justification
- **Technological Uncertainty:** What is the optimal way to create a seamless abstraction layer (`krowSDK`) that perfectly mimics the existing `base44` SDK's interface to minimize frontend refactoring, while integrating a completely different authentication provider (Firebase Auth)? A key uncertainty is how this facade will handle the significant differences in user session management and data retrieval (e.g., custom user fields like `user_role` which are not native to the Firebase Auth user object) between the two systems.
- **Systematic Investigation:** We will conduct experimental development to build a `krowSDK.auth` module. This involves systematically mapping each `base44.auth` method (`me`, `logout`, `isAuthenticated`) to its Firebase Auth equivalent. We will investigate and prototype a solution for fetching supplementary user data (like `user_role`) from our Firestore database and merging it with the core Firebase Auth user object. This will establish a clean, reusable, and scalable architectural pattern for all future SDK modules.
### Details
This task is the most critical prerequisite for migrating our backend. As defined in the `03-backend-api-specification.md`, every request to our new Data Connect and Cloud Functions API will require a `Bearer <Firebase-Auth-Token>`. Without this, no backend work can proceed.
#### The Strategy: A Facade SDK (`krowSDK`)
Instead of replacing `base44` calls with Firebase calls directly throughout the codebase, we will create an abstraction layer, or "Facade". This approach has three major benefits:
1. **Simplified Migration:** The new `krowSDK.auth` will expose the *exact same methods* as the old `base44.auth`. This means we can swap out the authentication logic with minimal changes to the UI components, drastically reducing the scope of refactoring.
2. **High Maintainability:** All authentication logic will be centralized in one place. If we ever need to change providers again, we only modify the SDK, not the entire application.
3. **Clear Separation of Concerns:** The UI components remain agnostic about the authentication provider. They just need to call `krowSDK.auth.me()`, not worry about the underlying implementation details.
#### Implementation Plan
The developer should create two new files:
**1. Firebase Configuration (`frontend-web/src/firebase/config.js`)**
This file will initialize the Firebase app and export the necessary services. It's crucial to use environment variables for the configuration keys to keep them secure and environment-specific.
```javascript
// frontend-web/src/firebase/config.js
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
import { getFirestore } from "firebase/firestore";
// Your web app's Firebase configuration
// IMPORTANT: Use environment variables for these values
const firebaseConfig = {
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
appId: import.meta.env.VITE_FIREBASE_APP_ID
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
// Export Firebase services
export const auth = getAuth(app);
export const db = getFirestore(app);
export default app;
```
**2. Krow SDK (`frontend-web/src/lib/krowSDK.js`)**
This is the core of the task. This file will implement the facade, importing the Firebase `auth` service and recreating the `base44.auth` interface.
```javascript
// frontend-web/src/lib/krowSDK.js
import { auth, db } from '../firebase/config';
import {
onAuthStateChanged,
signOut,
updateProfile,
// Import other necessary auth functions like signInWithEmailAndPassword, createUserWithEmailAndPassword, etc.
} from "firebase/auth";
import { doc, getDoc } from "firebase/firestore";
/**
* A promise-based wrapper for onAuthStateChanged to check the current auth state.
* @returns {Promise<boolean>} - A promise that resolves to true if authenticated, false otherwise.
*/
const isAuthenticated = () => {
return new Promise((resolve) => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
unsubscribe();
resolve(!!user);
});
});
};
/**
* Fetches the current authenticated user's profile.
* This function mimics `base44.auth.me()` by combining the Firebase Auth user
* with custom data from our Firestore database (e.g., user_role).
* @returns {Promise<object|null>} - A promise that resolves with the user object or null.
*/
const me = () => {
return new Promise((resolve, reject) => {
const unsubscribe = onAuthStateChanged(auth, async (user) => {
unsubscribe();
if (user) {
try {
// 1. Get the core user from Firebase Auth
const { uid, email, displayName } = user;
const baseProfile = {
id: uid,
email: email,
full_name: displayName,
};
// 2. Get custom fields from Firestore
// We assume a 'users' collection where the document ID is the user's UID.
const userDocRef = doc(db, "users", uid);
const userDoc = await getDoc(userDocRef);
if (userDoc.exists()) {
const customData = userDoc.data();
// 3. Merge the two data sources
resolve({
...baseProfile,
user_role: customData.user_role, // Example custom field
// ... other custom fields from Firestore
});
} else {
// User exists in Auth but not in Firestore. This can happen during sign-up.
// Resolve with base profile; the app should handle creating the Firestore doc.
resolve(baseProfile);
}
} catch (error) {
console.error("Error fetching user profile from Firestore:", error);
reject(error);
}
} else {
// No user is signed in.
resolve(null);
}
});
});
};
/**
* Updates the current user's profile.
* This mimics `base44.auth.updateMe()`.
* @param {object} profileData - Data to update, e.g., { full_name: "New Name" }.
*/
const updateMe = async (profileData) => {
if (auth.currentUser) {
// Firebase Auth's updateProfile only supports displayName and photoURL.
if (profileData.full_name) {
await updateProfile(auth.currentUser, {
displayName: profileData.full_name,
});
}
// For other custom fields, you would need to update the user's document in Firestore.
// const userDocRef = doc(db, "users", auth.currentUser.uid);
// await updateDoc(userDocRef, { custom_field: profileData.custom_field });
} else {
throw new Error("No authenticated user to update.");
}
};
/**
* Logs the user out and redirects them.
* @param {string} [redirectUrl='/'] - The URL to redirect to after logout.
*/
const logout = (redirectUrl = '/') => {
signOut(auth).then(() => {
// Redirect after sign-out.
window.location.href = redirectUrl;
}).catch((error) => {
console.error("Logout failed:", error);
});
};
// The krowSDK object that mimics the Base44 SDK structure
export const krowSDK = {
auth: {
isAuthenticated,
me,
updateMe,
logout,
// Note: redirectToLogin is not implemented as it's a concern of the routing library (e.g., React Router),
// which should protect routes and redirect based on the authentication state.
},
// Future modules will be added here, e.g., krowSDK.entities.Event
};
```
### ✅ Acceptance Criteria
- [ ] A `frontend-web/src/firebase/config.js` file is created, correctly initializing the Firebase app using environment variables.
- [ ] A `frontend-web/src/lib/krowSDK.js` file is created and implements the `krowSDK.auth` facade.
- [ ] The `krowSDK.auth` module exports `isAuthenticated`, `me`, `updateMe`, and `logout` functions with interfaces identical to their `base44.auth` counterparts.
- [ ] Key parts of the application (e.g., login pages, user profile components, auth checks) are refactored to import and use `krowSDK.auth` instead of `base44.auth`.
- [ ] A new user can sign up using a Firebase-powered form.
- [ ] An existing user can log in using a Firebase-powered form.
- [ ] The application UI correctly updates to reflect the user's authenticated state (e.g., showing user name, hiding login button).
- [ ] After logging in, the user's Firebase Auth ID Token can be retrieved and is ready to be sent in an `Authorization: Bearer` header for API calls.

View File

@@ -0,0 +1,110 @@
# [Admin] Scaffold the Admin Console Web Application
Labels: infra, platform:admin, priority:high, sred-eligible
Milestone: Phase 1: Foundation & Dev Environment Setup
### 🎯 Objective
Create the foundational scaffolding for a new, separate React application within the monorepo, which will serve as the Admin Console. This console will be the central hub for managing users, roles, and other system-level configurations.
### 🔬 SR&ED Justification
- **Technological Uncertainty:** What is the most efficient way to set up a second, independent React application within our existing Vite-based monorepo, ensuring that dependency management, build processes, and environment variable configurations are isolated from the main `frontend-web` app but still manageable from the root `Makefile`?
- **Systematic Investigation:** We will conduct experimental development to create a new `admin-web/` directory. We will test different Vite configurations to ensure it can run concurrently with the main app. We will also experiment with `npm` workspaces or similar solutions to optimize shared, non-UI dependencies and update the root `Makefile` to orchestrate this new application.
### Details
This is the first step in building our critical user management interface. The Admin Console will be a completely new application, not sharing any logic with the `krowSDK` facade. It will communicate directly with Firebase services.
### ✅ Acceptance Criteria
- [ ] A new directory `admin-web/` is created at the project root.
- [ ] A new React + Vite application is correctly scaffolded inside `admin-web/`.
- [ ] The new admin application can be started independently using `npm run dev` from within its directory.
- [ ] Firebase SDK is installed and a basic `firebase/config.js` is created for the admin app, using its own set of environment variables (`VITE_ADMIN_FIREBASE_*`).
- [ ] A basic, protected "AdminLayout" component is created that checks if a logged-in user has the `admin` role before rendering content.
- [ ] The root `Makefile` is updated with new targets (`make admin-install`, `make admin-dev`) to manage this new application.
---
# [Admin] Implement User Listing and Role Management
Labels: feature, platform:admin, priority:high, sred-eligible
Milestone: Phase 1: Foundation & Dev Environment Setup
### 🎯 Objective
Develop the core user management interface in the Admin Console, allowing administrators to view a list of all system users and modify their roles.
### 🔬 SR&ED Justification
- **Technological Uncertainty:** What is the most performant and secure way to query and display a potentially large list of users from Firestore in a React application, implementing real-time updates and secure role modification? Key uncertainties involve structuring Firestore security rules to ensure only admins can read the full user list and write role changes, and designing a robust UI component that prevents accidental, irreversible role changes.
- **Systematic Investigation:** We will experiment with different Firestore queries (`onSnapshot` for real-time vs. `getDocs` for static lists) to evaluate performance. We will prototype and test Firestore security rules extensively. We will also build a reusable and secure "RoleSelector" component that includes confirmation dialogs to prevent unintended administrative actions.
### Details
This feature is the primary function of the Admin Console MVP. It directly enables the unblocking of other teams by allowing admins to assign the correct roles (`client`, `vendor`, etc.) to newly registered users.
### ✅ Acceptance Criteria
- [ ] A new "Users" page is created in the Admin Console.
- [ ] The page fetches and displays a list of all users from the `users` collection in Firestore.
- [ ] The user list is displayed in a table showing at least `full_name`, `email`, and `user_role`.
- [ ] An administrator can change a user's `user_role` using a dropdown or select menu in the table.
- [ ] The role change is immediately reflected in Firestore upon selection.
- [ ] A confirmation modal is shown before the role change is finalized to prevent errors.
- [ ] Firestore security rules are implemented to ensure only authenticated users with `user_role: 'admin'` can read the `users` collection and write to the `user_role` field.
---
# [Backend] Implement User Invitation Cloud Function
Labels: feature, platform:backend, priority:high, sred-eligible
Milestone: Phase 1: Foundation & Dev Environment Setup
### 🎯 Objective
Create a secure, HTTP-triggered Cloud Function that handles the business logic for inviting new users to the platform.
### 🔬 SR&ED Justification
- **Technological Uncertainty:** What is the most secure and reliable method to generate a unique, single-use invitation token, associate it with an email and a specific role, and then securely verify this token upon user registration? The investigation will involve designing a data model for pending invitations in Firestore, implementing a secure token generation strategy (e.g., UUIDs), and creating a Cloud Function with robust input validation and IAM permissions to prevent unauthorized use.
- **Systematic Investigation:** We will experiment with different data structures in Firestore for storing pending invites (e.g., a top-level `invites` collection). We will develop and test an HTTP Cloud Function, ensuring it is protected by IAM and properly validates incoming requests (checking for admin privileges). We will also integrate an email sending service (e.g., SendGrid or Firebase's own Trigger Email extension) to dispatch the invitation emails.
### Details
This backend function is the engine of our invitation system. It will be called by the Admin Console and will be responsible for creating a pending invitation and sending an email to the invitee.
### ✅ Acceptance Criteria
- [ ] A new HTTP-triggered Cloud Function, `inviteUser`, is created in the `firebase/functions` directory.
- [ ] The function is protected and can only be called by authenticated users with an `admin` custom claim.
- [ ] The function accepts a request body containing `email` and `user_role`.
- [ ] Upon being called, it creates a new document in a `invites` collection in Firestore.
- [ ] The new document contains the invitee's email, the assigned role, a uniquely generated token, and an expiration date.
- [ ] The function sends an email to the provided address containing a unique registration link (e.g., `https://krow-workforce.com/register?invite_token=...`).
---
# [Admin] Implement User Invitation UI
Labels: feature, platform:admin, priority:high
Milestone: Phase 1: Foundation & Dev Environment Setup
### 🎯 Objective
Build the user interface within the Admin Console that allows administrators to invite new users to the platform.
### Details
This UI will serve as the frontend for the `inviteUser` Cloud Function. It provides a simple and intuitive way for admins to add new users without needing manual database intervention.
### ✅ Acceptance Criteria
- [ ] A new "Invite User" button or section is added to the "Users" page in the Admin Console.
- [ ] Clicking the button opens a modal or form with two fields: `Email Address` and `User Role`.
- [ ] The "User Role" field is a dropdown populated with the available roles (e.g., `client`, `vendor`, `procurement`).
- [ ] Submitting the form calls the `inviteUser` Cloud Function with the provided data.
- [ ] The UI provides clear feedback to the administrator on success or failure of the invitation.
- [ ] (Optional) A new section or page is created to display a list of pending invitations from the `invites` collection in Firestore.

View File

@@ -31,6 +31,9 @@
- name: "platform:backend"
description: "Tasks for Data Connect or Cloud Functions"
color: "5319e7"
- name: "platform:admin"
description: "Tasks specific to the Admin Console web app"
color: "5319e7"
# For Project Management
- name: "sred-eligible"

262
setup_admin_console.sh Normal file
View File

@@ -0,0 +1,262 @@
#!/bin/bash
# Script pour initialiser l'application Admin Console en 4 étapes.
# Exécutez ce script depuis la racine du projet.
# Assurez-vous d'avoir les permissions d'exécution : chmod +x setup_admin_console.sh
# --- CONFIGURATION ---
# Arrête le script si une commande échoue
set -e
# --- SCRIPT ---
echo "🚀 Démarrage de la configuration de l'Admin Console..."
# --- ÉTAPE 1: SCAFFOLDING DE L'APPLICATION ---
echo ""
echo "--- Étape 1: Scaffolding de l'application admin-web ---"
if [ -d "admin-web" ]; then
echo "⚠️ Le répertoire admin-web/ existe déjà. Le script va s'arrêter pour éviter d'écraser des données."
exit 1
fi
echo "==> Création d'un nouveau projet React + Vite dans admin-web/..."
npm create vite@latest admin-web -- --template react
echo "==> Installation des dépendances initiales..."
cd admin-web
npm install
cd ..
echo "✅ Étape 1 terminée."
# --- ÉTAPE 2: CONFIGURATION DU STYLE ET DES DÉPENDANCES ---
echo ""
echo "--- Étape 2: Configuration du style et des dépendances ---"
echo "==> Installation des dépendances pour Tailwind CSS..."
cd admin-web
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
echo "==> Copie des fichiers de configuration depuis frontend-web/..."
# Le -f force l'écrasement des fichiers générés par `tailwindcss init`
cp -f ../frontend-web/tailwind.config.js ./tailwind.config.js
cp -f ../frontend-web/postcss.config.js ./postcss.config.js
cp ../frontend-web/components.json ./components.json
cp ../frontend-web/jsconfig.json ./jsconfig.json
echo "==> Configuration de Vite pour les alias de chemin..."
# Crée un nouveau vite.config.js avec la configuration d'alias
cat <<EOF > ./vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path'
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
})
EOF
echo "==> Copie du fichier CSS de base..."
cp ../frontend-web/src/index.css ./src/index.css
echo "==> Installation des dépendances pour shadcn/ui..."
npm install class-variance-authority clsx tailwind-merge tailwindcss-animate lucide-react
cd ..
echo "✅ Étape 2 terminée."
# --- ÉTAPE 3: CRÉATION DE LA COQUILLE VISUELLE ---
echo ""
echo "--- Étape 3: Création de la coquille visuelle de l'application ---"
echo "==> Création des répertoires de base (pages, components)..."
mkdir -p admin-web/src/pages
mkdir -p admin-web/src/components/ui
mkdir -p admin-web/src/lib
echo "==> Copie de l'utilitaire shadcn/ui..."
cp frontend-web/src/lib/utils.js admin-web/src/lib/utils.js
echo "==> Création du fichier App.jsx avec le routing..."
cat <<EOF > admin-web/src/App.jsx
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Layout from '@/pages/Layout';
import Dashboard from '@/pages/Dashboard';
import UserManagement from '@/pages/UserManagement';
function App() {
return (
<Router>
<Layout>
<Routes>
<Route path="/" element={<Dashboard />} />
<Route path="/users" element={<UserManagement />} />
</Routes>
</Layout>
</Router>
);
}
export default App;
EOF
echo "==> Création du fichier de Layout (Layout.jsx)..."
cat <<EOF > admin-web/src/pages/Layout.jsx
import React from 'react';
import { Link, useLocation } from 'react-router-dom';
import { LayoutDashboard, Users, Settings } from 'lucide-react';
const navigation = [
{ name: 'Dashboard', href: '/', icon: LayoutDashboard },
{ name: 'User Management', href: '/users', icon: Users },
];
export default function Layout({ children }) {
const location = useLocation();
return (
<div className="min-h-screen flex">
<aside className="w-64 bg-slate-800 text-white flex flex-col">
<div className="p-4 border-b border-slate-700">
<h1 className="text-xl font-bold text-center">KROW ADMIN</h1>
</div>
<nav className="flex-1 p-4 space-y-2">
{navigation.map((item) => (
<Link
key={item.name}
to={item.href}
className={`flex items-center gap-3 px-3 py-2 rounded-md text-sm font-medium transition-colors ${
location.pathname === item.href
? 'bg-slate-900 text-white'
: 'text-slate-300 hover:bg-slate-700 hover:text-white'
}`}
>
<item.icon className="w-5 h-5" />
{item.name}
</Link>
))}
</nav>
</aside>
<main className="flex-1 bg-slate-100 p-8 overflow-auto">
{children}
</main>
</div>
);
}
EOF
echo "==> Création de la page Dashboard (Dashboard.jsx)..."
cat <<EOF > admin-web/src/pages/Dashboard.jsx
import React from 'react';
export default function Dashboard() {
return (
<div>
<h1 className="text-3xl font-bold text-slate-800">Admin Dashboard</h1>
<p className="text-slate-600 mt-2">Welcome to the Krow Admin Console.</p>
</div>
);
}
EOF
echo "==> Création de la page de gestion des utilisateurs (UserManagement.jsx)..."
cat <<EOF > admin-web/src/pages/UserManagement.jsx
import React from 'react';
// Note: Les composants Button, Card, etc. devront être ajoutés via shadcn-ui
export default function UserManagement() {
return (
<div>
<div className="flex items-center justify-between mb-6">
<h1 className="text-3xl font-bold text-slate-800">User Management</h1>
{/*
<Button>
<UserPlus className="w-4 h-4 mr-2" />
Invite User
</Button>
*/}
</div>
<div className="bg-white p-6 rounded-lg shadow-md">
<p>La table des utilisateurs apparaîtra ici.</p>
<p className="text-sm text-slate-500 mt-4">
Pour continuer, ajoutez les composants shadcn/ui nécessaires (table, button, etc.)
</p>
</div>
</div>
);
}
EOF
echo "==> Mise à jour de main.jsx pour inclure le Router..."
# Le App.jsx contient maintenant le Router, donc on met à jour main.jsx
cd admin-web
npm install react-router-dom
cat <<EOF > src/main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
EOF
cd ..
echo "✅ Étape 3 terminée."
# --- ÉTAPE 4: MISE À JOUR DU MAKEFILE ---
echo ""
echo "--- Étape 4: Mise à jour du Makefile racine ---"
echo "==> Ajout des nouvelles cibles au Makefile..."
cat <<EOF >> Makefile
# --- Admin Console ---
admin-install:
@echo "--> Installing admin console dependencies..."
@cd admin-web && npm install
admin-dev:
@echo "--> Starting admin console development server on http://localhost:5174 ..."
@cd admin-web && npm run dev -- --port 5174
admin-build:
@echo "--> Building admin console for production..."
@cd admin-web && VITE_APP_ENV=\$(ENV) npm run build
EOF
echo "✅ Étape 4 terminée."
# --- INSTRUCTIONS FINALES ---
echo ""
echo "🎉 --- Configuration terminée avec succès! --- 🎉"
echo ""
echo "Voici les prochaines étapes manuelles :"
echo ""
echo "1. Ajoutez les composants UI de base à votre nouvelle application :"
echo " cd admin-web"
echo " npx shadcn-ui@latest add button card table input label dialog select"
echo " cd .."
echo ""
echo "2. Mettez à jour la cible 'help' dans le Makefile pour inclure les nouvelles commandes :"
echo " - make admin-install"
echo " - make admin-dev"
echo " - make admin-build"
echo ""
echo "3. Lancez le serveur de développement de l'admin console avec :"
echo " make admin-dev"
echo ""
echo "L'application sera disponible sur http://localhost:5174"
echo ""