fix: keep /admin reachable while setup is required (#392)

The root layout replaced the entire app with the SetupScreen whenever
the config was incomplete (missing gallery.yaml or Immich credentials)
— including /admin, which lives under the same root layout. That locked
users out of the very tool that fixes an incomplete configuration.

The middleware now forwards the request pathname via an x-pathname
header, and the root layout skips the setup screen for admin paths, so
/admin renders normally (login when ADMIN_PASSWORD is set, the
enable-hint otherwise) while every other route keeps showing the setup
instructions.

Fixes #326

Co-authored-by: ralksta <ralksta@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Ralksta
2026-08-05 00:27:09 +02:00
committed by GitHub
parent f03011e0ec
commit 8f0bb94caf
4 changed files with 49 additions and 2 deletions

View File

@@ -0,0 +1,27 @@
import { describe, it, expect } from 'vitest';
import { isAdminPath } from '@/lib/admin/paths';
// The root layout must keep /admin reachable while the app is in setup mode
// (missing gallery.yaml or Immich credentials) — the admin panel is the tool
// that fixes exactly that state (#326).
describe('isAdminPath', () => {
it('matches /admin exactly', () => {
expect(isAdminPath('/admin')).toBe(true);
});
it('matches nested admin paths', () => {
expect(isAdminPath('/admin/settings')).toBe(true);
});
it('does not match the homepage', () => {
expect(isAdminPath('/')).toBe(false);
});
it('does not match sibling paths that merely start with "admin"', () => {
expect(isAdminPath('/administration')).toBe(false);
});
it('treats a missing pathname header as non-admin', () => {
expect(isAdminPath(null)).toBe(false);
});
});

12
lib/admin/paths.ts Normal file
View File

@@ -0,0 +1,12 @@
/**
* Whether a request pathname belongs to the admin panel.
*
* Used by the root layout to keep /admin reachable while the app is in
* setup mode: the setup screen must not lock out the very tool that fixes
* an incomplete configuration (#326). A null pathname (header missing,
* e.g. a route not covered by the middleware matcher) counts as non-admin
* so the setup screen remains the safe default.
*/
export function isAdminPath(pathname: string | null): boolean {
return pathname === '/admin' || pathname?.startsWith('/admin/') === true;
}