A Puzzle game made from your own photos.
  • TypeScript 97.7%
  • Shell 1.3%
  • Dockerfile 0.8%
Find a file
2026-08-30 16:38:27 -05:00
backend feat: piece groups lock adjoining pieces anywhere and move/tray as one unit 2026-08-30 06:38:59 -05:00
docker fix: bootstrap base schema on every boot to repair reused postgres volume 2026-08-30 06:38:52 -05:00
docs fix: bootstrap base schema on every boot to repair reused postgres volume 2026-08-30 06:38:52 -05:00
frontend feat: zoom the puzzle canvas and have the pieces grow with it 2026-08-30 16:38:27 -05:00
.dockerignore Add Docker production deployment and improve E2E tests 2026-07-22 19:56:17 -05:00
.env.example Complete privacy-first jigsaw puzzle platform 2026-07-18 06:40:27 -05:00
.env.production.example Add Docker production deployment and improve E2E tests 2026-07-22 19:56:17 -05:00
.gitignore Update docs: mark phases complete, refresh README and guides 2026-08-15 20:18:17 -05:00
AGENTS.md feat: zoom the puzzle canvas and have the pieces grow with it 2026-08-30 16:38:27 -05:00
docker-compose.prod.yml Add Docker production deployment and improve E2E tests 2026-07-22 19:56:17 -05:00
docker-compose.yml fix: allow LAN thumbnail loading via FRONTEND_URL defaults 2026-08-30 16:38:27 -05:00
Dockerfile Add automatic database migration system 2026-08-23 13:30:07 -05:00
encrypt_work_checklist.md Update encryption checklist: phases 4-5 complete 2026-08-23 07:23:47 -05:00
init.sql Add piece outlines to Wall of Glory frames 2026-08-23 08:23:49 -05:00
LICENSE Initial commit 2026-07-17 20:49:22 +00:00
product_requirements.md Complete privacy-first jigsaw puzzle platform 2026-07-18 06:40:27 -05:00
README.md feat: zoom the puzzle canvas and have the pieces grow with it 2026-08-30 16:38:27 -05:00
social_sharing_build_plan.md Update social sharing build plan to mark as complete 2026-08-23 08:10:06 -05:00
start.sh Add Docker production deployment and improve E2E tests 2026-07-22 19:56:17 -05:00

Privacy-First Custom Jigsaw Puzzle Platform

A privacy-focused web application that lets you create custom jigsaw puzzles from your own photos. Built with zero-knowledge encryption to ensure your photos remain private.

Features

  • Custom Puzzles: Create jigsaw puzzles from your own photos with adjustable difficulty (4-5000 pieces)
  • Zero-Knowledge Encryption: Optional client-side encryption ensures only you can view your encrypted photos
  • Progress Saving: Auto-saves puzzle progress every 15 seconds
  • Upload Progress Tracking: Real-time progress feedback with speed and ETA during photo uploads
  • Full-Board Image Display: Puzzle image fills the entire board area for an immersive experience
  • Guide Overlay: Optional ghost image overlay to help with piece placement (adjustable opacity)
  • Responsive Design: Works seamlessly on desktop and mobile devices with automatic tray repositioning on orientation change
  • Full Screen Mode: Immersive fullscreen puzzle solving with touch-optimized controls
  • Dark Mode: Full dark mode support
  • Admin Dashboard: User management, site settings, and IP blocking
  • Wall of Glory: Showcase completed puzzles in a customizable gallery with piece outlines, drag-and-drop positioning, and resize handles
  • Social Sharing: Share completed puzzles and galleries with public links, with optional gallery access control
  • Photo Encryption: Full encryption/decryption flow with passphrase management and re-encryption support
  • Photo Usage Badges: Puzzle-piece and checkmark count badges on photos that have been used to create puzzles, shown on both the upload page and puzzle creation page
  • Piece Groups: Adjoining pieces lock together wherever you place them, move as a single unit, and tray as one compact block — "Tray All Unlocked" and drag-over-tray keep groups intact. A group only locks in place after it snaps as a whole unit into its solved position; an off-target group always stays draggable
  • Zoom & Pan: Zoom grows both the puzzle and the tray 1:1 up to 6x (tray capped at 25% of the canvas width, oversized trays fit-to-tray). Mouse wheel, trackpad pinch (ctrl+wheel), and multi-touch two-finger pinch are all anchored at the pointer; locked pieces and piece groups are never disturbed by zooming or panning. The tray also captures wheel/scroll input in a small margin to its left, so aiming a few pixels off the tray still scrolls the tray instead of zooming the board
  • Audit Logging: Track all user and admin actions

Tech Stack

Frontend

  • Next.js 16 (App Router)
  • TypeScript
  • Tailwind CSS
  • PixiJS (puzzle canvas rendering)

Backend

  • Node.js + Express
  • TypeScript
  • Lucia Auth (authentication)
  • PostgreSQL (database)
  • MinIO (S3-compatible object storage)
  • ClamAV (virus scanning)

Infrastructure

  • Docker Compose
  • Zero-knowledge encryption (Web Crypto API)

Quick Start

Prerequisites

  • Docker and Docker Compose
  • Node.js 20+ (for development)
  • npm or yarn (for development)

Option 1: Docker Hub Image (Easiest)

Pull and run the pre-built image with only the infrastructure services:

  1. Create a project directory and add the production compose file:
mkdir puzzle && cd puzzle
curl -sO https://raw.githubusercontent.com/<repo>/main/docker-compose.prod.yml
curl -sO https://raw.githubusercontent.com/<repo>/main/.env.production.example
cp .env.production.example .env
# Edit .env with your secure passwords
  1. Start everything:
docker compose -f docker-compose.prod.yml up -d
  1. Open http://localhost:8080 and register your first user (becomes admin automatically).

Services:

Option 2: Build from Source (Docker Compose)

Build and run the full stack locally with Docker:

  1. Clone the repository:
git clone <repository-url>
cd get_puzzles
  1. Start all services (builds backend and frontend images, starts Postgres, MinIO, and ClamAV):
docker compose up -d --build
  1. Open http://localhost:3002 in your browser

  2. Register your first user - they will automatically become an admin

Services:

Stop all services:

docker compose down

Stop and remove data volumes:

docker compose down -v

Option 3: Development Setup

For local development with hot reload:

  1. Clone the repository:
git clone <repository-url>
cd get_puzzles
  1. Copy the backend environment file:
cp .env.example backend/.env
  1. Update environment variables in backend/.env as needed.

  2. Start infrastructure services (Postgres, MinIO, ClamAV):

docker compose up -d postgres minio clamav
  1. Install and start the backend:
cd backend
npm install
npm run dev
  1. Install and start the frontend (in a new terminal):
cd frontend
npm install
npm run dev
  1. Open http://localhost:3000 in your browser

  2. Register your first user - they will automatically become an admin

View logs (production):

docker compose -f docker-compose.prod.yml logs -f

Stop all services:

docker compose -f docker-compose.prod.yml down

Stop and remove volumes:

docker compose -f docker-compose.prod.yml down -v

Documentation

Testing

Unit tests (136 backend tests):

cd backend
npm test

Backend E2E tests (31 tests — requires the full stack running on http://localhost:3002):

cd backend
npx playwright test

Frontend E2E tests (49 tests x 5 browsers, 245 total — starts its own dev server):

cd frontend
npx playwright test

The project includes:

  • 89 unit tests covering auth, uploads, puzzle creation, hints, admin, user settings, gallery, social sharing, photo usage badges, piece groups, and zoom/tray layout math (including the tray capture margin so wheel-scroll a few px left of the tray still scrolls the tray)
  • E2E tests covering registration, login, admin settings, photo upload, puzzle creation, thumbnails, user settings, and photo usage badges
  • Frontend E2E tests covering puzzle layout, tray behavior, piece-group behavior (group formation, tray-all-unlocked unit behavior, drag-over-tray grouping, group solve-snap/lock correctness), zoom controls (tray growth, locked/group invariance, zoom-aware dragging, fit-on-reload, tray pieces staying in the tray across a reload while zoomed), and mobile responsiveness

Security Features

  • Zero-Knowledge Encryption: Photos can be encrypted client-side before upload
  • Virus Scanning: All uploads scanned with ClamAV
  • Audit Logging: All actions logged for security review
  • IP Blocking: Admin can block suspicious IP addresses
  • Password Hashing: Argon2id password hashing
  • Session Management: Secure session handling with Lucia Auth

Project Structure

get_puzzles/
├── backend/              # Express API server
│   ├── src/
│   │   ├── controllers/  # Request handlers
│   │   ├── services/     # Business logic
│   │   ├── middleware/   # Express middleware
│   │   └── config/       # Configuration
│   ├── migrations/       # Database migration scripts
│   └── e2e/              # Playwright E2E tests
├── frontend/             # Next.js application
│   ├── app/              # App router pages
│   ├── components/       # React components
│   └── lib/              # Utilities and API client
├── docker/               # Docker support files
│   ├── nginx.conf        # Reverse proxy config
│   ├── entrypoint.sh     # Container startup script
│   └── run-migrations.sh # Automatic migration runner
├── docs/                 # Documentation
├── Dockerfile            # Multi-stage production build
├── docker-compose.yml    # Development compose
├── docker-compose.prod.yml # Production compose
├── init.sql              # Database schema
└── .env.production.example

Development Phases

  • Phase 1: Authentication (Login/Registration)
  • Phase 2: Photo Upload (with virus scanning)
  • Phase 3: Puzzle Creation (jigsaw cut algorithm)
  • Phase 4: Puzzle Solving (drag-and-drop, hints)
  • Phase 5: Admin Dashboard (user management, settings)
  • Phase 6: User Settings (profile, password, encryption)
  • Phase 7: Wall of Glory (gallery showcase with piece outlines)
  • Phase 8: Social Sharing (share puzzles and galleries publicly)
  • Phase 9: Photo Encryption (full encryption/decryption flow)

Database Migrations

The application includes an automatic migration system that runs on container startup:

  • The base schema (users, sessions, uploaded_photos, puzzles, ...) lives in init.sql and is applied idempotently on every boot by docker/run-migrations.sh — it does not depend on the Postgres volume being fresh (Docker's /docker-entrypoint-initdb.d hook runs only once on an empty data volume)
  • Migration changes are stored in backend/migrations/
  • The docker/run-migrations.sh script tracks applied migrations in a schema_migrations table
  • Migrations are applied in alphabetical order and are idempotent
  • No manual intervention required - just pull the new image and restart

To create a new migration:

  1. Add a new .sql file to backend/migrations/ with a numbered prefix (e.g., 010_add_feature.sql)
  2. Use IF NOT EXISTS or IF EXISTS clauses to make migrations idempotent
  3. The migration will run automatically on next container startup

Contributing

Contributions are welcome! Please ensure:

  • All tests pass (npm test)
  • Code follows existing patterns
  • New features include tests
  • Documentation is updated

License

MIT License - see LICENSE file for details

Support

For issues and feature requests, please use the GitHub issue tracker.