StagePhoto.ru is a professional platform for concert and theater photography, connecting photographers with fans, bands, and event organizers. Built with Laravel 13 and Livewire 4.
π Live Site: stagephoto.ru
- Entity Pages - Dedicated pages for theaters, bands, and individual artists
- Multi-entity Support - Theaters, musical groups, and individuals each have their own profile pages
- Rich Profiles - Bios, stories, contact information, social links, and media galleries
- Hierarchical Relationships - See which individuals belong to which bands/theaters
- Privacy Controls - Contact information visibility based on user role (public, registered, photographers only)
- Multi-language - Entity profiles support Russian, English, and Esperanto
- Full-width responsive album grid - No containers, pure masonry layout
- Dark mode - System preference detection with manual toggle
- Multi-language support - Russian, English, and Esperanto
- Album browsing - Filter by genre, type, and sort options
- Photo viewing - Lightbox modal with full-size images
- Comments - Threaded comments on albums and individual photos
- Rating system - 5-star ratings with user persistence
- Like system - Like/unlike comments
- Album browsing - Browse published albums with grid/list views
- Photographer portfolios - Each photographer has a dedicated albums page
- Album management - Create, edit, publish/unpublish, and delete albums with soft delete
- Photo upload - Single and multiple photo uploads with drag-and-drop support
- Image processing - Automatic WebP conversion and optimization (Intervention Image v4)
- EXIF extraction - Automatic camera settings, capture date, and GPS data extraction
- Status workflow - Albums go through pending β approved β published workflow
- Album covers - Auto-generates square (800Γ800) and hero (2000Γ800) covers
- Unsorted album - Default album for unorganized uploads with bulk organization
- Trash management - Soft delete with restore and permanent delete options
-
- Multi-level albums - Create sub-albums under parent albums (unlimited nesting)
- Visual hierarchy - Tree structure display with indentation (π for root, ββ for sub-albums)
- Parent selection - Choose parent album when creating new albums
- Automatic organization - Upload directly to any level in the hierarchy
- Photographer requests - Request specific photographers
- High-res downloads - Request high-resolution photos
- Print permissions - Request print rights
- Commercial licensing - Request commercial usage rights
- Pending - Album submitted, waiting for admin review
- Approved - Album approved by admin, ready for publication
- Published - Album visible to public
- Rejected - Album rejected with feedback comments
- Blocked - Album blocked due to policy violation
All status changes are tracked with:
- Who changed the status
- When the change occurred
- Comments/reasons for the change
| Category | Technologies |
|---|---|
| Backend | Laravel 13, PHP 8.4+ |
| Frontend | Livewire 4, Alpine.js 3, Tailwind CSS 4 |
| Database | SQLite / MySQL / PostgreSQL |
| Image Processing | Intervention Image |
| Queue | Laravel Queue (Redis/Database) |
| Cache | Laravel Cache (Redis/File) |
- PHP >= 8.4
- Composer
- Node.js & NPM (for Vite)
- SQLite / MySQL / PostgreSQL
- GD or Imagick PHP extension
git clone https://github.com/SirAndrewGotham/StagePhoto.git
cd StagePhotocomposer install
npm installcp .env.example .env
php artisan key:generateConfigure your database in .env:
DB_CONNECTION=sqlite
# or for MySQL:
# DB_CONNECTION=mysql
# DB_HOST=127.0.0.1
# DB_PORT=3306
# DB_DATABASE=stagephoto
# DB_USERNAME=root
# DB_PASSWORD=php artisan migrate:fresh --seednpm run build
# or for development:
npm run devphp artisan serveVisit http://localhost:8000
app/
βββ Livewire/ # Livewire components
βββ Models/ # Eloquent models
β βββ Entity.php # Polymorphic entity model
β βββ EntityProfile.php # Multi-language entity profiles
β βββ EntityContact.php # Contact info with visibility
β βββ EntityMembership.php # Relationships (individuals in bands/theaters)
β βββ Band.php # Band-specific attributes
β βββ Theater.php # Theater-specific attributes
β βββ Individual.php # Individual-specific attributes
β βββ ...
βββ Services/
βββ Http/
database/
βββ factories/ # Model factories
βββ migrations/ # Database migrations
β βββ create_entities_table.php
β βββ create_entity_profiles_table.php
β βββ create_entity_contacts_table.php
β βββ create_entity_memberships_table.php
β βββ create_entity_album_table.php
β βββ create_entity_photos_table.php
βββ seeders/
resources/views/
βββ components/
β βββ frontend/
β βββ pages/
β βββ persona/
β βββ β‘show.blade.php # Entity page component
βββ ...
lang/ # Multi-language files (RU, EN, EO)
βββ en.json
βββ ru.json
βββ eo.json
StagePhoto.ru supports dedicated pages for theaters, musical groups, and individual artists.
| Type | Description | URL Example |
|---|---|---|
| Theater | Performance venues with capacity, founded year, artistic director | /persona/bolshoi-theatre |
| Band | Musical groups with genre, formed year, record label | /persona/kino |
| Individual | Artists, musicians, actors with biographical information | /persona/viktor-tsoi |
- Multi-language Profiles - Each entity has profiles in Russian, English, and Esperanto
- Contact Privacy - Contact information visibility based on user role:
public- Visible to everyoneregistered- Visible to logged-in users onlyphotographers- Visible only to verified photographersadmin- Visible only to administrators
- Relationships - Track which individuals belong to which bands or theaters
- Media Integration - Link albums and tag individual photos to entities
- SEO-friendly URLs - Clean slugs like
/persona/band-name
-- Main entity table (polymorphic)
entities:
- id
- entityable_id (references band/theater/individual)
- entityable_type (class name)
- slug (unique)
- type (theater/band/individual)
- is_published
- settings (JSON for privacy preferences)
-- Multi-language profiles
entity_profiles:
- entity_id
- locale (ru/en/eo)
- name, bio, story
- website, social_links (JSON)
- email, phone, address
- founded_year, genre
- avatar_path, cover_path
-- Contact visibility
entity_contacts:
- entity_id
- contact_type (email/phone/telegram/vk/instagram)
- value
- visibility (public/registered/photographers/admin)
-- Relationships (individuals in bands/theaters)
entity_memberships:
- entity_id (individual)
- parent_entity_id (band/theater)
- role, joined_at, left_at
-- Media links
entity_album (pivot): entity_id, album_id, relationship_type
entity_photos (pivot): entity_id, photo_id// Main entity route
Route::livewire('/persona/{entity:slug}', 'frontend.pages.persona.β‘show')
->name('persona.show');
// Convenience redirects
Route::get('/theater/{entity:slug}', fn($slug) => redirect()->route('persona.show', $slug));
Route::get('/band/{entity:slug}', fn($slug) => redirect()->route('persona.show', $slug));
Route::get('/artist/{entity:slug}', fn($slug) => redirect()->route('persona.show', $slug));All uploaded images are automatically processed using Intervention Image v4:
| Variant | Dimensions | Format | Quality | Usage |
|---|---|---|---|---|
| Original | User-uploaded | Preserved | 100% | Archival |
| Full-size | 1600px max side | WebP | 85% | Photo modal |
| Thumbnail | 600Γ600 (center crop) | WebP | 80% | Grid preview |
| Cover Square | 800Γ800 (center crop) | WebP | 85% | Album cards |
| Cover Hero | 2000Γ800 (cover crop) | WebP | 85% | Album header |
- Camera make and model
- Lens model
- Focal length, aperture, shutter speed, ISO
- Capture date/time
- GPS coordinates (if available)
storage/app/public/stagephoto/
βββ originals/{user_id}/{album_id}/{photo_id}_original.{ext}
βββ webp/{user_id}/{album_id}/
β βββ {photo_id}_full.webp
β βββ {photo_id}_thumb.webp
βββ albums/{user_id}/{album_id}/
βββ cover_square.webp
βββ cover_hero.webp
Photographers can upload single photos with:
- Album selection - Choose existing album or create a new one
- Title & description - Optional metadata for better organization
- EXIF data extraction - Automatically captures camera make/model, lens, settings, and GPS
- WebP conversion - All images are converted to WebP format with optimized quality
- Automatic thumbnails - 600Γ600 center-cropped thumbnails for grid display
- Full-size optimization - 1600px max dimension for modal viewing
- Select or create an album
- Choose a photo file (JPG, PNG, GIF, WebP, max 50MB)
- Add optional title and description
- Submit - system processes and stores all variants
- First photo in album automatically becomes the album cover
Supported languages:
- π·πΊ Russian (default)
- π¬π§ English
- π Esperanto
Language switching uses Laravel's localization with JSON files in /lang.
- UI Elements - Buttons, labels, navigation, modals
- Entity Profiles - Names, bios, stories for all entities
- Legal Pages - Terms, privacy, guidelines, copyright, cookie settings
- Info Pages - For Bands, For Theaters, Photographer Guide
- Upload Components - All upload interfaces and messages
- Full-width layout - No
containerormax-w-*constraints on main content - Responsive grid -
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)) - Dark mode - CSS class-based with system preference detection
- Mobile-first - Responsive breakpoints from 640px to 1920px
# Run all tests
php artisan test
# Run specific test suite
php artisan test --filter=AlbumTest
# Run Livewire component tests
php artisan test --filter=LivewireThis project is proprietary software. All rights reserved.
Andrew Gotham
- π§ Email: andrewgotham@mail.ru
- π¬ Telegram: @AndrewGotham
- π± Phone: +7 (991) 873-9137
- π VK: vk.com/AndrewGotham
- Laravel - The PHP framework
- Livewire - Full-stack framework
- Tailwind CSS - Utility-first CSS
- Alpine.js - Lightweight JavaScript framework
- Intervention Image - Image processing library
| Feature | Status |
|---|---|
| Album grid | β Complete |
| Filter bar | β Complete |
| Album show page | β Complete |
| Photo modal | β Complete |
| Comments | β Complete |
| Rating system | β Complete |
| Like system | β Complete |
| Request system | β Complete |
| Multi-language | β Complete |
| Dark mode | β Complete |
| Image upload | β Complete |
| Image processing | β Complete |
| Soft deletes | β Complete |
| Trash manager | β Complete |
| Unsorted albums | β Complete |
| Admin dashboard | β³ Planned |
This is a private project. For suggestions or bug reports, please contact the author directly.
- Initial release
- Full album management system
- Multi-language support (RU, EN, EO)
- Image processing with WebP conversion
- Comment, rating, and like systems
- Photographer request system
- Soft delete with trash management
Built with β€οΈ in Moscow
---
## Additional Files to Consider
### `CONTRIBUTING.md`
```markdown
# Contributing to StagePhoto.ru
This is a private project. Please contact Andrew Gotham directly for any contributions.
**Contact Information:**
- Email: andrewgotham@mail.ru
- Telegram: @AndrewGotham
- VK: vk.com/AndrewGotham
# Changelog
## [1.0.0] - 2026-04-15
### Added
- Initial release
- Album grid with infinite scroll
- Filter bar with genre, type, and sort options
- Album show page with photo grid
- Photo modal with lightbox navigation
- Comment system (albums and photos)
- Rating system (5-star)
- Like system for comments
- Tag system for albums
- Category system with translations
- Request system for photographers
- Image upload (single, multiple, ZIP)
- WebP conversion and optimization
- Watermark application
- Soft deletes for albums and photos
- Trash manager
- Unsorted albums
- Multi-language support (RU, EN, EO)
- Dark mode---
name: Bug Report
about: Report a bug to help us improve
title: '[BUG] '
labels: bug
assignees: SirAndrewGotham
---
## Description
A clear description of the bug.
## Steps to Reproduce
1. Go to '...'
2. Click on '...'
3. Scroll to '...'
4. See error
## Expected Behavior
What you expected to happen.
## Screenshots
If applicable, add screenshots.
## Environment
- OS: [e.g., macOS]
- Browser: [e.g., Chrome, Safari]
- Version: [e.g., 22]
## Additional Context
Add any other context here.---
name: Feature Request
about: Suggest an idea for this project
title: '[FEATURE] '
labels: enhancement
assignees: SirAndrewGotham
---
## Is your feature request related to a problem?
A clear description of what the problem is.
## Solution
A clear description of what you want to happen.
## Alternatives
Any alternative solutions you've considered.
## Additional Context
Add any other context here.