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.