feat(mvp): phase 4 - app registry & healthcheck

Add app CRUD API endpoints, healthcheck service with node-cron scheduler,
icon resolver (Lucide, Simple Icons, CDN, uploads), app management UI
with Superforms, health badge component, and Docker health endpoint.
This commit is contained in:
2026-03-24 20:53:50 +03:00
parent 2c001df322
commit 4d941f566f
17 changed files with 962 additions and 21 deletions
@@ -0,0 +1,65 @@
<script lang="ts">
interface Props {
iconType: string;
iconValue: string;
onchange?: (type: string, value: string) => void;
}
let { iconType = $bindable('lucide'), iconValue = $bindable(''), onchange }: Props = $props();
function handleTypeChange(e: Event) {
const target = e.target as HTMLSelectElement;
iconType = target.value;
iconValue = '';
onchange?.(iconType, iconValue);
}
function handleValueChange(e: Event) {
const target = e.target as HTMLInputElement;
iconValue = target.value;
onchange?.(iconType, iconValue);
}
</script>
<div class="space-y-2">
<label class="block text-sm font-medium text-card-foreground">Icon</label>
<div class="flex gap-2">
<select
value={iconType}
onchange={handleTypeChange}
class="rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-ring"
>
<option value="lucide">Lucide Icon</option>
<option value="simple">Simple Icons</option>
<option value="url">Image URL</option>
<option value="emoji">Emoji</option>
</select>
<input
type="text"
value={iconValue}
oninput={handleValueChange}
placeholder={iconType === 'lucide'
? 'e.g. globe, server, home'
: iconType === 'simple'
? 'e.g. github, docker'
: iconType === 'url'
? 'https://example.com/icon.png'
: 'e.g. 🌐'}
class="flex-1 rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring"
/>
</div>
{#if iconType === 'emoji' && iconValue}
<div class="text-2xl">{iconValue}</div>
{:else if iconType === 'url' && iconValue}
<img src={iconValue} alt="Icon preview" class="h-8 w-8 rounded object-contain" />
{:else if iconType === 'simple' && iconValue}
<img
src="https://cdn.simpleicons.org/{iconValue.toLowerCase()}"
alt="{iconValue} icon"
class="h-8 w-8"
/>
{/if}
</div>