Files
simone 23cb057f0b docs(07): phase 7 planning complete — 2 plans (schema migration + admin crud)
Wave 1: 07-01-PLAN.md — Unified services table (audit trail, backfill, validation)
Wave 2: 07-02-PLAN.md — Admin catalog CRUD rewire (preserve historical references)

Ready for execution: /gsd-execute-phase 7

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-11 06:17:29 +02:00

7.9 KiB

plan_id, phase, wave, title, type, depends_on, files_modified, requirements_addressed, autonomous, must_haves
plan_id phase wave title type depends_on files_modified requirements_addressed autonomous must_haves
06-01 6 1 Sidebar layout — AdminSidebar + AppShell + move client list to /admin/clients execute
src/app/admin/layout.tsx
src/components/admin/NavBar.tsx
src/app/admin/page.tsx
src/app/admin/clients/page.tsx
src/components/admin/AdminSidebar.tsx
UX-01
UX-03
true
truths artifacts key_links
AdminLayout uses a flex-row shell: sidebar left (fixed width) + main content right
NavBar.tsx is replaced by AdminSidebar.tsx — header nav no longer exists
AdminSidebar has links: Dashboard, Clienti, Progetti, Offerte, Forecast, Catalogo, Impostazioni + Logout at bottom
Active route is highlighted in the sidebar (usePathname)
Client list (previously at /admin) is now at /admin/clients with identical functionality
/admin page exists but shows a placeholder or redirects — replaced in 06-02 with real dashboard
path provides contains
src/components/admin/AdminSidebar.tsx Sidebar client component with navigation links and logout usePathname, signOut, all nav links
path provides contains
src/app/admin/layout.tsx AppShell layout: flex row, sidebar + main AdminSidebar, flex, min-h-screen
path provides contains
src/app/admin/clients/page.tsx Client list page moved from /admin getAllClientsWithPayments
from to via pattern
src/components/admin/AdminSidebar.tsx src/app/admin/layout.tsx import AdminSidebar
Replace the top header NavBar with a persistent left sidebar. Move the client list from /admin to /admin/clients. The /admin route will be a blank placeholder for now — the real dashboard comes in 06-02.

This is a pure layout + routing refactor. No data model changes. No new queries.

<execution_context> @/Users/simonecavalli/IAMCAVALLI/.claude/get-shit-done/workflows/execute-plan.md @/Users/simonecavalli/IAMCAVALLI/.claude/get-shit-done/templates/summary.md </execution_context>

@/Users/simonecavalli/IAMCAVALLI/.planning/ROADMAP.md @/Users/simonecavalli/IAMCAVALLI/.planning/STATE.md Task 1: Create AdminSidebar component src/components/admin/AdminSidebar.tsx

<read_first> - src/components/admin/NavBar.tsx — copy links and logout logic - src/app/admin/layout.tsx — understand current layout </read_first>

Create `src/components/admin/AdminSidebar.tsx` as a client component:
"use client";

import Link from "next/link";
import { usePathname } from "next/navigation";
import { signOut } from "next-auth/react";
import {
  LayoutDashboard,
  Users,
  FolderOpen,
  Tag,
  TrendingUp,
  BookOpen,
  Settings,
  LogOut,
} from "lucide-react";

const NAV_ITEMS = [
  { href: "/admin",           label: "Dashboard",    icon: LayoutDashboard, exact: true },
  { href: "/admin/clients",   label: "Clienti",      icon: Users },
  { href: "/admin/projects",  label: "Progetti",     icon: FolderOpen },
  { href: "/admin/offers",    label: "Offerte",      icon: Tag },
  { href: "/admin/forecast",  label: "Forecast",     icon: TrendingUp },
  { href: "/admin/catalog",   label: "Catalogo",     icon: BookOpen },
  { href: "/admin/impostazioni", label: "Impostazioni", icon: Settings },
];

export function AdminSidebar() {
  const pathname = usePathname();

  const isActive = (href: string, exact?: boolean) =>
    exact ? pathname === href : pathname === href || pathname.startsWith(href + "/");

  return (
    <aside className="w-56 shrink-0 min-h-screen bg-[#1A463C] flex flex-col">
      {/* Logo */}
      <div className="px-5 py-5 border-b border-white/10">
        <span className="font-bold text-white tracking-tight text-sm">iamcavalli</span>
      </div>

      {/* Nav links */}
      <nav className="flex-1 px-3 py-4 flex flex-col gap-0.5">
        {NAV_ITEMS.map(({ href, label, icon: Icon, exact }) => {
          const active = isActive(href, exact);
          return (
            <Link
              key={href}
              href={href}
              className={`flex items-center gap-3 px-3 py-2 rounded-md text-sm transition-colors ${
                active
                  ? "bg-white/15 text-white font-medium"
                  : "text-white/65 hover:text-white hover:bg-white/10"
              }`}
            >
              <Icon size={16} strokeWidth={1.8} />
              {label}
            </Link>
          );
        })}
      </nav>

      {/* Logout */}
      <div className="px-3 py-4 border-t border-white/10">
        <button
          onClick={() => signOut({ callbackUrl: "/admin/login" })}
          className="flex items-center gap-3 px-3 py-2 w-full rounded-md text-sm text-white/65 hover:text-white hover:bg-white/10 transition-colors"
        >
          <LogOut size={16} strokeWidth={1.8} />
          Esci
        </button>
      </div>
    </aside>
  );
}

Check that lucide-react is already a dependency (package.json). If not, note it as a deviation but do NOT install it — shadcn/ui already bundles it transitively in this project.

Task 2: Update AdminLayout to AppShell (sidebar + main) src/app/admin/layout.tsx Replace the current vertical layout (nav on top, max-w-5xl centered main) with a horizontal AppShell:
import { AdminSidebar } from "@/components/admin/AdminSidebar";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";

export default async function AdminLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const session = await getServerSession(authOptions);
  return (
    <div className="flex min-h-screen bg-gray-50">
      {session && <AdminSidebar />}
      <main className="flex-1 px-8 py-8 overflow-y-auto">
        {children}
      </main>
    </div>
  );
}

Remove the import of NavBar. The sidebar handles all navigation.

Task 3: Move client list to /admin/clients/page.tsx src/app/admin/clients/page.tsx, src/app/admin/page.tsx

<read_first> - src/app/admin/page.tsx — full content to copy - src/app/admin/clients/ — check if page.tsx already exists </read_first>

1. Copy the full content of `src/app/admin/page.tsx` to `src/app/admin/clients/page.tsx`. Update the "Nuovo cliente" link href if it points to `/admin/clients/new` — it should already be correct. Update the "Mostra archiviati" toggle link from `?archived=1` on `/admin` to `/admin/clients?archived=1`.
  1. Replace src/app/admin/page.tsx with a minimal redirect placeholder for now (dashboard content comes in 06-02):
import { redirect } from "next/navigation";

// Dashboard page — content added in Phase 6 Plan 02
export default function AdminRoot() {
  redirect("/admin/clients");
}

This keeps the app functional during the transition: clicking Dashboard in the sidebar goes to /admin which redirects to /admin/clients until the real dashboard exists.

Task 4: Delete NavBar.tsx and verify TypeScript builds src/components/admin/NavBar.tsx Delete `src/components/admin/NavBar.tsx` since it is fully replaced by AdminSidebar.

Run npx tsc --noEmit to verify no TypeScript errors. If NavBar is imported anywhere else, remove those imports.

Run npm run build to confirm the Next.js build passes.

- [ ] `npx tsc --noEmit` passes with no errors - [ ] `npm run build` completes successfully - [ ] Sidebar renders with all 7 nav links + logout button - [ ] Active link is visually highlighted - [ ] `/admin/clients` loads the client list correctly - [ ] `/admin` redirects to `/admin/clients` - [ ] No references to NavBar remain in the codebase