* fix(pdf): RFC 6266-encode Content-Disposition on quote/invoice PDFs (#1024) The six quote/invoice PDF endpoints interpolated buildPdfFilename()'s result straight into `inline; filename="${filename}"`. That result deliberately preserves non-ASCII (it doubles as the PDF's internal Title metadata), and HTTP header values are latin1 — so a customer label reaching the header directly failed in one of two ways: - U+0080-U+00FF (ä ö ü ß — every German umlaut): no throw. The raw byte goes out and the client reads back a mangled name. Silent corruption. - above U+00FF (Polish ł, Czech ř, Turkish ş, €, Cyrillic, CJK, emoji): Node's setHeader rejects it with ERR_INVALID_CHAR. The throw lands after the PDF buffer is already rendered, so the request 500s. Note this corrects the issue's diagnosis: it reported umlauts as the 500 case, but umlauts are inside latin1 and mangle rather than throw. Both symptoms share this root cause and both are fixed here. Route through buildContentDisposition() (utils/filenameSanitizer, already used by secureImages.js), which emits an ASCII fallback plus the RFC 5987 `filename*=UTF-8''…` form, so the unicode name survives in browsers and the header stays legal. Applied to all six sites: adminQuotes (persisted + preview), adminInvoices (persisted + preview), customer (quote + invoice). Also correct buildPdfFilename's docstring, which advertised the preserved non-ASCII as suitable for Content-Disposition — the exact misreading that produced these call sites. * test(pdf): pin the ASCII fallback for fully non-Latin customer names (#1024) A name written entirely in another script leaves the legacy filename= token with just the document number (Q-2026-0042_.pdf) — filename* carries the real name. That's the intended trade, but it's the token a client without RFC 5987 support actually saves, so assert it stays legal, non-empty and carries the document number rather than leaving it unpinned. * fix(pdf): don't split surrogate pairs when truncating the filename (#1024) Codex review caught this. sanitiseSegment caps each segment at 80 UTF-16 code units, so a cap landing inside an astral character (emoji, rarer CJK) left a dangling high surrogate. encodeURIComponent throws URIError: URI malformed on a lone surrogate, so buildContentDisposition — the helper this PR routes the six PDF endpoints through — 500'd for e.g. company_name = 'a'.repeat(79)+'🎉', well inside the 120-char validator limit. Same 500 the PR set out to remove, reached a different way. Drop the orphaned surrogate instead of widening the cap, so the byte budget the limit exists to protect is unchanged. Tests cover both boundary cases and assert the cap semantics; they fail against the previous slice(). --------- Co-authored-by: Paul Nothaft <paul@MacStudio-von-Paul.local>
PicPeak is a powerful, self-hosted open-source alternative to commercial photo-sharing platforms like PicDrop.com and Scrapbook.de. Built for photographers and event organizers, it makes it simple to share beautiful, time-limited photo galleries with clients while keeping full control over your data and branding.
Important
PicPeak has moved to its own GitHub organization. Docker images are now at
ghcr.io/picpeak/picpeak/{backend,frontend}and active development is onmain. The oldghcr.io/the-luap/...path still responds but its tags are frozen at 2026-05-27 — if updates never arrive, check your image path first. Seedocs/migration-to-org.mdfor the one-linedocker-compose.ymledit.
Contents
- Live Demo
- Quick Start
- Why PicPeak?
- Features
- Documentation
- Comparison
- Tech Stack
- Contributing & Support
- License
🎮 Live Demo
Try PicPeak without installing anything — demo.picpeak.app · admin panel
| Password | |
|---|---|
demo@picpeak.app |
Demo2026! |
The demo resets periodically. Uploaded content may be removed without notice.
🚀 Quick Start
Get PicPeak running in under 5 minutes:
# Clone the repository
git clone https://github.com/PicPeak/picpeak.git
cd picpeak
# Copy the environment template — the defaults work out of the box.
# Machine secrets (JWT, DB, Redis) are auto-generated on first run, and the
# admin account is created in the browser. Edit .env only to customise
# (domain, SMTP, storage paths, …) — nothing is required.
cp .env.example .env
# Start with Docker Compose
docker compose up -d
# Access at http://localhost:3000
On first start, open http://localhost:3000/admin and follow the in-browser setup to create your admin account. Full details — the one-time setup token, Docker file permissions, and ARM64 notes — are in First-run setup.
Updating / release channels: set
PICPEAK_CHANNEL(stabledefault, orbeta) in.env, thendocker compose pull && docker compose up -d. See RELEASING.md for the promotion cadence.
🌟 Why PicPeak?
Unlike expensive SaaS solutions, PicPeak gives you:
- 💰 No Monthly Fees — one-time setup, unlimited galleries
- 🔒 Complete Data Control — your photos stay on your server
- 🎨 White-Label Ready — full branding customization
- 📱 Mobile-First Design — beautiful on all devices
- 🌍 Multi-Language — built-in i18n (EN, DE)
✨ Features
For photographers — drag & drop upload, auto-expiring & password-protected galleries, automated emails, an analytics dashboard, custom themes, a public landing page, and a Live Slideshow projector view that auto-picks-up new uploads during live events.
For clients — clean mobile-optimized galleries, one-click bulk downloads, smart search, optional guest uploads, and download protection (watermarking + right-click prevention).
Technical — Docker-ready, automatic thumbnail generation, external media reference mode, smart archiving of expired galleries, S3-compatible storage backends, webhooks, and security-first defaults (JWT, rate limiting, CORS).
🧾 For studios — CRM & Accounting (Beta, off by default)
- 📝 Quotes → Contracts → Invoices — one deal lineage; cancel-and-reissue (Storno) keeps issued invoices immutable
- ⏱️ Hours Logging & Calendar — per-customer time tracking; admin calendar of events, logged hours, and pending quotes/contracts
- 🧾 Inbound Supplier Invoices & Expenses — capture received invoices (upload/camera, rasterised server-side), categorise, and re-bill costs to clients
- 📊 Tax Report & Accountant Export — period-scoped income/cost report with VAT breakdown; PDF/CSV plus a Treuhänder/Banana (Swiss/LI) journal export
- 🌍 VAT & Multi-currency — single VAT-code registry snapshotted onto each document
Warning
CRM & Accounting — examples only, verify locally. Feature-flagged off by default. Seeded contract blocks are written by the maintainer, not a lawyer; QR-bills/SEPA payloads and every tax, VAT and Treuhänder/Banana figure are computed from your input and defaults and are jurisdiction-specific guidance only. Have your lawyer review contracts, scan a test QR with your bank's app, and verify all numbers with your accountant / Treuhänder / tax authority before customer-facing use. Read the CRM disclaimers first.
📖 Documentation
Full documentation lives at docs.picpeak.app — deployment, admin settings, API, branding, and more.
| Topic | Link |
|---|---|
| 🚀 Deployment (Docker, env, reverse proxy, SSL) | docs.picpeak.app/deployment |
| ⚙️ Admin settings reference | docs.picpeak.app/guides/admin-settings |
| 🎯 Creating events | docs.picpeak.app/guides/creating-events |
| 📽️ Live Slideshow | docs.picpeak.app/features/live-slideshow |
| 💾 Backup & Restore | docs.picpeak.app/guides/backup-restore |
| 🔌 API reference | docs.picpeak.app/api |
| 🪝 Webhooks | docs.picpeak.app/features/webhooks |
| 💾 Storage backends (local / S3) | docs.picpeak.app/features/storage-backends |
| 💻 System requirements & tuning | docs.picpeak.app/deployment/system-requirements |
| 🧾 CRM & Accounting | docs.picpeak.app/features/crm · disclaimers |
| 🗺️ Roadmap | GitHub Issues |
Project meta: Contributing · License · Security · Code of Conduct
📊 Comparison with Alternatives
| Feature | PicPeak | PicDrop | Scrapbook.de | Pixieset |
|---|---|---|---|---|
| Self-Hosted | ✅ | ❌ | ❌ | ❌ |
| Custom Branding | ✅ Full | Limited | Limited | ✅ (paid) |
| Monthly Cost | $0* | $29-199 | €19-99 | ~$60 |
| Storage Limit | Unlimited** | 50-500GB | 100-1000GB | 3GB–Unlimited*** |
| Client Uploads | ✅ | ✅ | ✅ | Limited |
| API Access | ✅ | Paid | ❌ | ❌ |
| Open Source | ✅ | ❌ | ❌ | ❌ |
| Customer Accounts | ✅ | ❌ | ❌ | ✅ |
| Quotes / Contracts / Invoices | 🧪 Beta | ❌ | ❌ | ✅ |
| Incoming Invoices & Accounting | 🧪 Beta | ❌ | ❌ | ❌ |
*You bring your own server and, optionally, a domain. **Limited only by your server storage. ***Pixieset's "unlimited" is photos only; video is capped by plan. 🧪 Beta = built but feature-flagged off by default.
🏗️ Tech Stack
- Backend: Node.js, Express, SQLite/PostgreSQL
- Frontend: React, Tailwind CSS, Framer Motion
- Storage: Local filesystem (default) or S3-compatible object store (AWS S3, MinIO, R2, B2, Wasabi, Spaces) — see Storage Backends
- Email: SMTP with customizable templates
- Analytics: Privacy-focused with Umami integration
- External media: point PicPeak at
EXTERNAL_MEDIA_ROOTto reference existing originals read-only, index quickly, and generate thumbnails on demand
📸 Screenshots
Click to see the admin dashboard, analytics, and event management
🎛️ Admin Dashboard
📊 Analytics & Insights
📁 Event Management
🤝 Contributing
We love contributions! PicPeak is built by photographers, for photographers — whether you're fixing bugs, adding features, or improving docs. See the Contributing Guide to get started.
Found a security issue? Please open a security issue. See SECURITY.md for the policy.
☕ Support the Project
PicPeak is free, open source, and self-hostable forever. If it saves you time or replaces a paid subscription, consider buying me a coffee — it directly funds new features, bug fixes, and keeping the demo + docs running. You can also ⭐ star the repo, share it, file good bug reports, or open a PR.
🙏 Acknowledgments
PicPeak is inspired by the best features of commercial platforms while remaining completely open source. It's developed with AI assistance, but human-tested end-to-end, security-audited, and human-reviewed for quality.
👥 Contributors
A huge thank you to the people whose code, reports, and feedback have shaped PicPeak:
@the-luap — creator and lead maintainer
- Gallery foundation (events, uploads, sharing, download protection, templates)
- Backup & restore, analytics, branding/theming
- The architecture every later feature builds on
- Native Apple Silicon multi-arch images
- CRM & accounting suite (quotes/contracts/invoices)
- Hours logging & Treuhänder/Banana tax export
- Gallery header/banner decoupling
@Rekoo-PS — bug reports & product feedback
- Login-loop fix, mobile-lightbox overhaul, bulk-delete workflow
- Also a BuyMeACoffee supporter
If you've contributed and aren't listed here, please open a PR — this list is meant to grow.
📄 License
PicPeak is released under the MIT License. Use it freely for personal or commercial projects.
Made with ❤️ by photographers, for photographers
Homepage ·
Live Demo ·
Documentation ·
Support

