Skip to content

mmousawy/cpg-website

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

680 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Creative Photography Group Website

CI Unit Tests E2E Tests Release GitHub release Next.js React TypeScript Tailwind CSS Supabase Vercel

Community platform for photographers built with Next.js and Supabase. Features event management, photo galleries, and user profiles.

Features

Events

  • Event listings (upcoming/past)
  • Scene events: community-curated photography events (exhibitions, photowalks, talks, workshops, festivals, meetups) at /scene
  • RSVP system with email confirmation
  • Automated email reminders:
    • RSVP reminders (5 days before) for non-attendees
    • Attendee reminders (1 day before) for confirmed RSVPs
  • Calendar integration (Google, Outlook, Apple/iCal)
  • Attendee list with avatars
  • Attendance tracking for admins
  • "You went!" badge on past events you attended
  • reCAPTCHA protection

Photo Galleries

  • User albums with drag-and-drop reordering
  • Community photo albums: shared albums (open or closed membership), event albums auto-created per event (ownerless, any member can add), contributor attribution
  • Photo uploads with EXIF extraction (camera, lens, settings, GPS)
  • Photo captions
  • Album comments and tags with reply threading
  • Public/private visibility
  • Full-size viewing (PhotoSwipe)
  • Masonry grid layout
  • Likes on photos and albums
  • View tracking with "Most viewed this week" sections
  • Bulk photo and album editing (multi-select, batch operations)
  • Add photos to albums modal
  • Challenge badges on photos (shows which challenges a photo was accepted in)
  • Copyright & licensing: per-photo license selection (All Rights Reserved, CC BY, CC BY-NC, CC BY-NC-ND, CC0), automatic watermarking (corner or diagonal text), EXIF copyright embedding
  • Admin moderation (suspend/unsuspend)
  • Content reporting system (report photos, albums, profiles, comments)

Photo Challenges

  • Themed challenges with prompts created by admins
  • Members submit photos (upload or from library)
  • Submission limits per user (optional)
  • Admin review queue (accept/reject with reasons)
  • Bulk review actions
  • Public gallery of accepted submissions
  • Challenge comments
  • Email announcements to members
  • Notifications for submission results
  • Profile badges for challenge participation
  • "Featured in" section on photo detail pages shows accepted challenges

User Profiles

  • Public profile pages (/@username)
  • Custom avatar uploads
  • Bio, website, social links (with auto-detected icons)
  • Interests (up to 10 per profile)
  • Activity stats
  • Self-service account deletion (30-day retention with admin revert)

Authentication

  • Google OAuth
  • Discord OAuth
  • Email/password
  • Password reset
  • Sign-up CTAs on gallery, events, challenges, and members pages

Admin

  • Event CRUD with attendance tracking
  • Scene events moderation at /admin/scene
  • Photo challenge management (create, edit, announce)
  • Submission review queue with bulk actions
  • Album moderation (suspend/unsuspend)
  • Content reports review queue with resolution workflow
  • Newsletter tool: compose and send newsletters to members (respects opt-out preferences)

Search

  • Global search (Cmd/Ctrl+K)
  • Search across albums, photos, members, events, and tags
  • Keyboard navigation support
  • Debounced queries with loading states

Other

  • Dark/light/system theme
  • Responsive design with mobile menu
  • Tag-based caching with use cache
  • Loading skeletons
  • Custom 404 page
  • Help & FAQ pages with contextual help links (including licenses guide)
  • Email notifications (React Email + Resend)
  • In-app notifications with real-time toast notifications (Supabase Realtime)
  • Activity feed page with notification management
  • Weekly notification digest emails
  • Automated cron jobs (Vercel Cron): reminders, digest, hourly events revalidation, weekly content cleanup
  • Changelog page with version history

Tech Stack

Category Technology
Framework Next.js 16 (App Router, Turbopack)
Language TypeScript
UI Library React 19
Database Supabase (PostgreSQL)
Auth Supabase Auth
Storage Supabase Storage
Data Fetching TanStack Query (React Query)
Styling Tailwind CSS 4
Email React Email + Resend
Cron Jobs Vercel Cron
Gallery PhotoSwipe
Drag & Drop dnd-kit
Toasts Sonner
Analytics Vercel Analytics

Getting Started

Prerequisites

  • Node.js 18+
  • Supabase project
  • (Optional) Resend account, reCAPTCHA keys

Environment Variables

Copy .env.example to .env.local and fill in your values:

cp .env.example .env.local

See .env.example for all required variables. Key ones:

  • SUPABASE_SERVICE_ROLE_KEY - Found in Supabase Dashboard → Project Settings → API
  • RESEND_API_KEY - From your Resend dashboard
  • EMAIL_ASSETS_URL - Your production URL (for email images to work)
  • ENCRYPTION_KEY - Generate with openssl rand -hex 32
  • CRON_SECRET - Secret token for cron job authentication (generate a secure random string)

OAuth Configuration

For Production (Supabase Dashboard):

Configure Google and Discord credentials in Supabase Dashboard → Authentication → Providers.

For Local Development (Supabase CLI):

Set these environment variables before running supabase start:

# Google OAuth
export SUPABASE_AUTH_EXTERNAL_GOOGLE_CLIENT_ID="your-google-client-id"
export SUPABASE_AUTH_EXTERNAL_GOOGLE_SECRET="your-google-secret"

# Discord OAuth
export SUPABASE_AUTH_EXTERNAL_DISCORD_CLIENT_ID="your-discord-client-id"
export SUPABASE_AUTH_EXTERNAL_DISCORD_SECRET="your-discord-secret"

To get these credentials:

Set the redirect URI to: http://localhost:54321/auth/v1/callback

Run

npm install
npm run dev

Open http://localhost:3000.

Scripts

npm run dev        # Dev server (Turbopack)
npm run build      # Production build
npm run start      # Production server
npm run lint       # ESLint
npm run lint:fix   # ESLint with auto-fix
npm run typecheck  # TypeScript type checking
npm run test:run   # Run unit tests once
npm run test:ui    # Unit tests with UI
npm run test:e2e   # Playwright E2E tests
npm run analyze    # Bundle analysis (webpack)

Pre-commit Hooks

The project uses husky to run checks before each commit:

  1. Lint staged files - ESLint runs on staged .ts and .tsx files (warnings allowed, errors block)
  2. Type check - Full TypeScript check (tsc --noEmit) - warnings allowed, errors block
  3. Unit tests - Runs all Vitest tests

Warnings are allowed, but errors will block the commit. To bypass (not recommended):

git commit --no-verify -m "message"

CI Pipeline

On pull requests, GitHub Actions runs jobs in sequence:

  1. Lint & Type Check - ESLint and TypeScript validation
  2. Unit Tests - Vitest tests (runs after lint/typecheck)
  3. E2E Tests - Playwright tests with production build (runs after unit tests)

Project Structure

src/
├── app/                    # Pages (App Router)
│   ├── [nickname]/         # User profiles (@username)
│   ├── account/            # Account settings, user galleries
│   ├── admin/              # Admin dashboard
│   ├── api/                # API routes
│   ├── challenges/         # Photo challenges
│   ├── changelog/          # Version history pages
│   ├── events/             # Event pages
│   ├── scene/              # Scene events (community-curated photography events)
│   ├── gallery/            # Public gallery and tag pages
│   ├── members/            # Member discovery pages
│   └── ...
├── components/
│   ├── admin/              # Admin components
│   ├── album/              # Album display components
│   ├── auth/               # Auth components
│   ├── challenges/         # Challenge components
│   ├── events/             # Event components
│   ├── gallery/            # Paginated gallery views
│   ├── layout/             # Header, footer, etc.
│   ├── manage/             # Photo/album management (edit, bulk actions)
│   ├── notifications/      # In-app notifications
│   ├── onboarding/         # New user onboarding flow
│   ├── photo/              # Photo display and lightbox
│   ├── search/             # Global search modal
│   └── shared/             # Reusable UI
├── config/                 # Routes, socials
├── context/                # React context (Auth, Manage, UnsavedChanges)
├── emails/                 # Email templates (React Email)
├── hooks/                  # Custom hooks
├── lib/
│   ├── actions/            # Server actions (likes, notifications)
│   ├── data/               # Server-side data fetching functions
│   ├── notifications/      # Notification creation logic
│   └── sync/               # Real-time sync handlers (Supabase Realtime)
├── types/                  # TypeScript types
└── utils/                  # Utilities, Supabase clients

supabase/
└── migrations/             # Database migrations

Database

Tables

Table Description
profiles User profiles
events Events/meetups
events_rsvps RSVPs and attendance
event_announcements Event email announcement tracking
event_comments Event-comment junction
albums Photo albums (with likes_count, view_count, sharing settings)
album_photos Album-photo junction (with added_by for attribution)
album_comments Album-comment junction
album_likes Album likes
album_tags Album tags
album_views Individual album view events for trending queries
shared_album_members Shared album membership
shared_album_requests Join requests and invites for shared albums
photos Photo metadata + EXIF (with likes_count, view_count)
photo_comments Photo-comment junction
photo_tags Photo tags
photo_likes Photo likes
photo_views Individual photo view events for trending queries
tags Central tags table with usage counts
challenges Photo challenges with prompts and deadlines
challenge_submissions User photo submissions (pending/accepted/rejected)
challenge_announcements Challenge email announcement tracking
challenge_color_draws Challenge color draw records (user/guest color assignments)
challenge_comments Challenge-comment junction
comments Comment content with threading support
notifications In-app notifications
email_types Email preference types
email_preferences User email opt-in/out
feedback User-submitted feedback (bug reports, feature requests)
interests Central interests table with usage counts
profile_interests Profile-interests junction
auth_tokens Email verification & password reset tokens
reports User-submitted content reports (photos, albums, profiles, comments, scene events)
scene_events Community-curated photography events (exhibitions, photowalks, talks, etc.)
scene_event_comments Links comments to scene events
scene_event_interests Users who marked interest in scene events

Storage Buckets

  • cpg-public - General public assets
  • user-avatars - Profile pictures
  • user-photos - Gallery photos
  • event-covers - Event and challenge cover images

Generate Supabase Types

npx supabase gen types typescript --project-id "your-project-id" > ./src/database.types.ts

Or via SSH:

ssh user@domain "npx supabase gen types typescript --db-url 'postgresql://postgres.[tenant-id]:[password]@localhost:5432/postgres' --schema public" > ./src/database.types.ts

Performance

Bundle Optimization

Heavy dependencies are lazy-loaded to reduce initial bundle size:

Library Size Loaded When
PhotoSwipe ~25 KiB User clicks to view full-size image
@dnd-kit ~40 KiB User opens photo/album management
exifr ~15 KiB User uploads photos
Swiper ~30 KiB Activities slider rendered

Image Optimization

  • Modern formats enabled (AVIF, WebP)
  • Responsive sizes attributes on all images
  • Priority loading for LCP images

Bundle Analysis

npm run analyze

Opens an interactive treemap to visualize bundle composition. See docs/performance-optimization.md for details.

Deployment

Deploy to Vercel:

  1. Connect repository
  2. Set environment variables (including CRON_SECRET for reminder emails)
  3. Configure Supabase OAuth redirect URLs for production
  4. Set up RLS and storage policies
  5. Cron jobs are automatically configured via vercel.json (reminders daily 8:00 AM, events revalidation daily 5:01 PM, content cleanup Sundays 3:00 AM UTC)

Deployment Strategy:

  • Main branch commits and PR previews do not trigger production deployments directly
  • Release Please creates releases from main and the release workflow deploys those released commits to Vercel production explicitly

Roadmap

In Progress

  • Event comments
  • Photo challenges

Admin

  • Member management
  • Statistics/analytics dashboard
  • Admin tools

Photos

  • Display EXIF data to viewers
  • Bulk photo actions (delete, edit)
  • Member profile photo stream
  • Manual album cover selection
  • Tags on individual photos
  • Copyright & licensing (per-photo licenses, watermarking, EXIF copyright)
  • Mobile-friendly drag/drop

Events

  • Email reminders before events
  • "Happening now" status badge with timezone-aware event times (Europe/Amsterdam)
  • Event photo albums (auto-created per event, any member can contribute)

Challenges

  • Challenge creation with cover images
  • Submission flow (upload or library)
  • Admin review queue with bulk actions
  • Email announcements
  • Submission result notifications
  • Profile achievement badges
  • Challenge badges on photos (manage grid + photo detail pages)

Engagement

  • Photo/album likes
  • View tracking and stats
  • Follow photographers
  • Activity feed
  • In-app notifications
  • Community photo albums
  • Reply to comments

Discovery

  • Member interests in profile
  • Members page (only for logged-in users)
  • Browse by tags
  • Browse by interests
  • Member discovery sections:
    • Popular interests
    • Recently active members
    • New members
    • Explore by photo style (tags with member counts)
    • Random interests with member samples
  • Search (albums, photos, members, events, tags)
  • Featured/trending galleries (Most viewed this week)

Sharing

  • Social share buttons

Community

  • Forum (discussion boards, threads, categories)

Moderation

  • Report content

About

Resources

Stars

1 star

Watchers

1 watching

Forks

Packages

 
 
 

Contributors