I'm rebuilding Flickr!

Well, maybe not, but here’s a description of my recently created photo-sharing webapp. And I have many more ideas to improve this.

Photo Sharing WebApp - Feature Overview

A modern, full-stack travel photo gallery built with Next.js 15, featuring intelligent photo management, interactive maps, and seamless cloud storage integration.


🌟 Highlights

  • Zero-Database Architecture: Uses Vercel Blob for photos and Redis (via Vercel KV) for metadata
  • Privacy Controls: Public, unlisted, and private album visibility options
  • Interactive World Map: Displays photo locations extracted from EXIF GPS data
  • Responsive Design: Optimized for all devices from mobile to desktop
  • Admin Panel: Complete photo management without leaving the browser

Album Management

  • Collapsible Albums: Each travel album can be expanded or collapsed independently
  • Smart Defaults: Most recent album automatically expands on page load
  • Album Metadata: Title, description, and date for each collection
  • Privacy Levels:
    • Public: Visible to everyone on the homepage
    • Unlisted: Only accessible via direct link
    • Private: Visible only to authenticated admins

Photo Display

  • Grid Layout Options: Three display modes to suit your preference
    • Comfortable: Spacious 2-5 column grid with square thumbnails
    • Compact: Dense 3-6 column grid for maximum photos per screen
    • Masonry: Pinterest-style layout preserving original aspect ratios
  • Layout Persistence: Grid preference saved in browser localStorage
  • Newest First: Photos automatically sorted by upload date (newest at top-left)
  • Rounded Thumbnails: Modern, elegant aesthetic with subtle shadows
  • Hover Effects: Smooth scale and brightness animations on interaction
  • Upload Date Display: Shows when each photo was added (in comfortable/masonry modes)
  • Full-Screen Experience: Distraction-free photo viewing
  • Navigation Controls:
    • Keyboard arrows (← →) for previous/next
    • On-screen navigation buttons
    • ESC key to close
  • Photo Captions: Optional descriptions displayed below photos
  • Smooth Transitions: Animated photo changes with loading states
  • Mobile Optimized: Touch-friendly controls and responsive sizing

Interactive Features

  • World Map Integration:
    • Leaflet-based interactive map
    • Clustered markers for photos with GPS coordinates
    • Click markers to view photos from that location
    • Automatic bounds fitting to show all locations
    • Album information in marker popups
  • Random Featured Photo:
    • Displays a random photo from all albums on homepage
    • Changes on each page load
    • Shows caption if available
  • Mini Thumbnails:
    • Collapsed albums show preview of first 5 photos
    • Smooth animation on expand/collapse
    • Photo count badge for albums with 6+ photos

Content Syndication

  • RSS Feed: Subscribe to new photo uploads at /feed.xml
  • Analytics: Vercel Analytics integration for visitor tracking

🔐 Admin Panel Features

Authentication

  • Vercel Authentication: Secure login using your Vercel account
  • Protected Routes: /admin and sub-routes require authentication
  • Session Management: Logout functionality with redirect

Album Management

  • Create Albums:
    • Title (required)
    • Description (optional)
    • Date (optional, ISO format)
    • Privacy setting (public/unlisted/private)
  • Edit Albums:
    • Update all metadata including privacy settings
    • Inline editing interface
    • Cancel without saving
  • Delete Albums:
    • Confirmation dialog before deletion
    • Automatically deletes all photos in album
    • Removes both metadata and blob files

Photo Management

  • Bulk Upload:
    • Multi-file selection support
    • Drag-and-drop interface
    • Progress tracking for each file
    • Batch processing with individual status indicators
    • Total size calculation before upload
  • Upload Features:
    • Automatic EXIF extraction (GPS, camera, capture settings)
    • Optional captions (for single photo uploads)
    • Format support: JPG, PNG, WebP, and more
    • Visual upload progress bar
    • Success/error status for each file
  • Photo Organization:
    • Clickable photo count badges link to management page
    • Grid view of all photos in an album
    • Displays metadata: upload date, GPS, camera info
    • Empty state with call-to-action
  • Delete Photos:
    • Individual photo deletion from management page
    • Confirmation dialog with photo caption
    • Removes both Vercel Blob file and metadata
    • Instant UI update on successful deletion

Admin Dashboard

  • Album Overview:
    • List of all albums (sorted by date, newest first)
    • Photo count for each album
    • Privacy status indicators with icons
    • Quick access buttons (Edit, Upload, Manage, Delete)
  • Status Indicators:
    • 🌍 Public: Green badge with globe icon
    • 🔗 Unlisted: Yellow badge with link icon
    • 🔒 Private: Red badge with lock icon
  • Responsive Layout: Optimized for tablet and mobile management

🛠️ Technical Architecture

Frontend

  • Framework: Next.js 15 with App Router
  • Language: TypeScript for type safety
  • Styling: Tailwind CSS with custom configurations
  • Icons: Lucide React for consistent iconography
  • Image Optimization: Next.js Image component with automatic optimization
  • State Management: React hooks (useState, useEffect)
  • Client-Side Rendering: Dynamic imports for map components (SSR bypass)

Backend

  • API Routes: Next.js server-side API endpoints
  • File Upload: FormData with multipart handling
  • EXIF Parsing: exif-parser library for metadata extraction
  • Image Processing: Automatic format conversion and compression

Storage & Database

  • Photo Storage: Vercel Blob (CDN-backed object storage)
  • Metadata Storage: Redis via Vercel KV Marketplace integration
  • Database Client: ioredis for Redis connections
  • Data Structure:
    • Albums stored as JSON array in albums key
    • Photos stored per album in photos:{albumId} keys
    • No SQL database required

Deployment

  • Platform: Vercel
  • Environment:
    • BLOB_READ_WRITE_TOKEN: Vercel Blob access
    • KV_REDIS_URL: Redis connection string
  • CDN: Automatic edge caching for photos and pages
  • Domain: Custom domain support with automatic SSL

📊 Data Models

Album

{
  id: string;                          // album_timestamp_random
  title: string;                       // "Japan 2025"
  description: string;                 // Trip description
  date: string;                        // ISO date "2025-01-15"
  createdAt: number;                   // Unix timestamp
  visibility: "public" | "unlisted" | "private";
}

Photo

{
  id: string;                          // photo_timestamp_random
  albumId: string;                     // Reference to album
  blobUrl: string;                     // Vercel Blob URL
  caption?: string;                    // Optional description
  uploadedAt: number;                  // Unix timestamp
  metadata?: {
    gps?: {
      latitude: number;
      longitude: number;
      altitude?: number;
    };
    camera?: {
      make?: string;                   // "Canon"
      model?: string;                  // "EOS R5"
      lens?: string;
    };
    capture?: {
      dateTaken?: string;              // When photo was taken
      exposureTime?: string;           // "1/1000"
      fNumber?: number;                // 2.8
      iso?: number;                    // 100
      focalLength?: number;            // 50mm
    };
    dimensions?: {
      width: number;
      height: number;
    };
    orientation?: number;
  };
}

🎯 User Flows

Visitor Journey

  1. Land on homepage → See random featured photo
  2. View interactive world map with photo locations
  3. Browse albums (newest expanded by default)
  4. Click photo → Open lightbox viewer
  5. Navigate with arrows or keyboard
  6. Subscribe to RSS feed for updates

Admin Journey

  1. Navigate to /admin → Vercel auth redirect
  2. View dashboard with all albums and photo counts
  3. Create new album: Click “Create Album” → Fill form → Set privacy
  4. Upload photos: Click “Upload Photos” → Drag files → Add captions → Upload
  5. Manage photos: Click photo count badge → View grid → Delete unwanted photos
  6. Edit album: Click “Edit” → Update metadata/privacy → Save
  7. Delete album: Click “Delete” → Confirm → Album and all photos removed

🚀 Performance Optimizations

  • Image Optimization: Next.js automatic WebP conversion and lazy loading
  • CDN Caching: Vercel Edge Network caches photos globally
  • Code Splitting: Dynamic imports for heavy components (map)
  • Responsive Images: Multiple sizes served based on viewport
  • Minimal JavaScript: Client-side JS only where needed
  • Fast Page Loads: Static generation where possible
  • Efficient Queries: Single Redis calls for album/photo lists
  • LocalStorage: Grid layout preference cached client-side

🎨 Design Philosophy

Visual Design

  • Color Palette: Blue gradient accents with dark mode support
  • Typography: Clear hierarchy with responsive font sizes
  • Spacing: Generous whitespace for comfortable reading
  • Shadows: Layered depth with hover elevations
  • Animations: Subtle 300ms transitions throughout
  • Icons: Consistent Lucide icon library

User Experience

  • Progressive Disclosure: Collapsed albums reduce cognitive load
  • Keyboard Navigation: Full keyboard support in lightbox
  • Touch Optimization: Tap targets sized for mobile
  • Loading States: Spinners and skeletons during data fetches
  • Error Handling: User-friendly error messages
  • Confirmation Dialogs: Prevent accidental deletions

Accessibility

  • Semantic HTML: Proper heading hierarchy
  • Focus States: Visible keyboard focus indicators
  • Alt Text: Image descriptions for screen readers
  • Color Contrast: WCAG AA compliance
  • Responsive Design: Works on all screen sizes

📈 Use Cases

Personal Travel Blog

  • Document trips with organized photo albums
  • Share adventures with family and friends
  • Keep private memories secure with privacy controls

Photography Portfolio

  • Showcase work by location or project
  • Professional presentation with grid layouts
  • Metadata display for technical details

Family Photo Sharing

  • Create unlisted albums for family-only access
  • Easy upload from mobile devices
  • No complicated software required

Educational Projects

  • Demonstrate modern web development practices
  • Showcase Next.js 15 App Router patterns
  • Example of cloud storage integration

🔮 Future Enhancement Ideas

Photo Features

  • Bulk photo deletion (select multiple)
  • Photo reordering (drag-and-drop)
  • Photo editing (crop, rotate, filters)
  • Download full-resolution images
  • Print/photo book export

Search & Discovery

  • Full-text search across captions
  • Tag system for categorization
  • Timeline view (chronological)
  • Favorites/highlights collection

Social Features

  • Photo comments system
  • Social media share buttons
  • Individual photo permalinks
  • Public photo embeds

Analytics

  • View count tracking
  • Popular photos dashboard
  • Storage usage metrics
  • Visitor analytics

Mobile App

  • Native iOS/Android apps
  • Offline photo viewing (PWA)
  • Camera integration for uploads
  • Push notifications for new albums

💡 Why This Architecture?

Serverless-First

  • No server maintenance: Vercel handles infrastructure
  • Auto-scaling: Handles traffic spikes automatically
  • Global CDN: Photos served from edge locations
  • Cost-effective: Pay only for usage

Modern Stack

  • Type Safety: TypeScript catches bugs at compile time
  • React 19: Latest React features and optimizations
  • Next.js 15: App Router for improved performance
  • Tailwind CSS: Utility-first styling for rapid development

Cloud Storage

  • Vercel Blob: Purpose-built for media storage
  • Redis: Fast key-value storage for metadata
  • No database: Simpler architecture, fewer failure points
  • Atomic operations: Redis ensures data consistency

📝 Technical Decisions

Why ioredis instead of @vercel/kv?

The Vercel KV Marketplace integration provides a standard Redis URL, which works better with the ioredis package. This offers more flexibility and standard Redis features.

Why client-side rendering for the homepage?

The random featured photo and map interactions require JavaScript. Client-side rendering provides the most interactive experience while keeping the codebase simple.

Why separate manage page instead of edit-in-place?

Separating photo management from display keeps each view focused and performant. The upload page stays lightweight for quick uploads, while the manage page provides detailed controls.

Why not use a traditional database?

For a photo gallery, the access patterns are simple (list albums, list photos). Redis provides sub-millisecond reads and sufficient storage for metadata, while Vercel Blob handles the large files. This eliminates the need for PostgreSQL/MySQL.


🏗️ Project Structure

voyages-photo-gallery/
├── app/
│   ├── admin/
│   │   ├── manage/[albumId]/       # Photo management page
│   │   ├── upload/[albumId]/       # Photo upload page
│   │   └── page.tsx                # Admin dashboard
│   ├── api/
│   │   ├── admin/
│   │   │   ├── albums/
│   │   │   │   ├── [albumId]/      # Update/delete album
│   │   │   │   └── route.ts        # Create album
│   │   │   ├── photos/
│   │   │   │   └── route.ts        # Delete photo
│   │   │   └── upload/
│   │   │       └── route.ts        # Upload photos
│   │   ├── albums/
│   │   │   └── route.ts            # Get all albums (public)
│   │   ├── photos/
│   │   │   └── route.ts            # Get all photos (public)
│   │   └── auth/                   # Login/logout
│   ├── feed.xml/
│   │   └── route.ts                # RSS feed generation
│   ├── layout.tsx                  # Root layout with Analytics
│   ├── page.tsx                    # Public gallery homepage
│   └── globals.css                 # Global styles
├── components/
│   ├── AlbumSection.tsx            # Collapsible album component
│   ├── GridLayoutToggle.tsx        # Layout switcher
│   ├── Lightbox.tsx                # Photo viewer
│   └── WorldMap.tsx                # Interactive map
├── lib/
│   └── db.ts                       # Redis database functions
├── types/
│   └── index.ts                    # TypeScript type definitions
├── middleware.ts                   # Auth protection
└── package.json                    # Dependencies

🎓 Learning Resources

This project demonstrates:

  • Next.js 15 App Router patterns
  • TypeScript in React applications
  • Tailwind CSS utility-first styling
  • Vercel deployment and storage
  • Redis data modeling
  • EXIF metadata extraction
  • Responsive design principles
  • File upload handling
  • Authentication middleware
  • Dynamic routing
  • Client/server component separation

Perfect for developers learning modern full-stack web development!


📄 License

MIT License - Feel free to use this as a learning resource or starting point for your own projects.


🤝 Contributing

Built with Claude Code - AI-assisted development for rapid prototyping and feature implementation.

Technologies: Next.js 15 • React 19 • TypeScript • Tailwind CSS • Vercel • Redis • Leaflet

Built by: AI enthusiasts exploring the intersection of modern web development and AI-assisted coding