# Photography Portfolio & Client Galleries A flat-file PHP website for photographers, built for plain shared webhosting. No database, no framework, no build step — upload via FTP/SFTP and it runs. ## Features - **Landing page** — full-screen hero image with an artist introduction. - **Showreel** — the portfolio: selected images displayed full-screen, one per scroll step, on a minimal dark layout. Navigation hides while scrolling. - **Client galleries** — whole event galleries (weddings, events, …) hosted on Hetzner Object Storage (S3). Optionally password-protected and/or with an expiry date after which the gallery is hidden. Visitors load images directly from S3 through short-lived presigned URLs — nothing is proxied through the webhost. - **Topics** — optionally split a gallery into named sections (the days of a trip, the stops of a shoot). Each gets a heading the client can collapse, and its own folder in the ZIP download. Photos without a topic simply show first, so galleries that do not use them look exactly as before. Guest uploads land in their own section automatically. - **Admin backoffice** — a small CMS to edit the front page, manage the showreel, create galleries and bulk-upload images. Uploads go straight from the browser to S3, in full resolution, originals untouched; grid thumbnails are generated in the browser. A gallery can optionally cap its resolution or strip EXIF metadata (camera, lens, timestamps, GPS) from what it stores. - **Flat-file storage** — all content lives in JSON files; admin credentials live in a PHP config file. Password can be changed online. - **Backup & update** — the backoffice can back the installation up and install a new release, both through a central manage server. Backups run themselves on a weekly schedule that needs no cron; updates never do, and stay one deliberate click. Same operations from the command line where cron does exist. ## Version `v1.2.0` — semantic versioning, `vMAJOR.MINOR.PATCH`. The number lives in [app/version.php](app/version.php); the release script writes it and an update carries it along. See [docs/SETUP.md](docs/SETUP.md) §5a. ## Requirements - PHP 8.1+ with `curl` and `openssl` (standard on shared hosting) - Apache with `.htaccess` support (or any server with the document root pointed at this folder) - A private Hetzner Object Storage bucket (for client galleries) ## Quick start ```bash cp config/config.sample.php config/config.php # fill in S3 + site settings cp config/credentials.sample.php config/credentials.php # default login: admin / changeme php -S localhost:8080 router.php # local preview ``` Then open http://localhost:8080/admin/, log in, and **change the password first** (Settings). ## Documentation - [docs/SETUP.md](docs/SETUP.md) — deployment, Hetzner bucket + CORS setup, backups, and how to update an existing installation - [docs/ADMIN-GUIDE.md](docs/ADMIN-GUIDE.md) — using the backoffice - [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) — how it works inside ## Layout Upload the contents of this folder straight into your document root — `index.php` is the home page. ``` index.php landing page ← document root showreel.php gallery/ client galleries (/gallery/?g=) admin/ backoffice assets/ css + js media/ local images (hero + showreel) worker.php background archive builder manage-worker.php background backup + heartbeat app/ PHP library code ┐ config/ config + credentials │ data/ flat-file storage │ inside the docroot, docs/ documentation ├─ but blocked manage-client/ backup + update client │ by .htaccess migrations/ one-time release scripts │ scripts/ release build + cron examples ┘ router.php local dev only (php -S) ```