Commit Graph

254 Commits

Author SHA1 Message Date
Ralksta
11c077fed2 docs: add Immich API key permissions section to README (#318)
Co-authored-by: ralksta <ralksta@users.noreply.github.com>
2026-06-29 21:34:12 +03:00
Ralksta
a504f7296a feat: redesign album drawer into a gorgeous centered two-column modal (#243)
Co-authored-by: ralksta <ralksta@users.noreply.github.com>
2026-05-31 21:30:00 +02:00
Ralksta
8964877f6a feat: redesign admin pagebuilder with slide-over drawers and svg icons (#242)
Co-authored-by: ralksta <ralksta@users.noreply.github.com>
2026-05-31 21:27:13 +02:00
Ralksta
02f5e6a505 feat(admin): visual theme cards, album search, and status dashboard (#241)
* feat(admin): implement visual theme cards, album search, and system status diagnostics

* fix(admin): resolve type-checking build errors in SettingsEditor and status route

---------

Co-authored-by: ralksta <ralksta@users.noreply.github.com>
2026-05-31 21:17:52 +02:00
Ralksta
e24cd33a09 fix: correct step outputs reference in docker-publish.yml (#239)
Co-authored-by: ralksta <ralksta@users.noreply.github.com>
2026-05-31 10:14:29 +02:00
Ralksta
ff77519ea9 feat: release automation and doc fixes (#238)
* fix: align env vars and config paths in CI and contributing docs

* feat: add automatic docker publishing to ghcr workflow

---------

Co-authored-by: ralksta <ralksta@users.noreply.github.com>
2026-05-31 10:13:53 +02:00
Ralksta
93ac4d275d 🎨 Palette: Add skip-to-content link for keyboard accessibility (#169)
💡 What: Added a "Skip to content" link that is visually hidden by default but appears when focused via keyboard. Pointed it to the main content area using `id="main-content"` and `tabIndex={-1}`.
🎯 Why: Keyboard users and screen readers must otherwise tab through the entire navigation menu on every page load before reaching the actual page content. This is tedious and a poor UX.
📸 Before/After: Before, keyboard focus started on "Home" in the header. After, the first tab press shows the "Skip to content" link at the top left of the screen.
♿ Accessibility: Massively improves WCAG compliance (Bypass Blocks) and keyboard navigation efficiency.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: ralksta <ralksta@users.noreply.github.com>
2026-05-31 10:04:49 +02:00
Ralksta
9d2a13c9ab I have added a loading spinner to the PasswordGate confirmation button. (#176)
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-05-31 10:04:15 +02:00
dependabot[bot]
c5645a49fd chore(deps): bump the react group across 1 directory with 3 updates (#223)
Bumps the react group with 3 updates in the / directory: [react](https://github.com/facebook/react/tree/HEAD/packages/react), [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) and [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom).


Updates `react` from 19.2.5 to 19.2.6
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.6/packages/react)

Updates `@types/react` from 19.2.14 to 19.2.15
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `react-dom` from 19.2.5 to 19.2.6
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.6/packages/react-dom)

Updates `@types/react` from 19.2.14 to 19.2.15
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-version: 19.2.15
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: react
- dependency-name: "@types/react"
  dependency-version: 19.2.15
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: react
- dependency-name: react
  dependency-version: 19.2.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: react
- dependency-name: react-dom
  dependency-version: 19.2.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: react
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-31 10:03:14 +02:00
Ralksta
a91269eb42 🎨 Palette: Improve Lightbox counter accessibility (#235)
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-05-31 10:03:08 +02:00
Ralksta
746e9ae4c9 ⚡ Bolt: Memoize auth checks in Map API (#236)
Introduced a request-scoped `Map` (`authCache`) in `app/api/map/route.ts` to memoize `isAuthenticated` calls.
The `getMapData` loop iterates over all albums across all locations. Albums within the same subpage slug trigger repeated `isAuthenticated` checks, which execute expensive HMAC cryptographic operations, causing performance degradation for large datasets.
Eliminates redundant cryptographic operations during map data fetching, reducing CPU utilization and response times for the Map API.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-05-31 10:03:03 +02:00
Ralksta
c2fa8e7596 🛡️ Sentinel: Fix Stored XSS via Content-Type spoofing in asset proxies (#237)
Sanitized the Content-Type header on image and video proxy routes (`/api/image/*`, `/api/video/*`). The content type is forced to lowercase, validated against a safe prefix (`image/`, `video/`, `audio/`), and restricted to block `svg` and `xml`. Any invalid type falls back to `application/octet-stream`. This prevents an attacker from uploading an SVG file containing a malicious script and triggering a Stored XSS attack via these proxy endpoints, which are excluded from the global CSP.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-05-31 10:02:59 +02:00
ralksta
6b7fb09097 feat: use album hero image as grid thumbnail on subpage overview 2026-05-30 15:40:29 +02:00
ralksta
117685e47b fix: reload config without docker restart – mtime-based yaml cache instead of immortal in-memory cache 2026-05-30 15:38:55 +02:00
ralksta
19c3727afc feat: per-album hero image – picker from album assets, fullbleed banner on detail page 2026-05-30 15:33:43 +02:00
ralksta
af5da8f316 fix: use preview size for grid thumbnails to avoid blur on portrait images 2026-05-30 15:21:28 +02:00
ralksta
6f4cb467fd fix: revalidate all pages on admin save so hero/config changes appear immediately
Add revalidatePath('/', 'layout') calls to gallery save, settings save,
and reload routes. This tells Next.js to purge any cached page responses
so the next browser refresh picks up the new hero images and config.
2026-05-29 18:10:48 +02:00
ralksta
066e6f5af6 fix: asset picker grid overflow - images no longer stack on scroll 2026-05-29 18:03:00 +02:00
ralksta
e8e65e7172 feat(admin): add asset picker with favorites, drag-and-drop reordering, preview links, and keyboard shortcuts
- Asset Picker: Visual browser for hero images with Favorites tab (shown first)
  and All Photos tab. Includes infinite scroll and UUID fallback input for
  assets not easily found in the grid.
- Drag & Drop: All lists (hero images, standalone albums, subpage albums,
  subpage tiles) are now reorderable via drag handles using @dnd-kit.
- Preview Links: 'Preview Site' button in save bar, '↗ Site' in header, and
  per-subpage preview links with URL slug preview shown inline.
- Keyboard Shortcuts: ⌘+S / Ctrl+S to save in both Pages and Settings tabs.
- Unsaved Changes Guard: beforeunload warning prevents accidental data loss.
- New API route /api/admin/assets for browsing Immich assets with pagination
  and favorites filter via search/metadata endpoint.
2026-05-29 17:59:25 +02:00
ralksta
2e4cde4b6e fix: clear album cache on admin save so changes appear immediately
When saving gallery/settings via admin, the config cache was invalidated
but the Immich album cache (which stores resolved title overrides and
descriptions) was not cleared. This meant changes only appeared after
the TTL expired or a manual 'Reload' click.

Now both gallery and settings saves also call immich.invalidateAll()
to flush the album cache, making changes visible on next page load.
2026-05-29 17:47:08 +02:00
ralksta
3a8a890930 fix: resolve permission error when saving gallery config in Docker
The container was running as 'nextjs' (UID 1001) but bind-mounted
./content from the host has host-user ownership, making it unwritable.

Solution: start as root, fix /app/content ownership in entrypoint,
then drop privileges to nextjs via su-exec before running the app.
2026-05-29 17:40:02 +02:00
ralksta
4416502e14 feat: enlarge admin thumbnails for hero, album, and subpage grids
- Hero grid: 140px → 220px min tile width
- Album grid: 160px → 240px min tile width
- Subpage grid: 140px → 200px min tile width
- Picker thumbnails: 40px → 52px
- Admin main max-width: 960px → 1120px for more space
- Slightly larger overlay buttons and index badges
2026-05-29 17:37:34 +02:00
ralksta
f820a7b683 fix: use docker-compose.override.yml for server-specific config
- Remove :ro and network: host from base docker-compose.yml
- Add docker-compose.override.yml.example with network/healthcheck template
- Add docker-compose.override.yml to .gitignore

This allows git pull without conflicts on the server. Server-specific
settings (external networks, healthchecks) go in the override file.
2026-05-29 17:33:19 +02:00
ralksta
01dde84216 fix: remove read-only flag from content volume to allow admin saves
The content volume was mounted as :ro (read-only) which prevented
the admin panel from writing gallery.yaml and settings.yaml changes.
Removed the :ro flag so the admin panel can save config and create backups.
2026-05-29 17:30:28 +02:00
ralksta
0457a74dd1 feat: redesign subpages as collapsible tile grid for better overview
- Subpages shown as compact visual tiles in a grid (like folders)
- Each tile shows the first album's cover image + name + album count
- Click a tile to expand/edit that subpage's details below
- Active tile highlighted with accent border
- Only one subpage expanded at a time — no more endless scrolling
- Move arrows changed to ← → (horizontal) matching the grid layout
- Smooth slide-down animation when expanding a subpage
2026-05-29 17:29:26 +02:00
ralksta
502ca1d32c feat: redesign hero section as visual image grid with large previews
- Hero images shown as landscape tiles (16:10 aspect ratio) in a grid
- Full cover images instead of tiny thumbnails with UUID text
- Remove button appears on hover (red X, top-right corner)
- Slide number badge shown bottom-left for ordering reference
- Much more visual and recognizable at a glance
2026-05-29 17:26:54 +02:00
ralksta
276e9b3d68 feat: redesign admin album cards as grid tiles with large cover images
Replace the list-style album cards with a visual grid layout:
- Albums shown as tiles with square cover images (aspect-ratio: 1)
- Grid auto-fills with min 160px columns
- Edit/remove buttons appear as overlay on hover
- Album name and photo count shown below the cover
- Much more compact — multiple albums visible without scrolling
2026-05-29 17:24:53 +02:00
ralksta
b4fa37d680 fix: admin panel light/dark theme support, improved contrast, and backup confirmation
a) Admin panel now respects the site's light/dark theme toggle via CSS
   custom properties that respond to [data-theme='light'] on <html>.
   All hardcoded dark colors replaced with semantic CSS variables.

b) Improved contrast in dark mode: secondary text changed from #666/#555
   to #a0a0a0, muted text from #555 to #707070. All text is now clearly
   readable against dark backgrounds.

c) Backup system was already implemented in yaml-service.ts (creates
   timestamped backups in content/.backups/ before each save, keeps last
   10 versions). Now the UI shows a confirmation message that a backup
   was created after each successful save.
2026-05-29 17:20:56 +02:00
ralksta
4a0b57b932 feat: add thumbnail previews to admin panel for albums and hero images
- Add /api/admin/thumbnail/[id] proxy endpoint for serving Immich thumbnails
- Show album cover thumbnails in AlbumCard components (subpages + standalone)
- Show actual image thumbnails in AlbumPicker modal instead of emoji placeholders
- Show small thumbnail previews for hero image entries
- Add corresponding CSS styles for all thumbnail elements
2026-05-29 17:14:58 +02:00
ralksta
9b053e1648 fix: exclude /admin from CSP middleware to prevent script blocking
The admin panel is a static page with client-side React that gets
prerendered at build time. The nonce-based CSP from middleware doesn't
work for static pages because the nonce is generated per-request but
the HTML is served from cache without it. Exclude /admin from the
middleware matcher so its scripts can load normally.
2026-05-29 17:09:53 +02:00
ralksta
e723358514 chore: add Claude Code config and brainstorm notes 2026-05-29 17:05:18 +02:00
ralksta
5dffadbe3c feat: add video playback support in lightbox and photo grid
- Lightbox renders <video> with controls for video assets
- PhotoGrid shows video indicator overlay on video thumbnails
- Skip video preloading in lightbox (streams on demand)
- Add video-related CSS styles
- Update catch-all page to pass video URLs to components
2026-05-29 17:05:12 +02:00
ralksta
e9063d3a71 feat: add video streaming proxy and webhook cache invalidation
- Add /api/video/[id] route with Range header support for seeking
- Add /api/webhook route for Immich event-driven cache invalidation
- Add streamVideo() to ImmichClient with 206 Partial Content support
- Support album description overrides in gallery.yaml
- Add videoUrl() helper to lib/urls.ts
- Export cache.delete() and cache.clear() methods
2026-05-29 17:04:57 +02:00
ralksta
ce7c1742be docs: add admin panel documentation and update README
- Add docs/admin-panel.md with full guide (setup, features, security, Docker)
- Update README with admin panel feature listing and setup instructions
- Update gallery-config.md with tip about visual alternative
- Update CLAUDE.md with admin architecture and API routes
2026-05-29 17:04:41 +02:00
ralksta
9e52d7a0b8 feat: add visual admin panel with page builder and settings editor
- Add /admin route with password-protected visual page builder
- Page Builder: manage hero images, standalone albums, subpages, and sections
- Album Picker: browse all shared Immich albums with search and filtering
- Settings Editor: theme, grid, footer, legal, SEO configuration
- YAML service with atomic writes and automatic backups (content/.backups/)
- HMAC-signed admin sessions (24h expiry, HttpOnly cookies)
- API endpoints: /api/admin/{auth,gallery,settings,albums,reload}
- Enable with ADMIN_PASSWORD env var; disabled by default
- invalidateConfigCache() export for hot-reload after saves
2026-05-29 17:04:37 +02:00
ralksta
5887706775 fix: restore @ts-expect-error for request.ip in getClientIp
The property was removed from NextRequest types in Next.js 15+ but is
still populated by hosting platforms (Vercel, Netlify, etc.).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 12:15:33 +02:00
ralksta
771cee517a security: implement secure IP retrieval with TRUSTED_PROXIES support (closes #139) 2026-05-06 12:10:20 +02:00
Ralksta
3c5715e0b0 Merge PR #141
chore(deps): bump the nextjs group with 2 updates
2026-05-06 12:00:01 +02:00
Ralksta
773e62f579 Merge PR #142
chore(deps-dev): bump prettier from 3.8.2 to 3.8.3
2026-05-06 11:59:58 +02:00
Ralksta
3e310f142e Merge PR #147
🛡️ Sentinel: [MEDIUM] Fix TOCTOU vulnerability in file read
2026-05-06 11:59:55 +02:00
Ralksta
0aa775a08d Merge PR #160
🛡️ Sentinel: [security improvement]
2026-05-06 11:59:51 +02:00
Ralksta
fb32a8cabc Merge PR #164
🛡️ Sentinel: [HIGH] Fix scrypt lockout and timing fallback
2026-05-06 11:59:48 +02:00
Ralksta
3a4c65276d Merge PR #165
⚡ Bolt: [performance improvement] Optimize map bucketing memory and deduplicate getMapData promises
2026-05-06 11:59:45 +02:00
Ralksta
08207e2f16 Merge PR #163
🎨 Palette: Improve PhotoGrid screen reader accessibility
2026-05-06 11:59:42 +02:00
google-labs-jules[bot]
59321d88ca ⚡ Bolt: [performance improvement] Optimize map bucketing memory and deduplicate getMapData promises
Co-authored-by: ralksta <16941050+ralksta@users.noreply.github.com>
2026-05-05 10:44:12 +00:00
google-labs-jules[bot]
8ab1a3d5ea Fix scrypt hash generation in plaintext fallback
- Adjusted `generateScryptHash` parameter in plaintext fallback logic in `lib/auth.ts` to use `storedPassword` instead of the intermediate hashed value. This prevents users from getting locked out when they adopt the recommended hash.
- Enhanced plaintext fallback verification to hash `password` and `storedPassword` via keyed HMAC before executing `crypto.timingSafeEqual` to avoid potential timing attacks more securely.

Co-authored-by: ralksta <16941050+ralksta@users.noreply.github.com>
2026-05-05 10:34:52 +00:00
google-labs-jules[bot]
ebf60b12c3 Improve PhotoGrid screen reader accessibility
Co-authored-by: ralksta <16941050+ralksta@users.noreply.github.com>
2026-05-05 10:24:39 +00:00
google-labs-jules[bot]
71381342d6 🛡️ Sentinel: [security improvement]\n\nAdded rate limiting to the /api/health endpoint using the shared checkRateLimit utility. This prevents potential DoS attacks by restricting the number of requests per IP, utilizing the configured rateLimitRpm.
Co-authored-by: ralksta <16941050+ralksta@users.noreply.github.com>
2026-05-03 10:20:32 +00:00
google-labs-jules[bot]
8c573314d6 fix(about): resolve TOCTOU vulnerability by migrating to async file I/O
Co-authored-by: ralksta <16941050+ralksta@users.noreply.github.com>
2026-04-28 11:16:18 +00:00
dependabot[bot]
a344228fb9 chore(deps-dev): bump prettier from 3.8.2 to 3.8.3
Bumps [prettier](https://github.com/prettier/prettier) from 3.8.2 to 3.8.3.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.8.2...3.8.3)

---
updated-dependencies:
- dependency-name: prettier
  dependency-version: 3.8.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-27 07:48:48 +00:00