fix: address final review blockers

- Add /api/onboarding and /status to PUBLIC_PATHS in hooks.server.ts
  so onboarding wizard and status page work for unauthenticated users
- Add isOnboardingNeeded() guard to POST /api/onboarding to reject
  calls after onboarding is complete (security hardening)
- Add data-app-widget attribute to all AppWidget card variants to
  enable j/k keyboard navigation
This commit is contained in:
2026-03-25 14:29:11 +03:00
parent 1c0a7cb850
commit 014de026eb
3 changed files with 13 additions and 1 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ import * as apiTokenService from '$lib/server/services/apiTokenService.js';
import { extractBearerToken } from '$lib/server/middleware/authenticate.js';
import { isBoardGuestAccessible } from '$lib/server/middleware/guestAccess.js';
const PUBLIC_PATHS = ['/login', '/register', '/auth/', '/api/health'];
const PUBLIC_PATHS = ['/login', '/register', '/auth/', '/api/health', '/api/onboarding', '/status'];
function isPublicPath(pathname: string): boolean {
return PUBLIC_PATHS.some((path) => pathname === path || pathname.startsWith(path));
@@ -134,6 +134,8 @@
target="_blank"
rel="noopener noreferrer"
class="card-hover group flex items-center gap-2 rounded-lg {cardStyleClass} px-3 py-2 text-left transition-colors hover:border-primary/50"
data-app-widget
data-app-url={app.url}
oncontextmenu={handleContextMenu}
onclick={recordClick}
>
@@ -190,6 +192,8 @@
<!-- Large: icon + name + description + sparkline + tags + links -->
<div
class="card-hover group rounded-xl {cardStyleClass} p-5 transition-colors hover:border-primary/50"
data-app-widget
data-app-url={app.url}
oncontextmenu={handleContextMenu}
>
<a
@@ -283,6 +287,8 @@
<!-- Medium (default): icon + name + status + sparkline on hover + links -->
<div
class="card-hover group rounded-xl {cardStyleClass} p-4 transition-colors hover:border-primary/50"
data-app-widget
data-app-url={app.url}
oncontextmenu={handleContextMenu}
>
<a
+6
View File
@@ -48,6 +48,12 @@ export const POST: RequestHandler = async ({ request }) => {
const { step, data } = parsed.data;
try {
// Guard: reject calls after onboarding is complete
const needed = await onboardingService.isOnboardingNeeded();
if (!needed) {
return json(error('Onboarding is already complete'), { status: 403 });
}
switch (step) {
case 'admin': {
// Create admin user