feat(phase3): PWA, auto-discovery, bookmarklet, multi-tab sync

- PWA: manifest, service worker (cache-first static, network-first API),
  offline page, install prompt banner
- Auto-discovery: Docker socket + Traefik API scanning, approval UI
- Quick-add bookmarklet: popup-based add page, favicon auto-detect
- Multi-tab sync: BroadcastChannel for theme + data changes
- i18n translations for all new strings (EN/RU)
This commit is contained in:
2026-03-25 00:59:19 +03:00
parent c6a7de895d
commit dd6958b4d6
28 changed files with 1712 additions and 266 deletions
+41
View File
@@ -0,0 +1,41 @@
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import { requireAdmin } from '$lib/server/middleware/authorize.js';
import { discoverAll, type DiscoveryConfig } from '$lib/server/services/discoveryService.js';
import { success, error } from '$lib/server/utils/response.js';
/**
* POST /api/admin/discover — Scan Docker and Traefik for services. Admin only.
*
* Body: { dockerSocketPath?: string, traefikApiUrl?: string }
*/
export const POST: RequestHandler = async (event) => {
requireAdmin(event);
let body: DiscoveryConfig;
try {
body = await event.request.json();
} catch {
return json(error('Invalid JSON body'), { status: 400 });
}
const config: DiscoveryConfig = {
dockerSocketPath: body.dockerSocketPath || undefined,
traefikApiUrl: body.traefikApiUrl || undefined
};
if (!config.dockerSocketPath && !config.traefikApiUrl) {
return json(
error('At least one discovery source must be configured (dockerSocketPath or traefikApiUrl)'),
{ status: 400 }
);
}
try {
const result = await discoverAll(config);
return json(success(result));
} catch (err) {
const message = err instanceof Error ? err.message : 'Discovery scan failed';
return json(error(message), { status: 500 });
}
};