Files
AuditShield/frontend/components/layout/sidebar.tsx
Vincent 0fe1a1b751 feat: Phase 1 — socle backend FastAPI + frontend Next.js
Backend (FastAPI + SQLAlchemy):
- Modèles : User, Client, Audit, Cible, Vulnérabilité, Action
- Auth JWT (register/login/me) avec bcrypt
- Routes CRUD complets : clients, audits, cibles, vulnérabilités, actions
- Schémas Pydantic v2, migrations Alembic configurées
- Rate limiting (slowapi), CORS, structure scanners/reports pour phase 2

Frontend (Next.js 14 App Router):
- shadcn/ui : Button, Input, Card, Badge, Label
- Page login avec gestion token JWT
- Dashboard avec stats temps réel
- Pages Clients (grille) et Audits (liste) avec recherche
- Layout avec sidebar navigation + protection auth
- Dockerfiles multi-stage (backend + frontend standalone)

Infrastructure:
- docker-compose.yml : postgres, redis, backend, frontend
- docker-compose.prod.yml avec labels Traefik
- .env.example complet
- .gitignore mis à jour

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 17:16:12 +01:00

65 lines
2.0 KiB
TypeScript

"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { Shield, Users, ClipboardList, LayoutDashboard, LogOut } from "lucide-react";
import { cn } from "@/lib/utils";
import { removeToken } from "@/lib/auth";
import { useRouter } from "next/navigation";
const navItems = [
{ href: "/dashboard", label: "Tableau de bord", icon: LayoutDashboard },
{ href: "/clients", label: "Clients", icon: Users },
{ href: "/audits", label: "Audits", icon: ClipboardList },
];
export function Sidebar() {
const pathname = usePathname();
const router = useRouter();
function handleLogout() {
removeToken();
router.push("/login");
}
return (
<aside className="flex h-screen w-64 flex-col border-r bg-card">
{/* Logo */}
<div className="flex items-center gap-2 px-6 py-5 border-b">
<Shield className="h-7 w-7 text-primary" />
<span className="text-xl font-bold">AuditShield</span>
</div>
{/* Navigation */}
<nav className="flex-1 px-3 py-4 space-y-1">
{navItems.map(({ href, label, icon: Icon }) => (
<Link
key={href}
href={href}
className={cn(
"flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors",
pathname.startsWith(href)
? "bg-primary text-primary-foreground"
: "text-muted-foreground hover:bg-accent hover:text-accent-foreground"
)}
>
<Icon className="h-4 w-4" />
{label}
</Link>
))}
</nav>
{/* Logout */}
<div className="px-3 py-4 border-t">
<button
onClick={handleLogout}
className="flex w-full items-center gap-3 rounded-md px-3 py-2 text-sm font-medium text-muted-foreground hover:bg-accent hover:text-accent-foreground transition-colors"
>
<LogOut className="h-4 w-4" />
Déconnexion
</button>
</div>
</aside>
);
}