# Självhostad Postgres för Guidad Felsökning. # För produktion rekommenderas CloudNativePG-operatorn (automatiska # säkerhetskopior, failover, PITR) — den här StatefulSet:en är den enkla # grundplattan med samma schema. apiVersion: v1 kind: ConfigMap metadata: name: postgres-init namespace: guidad-felsokning data: # Körs vid första starten. Append-only garanteras med triggers — # historiken kan inte ändras eller raderas oavsett vilken roll som # ansluter. init.sql: | create extension if not exists pgcrypto; create table if not exists anvandare ( id uuid primary key default gen_random_uuid(), epost text unique not null, losen_hash text not null, namn text not null, skapad timestamptz not null default now() ); create table if not exists felsokning_arenden ( id text primary key, nummer integer not null, skapad timestamptz not null, delningskod text unique, metodik_id text, skapad_av uuid references anvandare(id), insatt timestamptz not null default now() ); create table if not exists felsokning_handelser ( id text primary key, arende_id text not null references felsokning_arenden(id), tidpunkt timestamptz not null, anvandare text not null, handelse jsonb not null, insatt timestamptz not null default now() ); create index if not exists felsokning_handelser_arende_idx on felsokning_handelser (arende_id, tidpunkt); create or replace function forbjud_andring() returns trigger language plpgsql as $$ begin raise exception 'Loggen är append-only — historik kan inte ändras eller raderas'; end $$; drop trigger if exists handelser_append_only on felsokning_handelser; create trigger handelser_append_only before update or delete on felsokning_handelser for each row execute function forbjud_andring(); drop trigger if exists arenden_append_only on felsokning_arenden; create trigger arenden_append_only before update or delete on felsokning_arenden for each row execute function forbjud_andring(); --- apiVersion: apps/v1 kind: StatefulSet metadata: name: postgres namespace: guidad-felsokning spec: serviceName: postgres replicas: 1 selector: matchLabels: { app: postgres } template: metadata: labels: { app: postgres } spec: containers: - name: postgres image: postgres:17-alpine ports: - containerPort: 5432 env: - name: POSTGRES_DB value: felsokning - name: POSTGRES_USER value: plattform - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: { name: felsokning-hemligheter, key: postgres-losenord } - name: PGDATA value: /var/lib/postgresql/data/pgdata volumeMounts: - name: data mountPath: /var/lib/postgresql/data - name: init mountPath: /docker-entrypoint-initdb.d resources: requests: { cpu: 250m, memory: 256Mi } limits: { cpu: "1", memory: 1Gi } readinessProbe: exec: command: ["pg_isready", "-U", "plattform", "-d", "felsokning"] initialDelaySeconds: 5 volumes: - name: init configMap: { name: postgres-init } volumeClaimTemplates: - metadata: name: data spec: accessModes: [ReadWriteOnce] resources: requests: storage: 10Gi --- apiVersion: v1 kind: Service metadata: name: postgres namespace: guidad-felsokning spec: selector: { app: postgres } ports: - port: 5432