Files
shadow-gunbuilder-ai-proto/.github/copilot-instructions.md
T
2026-01-18 08:39:29 -05:00

8.0 KiB

Gunbuilder Prototype — AI Coding Instructions

Project Overview

Gunbuilder is a Next.js 14 (App Router) admin UI + consumer builder for a firearms parts marketplace. The system manages merchant feeds, normalizes product catalogs, powers a rifle builder interface, and backs a Spring Boot API.

Key Architecture

  • Frontend: Next.js 14 (App Router), TypeScript, TailwindCSS, React 18
  • Backend: Spring Boot (proxied at /api/* via next.config.mjs)
  • Auth: JWT tokens stored in cookies (bb_access_token, bb_role), validated in middleware
  • State: React Context (AuthContext) for user/auth, client-side React hooks for UI state
  • Data: Spring Boot REST API—responses paginated via Spring's PageResponse<T> structure with content, totalElements, totalPages, number (0-based), size

File Structure & Naming Conventions

App Router Layout

app/
├── layout.tsx                 # Root (AuthProvider, metadata, theme script)
├── (admin)/layout.tsx         # Admin area: auth gate + left nav sidebar
├── (app)/layout.tsx           # Consumer builder: TopNav + BuilderNav
├── (account)/                 # User account routes (protected)
├── login/page.tsx, register/page.tsx
├── api/                       # Server-side API route handlers
└── actions/                   # Server Actions (e.g., sendEmail.ts)

Naming & Organization

  • Layout grouping: Use (admin), (app), (account) route groups to scope nav & auth logic
  • Client vs Server: Mark pages/components with "use client" if they use hooks, state, or browser APIs. Default is Server Component
  • Components: Store in /components with category subdirectories: builder/, parts/, ui/
  • Utilities: Place reusable logic in /lib (API calls, parsers, helpers)
  • Types: Centralize in /types (e.g., uiPart.ts, builderSlots.ts, user.ts)
  • Data: Non-fetched lookup tables in /data (e.g., gunbuilderParts.ts — builder slot definitions)

Critical Patterns

1. Authentication & Authorization

  • Token storage: Stored in HTTP-only cookies (bb_access_token, bb_role)
  • Client-side context: AuthContext provides token, user, login(), register(), logout(), refreshMeAndSession()
  • Middleware gate (middleware.ts): Admin routes at /admin/* require bb_access_token + role check
    if (pathname.startsWith("/admin")) {
      const token = req.cookies.get("bb_access_token")?.value;
      const role = req.cookies.get("bb_role")?.value;
      const ok = !!token && (!role || role === "ADMIN");
      if (!ok) redirect to /login
    }
    
  • Wrap pages: Use protectedPage() HOC for client-side auth walls

2. API Integration (lib/api.ts)

  • useApi() hook: Returns { get(), post(), put() } methods with auto-injected Bearer token
  • Response unwrapping (components/parts/PartsBrowseClient.tsx):
    function unwrapContent<T>(json: any) {
      if (Array.isArray(json)) return { items: json };
      if (Array.isArray(json.content)) return { items: json.content, page: json }; // Spring PageResponse
      return { items: [] };
    }
    
  • Pagination: API returns { content: T[], totalElements, totalPages, number, size }—unwrap before rendering

3. Builder State & Overlaps (lib/buildOverlaps.ts, data/gunbuilderParts.ts)

  • Category slots: Defined in /data/gunbuilderParts.ts (CATEGORIES array with id, name, group)
  • BuildState type: Partial<Record<CategoryId, string>> (maps slot ID to selected product ID)
  • Overlap logic: getOverlapChipsForCategory() educates users when incompatible parts selected
    • E.g., selecting "complete-upper" + "barrel" → show warning chip
    • Used in OverlapChip, PartCard

4. Parts Browsing & Filtering (components/parts/PartsBrowseClient.tsx)

  • Page size: Hardcoded to 24 items
  • Query params: platform, partRole, search, sort (relevance | price-asc | price-desc | brand-asc), page (0-based)
  • View modes: Card (grid) or list view via state hook
  • Product type: GunbuilderProductFromApi with id, name, brand, platform, partRole, price, imageUrl, buyUrl, inStock

5. Styling & Dark Mode

  • TailwindCSS: Configured for dark mode via "class" strategy (tailwind.config.ts)
  • Root script (app/layout.tsx): Inline JS checks localStorage for theme, applies dark class to <html>
  • Class pattern: Use dark: prefix for dark-mode overrides (e.g., dark:bg-black dark:text-zinc-50)
  • Colors: Zinc scale primary (white/950 light, black/50 dark); semantic grays for UI

6. Form & Rich Text (components/ui/RichTextEditor.tsx)

  • RichTextEditor: Wraps Quill with image resize module for email/admin content
  • Email form: send_email_form.tsx uses form context + RichTextEditor combo

Development Workflows

Local Setup

npm install
npm run dev  # Starts Next.js at http://localhost:3000

Environment Variables (.env.local)

NEXT_PUBLIC_API_BASE_URL=http://localhost:8080
NEXT_PUBLIC_ADMIN_BASE_PATH=/builder/admin
NEXT_PUBLIC_LAUNCH_ONLY_ROOT=false  # Set true to restrict non-launch content

Building

npm run build
npm run start  # Production mode
npm run lint  # ESLint check

Key Backend Endpoints (Spring Boot)

  • POST /api/auth/login → returns { token, user }
  • GET /api/gunbuilder/products?platform=...&partRole=... → returns Spring PageResponse
  • POST /api/admin/... → admin-only mutations (import, mapping, etc.)

Common Tasks & Patterns

Add a New Admin Page

  1. Create app/admin/[feature]/page.tsx with "use client"
  2. Add to AdminLeftNavigation navGroups
  3. Use useAuth() for permission checks; fallback <protectedPage /> if needed
  4. Fetch via useApi() hook

Modify Parts Filtering

  • Edit sort options in SortBar or query logic in PartsBrowseClient
  • Update PAGE_SIZE constant if needed
  • Ensure query params flow through useRouter + useSearchParams

Update Builder Slot Definitions

Add Server Action

  • Create file in app/actions/ (e.g., sendEmail.ts)
  • Mark top with "use server"
  • Import & call from client components; errors bubble naturally

Known Constraints & Workarounds

  • No test suite: Manual testing required; dev server hot-reload via npm run dev
  • Spring PageResponse unwrapping: Always check for .content array when parsing API responses
  • Image URLs: May be null; provide fallback in UI (e.g., placeholder image)
  • Mobile responsive: TailwindCSS handles breakpoints; test with dark mode class toggle
  • Type safety: Use strict TS config; leverage builder slot types to avoid string mismatches

Integration Points & Gotchas

  • CORS: Spring Boot backend must allow origin http://localhost:3000 (or production domain)
  • API rewrites: Next.js rewrites /api/* to backend at build time; ensure NEXT_PUBLIC_API_BASE_URL matches
  • Auth token refresh: Handled in AuthContext refreshMeAndSession()—called on mount or nav
  • Dark mode class toggle: Update <html> class, not just CSS var—required for TailwindCSS dark: selectors
  • Hydration: Theme script runs inline before React hydration to avoid FOUC (flash of unstyled content)