Arkitekturöversikt

Alla tenants delar samma Supabase-databas. Isolering upprätthålls av Row-Level Security (RLS)-policyer — PostgreSQL-nivåregler som filtrerar varje fråga baserat på den autentiserade användarens JWT-anspråk.

När en användare loggar in innehåller deras JWT ett workspace_id-anspråk. Varje RLS-policy kontrollerar detta anspråk mot en workspace_id-kolumn i tabellen. Användare kan bokstavligen inte fråga data från andra arbetsplatser — databasen upprätthåller det, inte applikationskoden.

Detta mönster är den industristandard som bolag som Klarna och Spotify använder i sina interna verktyg — och med Supabase kan du implementera det på en bråkdel av tiden och kostnaden.

Sätta upp workspace-strukturen

Tabeller du behöver:

1. workspaces (id, name, plan, created_at) 2. workspace_members (id, workspace_id, user_id, role, created_at) 3. Alla dina affärstabeller (med workspace_id-kolumn)

När en användare registrerar sig skapar du en arbetsplats och en workspace_members-post i en Supabase databasfunktion. workspace_id läggs in i användarens JWT via en anpassad claim-hook.

För svenska B2B SaaS-bolag rekommenderar vi att även lagra organisationsnummer (org_nr) i workspaces-tabellen. Det förenklar faktureringen och möjliggör automatisk berikande av kunddata via Bolagsverkets API.

Skriva RLS-policyer

För varje tenant-scopad tabell aktiverar du RLS och lägger till dessa policyer:

SELECT-policy: CREATE POLICY "users can read own workspace data" ON your_table FOR SELECT USING (workspace_id = (auth.jwt() ->> 'workspace_id')::bigint);

INSERT-policy: CREATE POLICY "users can insert to own workspace" ON your_table FOR INSERT WITH CHECK (workspace_id = (auth.jwt() ->> 'workspace_id')::bigint);

Detta upprätthåller isolering på databasnivå — oavsett vad din frontend eller API gör. En felaktig WeWeb-bindning eller en bugg i Xano kan aldrig läcka data mellan kunder — databasen är det sista försvarslinjen.

Rollbaserad åtkomstkontroll

Inom en arbetsplats har olika användare olika behörigheter (owner, admin, member). Lagra detta i workspace_members.role.

För data-nivå RBAC, använd Supabase-funktioner i dina RLS-policyer:

CREATE FUNCTION get_user_role() RETURNS text AS $$ SELECT role FROM workspace_members WHERE user_id = auth.uid() AND workspace_id = (auth.jwt() ->> 'workspace_id')::bigint $$ LANGUAGE sql STABLE;

Sedan i policyer: USING (get_user_role() IN ('admin', 'owner'))

För svenska enterprise-kunder är det vanligt att också vilja ha avdelningsbaserad åtkomst (t.ex. "bara HR kan se lönedata"). Detta byggs enkelt som ytterligare en roll eller en separat permissions-tabell.

Koppla ihop det i WeWeb

I WeWeb konfigurerar du din Supabase-datakälla med den autentiserade användarens token. WeWeb skickar JWT automatiskt med varje begäran.

För din apps navigation och UI, läs rollen från en global variabel (populerad från workspace_members-tabellen vid inloggning). Visa/dölj menyobjekt, knappar och hela sektioner baserat på roll — detta är enbart presentation, den verkliga säkerheten finns i RLS.

Aldrig hårdkoda tenant-ID:n i WeWeb. All datafiltrering ska komma från den autentiserade användarens JWT — Supabase hanterar resten. Det gör din WeWeb-app trygg att distribuera även till tekniskt kunniga kunder som inspekterar nätverkstrafik.