## Codebase Patterns - Project uses Next.js 16 with App Router, TypeScript, and TailwindCSS 4 - Source files are in `src/` directory (app, components, lib, types) - Supabase is configured with @supabase/supabase-js and @supabase/ssr packages - Environment variables follow NEXT_PUBLIC_* convention for client-side access - Use `npm run typecheck` to run TypeScript type checking (tsc --noEmit) - Flowchart types exported from `src/types/flowchart.ts` - Supabase migrations go in `supabase/migrations/` with timestamp prefix (YYYYMMDDHHMMSS_*.sql) - Database has profiles table (linked to auth.users) and projects table (with flowchart_data JSONB) - RLS policies enforce user_id = auth.uid() for project access - Supabase client utilities in `src/lib/supabase/`: client.ts (browser), server.ts (App Router), middleware.ts (route protection) - Next.js middleware.ts at project root handles route protection using updateSession helper - Public auth routes: /login, /signup, /forgot-password, /reset-password - Protected routes: /dashboard, /editor/* (redirect to /login if unauthenticated) - Auth pages use 'use client' with useState, createClient() from lib/supabase/client.ts, and useRouter for redirects - For lists with client-side updates (delete/add), use wrapper client component that receives initialData from server component - Toast component in `src/components/Toast.tsx` for success/error notifications (auto-dismiss after 3s) --- ## 2026-01-21 - US-001 - What was implemented: Project scaffolding and configuration - Files changed: - package.json - project dependencies and scripts - tsconfig.json - TypeScript configuration - next.config.ts - Next.js configuration - postcss.config.mjs - PostCSS with TailwindCSS - eslint.config.mjs - ESLint configuration - .env.example - environment variables template - .gitignore - git ignore rules - src/app/ - Next.js App Router pages - src/components/.gitkeep - components directory placeholder - src/lib/.gitkeep - lib directory placeholder - src/types/.gitkeep - types directory placeholder - **Learnings for future iterations:** - Next.js 16 uses `@tailwindcss/postcss` for TailwindCSS 4 integration - Use --src-dir flag for create-next-app to put source in src/ folder - npm package names can't have capital letters (use lowercase) - .gitignore needs explicit exclusion for .env files, but include .env.example --- ## 2026-01-21 - US-002 - What was implemented: TypeScript types for flowchart data structures - Files changed: - src/types/flowchart.ts - new file with all flowchart type definitions - package.json - added typecheck script (tsc --noEmit) - **Learnings for future iterations:** - Position is a helper type for {x, y} coordinates used by nodes - FlowchartNode is a union type of DialogueNode | ChoiceNode | VariableNode - ChoiceOption is a separate type to make options array cleaner - All types use `export type` for TypeScript isolatedModules compatibility --- ## 2026-01-21 - US-003 - What was implemented: Supabase schema for users and projects - Files changed: - supabase/migrations/20260121000000_create_profiles_and_projects.sql - new file with all database schema - **Learnings for future iterations:** - Supabase migrations are plain SQL files in supabase/migrations/ directory - Migration filenames use timestamp prefix (YYYYMMDDHHMMSS_description.sql) - RLS policies need separate policies for SELECT, INSERT, UPDATE, DELETE operations - Admin check policy uses EXISTS subquery to check is_admin flag on profiles table - projects table references profiles.id (not auth.users.id directly) for proper FK relationships - flowchart_data column uses JSONB type with default empty structure - Added auto-update trigger for updated_at timestamp on projects table --- ## 2026-01-21 - US-004 - What was implemented: Supabase client configuration utilities - Files changed: - src/lib/supabase/client.ts - browser client using createBrowserClient from @supabase/ssr - src/lib/supabase/server.ts - server client for App Router with async cookies() API - src/lib/supabase/middleware.ts - middleware helper with updateSession function - src/lib/.gitkeep - removed (no longer needed) - **Learnings for future iterations:** - @supabase/ssr package provides createBrowserClient and createServerClient functions - Server client requires async cookies() from next/headers in Next.js 16 - Middleware client returns both user object and supabaseResponse for route protection - Cookie handling uses getAll/setAll pattern for proper session management - setAll in server.ts wrapped in try/catch to handle Server Component limitations --- ## 2026-01-21 - US-005 - What was implemented: Protected routes middleware for authentication - Files changed: - middleware.ts - new file at project root for route protection - **Learnings for future iterations:** - Next.js middleware.ts must be at project root (not in src/) - updateSession helper from lib/supabase/middleware.ts returns { user, supabaseResponse } - Use startsWith() for route matching to handle nested routes (e.g., /editor/*) - Matcher config excludes static files and images to avoid unnecessary middleware calls - Clone nextUrl before modifying pathname for redirects --- ## 2026-01-21 - US-006 - What was implemented: Login page with email/password authentication - Files changed: - src/app/login/page.tsx - new file with login form and Supabase auth - **Learnings for future iterations:** - Auth pages use 'use client' directive since they need useState and form handling - Use createClient() from lib/supabase/client.ts for browser-side auth operations - supabase.auth.signInWithPassword returns { error } object for handling failures - useRouter from next/navigation for programmatic redirects after auth - Error state displayed in red alert box with dark mode support - Loading state disables submit button and shows "Signing in..." text - TailwindCSS dark mode uses dark: prefix (e.g., dark:bg-zinc-950) --- ## 2026-01-21 - US-007 - What was implemented: Sign up page for invite-only account setup - Files changed: - src/app/signup/page.tsx - new file with signup form and Supabase auth - **Learnings for future iterations:** - Supabase invite tokens come via URL hash fragment (window.location.hash) - Parse hash with URLSearchParams after removing leading '#' - Check for type=invite or type=signup to detect invite flow - Use setSession() with access_token and refresh_token to establish session from invite link - For invited users, update password with updateUser() then create profile with upsert() - Use upsert() instead of insert() for profiles to handle edge cases - Validate password confirmation before submission (passwords match check) - display_name defaults to email prefix (split('@')[0]) --- ## 2026-01-21 - US-008 - What was implemented: Logout functionality component - Files changed: - src/components/LogoutButton.tsx - new client component with signOut and redirect - src/components/.gitkeep - removed (no longer needed) - **Learnings for future iterations:** - LogoutButton is a reusable component that will be used in the navbar (US-011) - Component uses 'use client' directive for client-side auth operations - Loading state prevents double-clicks during signOut - Styled with neutral zinc colors to work as a secondary button in navbars --- ## 2026-01-21 - US-009 - What was implemented: Password reset - forgot password page - Files changed: - src/app/forgot-password/page.tsx - new file with forgot password form and email reset - **Learnings for future iterations:** - resetPasswordForEmail requires redirectTo option to specify where user lands after clicking reset link - Use `window.location.origin` to get the current site URL for redirectTo - Page shows different UI after success (conditional rendering with success state) - Use ' for apostrophe in JSX to avoid HTML entity issues - Follow same styling pattern as login page for consistency across auth pages --- ## 2026-01-21 - US-010 - What was implemented: Password reset - set new password page - Files changed: - src/app/reset-password/page.tsx - new file with password reset form - src/app/login/page.tsx - updated to show success message from password reset - **Learnings for future iterations:** - Supabase recovery tokens come via URL hash fragment with type=recovery - Use setSession() with access_token and refresh_token from hash to establish recovery session - Show loading state while verifying token validity (tokenValid === null) - Show error state with link to request new reset if token is invalid - After password update, sign out the user and redirect to login with success message - Use query param (message=password_reset_success) to pass success state between pages - Login page uses useSearchParams to read and display success messages - Success messages styled with green background (bg-green-50) --- ## 2026-01-21 - US-011 - What was implemented: Dashboard layout with navbar component - Files changed: - src/app/dashboard/layout.tsx - new file with dashboard layout wrapper - src/components/Navbar.tsx - new reusable navbar component - **Learnings for future iterations:** - Dashboard layout is a server component that fetches user data via createClient() from lib/supabase/server.ts - Navbar accepts userEmail prop to display current user - Layout wraps children with consistent max-w-7xl container and padding - Navbar uses Link component to allow clicking app title to go back to dashboard - Navbar has border-b styling with dark mode support for visual separation - Use gap-4 for spacing between navbar items (user email and logout button) --- ## 2026-01-21 - US-012 - What was implemented: Dashboard page listing user projects - Files changed: - src/app/dashboard/page.tsx - new file with project listing, cards, and empty state - **Learnings for future iterations:** - Dashboard page is a server component that fetches projects directly from Supabase - Use .eq('user_id', user.id) for RLS-backed queries (though RLS also enforces this) - Order by updated_at descending to show most recent projects first - formatDate() helper with toLocaleDateString for human-readable dates - Project cards use Link component for navigation to /editor/[projectId] - Empty state uses dashed border (border-dashed) with centered content and icon - Hover effects on cards: border-blue-300, shadow-md, and text color change on title - Error state displayed if Supabase query fails --- ## 2026-01-21 - US-013 - What was implemented: Create new project functionality - Files changed: - src/components/NewProjectButton.tsx - new client component with modal dialog - src/app/dashboard/page.tsx - added NewProjectButton to header area - src/app/signup/page.tsx - fixed lint error (setState in effect) by initializing email from searchParams - **Learnings for future iterations:** - Modal dialogs use fixed positioning with backdrop (bg-black/50) for overlay effect - Form submission uses Supabase insert with .select('id').single() to get the new record ID - Initialize flowchart_data with { nodes: [], edges: [] } for new projects - router.push() for programmatic navigation after successful creation - autoFocus on input for better UX when modal opens - Prevent modal close while loading (check isLoading before calling handleClose) - ESLint rule react-hooks/set-state-in-effect warns against synchronous setState in useEffect - Initialize state from searchParams directly in useState() instead of setting in useEffect --- ## 2026-01-21 - US-014 - What was implemented: Delete project functionality with confirmation dialog and toast - Files changed: - src/components/ProjectCard.tsx - new client component replacing Link, with delete button and confirmation dialog - src/components/ProjectList.tsx - new wrapper component to manage project list state and toast notifications - src/components/Toast.tsx - new reusable toast notification component - src/app/dashboard/page.tsx - updated to use ProjectList instead of inline rendering - **Learnings for future iterations:** - To enable client-side state updates (like removing items), extract list rendering from server components into client components - ProjectList accepts initialProjects from server and manages state locally for immediate UI updates - Use onDelete callback pattern to propagate deletion events from child (ProjectCard) to parent (ProjectList) - Delete button uses e.stopPropagation() to prevent card click navigation when clicking delete - Confirmation dialogs should disable close/cancel while action is in progress (isDeleting check) - Toast component uses useCallback for handlers and auto-dismiss with setTimeout - Toast animations can use TailwindCSS animate-in utilities (fade-in, slide-in-from-bottom-4) - Delete icon appears on hover using group-hover:opacity-100 with parent group class --- ## 2026-01-21 - US-015 - What was implemented: Rename project functionality - Files changed: - src/components/ProjectCard.tsx - added rename button, modal dialog, and Supabase update logic - src/components/ProjectList.tsx - added handleRename callback and toast notification - **Learnings for future iterations:** - Multiple action buttons on a card can be grouped in a flex container with gap-1 - Rename modal follows same pattern as delete dialog: fixed positioning, backdrop, form - Use onKeyDown to handle Enter key for quick form submission - Reset form state (newName, error) when opening modal to handle edge cases - Check if name is unchanged before making API call to avoid unnecessary requests - Trim whitespace from input value before validation and submission - handleRename callback updates project name in state using map() to preserve list order ---