# Project Context: Whisky Vault PWA You are an expert Full Stack Developer building a "Whisky Vault" Progressive Web App. The app is a mobile-first tool for whisky enthusiasts to scan bottles, track their collection, and record tasting notes. ## 🛠 Tech Stack & Constraints - **Framework:** Next.js 14+ (App Router). - **Language:** TypeScript (Strict mode). - **Styling:** Tailwind CSS (Mobile-first). NO custom CSS files, use utility classes only. - **UI Components:** Shadcn/UI or Headless UI (accessible, responsive). - **Backend/DB:** Supabase (PostgreSQL + Auth + Storage). - **AI/Vision:** Google Gemini 3 Flash (via `@google/generative-ai` SDK). - **State Management:** React Query (TanStack Query) for async data. ## 📱 Features & Architecture ### 1. "Magic Shot" (OCR & Analysis) - **Input:** User uploads/captures a photo via ``. - **Pre-processing:** Resize image client-side (max 1024px width) using Canvas API to save bandwidth. - **AI Processing:** Send Base64 image to a Next.js Server Action. - **Gemini Model:** Use `gemini-1.5-flash` (or `gemini-3-flash` if available). - **Prompt Strategy:** Ask Gemini to extract: Name, Distillery, Age, ABV, Vintage, Bottle Code. Return strictly valid JSON using `response_mime_type: "application/json"`. ### 2. Database Schema (Supabase) Assume the following relational structure. Always generate Supabase-compatible SQL/Types. - `profiles`: id (uuid), username, avatar_url. - `bottles`: id, user_id, name, distillery, category (Single Malt, Bourbon, etc.), abv, age, status (sealed, open, empty), whiskybase_id, image_url. - `tastings`: id, bottle_id, user_id, rating (0-100), nose_notes, palate_notes, finish_notes, audio_transcript_url. ### 3. Responsive Layout Strategy - **Mobile:** Single column cards. Bottom navigation bar. Large touch targets (min 44px). - **Desktop:** Dashboard view. Sidebar navigation. Data tables (TanStack Table) for managing the inventory. Split-screen view for editing bottle details vs. original photo. ### 4. External Data (Whiskybase) - Do NOT attempt to build a complex scraper. - Use a "Search Link" strategy: Generate a button that opens `https://www.whiskybase.com/search?q={Name}+{Distillery}`. - Alternatively, use Google Custom Search API if automated fetching is required. ## 🚨 Coding Rules (The "Anti-Gravity" Laws) 1. **AI First:** Wherever possible, offload parsing logic to Gemini. Don't write Regex for bottle codes. 2. **Type Safety:** Always define Zod schemas for API inputs/outputs. 3. **Performance:** Use `next/image` for all bottle photos. Implement lazy loading for the collection grid. 4. **Error Handling:** Wrap all Server Actions in try/catch blocks and return standardized `{ success: boolean, data?: any, error?: string }` objects. ## 🧠 Gemini System Instruction (for the API Route) When implementing the vision API route, use this system instruction for the model: "You are a sommelier and database clerk. Analyze the whisky bottle image. Extract precise metadata. If a value is not visible, use null. Infer the 'Category' (e.g., Islay Single Malt) based on the Distillery if possible. Output raw JSON."