dialog: Diskussionsplattform mit Foren, Rollen & Moderation + RLS-Fix
Auth/RLS-Fix (Schreiben gab 400): - supabase.js: eigener supabaseAuth-Client für Login/Token-Check, damit signInWithPassword den Service-Daten-Client nicht prozessweit aufs User-Token umstellt (sonst lief insert als role=authenticated → RLS-Block). Rollen (admin > editor > user): - auth.js: roleOf() aus app_metadata.role + ADMIN_EMAILS, requireModerator. - users.js: Rolle anzeigen/setzen über GoTrue app_metadata; .env-Admins fix. Datenmodell (schema.sql): - forums (Kategorien) + threads; Seed Allgemein/Projekte/Technik/Off-Topic und Sonder-Kategorie Beiträge. Library-Beiträge werden als Threads gespiegelt (dialog-store.syncLibrary). API (routes/dialog.js, dialog-store.js): - öffentlich: /api/forums, /api/forums/:slug, /api/recent, /api/thread - eingeloggt: POST /api/threads (Thread starten, nur in Foren) - Moderation: /api/mod/* (sperren/ausblenden), Admin: /api/admin/forums CRUD - comments: Lock-Prüfung beim Schreiben, Moderation darf jede löschen. Frontend: - static/dialog.js: Router (Übersicht-Split-View | Forum | Thread), neuer Thread, Mod-Leiste, subtiles Login (dezente Zeile statt Formular). - Admin-UI: Tabs Foren + Moderation, Rollen-Dropdown bei Autor:innen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -49,3 +49,52 @@ create table if not exists public.comments (
|
||||
create index if not exists comments_thread_idx on public.comments (thread, created_at);
|
||||
alter table public.comments enable row level security;
|
||||
grant all on public.comments to anon, authenticated, service_role;
|
||||
|
||||
-- ── Foren / Subforen ────────────────────────────────────────────────────
|
||||
-- Kategorien, in denen Threads leben. Admin-verwaltet. `kind=library` ist die
|
||||
-- Sonder-Kategorie, in der die Library-Beiträge automatisch als Threads landen.
|
||||
create table if not exists public.forums (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
slug text not null unique,
|
||||
name text not null,
|
||||
description text default '',
|
||||
color text, -- optionale Akzentfarbe
|
||||
sort int not null default 0,
|
||||
kind text not null default 'forum', -- forum | library
|
||||
created_at timestamptz not null default now()
|
||||
);
|
||||
alter table public.forums enable row level security;
|
||||
grant all on public.forums to anon, authenticated, service_role;
|
||||
|
||||
-- ── Threads (Diskussionen) ──────────────────────────────────────────────
|
||||
-- key = stabiler Bezeichner, den comments.thread referenziert:
|
||||
-- Forum-Thread → 't/<uuid>'
|
||||
-- Library-Beitrag → Beitragspfad (z.B. /library/software/stack/)
|
||||
create table if not exists public.threads (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
forum_id uuid references public.forums(id) on delete cascade,
|
||||
key text not null unique,
|
||||
title text not null,
|
||||
url text, -- Ziel-Link (Library: Beitragspfad)
|
||||
kind text not null default 'forum', -- forum | library
|
||||
author_name text,
|
||||
user_id uuid,
|
||||
locked boolean not null default false,
|
||||
deleted boolean not null default false,
|
||||
created_at timestamptz not null default now()
|
||||
);
|
||||
create index if not exists threads_forum_idx on public.threads (forum_id);
|
||||
alter table public.threads enable row level security;
|
||||
grant all on public.threads to anon, authenticated, service_role;
|
||||
|
||||
-- Seed-Kategorien (idempotent; im Admin umbenenn-/erweiterbar).
|
||||
insert into public.forums (slug, name, sort, kind) values
|
||||
('allgemein', 'Allgemein', 10, 'forum'),
|
||||
('projekte', 'Projekte', 20, 'forum'),
|
||||
('technik', 'Technik', 30, 'forum'),
|
||||
('off-topic', 'Off-Topic', 40, 'forum')
|
||||
on conflict (slug) do nothing;
|
||||
-- Sonder-Kategorie für die Library-Beiträge.
|
||||
insert into public.forums (slug, name, sort, kind) values
|
||||
('beitraege', 'Beiträge', 0, 'library')
|
||||
on conflict (slug) do nothing;
|
||||
|
||||
Reference in New Issue
Block a user