PhotoBattle

Competitive photo battle platform: Photographers submit photos, voters choose their favorites in 1-on-1 duels, and an Elo rating system calculates objective rankings.

Architecture

Hybrid approach: Event Sourcing for the core competitive domains, CRUD for the rest.

┌─────────────────────────────────────────────┐
│           FotoBattle Domains                │
├──────────────────┬──────────────────────────┤
│   CRUD           │   Event Sourced (ES)     │
├──────────────────┼──────────────────────────┤
│ User Management  │ Battle Domain            │
│ Photo Management │ Rating Domain            │
│ Social Features  │ Infrastructure           │
│ Read-Side        │  (Event Store)           │
└──────────────────┴──────────────────────────┘

Roles

Role Description
Visitor View gallery, leaderboard, and top photos
Voter Registration with email/password. Vote, comment, like, follow
Photographer Must be approved by admin. Upload photos and submit them to Battles
Admin Approve photographers, manage Battles, moderation, statistics

Features

MVP (P0)

ID Feature Description
PHOTO-1 User Registration & Login Email/password, bcrypt, rate limiting (5 attempts → 15-minute lockout)
PHOTO-2 Photographer Approval & Roles Application, admin approval, role change
PHOTO-3 Photo Upload & Management Upload to battles, status management (pending → active → withdrawn)
PHOTO-4 Event Store & Aggregate Infrastructure MySQL-based event sourcing with optimistic locking
PHOTO-5 1v1 Photo Battle & Voting Pairwise matchmaking (min. 10 photos), duplicate protection (24h)
PHOTO-6 Elo Rating Engine K-factor: 40 (new) / 20 (established), Floor 100, Start 1500
PHOTO-7 Ranking & Leaderboard Photo and photographer rankings from rating_history

Social (P1)

ID Feature Description
PHOTO-8 Comments Comments on photos
PHOTO-9 Likes Favorites toggle (unique per user+entry)
PHOTO-10 Follow System Follow photographers
PHOTO-11 User Profiles & Galleries Profile with avatar, bio, photo gallery

Advanced (P2)

ID Feature Description
PHOTO-12 Categories & Tags Battle and entry categorization
PHOTO-13 Battle History & Statistics Voting volume, top voters, battle statistics
FOTO-14 Notifications In-app notifications

Elo Rating

Erwartete Punktzahl:  E_A = 1 / (1 + 10^((R_B - R_A) / 400))
Neues Rating:         R'_A = R_A + K × (S - E_A)

K-Faktor:  40 (< 30 Battles)  /  20 (≥ 30 Battles)
Floor:     100 (Ratings fallen nie unter 100)
Startwert: 1500

Event Store

Custom implementation (no external EventStore):

  • append(AggregateRoot) — Write event to event_store table
  • getEvents(aggregateId) — Load all events for an aggregate
  • Optimistic locking via aggregate_id + event_version (Unique)
  • ConcurrencyException for version conflicts
  • Projections: elo_rating to battle_entries (Cache), rating_history (Leaderboard)

Routing

Public

Method Path Description
GET / Home page (votable battles)
GET/POST /register Registration
GET/POST /login Login
POST /logout Logout
GET /leaderboard Photo Rankings
GET /leaderboard/photographers Photographer Rankings
GET /vote/{id} Battle Arena (1v1)
POST /api/vote Voting (AJAX)
GET /entry/{id} Photo Details Page
POST /api/favorite/{id} Like Toggle

Authenticated

Method Path Description
GET/POST /apply Photographer Application
GET /my-entries My Photos
GET /profile/{username} User Profile
GET /following Following List
POST /api/follow/{id} Follow Toggle

Admin

Method Path Description
GET/POST /admin/battles Create and manage battles (draft → open → voting → closed)
GET/POST /admin/photographers Approve applications
GET/POST /admin/users User management
GET /admin/statistics Statistics and ratings

Gallery Integration (HMAC-protected)

Method Path Description
POST /api/gallery-submit Send photo from Gallery to Battle
POST /api/gallery-withdraw Withdraw photo from Battle

Database (FotoBattle Tables)

User & Auth

Table Description
users Username, Email, Password Hash, Role (voter/photographer/admin), Avatar, Bio
photographer_applications Applications with status (pending/approved/rejected)
login_attempts Rate limiting by IP hash

Battles & Voting

Table Description
battles Title, Status (draft/open/voting/closed), Timeframe
battle_entries Photos in Battles, FK on images.id (Gallery), Elo Rating Cache
battle_votes Votes (left/right/winner Entry, User, IP hash)

Rating & Events

Table Description
rating_history Elo history per entry (old → new, K-factor, opponent)
event_store Event Sourcing (aggregate_id, type, data JSON, version)

Social

Table Description
comments Comments on entries
favorites Likes (unique per user+entry)
follows Follow relationships (unique per pair)
notifications In-app notifications

Metadata

Table Description
categories + entry_categories Categories (M:N)
tags + entry_tags Tags (M:N)

Tests

19 PHPUnit test files:

  • Event Store & Aggregate (2 tests)
  • Elo calculation & Rating Service (2 tests)
  • Auth, Battle, Vote, Entry Services (4 tests)
  • Social Services: Comment, Favorite, Follow, Profile, Notification (5 tests)
  • Leaderboard, Category, Role, Statistics, Tag, RateLimiter (6 tests)