Files

2.1 KiB

Picta

Image sharing app: dark-mode masonry gallery, drag-and-drop / click / clipboard paste uploads, 4K re-encoding, voting, and threaded comments.

Stack

  • Backend: Node 20 (Alpine), Express, multer (multipart), sharp (image pipeline), cors
  • Frontend: vanilla HTML/CSS/JS, CSS masonry grid, no build step
  • Storage: local public/uploads/ (in-memory + file persistence in data/)
  • Image processing: any upload is re-encoded to JPEG q92, downscaled to max 3840px (4K) while preserving aspect ratio

API

Method Path Description
GET /api/health health + counts
GET /api/posts?sort=new|viral|user|top list posts
GET /api/posts/:id single post
POST /api/upload multipart (image, title, tags, author)
POST /api/posts/:id/vote JSON {direction, userId}
GET /api/comments/:postId list comments (flat, with parentId)
POST /api/comments/:postId JSON {author, text, parentId?}

Frontend

  • Masonry gallery with staggered card entrance animation
  • Filter tabs: New, Most Viral, User Submitted, Top Today
  • Upload via: file picker, drag-and-drop, or Ctrl+V paste (opens modal with preview, auto-submits)
  • Floating action button (FAB) as the persistent upload CTA
  • New posts scroll into view with a highlight pulse
  • Post detail modal: voting, views, tags, threaded comments
  • Focus-visible states and reduced-motion support

Run locally

npm ci
node server.js          # http://localhost:3000

Docker

docker build -t imgur-clone:latest .
docker run -d --name imgur-clone --restart unless-stopped -p 3001:3000 imgur-clone:latest

Note: The Docker image and container names remain imgur-clone for deployment compatibility.

Security

  • Runtime image strips npm/corepack (only node server.js runs at runtime)
  • apk upgrade on every build for base-image CVE coverage
  • Verified with Trivy: 0 vulnerabilities across all OS + node packages

Production

Deployed on Unraid (192.168.0.123), Caddy reverse proxy with auto-TLS → https://imgur.krisforbes.ca