Validering av fase 22 (SpacetimeDB-migrering) bekrefter:
1. WebSocket-sanntid fungerer:
- maskinrommet lytter på PG NOTIFY-kanaler (node_changed, edge_changed,
access_changed, mixer_channel_changed)
- Enrichment av events med fulle rader fra PG
- Broadcast via tokio::broadcast til WebSocket-klienter
- Tilgangskontroll filtrerer events per bruker
- Frontend kobler til /ws med JWT, mottar initial_sync + inkrementelle events
2. PG LISTEN/NOTIFY-triggere verifisert i database:
- 4 notify-funksjoner: notify_node_change, notify_edge_change,
notify_access_change, notify_mixer_channel_change
- 4 triggere: nodes_notify, edges_notify, node_access_notify,
mixer_channels_notify
3. Ingen STDB-rester i aktiv kode/konfig:
- maskinrommet/src/: rent
- Cargo.toml: ingen spacetimedb-avhengigheter
- docker-compose.yml: ingen spacetimedb-tjeneste
- Caddyfile: ingen spacetimedb-proxy
- Eneste funn: frontend/src/lib/spacetime/ katalognavn —
omdøpt til frontend/src/lib/realtime/ (32 filer oppdatert)
- Historiske referanser i docs/arkiv og scripts/synops.md er OK
50 lines
1.5 KiB
Svelte
50 lines
1.5 KiB
Svelte
<script lang="ts">
|
|
import type { Node } from '$lib/realtime';
|
|
import TraitPanel from './TraitPanel.svelte';
|
|
|
|
interface Props {
|
|
collection?: Node;
|
|
config: Record<string, unknown>;
|
|
}
|
|
|
|
let { collection, config }: Props = $props();
|
|
|
|
const format = $derived((config.format as string) ?? 'rss');
|
|
const maxItems = $derived((config.max_items as number) ?? 50);
|
|
|
|
/** Build the feed URL from publishing slug if available */
|
|
const feedUrl = $derived.by(() => {
|
|
if (!collection) return '';
|
|
try {
|
|
const meta = JSON.parse(collection.metadata ?? '{}');
|
|
const slug = meta.traits?.publishing?.slug;
|
|
if (slug) return `/pub/${slug}/feed.xml`;
|
|
} catch { /* ignore */ }
|
|
return `/api/rss/${collection.id}`;
|
|
});
|
|
</script>
|
|
|
|
<TraitPanel name="rss" label="RSS-feed" icon="📡">
|
|
{#snippet children()}
|
|
<div class="space-y-2 text-sm">
|
|
<div class="flex items-center gap-2">
|
|
<span class="text-xs text-gray-500">Format:</span>
|
|
<span class="rounded bg-orange-50 px-2 py-0.5 text-xs font-medium text-orange-700">{format.toUpperCase()}</span>
|
|
</div>
|
|
<div>
|
|
<span class="text-xs text-gray-500">Maks elementer:</span>
|
|
<span class="ml-1 text-gray-900">{maxItems}</span>
|
|
</div>
|
|
<div class="mt-2">
|
|
<a
|
|
href={feedUrl}
|
|
target="_blank"
|
|
rel="noopener"
|
|
class="inline-flex items-center gap-1.5 rounded bg-orange-100 px-3 py-1.5 text-xs font-medium text-orange-800 hover:bg-orange-200"
|
|
>
|
|
Feed-URL →
|
|
</a>
|
|
</div>
|
|
</div>
|
|
{/snippet}
|
|
</TraitPanel>
|