3.8 KiB
3.8 KiB
AGENTS.md — GestionDesCompetences
Project
React 19 SPA (skills management) built with Vite 8, JavaScript (not TypeScript), Tailwind CSS v4, shadcn/ui, Supabase backend, React Router v7.
Commands
npm run dev # Vite dev server with HMR
npm run build # Production build → dist/
npm run lint # ESLint (flat config)
npm run preview # Serve dist/ locally
npm run test # Vitest run (hooks tests)
npm run test:watch# Vitest watch mode
No typecheck script.
Architecture
- Entry:
src/main.jsx→ wrapped in<ThemeProvider>(next-themes) →src/App.jsx - Auth:
src/context/AuthContext.jsx— Supabase Auth +memberstable profile (role: admin/member) - Routing:
src/App.jsx— public routes/login,/register,/accept-invite; protected routes wrapped in<ProtectedRoute>; admin-only routes (/members,/skills) also wrapped in<AdminRoute>+<Suspense>(React.lazy code splitting) - Error handling:
<ErrorBoundary>wraps all protected routes - Pages:
src/pages/— Dashboard, Members, Skills, SkillMatrix, History, Profile - UI:
src/components/ui/— shadcn components (radix-nova style, JS, no TSX) - Supabase client:
src/lib/supabase.js— readsVITE_SUPABASE_URL/VITE_SUPABASE_ANON_KEYfrom env - Path alias:
@/*→src/*(configured in bothvite.config.jsandjsconfig.json)
Data Layer
Custom hooks in src/hooks/
| Hook | Returns | Notes |
|---|---|---|
useMembers() |
{ members, loading, refetch } |
Full-text search via GIN index |
useSkills() |
{ skills, loading, refetch } |
Includes category:category_id(name) join |
useCategories() |
{ categories, loading, refetch } |
Ordered by name |
useSkillLevels() |
{ levels, loading, refetch, updateLevel, getAverageSkillRating } |
levels is a {memberId-skillId → level} map. Has real-time subscription |
useHistory() |
{ history, loading, count, page, totalPages, filters, setFilter, nextPage, prevPage, refetch } |
Paginated (50/page), real-time on INSERT |
Data fetching patterns
- Hooks call Supabase directly (no additional API layer)
- No global state management (hooks + local state only)
- Real-time subscriptions via
supabase.channel()onskill_levelsandskill_history
Supabase
- DB schema + RLS policies in
supabase/migrations/001_init.sql - Tables:
categories,skills,members,level_descriptions,skill_levels,skill_history,invitations handle_new_user()trigger auto-creates amembersrow on auth signup- RLS: read-all for most tables, write restricted to admin role
- UPDATE policies include
WITH CHECKmatching theUSINGclause invitations_read_adminpolicy filtersexpires_at > now()- Full-text search enabled via GIN indexes on
skills.nameandmembers.full_name - Realtime publication enabled on
skill_levelsandskill_history .envpoints to a local Supabase instance (vm-docker5.home.arpa:8000) — this is committed but.envis gitignored; adjust for your environment
Docker
Multi-stage: node:20-alpine build → nginx:alpine serve.
Requires VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY as build args.
SPA routing handled by nginx try_files.
shadcn/ui
Config in components.json. Add components with:
npx shadcn@latest add <component>
Components land in src/components/ui/. Uses Lucide icons.
Conventions
- JavaScript only (
.jsx), no TypeScript - ESLint flat config (
eslint.config.js) — ignoresdist/ - Tailwind v4 via
@tailwindcss/viteplugin (notailwind.config.js) - French UI labels (application is in French)
- Dark mode support via
next-themeswith class strategy - Layout: Lucide icons, responsive sidebar (hamburger on mobile)
- CSV exports for Members and Matrix pages