Opprett PostgreSQL-skjema for Synops (oppgave 1.1)
Oppretter database `synops` på serveren med kjerneskjemaet: - Enums: visibility (hidden/discoverable/readable/open), access_level (reader/member/admin/owner) - Tabeller: nodes, edges, node_access, auth_identities - Funksjon: recompute_access for tilgangsmatrise-oppdatering - Indekser iht. docs/primitiver/nodes.md og edges.md Migrasjonen er kjørt og verifisert på produksjonsserver (sidelinja-postgres-1, database: synops). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
0746b4555a
commit
a30a484076
2 changed files with 119 additions and 2 deletions
118
migrations/001_initial_schema.sql
Normal file
118
migrations/001_initial_schema.sql
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
-- 001_initial_schema.sql
|
||||
-- Oppretter kjerneskjema for Synops: enums, nodes, edges, node_access, auth_identities.
|
||||
-- Ref: docs/primitiver/nodes.md, docs/primitiver/edges.md, docs/retninger/bruker_ikke_workspace.md
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- =============================================================================
|
||||
-- Enums
|
||||
-- =============================================================================
|
||||
|
||||
CREATE TYPE visibility AS ENUM ('hidden', 'discoverable', 'readable', 'open');
|
||||
CREATE TYPE access_level AS ENUM ('reader', 'member', 'admin', 'owner');
|
||||
|
||||
-- =============================================================================
|
||||
-- Nodes
|
||||
-- =============================================================================
|
||||
|
||||
CREATE TABLE nodes (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
node_kind TEXT NOT NULL DEFAULT 'content',
|
||||
title TEXT,
|
||||
content TEXT,
|
||||
visibility visibility NOT NULL DEFAULT 'hidden',
|
||||
metadata JSONB NOT NULL DEFAULT '{}',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
created_by UUID REFERENCES nodes(id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_nodes_kind ON nodes (node_kind);
|
||||
CREATE INDEX idx_nodes_created_by ON nodes (created_by);
|
||||
CREATE INDEX idx_nodes_visibility ON nodes (visibility);
|
||||
|
||||
-- =============================================================================
|
||||
-- Edges
|
||||
-- =============================================================================
|
||||
|
||||
CREATE TABLE edges (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
source_id UUID NOT NULL REFERENCES nodes(id) ON DELETE CASCADE,
|
||||
target_id UUID NOT NULL REFERENCES nodes(id) ON DELETE CASCADE,
|
||||
edge_type TEXT NOT NULL,
|
||||
metadata JSONB NOT NULL DEFAULT '{}',
|
||||
system BOOLEAN NOT NULL DEFAULT false,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
created_by UUID REFERENCES nodes(id),
|
||||
|
||||
UNIQUE (source_id, target_id, edge_type)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_edges_source ON edges (source_id);
|
||||
CREATE INDEX idx_edges_target ON edges (target_id);
|
||||
CREATE INDEX idx_edges_type ON edges (edge_type);
|
||||
|
||||
-- =============================================================================
|
||||
-- Tilgangsmatrise (node_access)
|
||||
-- =============================================================================
|
||||
|
||||
CREATE TABLE node_access (
|
||||
subject_id UUID NOT NULL REFERENCES nodes(id) ON DELETE CASCADE,
|
||||
object_id UUID NOT NULL REFERENCES nodes(id) ON DELETE CASCADE,
|
||||
access access_level NOT NULL,
|
||||
via_edge UUID REFERENCES edges(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (subject_id, object_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_na_subject ON node_access (subject_id);
|
||||
|
||||
-- =============================================================================
|
||||
-- Auth-identiteter (bro mellom HTTP-sesjon og graf)
|
||||
-- =============================================================================
|
||||
|
||||
CREATE TABLE auth_identities (
|
||||
node_id UUID PRIMARY KEY REFERENCES nodes(id) ON DELETE CASCADE,
|
||||
authentik_sub TEXT UNIQUE NOT NULL,
|
||||
email TEXT UNIQUE NOT NULL
|
||||
);
|
||||
|
||||
-- =============================================================================
|
||||
-- Tilgangsberegning (recompute_access)
|
||||
-- Oppdaterer node_access-matrisen når edges endres.
|
||||
-- Ref: docs/retninger/bruker_ikke_workspace.md
|
||||
-- =============================================================================
|
||||
|
||||
CREATE OR REPLACE FUNCTION recompute_access(
|
||||
p_subject_id UUID,
|
||||
p_root_node_id UUID,
|
||||
p_access access_level,
|
||||
p_via_edge UUID
|
||||
) RETURNS void AS $$
|
||||
BEGIN
|
||||
-- Direkte tilgang til roten
|
||||
INSERT INTO node_access (subject_id, object_id, access, via_edge)
|
||||
VALUES (p_subject_id, p_root_node_id, p_access, p_via_edge)
|
||||
ON CONFLICT (subject_id, object_id)
|
||||
DO UPDATE SET access = GREATEST(node_access.access, p_access);
|
||||
|
||||
-- Transitiv: noder som tilhører roten
|
||||
INSERT INTO node_access (subject_id, object_id, access, via_edge)
|
||||
SELECT p_subject_id, e.source_id, p_access, p_via_edge
|
||||
FROM edges e
|
||||
WHERE e.target_id = p_root_node_id
|
||||
AND e.edge_type = 'belongs_to'
|
||||
ON CONFLICT (subject_id, object_id)
|
||||
DO UPDATE SET access = GREATEST(node_access.access, p_access);
|
||||
|
||||
-- Hvis subject er et team: propager til alle teammedlemmer
|
||||
INSERT INTO node_access (subject_id, object_id, access, via_edge)
|
||||
SELECT e.source_id, na.object_id, na.access, na.via_edge
|
||||
FROM node_access na
|
||||
JOIN edges e ON e.target_id = p_subject_id
|
||||
AND e.edge_type = 'member_of'
|
||||
WHERE na.subject_id = p_subject_id
|
||||
ON CONFLICT (subject_id, object_id)
|
||||
DO UPDATE SET access = GREATEST(node_access.access, EXCLUDED.access);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
COMMIT;
|
||||
3
tasks.md
3
tasks.md
|
|
@ -43,8 +43,7 @@ Uavhengige faser kan fortsatt plukkes.
|
|||
|
||||
## Fase 1: Infrastruktur-fundament
|
||||
|
||||
- [~] 1.1 PostgreSQL schema: opprett database `synops`, enums (`visibility`, `access_level`), tabeller (`nodes`, `edges`, `node_access`, `auth_identities`) med indekser. Kjør på server via SSH. Ref: `docs/primitiver/nodes.md`, `docs/primitiver/edges.md`, `docs/retninger/bruker_ikke_workspace.md`.
|
||||
> Påbegynt: 2026-03-17T11:51
|
||||
- [x] 1.1 PostgreSQL schema: opprett database `synops`, enums (`visibility`, `access_level`), tabeller (`nodes`, `edges`, `node_access`, `auth_identities`) med indekser. Kjør på server via SSH. Ref: `docs/primitiver/nodes.md`, `docs/primitiver/edges.md`, `docs/retninger/bruker_ikke_workspace.md`.
|
||||
- [ ] 1.2 Seed-data: opprett Vegards brukernode (`node_kind='person'`, `title='Vegard'`) og `auth_identities`-rad. Opprett Sidelinja samlings-node og `owner`-edge fra Vegard.
|
||||
- [ ] 1.3 SpacetimeDB modul: opprett Rust-modul med `nodes` og `edges`-tabeller som speiler PG-skjema. Grunnleggende reducers for CRUD. Deploy til server. Ref: `docs/retninger/datalaget.md`, `docs/erfaringer/spacetimedb_integrasjon.md`.
|
||||
- [ ] 1.4 Caddy-config: reverse proxy for maskinrommet (api.sidelinja.org), SpacetimeDB, og SvelteKit. Auto-TLS. Ref: `docs/setup/produksjon.md`.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue