# PunimTag Photo Viewer - Frontend Website Plan

## Executive Summary

This document outlines the detailed plan for creating a new, lightweight, public-facing photo viewing website that connects to the existing PunimTag PostgreSQL database. This website will be separate from the admin interface and focused on providing a beautiful, fast, and intuitive photo browsing experience.

---

## 1. Project Overview

### 1.1 Purpose
Create a read-only photo gallery website that allows users to:
- Browse photos from the PunimTag database
- Search by people names, dates taken, and tags
- View high-quality photos with smooth navigation
- Experience a modern, responsive design

### 1.2 Key Differentiators from Admin Interface
| Feature | Admin Interface | Photo Viewer |
|---------|----------------|--------------|
| Purpose | Photo management & AI processing | Photo viewing & browsing |
| Authentication | Required | Optional (configurable) |
| Operations | Read/Write (CRUD) | Read-only |
| Target Users | Administrators | End users/Family members |
| Complexity | Feature-rich, complex | Simple, elegant |
| Performance | Batch operations | Optimized for browsing |

---

## 2. Technology Stack

### 2.1 Frontend Framework
**Next.js 14+ (App Router)**
- **Why Next.js?**
  - Built-in SSR/SSG for excellent performance
  - Image optimization out of the box
  - File-based routing
  - API routes for backend proxy
  - Excellent SEO support
  - Great TypeScript support

**Alternative: Astro 4+ with React Islands**
- Even faster page loads
- Partial hydration
- Great for content-heavy sites
- Zero JS by default

**Recommendation: Next.js 14** (more mature ecosystem, better for dynamic data)

### 2.2 UI Framework & Styling
**shadcn/ui + Tailwind CSS**
- Modern, accessible components
- Highly customizable
- Built on Radix UI primitives
- Consistent design system
- Copy-paste components (no npm bloat)

**Additional UI Libraries:**
- **Framer Motion** - Smooth animations and transitions
- **Lucide React** - Beautiful, consistent icons
- **React Photo Album** - Optimized photo grid layouts
- **Yet Another React Lightbox** - Photo viewing/slideshow

### 2.3 State Management
**TanStack Query (React Query) v5**
- Perfect for server state management
- Built-in caching and invalidation
- Loading and error states
- Infinite scroll support
- Optimistic updates

**Zustand** (optional, for client state)
- Lightweight alternative to Redux
- Simple API
- Only if needed for complex client state

### 2.4 Backend Architecture

#### Option A: Direct Database Access (Recommended for simplicity)
```
Next.js App → Prisma ORM → PostgreSQL Database
```

**Prisma ORM**
- Type-safe database client
- Auto-generated types from schema
- Excellent PostgreSQL support
- Read-only mode for safety

#### Option B: Backend Proxy (Recommended for security)
```
Next.js App → Lightweight API Layer → PostgreSQL Database
```

**Lightweight API Options:**
1. **Next.js API Routes** - Built-in, simple
2. **tRPC** - End-to-end typesafe APIs
3. **Separate FastAPI microservice** - Reuse existing backend code

**Recommendation: Next.js API Routes with Prisma** (simplest, most integrated)

### 2.5 Database Strategy
**Read-Only PostgreSQL Access**
- Connect to existing PunimTag PostgreSQL database
- Read-only database user for security
- Use connection pooling (PgBouncer or Prisma Accelerate)
- No schema changes needed

---

## 3. Architecture Design

### 3.1 Project Structure
```
punimtag-viewer/
├── src/
│   ├── app/                    # Next.js 14 App Router
│   │   ├── (marketing)/       # Public pages (landing, about)
│   │   ├── (viewer)/          # Main photo viewer pages
│   │   │   ├── layout.tsx     # Viewer layout with nav
│   │   │   ├── page.tsx       # Home/Gallery grid
│   │   │   ├── photo/[id]/    # Individual photo view
│   │   │   ├── people/        # Browse by people
│   │   │   ├── tags/          # Browse by tags
│   │   │   └── search/        # Search results
│   │   ├── api/               # API routes (if needed)
│   │   └── layout.tsx         # Root layout
│   ├── components/            # React components
│   │   ├── ui/                # shadcn/ui components
│   │   ├── gallery/           # Gallery-specific components
│   │   │   ├── PhotoGrid.tsx
│   │   │   ├── PhotoCard.tsx
│   │   │   ├── Lightbox.tsx
│   │   │   └── InfiniteScroll.tsx
│   │   ├── search/            # Search components
│   │   │   ├── SearchBar.tsx
│   │   │   ├── FilterPanel.tsx
│   │   │   └── DateRangePicker.tsx
│   │   └── layout/            # Layout components
│   │       ├── Header.tsx
│   │       ├── Sidebar.tsx
│   │       └── Footer.tsx
│   ├── lib/                   # Utilities and configs
│   │   ├── db.ts             # Prisma client
│   │   ├── queries.ts        # Database queries
│   │   ├── utils.ts          # Helper functions
│   │   └── constants.ts      # Constants
│   ├── hooks/                 # Custom React hooks
│   │   ├── usePhotos.ts
│   │   ├── usePeople.ts
│   │   ├── useTags.ts
│   │   └── useInfiniteScroll.ts
│   └── types/                 # TypeScript types
│       └── database.ts
├── prisma/
│   └── schema.prisma         # Prisma schema (read-only)
├── public/
│   └── assets/               # Static assets
├── .env.local                # Environment variables
├── next.config.js
├── tailwind.config.ts
├── package.json
└── README.md
```

### 3.2 Data Flow

```
User Browser
    ↓
Next.js Frontend (React Components)
    ↓
TanStack Query (Caching & State)
    ↓
Next.js API Routes (Optional Proxy)
    ↓
Prisma ORM (Type-safe queries)
    ↓
PostgreSQL Database (Read-Only)
    ↓
Return Photo Data + URLs
    ↓
Next.js Image Optimization
    ↓
Optimized Images to User
```

### 3.3 Image Serving Strategy

**Hybrid Approach (Implemented):** Automatically detects URL vs file system path

#### Direct File Access (For URLs - SharePoint, CDN, etc.)
- Next.js serves images directly from HTTP/HTTPS URLs
- Use Next.js Image component for optimization
- Configure `remotePatterns` in `next.config.ts` for external sources
- Works with SharePoint Online, SharePoint Server, CDNs, and other HTTP-accessible sources
- **Automatic detection:** If `photo.path` starts with `http://` or `https://`, uses direct access

#### API Proxy (For File System Paths)
- API endpoint serves images from database-referenced file system paths
- Supports image resizing and caching
- Can add watermarks, metadata stripping
- Used automatically when `photo.path` is a file system path (not a URL)

**Implementation:**
- PhotoGrid component automatically detects URL vs file system path
- URLs (SharePoint, CDN) → Direct access with Next.js Image optimization
- File system paths → API proxy route (`/api/photos/[id]/image`)
- **No database queries needed:** Path is passed via query parameter to avoid N+1 queries

**Benefits:**
- ✅ Works with both SharePoint URLs and local file system
- ✅ Automatic detection - no configuration needed per photo
- ✅ Optimal performance for both storage types
- ✅ Backward compatible with existing file system paths

---

## 4. Core Features & Pages

### 4.1 Home/Gallery Page
**URL:** `/`

**Features:**
- Infinite scroll photo grid (masonry or justified layout)
- Lazy loading with blur placeholders
- Quick filters: All, Favorites, Recent
- Photo count badge
- Smooth animations on load

**Components:**
- `PhotoGrid` - Main grid container
- `PhotoCard` - Individual photo card with hover effects
- `InfiniteScroll` - Load more on scroll
- `FilterBar` - Quick filter chips

**Performance:**
- Initial load: 30 photos
- Lazy load: 30 photos per page
- Virtual scrolling for 10,000+ photos

### 4.2 Search Page
**URL:** `/search`

**Search Criteria:**
1. **People Search**
   - Autocomplete dropdown
   - Multiple people selection
   - "Match all" vs "Match any" toggle

2. **Date Search**
   - Date range picker
   - Preset ranges (Today, This week, This month, This year)
   - Custom date range

3. **Tag Search**
   - Tag cloud with counts
   - Multi-select tags
   - Hierarchical tags (if implemented)

4. **Combined Search**
   - All filters work together (AND logic)
   - Clear filters button
   - Search result count

**Components:**
- `SearchBar` - Main search input
- `PeopleFilter` - People selection
- `DateRangePicker` - Date picker
- `TagFilter` - Tag selection
- `SearchResults` - Results grid

### 4.3 Photo Detail Page
**URL:** `/photo/[id]`

**Features:**
- Full-size photo viewer
- Photo metadata panel
  - Date taken
  - Dimensions
  - Tagged people (with links)
  - Tags (with links)
- Previous/Next navigation
- Keyboard shortcuts (←/→ arrows, Esc)
- Download button (optional, configurable)
- Share button (copy link)

**Components:**
- `Lightbox` - Full-screen photo viewer
- `MetadataPanel` - Photo information
- `PeopleList` - Tagged people
- `TagList` - Photo tags

### 4.4 People Browser
**URL:** `/people`

**Features:**
- Grid of people with representative photo
- Person name and photo count
- Sort by: Name, Photo count, Recent
- Search/filter people

**Detail Page:** `/people/[id]`
- Person's name and details
- Grid of all photos featuring this person
- Timeline view option
- Photo count

### 4.5 Tags Browser
**URL:** `/tags`

**Features:**
- Tag cloud or list view
- Photo count per tag
- Color-coded tags (if applicable)
- Search tags

**Detail Page:** `/tags/[id]`
- All photos with this tag
- Related tags
- Tag description (if available)

### 4.6 Timeline View (Optional)
**URL:** `/timeline`

**Features:**
- Chronological photo layout
- Group by year/month/day
- Timeline scrubber
- Jump to date

---

## 5. UI/UX Design

### 5.1 Design System

**Color Palette (Modern & Clean):**
```
Primary: 
  - Light: #3b82f6 (Blue 500)
  - Dark: #60a5fa (Blue 400)

Secondary:
  - Light: #8b5cf6 (Violet 500)
  - Dark: #a78bfa (Violet 400)

Neutral:
  - Background Light: #ffffff
  - Background Dark: #0f172a (Slate 900)
  - Surface Light: #f8fafc (Slate 50)
  - Surface Dark: #1e293b (Slate 800)

Text:
  - Primary Light: #0f172a (Slate 900)
  - Primary Dark: #f8fafc (Slate 50)
  - Secondary Light: #64748b (Slate 500)
  - Secondary Dark: #94a3b8 (Slate 400)
```

**Typography:**
```
Font Family: 
  - Headings: Inter (Google Fonts)
  - Body: Inter
  - Mono: JetBrains Mono (for metadata)

Font Sizes:
  - Display: 4rem (64px)
  - H1: 3rem (48px)
  - H2: 2.25rem (36px)
  - H3: 1.875rem (30px)
  - H4: 1.5rem (24px)
  - Body: 1rem (16px)
  - Small: 0.875rem (14px)
  - Tiny: 0.75rem (12px)
```

**Spacing Scale:**
- 4, 8, 12, 16, 20, 24, 32, 40, 48, 64, 80, 96 (px)

**Border Radius:**
- Small: 4px
- Medium: 8px
- Large: 12px
- XLarge: 16px

### 5.2 Layout & Navigation

**Header (Desktop):**
```
┌────────────────────────────────────────────────────┐
│ [Logo] PunimTag              [Search]  [User Menu] │
│ Home | People | Tags | Timeline                    │
└────────────────────────────────────────────────────┘
```

**Header (Mobile):**
```
┌─────────────────────────────┐
│ [☰] PunimTag     [Search] │
└─────────────────────────────┘
```

**Sidebar Filter Panel (Desktop):**
```
┌──────────────┐
│ Filters      │
│              │
│ People       │
│ □ John       │
│ □ Jane       │
│              │
│ Date Range   │
│ [Picker]     │
│              │
│ Tags         │
│ □ Family     │
│ □ Vacation   │
│              │
│ [Apply]      │
└──────────────┘
```

### 5.3 Responsive Design

**Breakpoints:**
- Mobile: < 640px (1 column)
- Tablet: 640px - 1024px (2-3 columns)
- Desktop: > 1024px (4-5 columns)
- Wide: > 1536px (5-6 columns)

**Photo Grid:**
- Mobile: 1-2 columns
- Tablet: 3-4 columns
- Desktop: 4-5 columns
- Wide: 6+ columns

### 5.4 Animation & Transitions

**Principles:**
- Subtle and smooth (no jarring animations)
- Fast transitions (150-300ms)
- Meaningful motion (guide user attention)

**Key Animations:**
1. Photo Grid
   - Fade in on load
   - Scale on hover
   - Smooth masonry layout shifts

2. Page Transitions
   - Fade between pages
   - Slide in sidebars

3. Lightbox
   - Zoom in from thumbnail
   - Smooth previous/next transitions

**Framer Motion Variants:**
```typescript
const photoCardVariants = {
  hidden: { opacity: 0, y: 20 },
  visible: { 
    opacity: 1, 
    y: 0,
    transition: { duration: 0.3 }
  },
  hover: { 
    scale: 1.05,
    transition: { duration: 0.2 }
  }
}
```

---

## 6. Performance Optimization

### 6.1 Image Optimization

**Next.js Image Component:**
```typescript
<Image
  src={photo.path}
  alt={photo.filename}
  width={800}
  height={600}
  quality={85}
  placeholder="blur"
  blurDataURL={photo.blurHash}
  loading="lazy"
  sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>
```

**Strategies:**
1. **Responsive Images**
   - Generate multiple sizes (thumbnail, medium, large, full)
   - Serve appropriate size based on viewport
   - Use `srcset` and `sizes` attributes

2. **Blur Placeholder**
   - Generate blur hash on backend
   - Show blur while loading
   - Smooth transition to full image

3. **Lazy Loading**
   - Load images as they enter viewport
   - Prefetch next page of images
   - Intersection Observer API

4. **CDN Integration (Optional)**
   - Cloudflare Images
   - Vercel Image Optimization
   - imgix or Cloudinary

### 6.2 Data Fetching Optimization

**React Query Configuration:**
```typescript
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 5 * 60 * 1000,      // 5 minutes
      cacheTime: 10 * 60 * 1000,     // 10 minutes
      refetchOnWindowFocus: false,
      retry: 1,
    },
  },
});
```

**Strategies:**
1. **Prefetching**
   - Prefetch next page on current page load
   - Prefetch photo details on hover

2. **Infinite Scroll**
   - Use React Query's `useInfiniteQuery`
   - Load 30 photos per page
   - Keep 3 pages in memory

3. **Debouncing**
   - Debounce search inputs (300ms)
   - Debounce filter changes

4. **Parallel Queries**
   - Fetch photos and metadata simultaneously
   - Batch API requests

### 6.3 Database Optimization

**Indexing Strategy:**
```sql
-- Existing indices (already in PunimTag)
CREATE INDEX idx_photos_date_taken ON photos(date_taken);
CREATE INDEX idx_photos_processed ON photos(processed);
CREATE INDEX idx_faces_person_id ON faces(person_id);
CREATE INDEX idx_faces_photo_id ON faces(photo_id);
CREATE INDEX idx_photo_tags_tag ON phototaglinkage(tag_id);
CREATE INDEX idx_photo_tags_photo ON phototaglinkage(photo_id);

-- Additional indices for viewer
CREATE INDEX idx_photos_date_added_desc ON photos(date_added DESC);
CREATE INDEX idx_people_names ON people(first_name, last_name);
CREATE INDEX idx_tags_name ON tags(tag_name);
```

**Query Optimization:**
1. **Pagination**
   - Use cursor-based pagination for infinite scroll
   - Avoid OFFSET for large datasets

2. **Joins**
   - Minimize JOIN operations
   - Use SELECT only needed columns
   - Aggregate queries for counts

3. **Connection Pooling**
   - Use PgBouncer or Prisma connection pooling
   - Limit max connections

### 6.4 Caching Strategy

**Multi-Layer Caching:**

1. **Browser Cache**
   - Cache static assets (1 year)
   - Cache images (1 month)
   - Cache API responses (5 minutes)

2. **React Query Cache**
   - Cache query results in memory
   - Automatic invalidation
   - Background refetching

3. **Next.js Cache**
   - Static page generation (ISR)
   - API route caching
   - Image optimization cache

4. **Database Cache (Optional)**
   - Redis for frequently accessed data
   - Cache photo counts, tag lists
   - Cache search results

### 6.5 Performance Targets

| Metric | Target | Measurement |
|--------|--------|-------------|
| First Contentful Paint | < 1.5s | Lighthouse |
| Largest Contentful Paint | < 2.5s | Lighthouse |
| Time to Interactive | < 3.5s | Lighthouse |
| Cumulative Layout Shift | < 0.1 | Lighthouse |
| API Response Time | < 200ms | Server logs |
| Photo Load Time | < 1s | Network tab |
| Infinite Scroll Delay | < 500ms | User testing |

---

## 7. Search Implementation

### 7.1 Search API Endpoints

**Existing PunimTag API:** `/api/photos`
```typescript
// Search photos by multiple criteria
GET /api/photos?search_type=name&person_name=John&page=1&page_size=30
GET /api/photos?search_type=date&date_from=2024-01-01&date_to=2024-12-31
GET /api/photos?search_type=tags&tag_names=family,vacation&match_all=false
```

**New Viewer API (Recommended):**
```typescript
// Combined search endpoint
GET /api/viewer/photos?people=1,2&tags=3,4&date_from=2024-01-01&page=1

// Get all people with photo counts
GET /api/viewer/people

// Get all tags with photo counts
GET /api/viewer/tags

// Get photo by ID with full metadata
GET /api/viewer/photos/:id
```

### 7.2 Search UI Components

**SearchBar Component:**
```typescript
interface SearchBarProps {
  onSearch: (query: string) => void;
  placeholder?: string;
}

// Features:
// - Debounced input (300ms)
// - Clear button
// - Search icon
// - Keyboard shortcuts (Cmd+K, Ctrl+K)
```

**FilterPanel Component:**
```typescript
interface FilterPanelProps {
  people: Person[];
  tags: Tag[];
  dateRange: DateRange;
  onFilterChange: (filters: Filters) => void;
}

// Features:
// - Collapsible sections
// - Multi-select with checkboxes
// - Date range picker
// - Clear all filters
// - Active filter count badge
```

**PeopleAutocomplete:**
```typescript
interface PeopleAutocompleteProps {
  onSelect: (people: Person[]) => void;
  multiple?: boolean;
}

// Features:
// - Fuzzy search
// - Avatar thumbnails
// - Photo count badges
// - Keyboard navigation
```

### 7.3 Search Query Building

**Prisma Query Example:**
```typescript
async function searchPhotos(filters: SearchFilters) {
  const where = {
    processed: true,
    AND: [
      // Date filter
      filters.dateFrom ? { date_taken: { gte: filters.dateFrom } } : {},
      filters.dateTo ? { date_taken: { lte: filters.dateTo } } : {},
      
      // People filter (photo has face with person_id in list)
      filters.people?.length ? {
        faces: {
          some: {
            person_id: { in: filters.people }
          }
        }
      } : {},
      
      // Tags filter
      filters.tags?.length ? {
        photo_tags: {
          some: {
            tag_id: { in: filters.tags }
          }
        }
      } : {},
    ]
  };

  return await prisma.photo.findMany({
    where,
    include: {
      faces: {
        include: { person: true }
      },
      photo_tags: {
        include: { tag: true }
      }
    },
    orderBy: { date_taken: 'desc' },
    take: 30,
    skip: (page - 1) * 30,
  });
}
```

### 7.4 Search Performance

**Optimization Techniques:**
1. **Full-Text Search (Future Enhancement)**
   ```sql
   -- Add tsvector column for fast text search
   ALTER TABLE photos ADD COLUMN search_vector tsvector;
   CREATE INDEX idx_photos_search ON photos USING gin(search_vector);
   ```

2. **Materialized Views (For Aggregate Counts)**
   ```sql
   -- Precompute photo counts per person
   CREATE MATERIALIZED VIEW person_photo_counts AS
   SELECT person_id, COUNT(*) as photo_count
   FROM faces
   WHERE person_id IS NOT NULL
   GROUP BY person_id;
   ```

3. **Elasticsearch Integration (Advanced)**
   - Index photos in Elasticsearch
   - Fast full-text search
   - Faceted search
   - Relevance scoring

---

## 8. Security & Access Control

### 8.1 Authentication (Optional but Recommended)

**Auth Options:**

1. **Simple Password Protection**
   - Single shared password
   - Session-based auth
   - Cookie storage

2. **Email/Password Auth**
   - User registration
   - Password hashing (bcrypt)
   - JWT tokens

3. **OAuth/Social Login**
   - Google, Facebook, GitHub
   - NextAuth.js integration
   - Easy for users

4. **Family Sharing Model**
   - Invite codes
   - Family groups
   - Role-based access

**Recommendation:** Start with NextAuth.js for flexibility

**NextAuth.js Configuration:**
```typescript
// app/api/auth/[...nextauth]/route.ts
import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import GoogleProvider from "next-auth/providers/google";

export const authOptions = {
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_ID,
      clientSecret: process.env.GOOGLE_SECRET,
    }),
    CredentialsProvider({
      // Simple password or email/password
      credentials: {
        password: { label: "Password", type: "password" }
      },
      authorize: async (credentials) => {
        // Verify password
        if (credentials.password === process.env.VIEWER_PASSWORD) {
          return { id: "viewer", name: "Family Member" };
        }
        return null;
      }
    })
  ],
  pages: {
    signIn: '/login',
  },
  session: {
    strategy: "jwt",
  }
};
```

### 8.2 Read-Only Database Access

**PostgreSQL Read-Only User:**
```sql
-- Create read-only user
CREATE USER viewer_readonly WITH PASSWORD 'secure_password_here';

-- Grant connect permission
GRANT CONNECT ON DATABASE punimtag TO viewer_readonly;

-- Grant usage on schema
GRANT USAGE ON SCHEMA public TO viewer_readonly;

-- Grant SELECT on all tables
GRANT SELECT ON ALL TABLES IN SCHEMA public TO viewer_readonly;

-- Grant SELECT on future tables
ALTER DEFAULT PRIVILEGES IN SCHEMA public 
GRANT SELECT ON TABLES TO viewer_readonly;

-- Ensure no write permissions
REVOKE INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public FROM viewer_readonly;
```

**Prisma Configuration:**
```typescript
// prisma/schema.prisma
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL_READONLY")
}

// .env.local
DATABASE_URL_READONLY="postgresql://viewer_readonly:secure_password@localhost:5432/punimtag"
```

### 8.3 API Security

**Rate Limiting:**
```typescript
// middleware.ts
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";

const ratelimit = new Ratelimit({
  redis: Redis.fromEnv(),
  limiter: Ratelimit.slidingWindow(10, "10 s"),
});

export async function middleware(request: Request) {
  const ip = request.headers.get("x-forwarded-for") ?? "127.0.0.1";
  const { success } = await ratelimit.limit(ip);
  
  if (!success) {
    return new Response("Too Many Requests", { status: 429 });
  }
}
```

**Input Validation:**
```typescript
import { z } from "zod";

const searchParamsSchema = z.object({
  people: z.array(z.number().int().positive()).optional(),
  tags: z.array(z.number().int().positive()).optional(),
  dateFrom: z.string().datetime().optional(),
  dateTo: z.string().datetime().optional(),
  page: z.number().int().positive().default(1),
  pageSize: z.number().int().positive().max(100).default(30),
});
```

**Content Security Policy:**
```typescript
// next.config.js
const securityHeaders = [
  {
    key: 'Content-Security-Policy',
    value: `
      default-src 'self';
      img-src 'self' data: https:;
      script-src 'self' 'unsafe-eval' 'unsafe-inline';
      style-src 'self' 'unsafe-inline';
    `.replace(/\s{2,}/g, ' ').trim()
  },
  {
    key: 'X-Frame-Options',
    value: 'DENY'
  },
  {
    key: 'X-Content-Type-Options',
    value: 'nosniff'
  },
];
```

### 8.4 Privacy Considerations

**Configuration Options:**
1. **Public vs Private Mode**
   - Public: No auth required
   - Private: Auth required for all pages
   - Hybrid: Auth required for specific people/tags

2. **Download Controls**
   - Enable/disable photo downloads
   - Watermark on downloads
   - Resolution limits

3. **EXIF Data**
   - Strip GPS coordinates
   - Remove camera metadata
   - Keep only date_taken

4. **Favorites & User Data**
   - Per-user favorites
   - View history
   - User-specific albums

---

## 9. Development Roadmap

### Phase 1: Foundation (Week 1-2)
**Goal:** Basic project setup and infrastructure

**Tasks:**
1. **Project Initialization**
   - [ ] Create Next.js 14 project with TypeScript
   - [ ] Install dependencies (TailwindCSS, shadcn/ui, React Query)
   - [ ] Configure ESLint, Prettier
   - [ ] Set up Git repository

2. **Database Setup**
   - [ ] Create Prisma schema from existing PostgreSQL schema
   - [ ] Generate Prisma client
   - [ ] Test read-only database connection
   - [ ] Create database query helpers

3. **Design System**
   - [ ] Install shadcn/ui components
   - [ ] Configure Tailwind theme
   - [ ] Create color palette
   - [ ] Set up typography
   - [ ] Create base layout components (Header, Footer)

4. **Authentication (Optional)**
   - [ ] Set up NextAuth.js
   - [ ] Create login page
   - [ ] Implement simple password protection
   - [ ] Add session management

**Deliverables:**
- Working Next.js app with database connection
- Basic layout and navigation
- Authentication (if required)

### Phase 2: Core Features (Week 3-4)
**Goal:** Photo gallery and basic navigation

**Tasks:**
1. **Photo Grid**
   - [ ] Create PhotoGrid component
   - [ ] Implement infinite scroll
   - [ ] Add lazy loading
   - [ ] Create photo card with hover effects

2. **Photo Detail Page**
   - [ ] Create Lightbox component
   - [ ] Add metadata panel
   - [ ] Implement previous/next navigation
   - [ ] Add keyboard shortcuts

3. **Image Optimization**
   - [ ] Configure Next.js Image component
   - [ ] Generate blur placeholders
   - [ ] Test responsive images
   - [ ] Implement lazy loading

4. **API Routes**
   - [ ] Create `/api/photos` endpoint
   - [ ] Create `/api/photos/[id]` endpoint
   - [ ] Add pagination support
   - [ ] Implement error handling

**Deliverables:**
- Working photo gallery with infinite scroll
- Photo detail page with lightbox
- Optimized image loading

### Phase 3: Search & Filtering (Week 5-6)
**Goal:** Comprehensive search functionality

**Tasks:**
1. **People Search**
   - [ ] Create people browser page
   - [ ] Add people filter component
   - [ ] Implement people autocomplete
   - [ ] Create person detail page

2. **Tag Search**
   - [ ] Create tags browser page
   - [ ] Add tag filter component
   - [ ] Implement tag cloud
   - [ ] Create tag detail page

3. **Date Search**
   - [ ] Add date range picker
   - [ ] Implement date presets
   - [ ] Create timeline view (optional)

4. **Combined Search**
   - [ ] Create search page
   - [ ] Implement filter panel
   - [ ] Add URL query parameter sync
   - [ ] Create search results view

**Deliverables:**
- Working search with all filter types
- People and tags browsers
- Combined search functionality

### Phase 4: Polish & Optimization (Week 7-8)
**Goal:** Performance, UX, and visual polish

**Tasks:**
1. **Performance Optimization**
   - [ ] Audit Lighthouse scores
   - [ ] Optimize bundle size
   - [ ] Implement code splitting
   - [ ] Add service worker (PWA)

2. **UX Improvements**
   - [ ] Add loading skeletons
   - [ ] Implement error boundaries
   - [ ] Add toast notifications
   - [ ] Create empty states

3. **Animations**
   - [ ] Add page transitions
   - [ ] Implement photo grid animations
   - [ ] Add hover effects
   - [ ] Create lightbox transitions

4. **Responsive Design**
   - [ ] Test on mobile devices
   - [ ] Optimize touch interactions
   - [ ] Add mobile navigation
   - [ ] Test tablet layouts

**Deliverables:**
- Lighthouse score > 90
- Smooth animations and transitions
- Fully responsive design

### Phase 5: Advanced Features (Week 9-10)
**Goal:** Nice-to-have features

**Tasks:**
1. **User Features**
   - [ ] Favorites system
   - [ ] Create albums (optional)
   - [ ] Share links
   - [ ] Download photos (configurable)

2. **Social Features**
   - [ ] Comments on photos (optional)
   - [ ] Photo ratings (optional)
   - [ ] Share to social media

3. **Advanced Search**
   - [ ] Full-text search
   - [ ] Save searches
   - [ ] Search suggestions
   - [ ] Similar photos

4. **Admin Panel (Light)**
   - [ ] Basic configuration
   - [ ] View usage stats
   - [ ] Manage access

**Deliverables:**
- Enhanced user experience
- Social and sharing features
- Advanced search capabilities

### Phase 6: Testing & Deployment (Week 11-12)
**Goal:** Production-ready application

**Tasks:**
1. **Testing**
   - [ ] Unit tests (Vitest)
   - [ ] Integration tests (Playwright)
   - [ ] Performance testing
   - [ ] Security audit

2. **Documentation**
   - [ ] User guide
   - [ ] Admin documentation
   - [ ] API documentation
   - [ ] Deployment guide

3. **Deployment**
   - [ ] Set up production environment
   - [ ] Configure environment variables
   - [ ] Deploy to Vercel/Railway/VPS
   - [ ] Set up monitoring

4. **Production Optimization**
   - [ ] Configure CDN
   - [ ] Set up error tracking (Sentry)
   - [ ] Add analytics (optional)
   - [ ] Create backup strategy

**Deliverables:**
- Deployed, production-ready application
- Complete documentation
- Monitoring and analytics

---

## 10. Deployment Options

### 10.1 Vercel (Recommended - Easiest)

**Pros:**
- Zero-config deployment for Next.js
- Automatic HTTPS
- Global CDN
- Image optimization built-in
- Free tier available

**Cons:**
- Requires internet access to database
- Can be expensive for high traffic

**Setup:**
```bash
# Install Vercel CLI
npm i -g vercel

# Deploy
vercel deploy

# Set environment variables
vercel env add DATABASE_URL_READONLY
vercel env add NEXTAUTH_SECRET
vercel env add NEXTAUTH_URL
```

**Configuration:**
```json
// vercel.json
{
  "buildCommand": "npm run build",
  "outputDirectory": ".next",
  "devCommand": "npm run dev",
  "installCommand": "npm install",
  "framework": "nextjs",
  "regions": ["iad1"]
}
```

### 10.2 Docker (Self-Hosted)

**Pros:**
- Full control
- Can run on local network
- One-time cost
- No vendor lock-in

**Cons:**
- Requires server management
- Need to handle HTTPS, CDN

**Dockerfile:**
```dockerfile
FROM node:20-alpine AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci

COPY . .
RUN npx prisma generate
RUN npm run build

FROM node:20-alpine AS runner
WORKDIR /app

ENV NODE_ENV production

COPY --from=builder /app/next.config.js ./
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static

EXPOSE 3000
ENV PORT 3000

CMD ["node", "server.js"]
```

**docker-compose.yml:**
```yaml
version: '3.8'

services:
  viewer:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL_READONLY=postgresql://viewer_readonly:password@postgres:5432/punimtag
      - NEXTAUTH_SECRET=your_secret_here
      - NEXTAUTH_URL=http://localhost:3000
    restart: unless-stopped
    depends_on:
      - postgres

  postgres:
    image: postgres:16
    # Use existing PunimTag database
    environment:
      - POSTGRES_DB=punimtag
      - POSTGRES_USER=punimtag
      - POSTGRES_PASSWORD=punimtag_password
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:
```

### 10.3 Railway

**Pros:**
- Easy deployment from GitHub
- Built-in database support
- Affordable pricing
- Good for hobby projects

**Cons:**
- Smaller network than Vercel
- Less mature platform

### 10.4 Netlify

**Pros:**
- Great for static sites
- Free tier
- Good CDN

**Cons:**
- Less optimized for Next.js than Vercel
- Limited API route capabilities

### 10.5 VPS (DigitalOcean, Linode, AWS EC2)

**Pros:**
- Full control
- Predictable pricing
- Can run on private network

**Cons:**
- Requires DevOps knowledge
- Manual scaling

**Recommended:** Use Docker + Caddy for automatic HTTPS

---

## 11. Configuration & Customization

### 11.1 Environment Variables

**.env.local:**
```bash
# Database (Read-Only)
DATABASE_URL_READONLY="postgresql://viewer_readonly:password@localhost:5432/punimtag"

# Authentication
NEXTAUTH_SECRET="generate-with-openssl-rand-base64-32"
NEXTAUTH_URL="http://localhost:3000"

# Optional: OAuth Providers
GOOGLE_ID="your-google-client-id"
GOOGLE_SECRET="your-google-client-secret"

# Site Configuration
NEXT_PUBLIC_SITE_NAME="Family Photos"
NEXT_PUBLIC_SITE_DESCRIPTION="Our family photo collection"
NEXT_PUBLIC_REQUIRE_AUTH="true"

# Feature Flags
NEXT_PUBLIC_ENABLE_DOWNLOADS="false"
NEXT_PUBLIC_ENABLE_FAVORITES="true"
NEXT_PUBLIC_ENABLE_COMMENTS="false"

# Image Serving
NEXT_PUBLIC_PHOTO_BASE_PATH="/path/to/photos"

# Optional: Analytics
NEXT_PUBLIC_ANALYTICS_ID=""

# Optional: Sentry
SENTRY_DSN=""
```

### 11.2 Feature Flags

**config/features.ts:**
```typescript
export const features = {
  auth: {
    enabled: process.env.NEXT_PUBLIC_REQUIRE_AUTH === "true",
    providers: ['google', 'credentials'],
  },
  photos: {
    allowDownload: process.env.NEXT_PUBLIC_ENABLE_DOWNLOADS === "true",
    maxDownloadSize: 1920, // max width/height for downloads
    showExif: false, // Don't expose EXIF data in UI
  },
  social: {
    favorites: process.env.NEXT_PUBLIC_ENABLE_FAVORITES === "true",
    comments: process.env.NEXT_PUBLIC_ENABLE_COMMENTS === "true",
    sharing: true,
  },
  search: {
    fuzzySearch: true,
    fullTextSearch: false, // Requires Elasticsearch
  },
  ui: {
    theme: 'system', // 'light' | 'dark' | 'system'
    defaultView: 'grid', // 'grid' | 'masonry' | 'timeline'
    photosPerPage: 30,
  },
};
```

### 11.3 Branding Customization

**config/branding.ts:**
```typescript
export const branding = {
  siteName: process.env.NEXT_PUBLIC_SITE_NAME || "PunimTag Viewer",
  siteDescription: process.env.NEXT_PUBLIC_SITE_DESCRIPTION || "Photo Gallery",
  logo: "/logo.svg",
  favicon: "/favicon.ico",
  colors: {
    primary: "#3b82f6",
    secondary: "#8b5cf6",
  },
  fonts: {
    heading: "Inter",
    body: "Inter",
  },
};
```

---

## 12. Testing Strategy

### 12.1 Unit Tests (Vitest)

**Components:**
```typescript
// __tests__/components/PhotoCard.test.tsx
import { render, screen } from '@testing-library/react';
import { PhotoCard } from '@/components/gallery/PhotoCard';

describe('PhotoCard', () => {
  it('renders photo correctly', () => {
    const photo = {
      id: 1,
      path: '/photos/test.jpg',
      filename: 'test.jpg',
    };
    
    render(<PhotoCard photo={photo} />);
    expect(screen.getByAlt('test.jpg')).toBeInTheDocument();
  });
});
```

**Utilities:**
```typescript
// __tests__/lib/queries.test.ts
import { searchPhotos } from '@/lib/queries';

describe('searchPhotos', () => {
  it('filters by date range', async () => {
    const results = await searchPhotos({
      dateFrom: new Date('2024-01-01'),
      dateTo: new Date('2024-12-31'),
    });
    
    expect(results.length).toBeGreaterThan(0);
  });
});
```

### 12.2 Integration Tests (Playwright)

**E2E Tests:**
```typescript
// e2e/photo-gallery.spec.ts
import { test, expect } from '@playwright/test';

test('should load photo gallery', async ({ page }) => {
  await page.goto('/');
  
  // Wait for photos to load
  await expect(page.locator('[data-testid="photo-card"]').first()).toBeVisible();
  
  // Check infinite scroll
  await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
  await page.waitForTimeout(1000);
  
  const photoCount = await page.locator('[data-testid="photo-card"]').count();
  expect(photoCount).toBeGreaterThan(30);
});

test('should search by person', async ({ page }) => {
  await page.goto('/');
  
  // Open search
  await page.click('[data-testid="search-button"]');
  
  // Select person
  await page.fill('[data-testid="people-search"]', 'John');
  await page.click('[data-testid="person-option-1"]');
  
  // Apply filter
  await page.click('[data-testid="apply-filters"]');
  
  // Verify results
  await expect(page.locator('[data-testid="person-badge"]')).toContainText('John');
});
```

### 12.3 Performance Tests

**Lighthouse CI:**
```yaml
# .github/workflows/lighthouse.yml
name: Lighthouse CI
on: [push]

jobs:
  lighthouse:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      - run: npm ci
      - run: npm run build
      - run: npm run start &
      - uses: treosh/lighthouse-ci-action@v9
        with:
          urls: |
            http://localhost:3000
            http://localhost:3000/people
            http://localhost:3000/search
          uploadArtifacts: true
          temporaryPublicStorage: true
```

### 12.4 Load Testing (K6)

```javascript
// load-test.js
import http from 'k6/http';
import { check, sleep } from 'k6';

export let options = {
  stages: [
    { duration: '1m', target: 50 },
    { duration: '3m', target: 50 },
    { duration: '1m', target: 0 },
  ],
};

export default function () {
  // Test photo gallery
  let res = http.get('http://localhost:3000/api/photos?page=1&pageSize=30');
  check(res, {
    'status is 200': (r) => r.status === 200,
    'response time < 200ms': (r) => r.timings.duration < 200,
  });
  
  sleep(1);
}
```

---

## 13. Monitoring & Analytics

### 13.1 Error Tracking (Sentry)

**Setup:**
```bash
npm install @sentry/nextjs
npx @sentry/wizard -i nextjs
```

**Configuration:**
```typescript
// sentry.client.config.ts
import * as Sentry from '@sentry/nextjs';

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  tracesSampleRate: 0.1,
  environment: process.env.NODE_ENV,
  beforeSend(event, hint) {
    // Don't send errors in development
    if (process.env.NODE_ENV === 'development') {
      return null;
    }
    return event;
  },
});
```

### 13.2 Analytics (Vercel Analytics or Plausible)

**Vercel Analytics:**
```typescript
// app/layout.tsx
import { Analytics } from '@vercel/analytics/react';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <Analytics />
      </body>
    </html>
  );
}
```

**Plausible (Privacy-Friendly):**
```typescript
// app/layout.tsx
import Script from 'next/script';

export default function RootLayout({ children }) {
  return (
    <html>
      <head>
        <Script
          defer
          data-domain="yoursite.com"
          src="https://plausible.io/js/script.js"
        />
      </head>
      <body>{children}</body>
    </html>
  );
}
```

### 13.3 Performance Monitoring

**Custom Metrics:**
```typescript
// lib/monitoring.ts
import { performance } from 'perf_hooks';

export function measurePhotoLoad() {
  const start = performance.now();
  
  return () => {
    const duration = performance.now() - start;
    
    // Send to analytics
    if (typeof window !== 'undefined' && window.gtag) {
      window.gtag('event', 'photo_load_time', {
        value: Math.round(duration),
        event_category: 'performance',
      });
    }
  };
}
```

---

## 14. Maintenance & Updates

### 14.1 Database Schema Changes

**If PunimTag Schema Changes:**
1. Update Prisma schema
2. Regenerate Prisma client
3. Update TypeScript types
4. Test queries
5. Deploy new version

```bash
# Update schema
npx prisma db pull

# Generate client
npx prisma generate

# Restart app
npm run build
npm run start
```

### 14.2 Dependency Updates

**Regular Updates:**
```bash
# Check outdated packages
npm outdated

# Update dependencies
npm update

# Update major versions (carefully)
npx npm-check-updates -u
npm install
```

### 14.3 Backup Strategy

**Database:**
- Use existing PunimTag backup strategy
- Read-only user can't modify data

**Configuration:**
```bash
# Backup environment variables
cp .env.local .env.backup

# Backup custom configuration
tar -czf config-backup.tar.gz config/
```

---

## 15. Future Enhancements

### 15.1 Short-Term (3-6 months)

1. **Mobile App**
   - React Native or Capacitor
   - Offline support
   - Push notifications

2. **Albums & Collections**
   - Create custom albums
   - Share albums with links
   - Album covers

3. **Advanced Search**
   - Visual similarity search
   - AI-powered search (search by description)
   - Face-based search

### 15.2 Long-Term (6-12 months)

1. **AI Features**
   - Auto-tagging with AI
   - Scene recognition
   - Object detection
   - Smart cropping

2. **Collaboration**
   - Multi-user albums
   - Comments and reactions
   - Photo requests

3. **Integration**
   - Apple Photos import
   - Google Photos import
   - Auto-backup from phone

---

## 16. Cost Estimation

### 16.1 Development Costs

**Freelancer/Agency:**
- Phase 1-2 (Foundation): $5,000 - $8,000
- Phase 3-4 (Features): $8,000 - $12,000
- Phase 5-6 (Polish & Deploy): $5,000 - $8,000
- **Total: $18,000 - $28,000**

**In-House Developer:**
- 12 weeks × 40 hours = 480 hours
- At $50/hour: $24,000
- At $100/hour: $48,000

**DIY (Self-Development):**
- Time investment: 200-300 hours
- Learning curve: High (if new to Next.js)
- Cost: Time + tool subscriptions

### 16.2 Hosting Costs (Monthly)

**Option 1: Vercel (Hobby - Free)**
- Cost: $0
- 100 GB bandwidth
- Unlimited requests
- Good for small families

**Option 2: Vercel (Pro)**
- Cost: $20/month
- 1 TB bandwidth
- Priority support
- Good for medium usage

**Option 3: Railway**
- Cost: $5-20/month
- Based on usage
- Includes database

**Option 4: VPS (DigitalOcean)**
- Cost: $12-24/month (2-4 GB RAM)
- Full control
- Unlimited bandwidth

**Option 5: Self-Hosted (Home Server)**
- Cost: $0/month (after hardware)
- Requires: Raspberry Pi 4 or old laptop
- No recurring costs

### 16.3 Additional Costs

**Domain Name:** $10-15/year
**SSL Certificate:** Free (Let's Encrypt)
**CDN (Cloudflare):** Free tier sufficient
**Email (Transactional):** $0 (Resend free tier)
**Error Tracking (Sentry):** $0 (free tier: 5k events/month)
**Analytics (Plausible):** $9/month or self-hosted (free)

**Total Minimum:** $0-10/month (using free tiers)
**Total Recommended:** $30-50/month (paid hosting + services)

---

## 17. Success Metrics

### 17.1 Technical Metrics

- **Lighthouse Score:** > 90 in all categories
- **API Response Time:** < 200ms (p95)
- **Image Load Time:** < 1s (p95)
- **Page Load Time:** < 2s (p95)
- **Error Rate:** < 0.1%
- **Uptime:** > 99.9%

### 17.2 User Experience Metrics

- **Time to First Photo:** < 1.5s
- **Photos Viewed per Session:** > 20
- **Search Success Rate:** > 80%
- **Mobile Responsiveness:** 100%
- **Accessibility Score:** > 90 (WCAG AA)

### 17.3 Business Metrics

- **User Adoption:** 90% of family members
- **Daily Active Users:** > 50%
- **Session Duration:** > 5 minutes
- **Return Visit Rate:** > 60% weekly
- **User Satisfaction:** > 4.5/5

---

## 18. Risks & Mitigations

### 18.1 Technical Risks

| Risk | Impact | Likelihood | Mitigation |
|------|--------|------------|------------|
| Database connection issues | High | Medium | Connection pooling, retry logic, fallback to cache |
| Image loading performance | High | High | CDN, image optimization, lazy loading, blur placeholders |
| Search query performance | Medium | Medium | Database indices, query optimization, caching |
| Browser compatibility | Low | Low | Use modern standards, test on multiple browsers |
| Mobile performance | Medium | Medium | Responsive images, code splitting, lazy loading |

### 18.2 Security Risks

| Risk | Impact | Likelihood | Mitigation |
|------|--------|------------|------------|
| Unauthorized database access | High | Low | Read-only user, network isolation, strong passwords |
| Photo file access | Medium | Medium | Serve through API, check permissions, rate limiting |
| XSS attacks | Medium | Low | Input sanitization, CSP headers, secure frameworks |
| DDoS attacks | Medium | Medium | Rate limiting, CDN, Cloudflare protection |
| Data breaches | High | Low | HTTPS only, secure sessions, no sensitive data storage |

### 18.3 Operational Risks

| Risk | Impact | Likelihood | Mitigation |
|------|--------|------------|------------|
| Hosting costs exceed budget | Medium | Medium | Monitor usage, set alerts, use free tiers |
| Developer unavailability | Medium | Low | Good documentation, clean code, backup developer |
| Data migration issues | High | Low | Test thoroughly, backup database, rollback plan |
| User adoption failure | High | Low | User testing, feedback loop, training materials |

---

## 19. Comparison with Admin Interface

| Feature | Admin Interface | Photo Viewer |
|---------|----------------|--------------|
| **Purpose** | Photo management | Photo viewing |
| **Users** | Admin only | All family members |
| **Authentication** | Required | Optional |
| **Photo Upload** | ✅ Yes | ❌ No |
| **Face Processing** | ✅ Yes | ❌ No |
| **Person Management** | ✅ Full CRUD | 👁️ View only |
| **Tag Management** | ✅ Full CRUD | 👁️ View only |
| **Search** | ✅ Advanced | ✅ User-friendly |
| **Photo Editing** | ✅ Yes | ❌ No |
| **Bulk Operations** | ✅ Yes | ❌ No |
| **Performance** | ⚡ Good | ⚡⚡ Excellent |
| **UI Complexity** | 🎚️ High | 🎚️ Low |
| **Mobile Experience** | 📱 Functional | 📱 Optimized |
| **Favorites** | ✅ Yes | ✅ Yes |
| **Comments** | ❌ No | ⚠️ Optional |
| **Sharing** | ❌ No | ✅ Yes |
| **Download** | ✅ Yes | ⚠️ Configurable |

---

## 20. Getting Started Checklist

### For the Developer/Agent

- [ ] Read entire plan document
- [ ] Understand PunimTag database schema
- [ ] Set up development environment
  - [ ] Install Node.js 20+
  - [ ] Install PostgreSQL client
  - [ ] Install Git
- [ ] Create Next.js project
  - [ ] Initialize with TypeScript
  - [ ] Install dependencies
  - [ ] Configure Tailwind CSS
- [ ] Set up database connection
  - [ ] Create read-only PostgreSQL user
  - [ ] Test database connection
  - [ ] Set up Prisma
- [ ] Create basic layout
  - [ ] Header component
  - [ ] Footer component
  - [ ] Navigation
- [ ] Implement photo grid
  - [ ] Fetch photos from database
  - [ ] Display in grid
  - [ ] Add lazy loading
- [ ] Follow Phase 1 tasks

### For the Project Owner

- [ ] Review and approve plan
- [ ] Provide database access credentials
- [ ] Decide on authentication requirement
- [ ] Choose hosting platform
- [ ] Set budget and timeline expectations
- [ ] Prepare test data
- [ ] Identify key users for feedback

---

## 21. Conclusion

This plan provides a comprehensive roadmap for creating a modern, performant, and user-friendly photo viewing website that complements the existing PunimTag admin interface. By leveraging Next.js 14, modern UI libraries, and the existing PostgreSQL database, we can deliver a fast, beautiful, and maintainable solution.

**Key Success Factors:**
1. **Performance First:** Optimize images and queries from day one
2. **User Experience:** Simple, intuitive interface
3. **Security:** Read-only access, proper authentication
4. **Maintainability:** Clean code, good documentation
5. **Scalability:** Built to handle thousands of photos

**Next Steps:**
1. Review and approve this plan
2. Set up development environment
3. Begin Phase 1 implementation
4. Iterate based on user feedback

---

## Appendix

### A. Technology Alternatives

**Frontend Frameworks:**
- Next.js 14 ⭐ (Recommended)
- Astro 4
- SvelteKit 2
- Remix
- Nuxt 3 (Vue)

**UI Libraries:**
- shadcn/ui + Tailwind ⭐ (Recommended)
- Material-UI (MUI)
- Chakra UI
- Ant Design
- DaisyUI

**Database ORM:**
- Prisma ⭐ (Recommended)
- Drizzle ORM
- TypeORM
- Kysely

**Image Libraries:**
- Next.js Image ⭐ (Recommended)
- React Photo Album
- React Image Gallery
- PhotoSwipe

### B. Reference Links

**Documentation:**
- Next.js: https://nextjs.org/docs
- Prisma: https://www.prisma.io/docs
- shadcn/ui: https://ui.shadcn.com/
- TanStack Query: https://tanstack.com/query/latest
- Tailwind CSS: https://tailwindcss.com/docs

**Inspiration (Photo Gallery Sites):**
- Google Photos
- iCloud Photos
- Flickr
- 500px
- Unsplash

**GitHub Repositories (Examples):**
- https://github.com/vercel/next.js/tree/canary/examples/with-prisma
- https://github.com/shadcn-ui/taxonomy
- https://github.com/steven-tey/nextjs-postgres-auth-starter

### C. Glossary

- **SSR:** Server-Side Rendering
- **SSG:** Static Site Generation
- **ISR:** Incremental Static Regeneration
- **CDN:** Content Delivery Network
- **ORM:** Object-Relational Mapping
- **PWA:** Progressive Web App
- **CSP:** Content Security Policy
- **EXIF:** Exchangeable Image File Format
- **WCAG:** Web Content Accessibility Guidelines

---

**Document Version:** 1.0
**Last Updated:** November 14, 2025
**Author:** AI Assistant (Claude Sonnet 4.5)
**Status:** Ready for Implementation

