Dokumentation

open-crm

Fullständig manual för Desktop CRM, Remote, Kundportal, Signering och Formulärapp.

GitHub ↗MIT Licensev1.0

Vad är open-crm?

open-crm är ett fullständigt CRM-system byggt för tjänsteföretag — bygg, hantverk, konsulter och liknande verksamheter. Det distribueras som öppen källkod under MIT-licens och körs självhostat: du äger all data, ingen månadsavgift, ingen inlåsning.

Systemet täcker hela affärsflödet i en enda sammanhängande miljö: kundregistrering, projektplanering, tidplan, offertskrivning med ROT-avdrag, digital signering, kostnadsuppföljning, orderhantering, fakturering, intern kommunikation och automatiserade AI-arbetsflöden.

Kärnan är en Electron-app (Desktop CRM) som kör lokalt på kontorets datorer och synkroniseras mot en Supabase-databas. Runt den finns tre kompletterande webbappar — Remote för fältpersonal, Kundportal för klienter och Signering för digital offertgodkännande.

De sex apparna

Systemkrav

Desktop CRM

  • Node.js 20 LTS eller senare
  • npm 10 eller senare
  • Git
  • macOS 12+, Windows 10+ eller Linux (Debian/Ubuntu rekommenderas)
  • Minimum 4 GB RAM, 2 GB ledigt diskutrymme

Webbapparna (Remote / Kundportal / Signering)

Alla tre webbappar är Next.js-projekt och kan hostarnas på valfri plattform som stöder Node.js — Vercel, Railway, en egen VPS eller liknande. De kräver Node.js 20+ och delar Supabase-databasen med Desktop CRM.

Databas

open-crm använder Supabase (hanterad PostgreSQL) som databas. Supabase Cloud med gratis tier räcker för de flesta installationer. Självhostad Supabase stöds också — se supabase.com/docs/guides/self-hosting för instruktioner.

Installation & setup

Desktop CRM

Klona repot och installera beroenden:

bash
git clone https://github.com/rankgnar/open-crm
cd open-crm
npm install

Skapa .env-fil

Skapa filen .env i projektets rot. Alla fyra variabler krävs:

.env
SUPABASE_URL=https://<ditt-projekt-ref>.supabase.co
SUPABASE_ANON_KEY=<din-anon-nyckel>
SUPABASE_SERVICE_KEY=<din-service-nyckel>
SUPABASE_ACCESS_TOKEN=<din-personal-access-token>

Var du hittar nycklarna:

  • SUPABASE_URL och ANON_KEY: supabase.com → ditt projekt → Settings → API → Project URL / anon key
  • SUPABASE_SERVICE_KEY: samma sida → service_role key (håll hemlig, används bara server-side)
  • SUPABASE_ACCESS_TOKEN: supabase.com/dashboard/account/tokens → "Generate new token"

Starta appen

bash
npm run dev

Electron-fönstret öppnas automatiskt med hot-reload. Vid första start körs databasmigreringar automatiskt — tabeller skapas i din Supabase-instans utan manuella steg.

Notera: Migrationssystemet spårar vilka SQL-filer som körts i tabellen _applied_migrations. Varje fil i supabase/migrations/ körs exakt en gång, i lexikografisk ordning. Det är idempotent — det är säkert att starta om appen.

Bygg för produktion

bash
npm run build
# Output: /dist/<platform>/

Bygg genererar en installationsfil per plattform — .dmg för macOS, .exe för Windows och .AppImage / .deb för Linux.

Workspace

Desktop CRM

Workspace är startskärmen i appen. Den samlar verksamhetens viktigaste nyckeltal i en enda vy utan att du behöver navigera runt i systemet.

open-crm Workspace — samlad vy av nyckeltal

Workspace visar i realtid:

Kunder & Projekt

Aktiva kunder, öppna projekt och pipelinestatus

Förslag

Offerter under behandling, signerade och väntande

Order

Pågående ordrar med statusöversikt

Ekonomi

Kostnader, fakturaflöde och budgetstatus

Personal

Tillgänglighet och aktivitetsstatus för teamet

AI-status

Senaste AI-arbetsflöden och pågående körningar

Workspace aggregerar data från alla moduler — den har inga egna tabeller i databasen.

Kunder

Desktop CRM

Kundregistret är grunden i systemet. Varje kund har kontaktuppgifter, anteckningar och en komplett historik av projekt, offerter och kommunikation.

open-crm Kunder — kundlista

Fält per kund

  • Namn, organisationsnummer (valfritt)
  • Primär kontaktperson: namn, e-post, telefon
  • Faktureringsadress
  • Anteckningar (fritext)
  • Status: Aktiv / Inaktiv

Åtgärder

  • Skapa ny kund — fyll i formuläret via "Ny kund"-knappen
  • Redigera kontaktuppgifter direkt i detaljvyn
  • Se alla projekt, offerter och fakturor kopplade till kunden
  • Bjud in kunden till Kundportalen (se Kundportal-sektionen)
Tips: Sökfältet i kundlistan filtrerar på namn, organisationsnummer och e-post i realtid. Inga knappar — skriv bara och listan uppdateras.

Tabell: kunder · IPC: db:kunder:list, db:kunder:create, db:kunder:update

Projekt

Desktop CRM

Projekt är navet i systemet. Nästan alla moduler — kalender, tidplan, förslag, order, kostnader, fakturor — är kopplade till ett specifikt projekt. En kund kan ha hur många projekt som helst.

open-crm Projekt — detaljvy

Projektstatus

Planerad

Projektet är skapat men arbetet har inte börjat

Pågående

Aktivt projekt med löpande uppföljning

Slutförd

Avslutat projekt, arkiveras men raderas ej

Avbruten

Projekt som ej genomförs

Pausad

Tillfälligt stoppad, återupptas senare

Fält per projekt

  • Titel och beskrivning
  • Kopplad kund
  • Status och startdatum / beräknat slutdatum
  • Budgetbelopp (SEK inkl. moms)
  • Intern anteckning

Tabell: projekt · IPC: db:projekt:list, db:projekt:get, db:projekt:create, db:projekt:update

Kalender & Tidplan

Desktop CRM

Kalendermodulen är en veckokalender för planering av händelser kopplade till projekt och personal. Tidplanen ger en visuell Gantt-liknande vy per projekt.

open-crm Kalender — veckovy

Händelsetyper i Kalender

Uppgift

Intern arbetsuppgift att slutföra

Besök

Kundmöte eller platsbesök

Leverans

Materialleverans till arbetsplats

Möte

Internt eller externt möte

Carry-over — ej slutförda händelser

Händelser som passerat datum och inte markerats som slutförda (och inte är återkommande) visas automatiskt i nuvarande vecka. Historiken är oföränderlig — händelserna visas i dag men ändrar inte ursprungsdatum.

Notera: Carry-over gäller alla icke-slutförda, icke-återkommande händelser med datum i det förflutna — oavsett projekt. Det är ett säkerhetsnet för att inget ska tappas bort.
open-crm Tidplan — Gantt-vy per projekt

Tidplan

Tidplanen visar ett projekts faser och milstolpar i en horisontell tidslinje. Varje fas kan ha ett start- och slutdatum och kopplas till Kalenders händelser. Tidplan är per projekt — välj projekt i dropdown för att se dess plan.

Tabeller: kalender_events, tidplan_faser · IPC: db:kalender:list, db:tidplan:list

Förslag & Offert

Desktop CRM

Förslag (offert) konsoliderar projektets arbets- och materialkostnader i ett strukturerat dokument som kan skickas till kunden för godkännande och digital signering.

open-crm Förslag — offertlista

Struktur

Ett förslag byggs upp av faser — t.ex. "Rivning", "Stomme", "Ytskikt". Varje fas innehåller rad-för-rad specificerade arbets- och materialkostnader. Systemet beräknar automatiskt delsummor, moms och ROT-avdrag.

ROT-avdrag

Swedish ROT-avdrag (30 % skatteåterbäring för hushållsarbeten) hanteras per rad. Markera vilka rader som kvalificerar — totalen justeras automatiskt och visas separat i PDF-offerten.

AI-genererade offerter

Via AI Workflows-modulen kan du automatisera offertskrivning baserat på projektbeskrivning och historik. Systemet genererar ett utkast som du sedan justerar manuellt.

Förslagens status

  • Utkast — redigeras och förfinas internt
  • Skickad — offerten har levererats till kunden
  • Signerad — kunden har signerat digitalt
  • Avvisad — kunden har avböjt

Tabell: forslag, forslag_faser, forslag_rader · IPC: db:forslag:list, db:forslag:create

Skicka för signering

Desktop CRM

Flödet för att skicka en offert för digital signering sker helt inifrån Desktop CRM. Kunden behöver inte ha ett konto i Kundportalen.

Steg-för-steg

  1. 1

    Öppna förslaget

    Gå till Förslag och öppna det aktuella förslaget.

  2. 2

    Skicka för signering

    Klicka "Skicka för signering". Systemet genererar en unik URL och skickar ett e-postmeddelande till kundens e-postadress med en länk.

  3. 3

    Kunden signerar

    Kunden öppnar länken i Signeringsportalen, granskar offerten och klickar "Signera". Ingen inloggning krävs.

  4. 4

    Arkivering

    Signaturen stämplas med tidsstämpel, IP-adress och kryptografisk hash. PDF-dokumentet arkiveras och skickas automatiskt till båda parter.

  5. 5

    Status uppdateras

    Förslaget markeras automatiskt som "Signerat" i Desktop CRM.

Tips: Länken till signeringsportalen har en begränsad giltighetstid (konfigurerbar i Inställningar). Om länken löper ut kan du generera en ny från samma förslag.

Order & ÄTA

Desktop CRM

Ordermodulen hanterar beställningar av material och tjänster kopplade till projekt. ÄTA-modulen (ändrings- och tilläggsarbeten) dokumenterar arbeten som tillkommer utanför ursprungsofferten.

open-crm Order — orderhantering

Orderstatus

  • Utkast — skapas och redigeras internt
  • Godkänd — internt godkänd för beställning
  • Skickad — beställning skickad till leverantör
  • Levererad — material/tjänst mottagen
  • Avbruten — order ej genomförd
open-crm ÄTA — ändrings och tilläggsarbeten

ÄTA — Ändrings- och tilläggsarbeten

ÄTA-poster skapas när kunden beställer arbeten utanför den ursprungliga offerten. Varje ÄTA kopplas till ett projekt och innehåller beskrivning, timmar/material och pris. ÄTA-poster kan faktureras separat eller samlas till en slutfaktura.

Tabeller: order, ata · IPC: db:order:list, db:ata:list

Ekonomi

Desktop CRM

Ekonomimodulerna ger fullständig kontroll över kostnader, fakturering och kvitton per projekt.

Kostnader

open-crm Kostnader — kostnadsuppföljning

Kostnadsmodulen separerar arbets- och materialkostnader. Varje post kopplas till ett projekt och eventuellt till en fas i Tidplanen.

  • Arbetskostnad: antal timmar × timpris per resurs
  • Materialkostnad: antal × enhetspris per artikel
  • ROT-markering per post
  • Automatisk summering mot projektets budget

Tabeller: arbetskostnad, materialkostnad

Fakturering

open-crm Fakturering — fakturahantering

Fakturamodulen hanterar utgående fakturor. Fakturor kopplas till projekt och kan innehålla rader från kostnader, ÄTA eller manuellt tillagda poster.

  • Status: Planerad → Skickad → Betald / Förfallen
  • Förfallodatum med automatisk påminnelseflagga

Tabell: fakturor · IPC: db:fakturor:list

Kvitto

open-crm Kvitto — kvittoregistrering

Kvittomodulen tar emot inkommande kvitton (inköp, utlägg) och kopplar dem till projekt och kostnadsrader. Kvitton kan importeras som bild och matchas mot befintliga materialkostnadsposter.

E-post & Chat

Desktop CRM

E-post

open-crm E-post — integrerad inkorg

Den inbyggda e-postmodulen är en fullständig inkorg integrerad via Zoho Mail. Meddelanden kopplas automatiskt till rätt kund och projekt baserat på avsändarens e-postadress.

  • Läs, svara och skicka e-post direkt i appen
  • Automatisk kundkoppling baserat på avsändar-epost
  • Anpassningsbara mallar för offerter, fakturabekräftelser och uppföljningar
  • SMTP-stöd för alternativa e-postleverantörer
Tips: Konfigureras under Inställningar → E-post. Du behöver ett Zoho Mail-konto eller egna SMTP-uppgifter.

Chat

open-crm Chat — internkommunikation

Chattfunktionen är ett internt kommunikationsverktyg för teamet. Den är tillgänglig både i Desktop CRM och i Remote-appen, vilket gör att kontor och fältpersonal kan kommunicera i samma kanal.

  • Projektkanaler — ett chattrum per projekt
  • Direktmeddelanden mellan teammedlemmar
  • Olästa meddelanden visas som badge i sidomenyn
  • Medarbetare med status "Inaktiv" döljs från chattlistan

Personal & Leverantör

Desktop CRM

Personal

open-crm Personal — personalregister

Personalregistret samlar alla medarbetare med roller, kontaktuppgifter och tillgänglighet. Personaldata synkroniseras med Kalender och Remote-appen.

  • Roller: Admin, Projektledare, Tekniker, Fältpersonal
  • Status: Aktiv / Inaktiv (inaktiva döljs i chatt och kalender)
  • Tilldelning av händelser i Kalender
  • Åtkomst till Remote-appen konfigureras här (se Remote → Autentisering)

Tabell: personal · IPC: db:personal:list

Leverantör

open-crm Leverantör — leverantörsregister

Leverantörsregistret lagrar kontaktuppgifter för underleverantörer och materialleverantörer. Leverantörer kopplas till order och materialkostnadsposter.

  • Namn, organisationsnummer, kontaktperson
  • E-post och telefon
  • Koppling till order och materialposter

Tabell: leverantorer · IPC: db:leverantorer:list

Inställningar

Desktop CRM
open-crm Inställningar — konfiguration

Inställningsmodulen är kontrollpanelen för hela systemet. Ändringar träder i kraft omedelbart utan att appen behöver byggas om.

Branding

Företagsnamn, logotype, primärfärg

E-post

Zoho Mail-konfiguration och SMTP

Personal & åtkomst

Lägg till/ta bort Remote-användare

AI-modeller

API-nycklar för Claude, GPT, Gemini

Säkerhet

Supabase RLS-regler och sessioner

Tabell: app_installningar

AI Workflows

Desktop CRM
open-crm AI Workflows — visuell nodeditor

AI Workflows är en visuell nodeditor för att bygga automatiserade processer utan programmering. Koppla samman datakällor, AI-modeller och åtgärder i ett flöde.

Stödda AI-modeller

  • Anthropic Claude (Haiku, Sonnet, Opus) — rekommenderas för offertgenerering
  • OpenAI GPT-4 / GPT-4o
  • Google Gemini Pro
Tips: API-nycklar för AI-modeller konfigureras under Inställningar → AI-modeller. Varje workflow väljer sin modell separat.

Exempelarbetsflöden

SKAPA-OFER

Analyserar projektbeskrivning och genererar komplett offertunderlag med faser och prissättning

GRANSKA-OFFERT

Granskar ett existerande förslag och föreslår förbättringar baserat på historiska projekt

PROJEKTSTATUS

Sammanfattar projekthistorik och nuläge i ett strukturerat dokument för revisor eller kund

KUNDMAIL

Genererar kundanpassad e-post vid statusändringar i projekt eller faktura

Vad är Remote?

Remote
Mobiloptimerad admin-app för fältpersonal
Projekt
Sök projekt…

BRF Solbacken

Källarrenovering

aktiv

Lindblom Bygg

Fasadrenovering

planering

Vasarenen Sverige

Tillbyggnad – Vänaport 8

aktiv

Axel Norberg

Omläggning – Sörengen 63

aktiv

Erik Ström

Altan – Tegnergatan 95

planering
Kunder
Projekt
Kalender
3Chat

Remote är en Next.js-webbapp optimerad för mobil. Den riktar sig till tekniker, hantverkare och projektledare som arbetar ute på fältet och behöver tillgång till kalender, chat och projektinformation — utan att behöva öppna Desktop CRM.

Remote delar samma Supabase-databas som Desktop CRM. Ändringar som görs i Remote syns omedelbart i Desktop CRM och vice versa.

Kalender

Veckovy, markera händelser som slutförda

Chat

Projektkanaler och direktmeddelanden

Personal

Teamöversikt och tillgänglighet

Remote — Installation

Remote

Remote är ett separat Next.js-projekt som hostas oberoende av Desktop CRM. Det kan deployas på Vercel, Hostinger VPS eller Railway.

Hämta källkoden

bash
git clone https://github.com/rankgnar/crm-remote
cd crm-remote
npm install

Miljövariabler

.env
NEXT_PUBLIC_SUPABASE_URL=https://<ditt-projekt-ref>.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=<din-anon-nyckel>

Remote använder bara ANON_KEY med RLS-policys för åtkomststyrning. Ingen service key exponeras i webbappen.

Deploy till Vercel

bash
npm run dev        # Lokalt på port 3000

# Produktion
npx vercel --prod

Deploy till Hostinger VPS

bash
# På servern (Node.js 20+ krävs)
npm run build

# Starta med PM2
npm install -g pm2
pm2 start npm --name "remote" -- start
pm2 save && pm2 startup
Tips: Sätt ett anpassat domännamn (t.ex. remote.dittforetag.se) så att personalen kan bokmärka adressen på sin telefon.

Remote — Autentisering

Remote

Inloggning till Remote sker via Supabase Auth. En medarbetare får åtkomst enbart om deras e-postadress finns registrerad i tabellen app_admins.

Lägg till en Remote-användare

  1. 1Öppna Desktop CRM → Inställningar → Personal
  2. 2Välj medarbetaren och aktivera "Åtkomst till Remote"
  3. 3Ange medarbetarens e-postadress (samma adress de använder för att logga in)
  4. 4Spara — systemet skapar automatiskt en post i app_admins
  5. 5Medarbetaren får ett välkomstmejl med inloggningslänk
Notera: RLS-policyn is_app_admin() kontrollerar åtkomsten i databasen. Även om en användare känner till Supabase URL kan de inte läsa data utan att finnas i app_admins.

Remote — Funktioner

Remote

Kalender

Fältpersonalen ser sin personliga veckokalender med alla händelser tilldelade till dem. Händelser kan markeras som slutförda direkt från telefonen.

Chat

Samma chattfunktion som i Desktop CRM — projektkanaler och direktmeddelanden. Olästa meddelanden visas som badge vid ikonen. Medarbetare med status "Inaktiv" döljs från chattlistan.

Kunder

En förenklad kundöversikt för att snabbt hitta kontaktuppgifter och projektadress ute på fältet. Redigering sker i Desktop CRM.

Personal

Teamöversikt med tillgänglighet och kontaktuppgifter. Synkroniseras i realtid med Desktop CRM.

Vad är Anställdappen?

Anställdapp
Fältapp för anställda — schema, uppgifter och chatt
MK
Martin Karlsson
Tisdag 5 maj 2026

Incheckning

07:00

Utcheckning

15:30

Rast

8.0timmar

Projekt

PP-003 — Tillbyggnad
Timmar
Ledighet
Material
2Chat
Mer

Anställdappen är en mobiloptimerad webb-app för fältpersonal — tekniker, hantverkare och andra medarbetare som arbetar ute på arbetsplatser. Den är enklare och mer fokuserad än Remote: en anställd behöver bara se sitt schema, sina uppgifter och kommunicera med teamet.

Appen är lokaliserad på svenska, engelska, spanska och polska (SV / EN / ES / PL) för att täcka mångspråkiga team inom bygg och hantverk.

Schema

Dagens och veckans uppgifter i en enkel listvy

Uppgifter

Markera uppgifter som påbörjade eller slutförda

Chatt

Projektkanaler och direktmeddelanden med teamet

Flerspråkigt

SV / EN / ES / PL — väljs automatiskt från webbläsare

Tips: Skillnaden mot Remote: Remote riktar sig till administratörer och projektledare med full åtkomst. Anställdappen riktar sig till fältpersonal med begränsad vy — bara det de behöver för att utföra sitt arbete.

Anställdapp — Installation

Anställdapp

Anställdappen är ett separat Next.js-projekt med next-intl för flerspråksstöd. Deployas på Vercel, Hostinger VPS eller annan Node.js-plattform.

Hämta källkoden

bash
git clone https://github.com/rankgnar/crm-app
cd crm-app
npm install

Miljövariabler

.env
NEXT_PUBLIC_SUPABASE_URL=https://<ditt-projekt-ref>.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=<din-anon-nyckel>

Deploy till Vercel

bash
npm run dev   # Startar på port 3000

# Produktion
npx vercel --prod

Deploy till Hostinger VPS

bash
# På servern (Node.js 20+ krävs)
npm run build

# Starta med PM2
npm install -g pm2
pm2 start npm --name "crm-app" -- start
pm2 save && pm2 startup
Tips: Sätt en enkel domän som personalen kan spara som genväg på hemskärmen (t.ex. personal.dittforetag.se). Appen fungerar som en PWA och kan öppnas offline för att läsa scheman som cachats tidigare.

Anställdapp — Autentisering

Anställdapp

Inloggning sker via Supabase Auth med e-post och lösenord. En anställd får åtkomst enbart om deras e-postadress är registrerad i personalregistret i Desktop CRM.

Lägg till en anställd

  1. 1Öppna Desktop CRM → Personal
  2. 2Skapa eller välj medarbetaren
  3. 3Ange e-postadress och aktivera "Åtkomst till Anställdapp"
  4. 4Medarbetaren får ett välkomstmejl med länk för att sätta lösenord
  5. 5Vid första inloggning väljer medarbetaren sitt föredragna språk
Notera: Anställdappen och Remote kan ha överlappande användare — en projektledare kan ha tillgång till båda. Behörigheterna är separata och hanteras oberoende av varandra.

Anställdapp — Funktioner

Anställdapp

Schema

Den anställde ser sina tilldelade händelser från Kalendermodulen i Desktop CRM — uppgifter, besök och leveranser för dag och vecka. Vyn är avsiktligt enkel: datum, tid, plats och beskrivning.

Uppgifter

Uppgifter kan markeras som påbörjade eller slutförda direkt i appen. Statusen synkroniseras i realtid till Desktop CRM och syns i Kalendermodulen.

Chatt

Samma chattinfrastruktur som Desktop CRM och Remote — projektkanaler och direktmeddelanden. Den anställde ser bara kanaler kopplade till projekt de är tilldelade.

Flerspråkigt gränssnitt

Gränssnittet detekterar automatiskt webbläsarens språk och väljer bland SV, EN, ES och PL. Den anställde kan byta språk manuellt i inställningar. All affärsdata (kundnamn, projektnamn) visas som den lagrats — ingen maskinöversättning av innehåll.

Vad är Kundportalen?

Kundportal
Klientportal — webb-app för dina kunder
CRM
open-crm
PP-003aktiv

Tillbyggnad – Vänaport 8

3Signerade förslag
389kAvtalat värde
12Dokument

Tidplan

Maj 2025 – Dec 202545%

Arbetsplats

Vänaport 8, 414 51 Göteborg

Bilder

+7

Kontakt

Anna Lindqvist

Telefon

+46 70 123 45 67

Kundportalen är en autentiserad webbapp där dina kunder kan följa sina projekt, granska offerter och kommunicera med ditt företag. Den är designad för mobil i första hand — mer än 90 % av kunder öppnar portalen från sin telefon.

Portalen är lokaliserad på svenska, engelska och spanska (SV / EN / ES) med automatisk språkidentifiering baserad på webbläsarinställning.

  • Projektöversikt med status och tidslinje
  • Offertgranskning — läs och godkänn/avvisa
  • Direkt kommunikation med företaget via meddelandefunktion
  • Mobil-first design, 360 px uppåt

Kundportal — Installation

Kundportal

Kundportalen är ett Next.js 16-projekt med next-intl för flerspråksstöd. Deployas på Vercel, Hostinger VPS eller annan Node.js-plattform.

Hämta källkoden

bash
git clone https://github.com/rankgnar/open-crm-client-v2
cd open-crm-client-v2
npm install

Miljövariabler

.env
NEXT_PUBLIC_SUPABASE_URL=https://<ditt-projekt-ref>.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=<din-anon-nyckel>

Deploy till Vercel

bash
npm run dev   # Startar på port 3000

# Produktion
npx vercel --prod

Deploy till Hostinger VPS

bash
# På servern (Node.js 20+ krävs)
npm run build

# Starta med PM2
npm install -g pm2
pm2 start npm --name "kundportal" -- start
pm2 save && pm2 startup
Viktigt: Kundportalen kräver att Supabase RLS-policys är korrekt konfigurerade. En kund med giltig session ska enbart kunna se data kopplad till sin egna kund-ID. Kontrollera att is_kund_user_for()-policyn är aktiv på alla relevanta tabeller.

Kundportal — Autentisering

Kundportal

Kunder autentiseras via Supabase Auth. En kund får åtkomst enbart om deras e-postadress är registrerad i tabellen kund_users och kopplad till rätt kund i kunder-tabellen.

Bjud in en kund till portalen

  1. 1Öppna Desktop CRM → Kunder → Välj kunden
  2. 2Klicka "Bjud in kund till portal"
  3. 3Ange kundens e-postadress
  4. 4Systemet skapar en post i kund_users och skickar ett inbjudningsmejl
  5. 5Kunden klickar länken i mejlet och sätter ett lösenord
Notera: RLS-policyn is_kund_user_for(kund_id) garanterar att varje kund bara ser sin egen data — även om de försöker manipulera URL-parametrar ser de ingenting från andra kunder.

Kundportal — Funktioner

Kundportal

Projektöversikt

Kunden ser alla sina projekt med status, tidslinje och kortfattad beskrivning. Projektdetaljer uppdateras i realtid från Desktop CRM.

Offerter

Kunden kan läsa fullständiga offertdokument i portalen och välja att godkänna eller avvisa. Godkännande i portalen skickar kunden till Signeringsportalen för digital underskrift.

Meddelanden

Direkt kommunikation mellan kund och företag via ett inbyggt meddelandesystem. Meddelanden från portalen visas i Desktop CRM under kundens profil.

Signeringsportal — Installation

Signering

Signeringsportalen är ett fristående Next.js-projekt. Deployas på Vercel, Hostinger VPS eller annan Node.js-plattform.

Hämta källkoden

bash
git clone https://github.com/rankgnar/crm-sign
cd crm-sign
npm install

Miljövariabler

.env
NEXT_PUBLIC_SUPABASE_URL=https://<ditt-projekt-ref>.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=<din-anon-nyckel>
SUPABASE_SERVICE_ROLE_KEY=<din-service-role-nyckel>

Signeringsportalen kräver SERVICE_ROLE_KEY för server-side PDF-generering och signaturstämpling — nyckeln exponeras aldrig i klientkoden.

Deploy till Vercel

bash
npm run dev   # Startar på port 3000

# Produktion
npx vercel --prod

Deploy till Hostinger VPS

bash
# På servern (Node.js 20+ krävs)
npm run build

# Starta med PM2
npm install -g pm2
pm2 start npm --name "crm-sign" -- start
pm2 save && pm2 startup
Tips: Signeringsportalen behöver en dedikerad domän (t.ex. sign.dittforetag.se). Länken som skickas till kunden innehåller ett unikt token knutet till den domänen.

Signeringsflöde

Signering
Digital signering av offerter — utan inloggning
CRM
open-crm
Dokument att signera
OFFERT #OF-0042Utkast

Demo Bygg AB — Erik Ström Håkansson

Fas 1 – Grund45 000 kr
Fas 2 – Stomme82 500 kr
Fas 3 – Ytskikt38 000 kr
Totalt inkl. moms206 250 kr

Signera digitalt

Fullständigt namn

Erik Ström Håkansson

Signera med fingret…
IP-adress och tidpunkt registreras

Signeringsportalen är en fristående webbapp för att ta emot och signera offerter digitalt. Kunden behöver inget konto — offerten levereras via en unik engångslänk som skickas från Desktop CRM.

Fullständigt signeringsflöde

  1. 1

    Desktop CRM genererar länk

    Administratören klickar "Skicka för signering" på ett förslag. Systemet genererar en unik URL med begränsad giltighetstid och skickar ett e-postmeddelande till kundens adress.

  2. 2

    Kunden öppnar länken

    Signeringsportalen laddar offertdokumentet från länkens token. Ingen inloggning krävs. Länken kan bara användas en gång.

  3. 3

    Granskning

    Kunden läser igenom offerten med alla faser, rader och priser. Dokumentet kan scrollas och zoomstas.

  4. 4

    Digital signatur

    Kunden klickar "Signera" och bekräftar sitt namn. Inga plugin, inga certifikat — signaturens autenticitet garanteras av systemets metadata.

  5. 5

    Stämpling & arkivering

    Signaturen stämplas med exakt tidsstämpel (UTC), kundens IP-adress och en kryptografisk hash av dokumentinnehållet. PDF genereras och arkiveras.

  6. 6

    Bekräftelse till båda parter

    Det signerade PDF-dokumentet skickas automatiskt till kundens och företagets e-postadress. Förslaget uppdateras till status "Signerat" i Desktop CRM.

Signering — Teknisk detalj

Signering

Länkens livslängd

Signeringslänkar har en konfigurerbar TTL (time-to-live). Standardvärdet är 72 timmar. Om länken löper ut utan signering kan administratören generera en ny från samma förslag i Desktop CRM — det ursprungliga dokumentet ändras inte.

Dokumenthash

När signaturlänken genereras beräknas en SHA-256-hash av offertdokumentets innehåll och sparas i databasen. Samma hash beräknas vid signeringstillfället och jämförs — om dokumentet har manipulerats under resans gång avvisas signaturen.

Vad sparas i databasen

  • Signaturdatum och exakt tid (UTC)
  • Signatärens namn (som de angivit)
  • IP-adress vid signeringstillfället
  • SHA-256-hash av dokumentinnehållet
  • URL till arkiverat PDF-dokument
Viktigt: Signeringen är inte en kvalificerad elektronisk signatur (QES) enligt eIDAS-förordningen. Den ger juridisk grund via metadata och dokumenthash, men kontakta en jurist om projekten kräver formell QES.

Vad är Formulärappen?

Formulärapp
Klientfrågeformulär genererade med AI

Frågeformulär

Badrumsrenovering Lidingö

1. Vad är badrummets yta?

8,5 m²

2. Befintliga kakel att ta bort?

Ja

3. Önskat material

Storformat klinker

Skickat!

Formulärappen är en mobiloptimerad webbapp för att samla in strukturerad information från kunder innan offerten skrivs. Administratören genererar ett formulär med AI direkt från projektvyn i Desktop CRM, kopierar eller skickar länken via e-post till kunden, och kundens svar läses sedan automatiskt av AI-offertflödet.

Formulärappen kräver ingen inloggning — kunden öppnar länken och fyller i svaren i sin telefon. Inga cookies, inga konton.

AI-genererade frågor

Formuläret skapas av en konfigurerbar AI-assistent baserat på projektkontexten

Ingen inloggning

Kunden öppnar en unik länk — formuläret är giltigt tills det besvaras

Svar → offert

Svaren sparas och läses direkt av AI-offertflödet när offerten genereras

Formulärapp — Installation

Formulärapp

Formulärappen är ett Next.js-projekt utan autentisering. All dataåtkomst sker via anonyma Supabase RPCs med SECURITY DEFINER — ingen service role key behövs i webbappen.

Hämta källkoden

bash
git clone https://github.com/rankgnar/open-crm-form
cd open-crm-form
npm install

Miljövariabler

.env
NEXT_PUBLIC_SUPABASE_URL=https://<ditt-projekt-ref>.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=<din-anon-nyckel>

Formulärappen exponerar enbart ANON_KEY. Inga sekretnycklar används — all känslig logik hanteras server-side i Supabase Edge Functions.

Deploy till Vercel

bash
npm run dev   # Startar på port 3000

# Produktion
npx vercel --prod

Formulärappen bör ha en dedikerad domän, t.ex. form.dittforetag.se. Domänen konfigureras i Desktop CRM under Inställningar → Allmänt → Formulärappens URL — systemet använder den för att bygga länkarna som skickas till kunder.

Formulärapp — Funktioner

Formulärapp

Generera formulär med AI

I Desktop CRM, under Projekt → Frågor, klickar administratören Generera med AI. En konfigurerbar AI-assistent (typen Formulärgenerator) skapar ett JSON-formulär med relevanta frågor baserade på projektnamnet och eventuell beskrivning. Frågorna kan redigeras manuellt innan formuläret sparas.

Skicka länken

När formuläret är sparat visas en unik länk i formatet form.dittforetag.se/f/{token}. Länken kan kopieras direkt eller skickas via e-post med ett klick — systemet förifyller avsändare, mottagare (kundens e-postadress) och ämnesrad via e-postmallen Frågeformulär — länk till klient. Sändningen loggas i projektets Anteckningar.

Kunden svarar

Kunden öppnar länken och möts av en välkomstskärm med företagsnamn och projektnamn. Formuläret visas sedan fråga för fråga. När kunden skickar svaren sparas de i databasen och en notifikation skickas till företagets e-post via Supabase Edge Function. Svarstillfället loggas som en grön anteckning i projektets Anteckningar.

Svar i AI-offertflödet

Svaren sparas som en .md-fil i projektets dokumentbibliotek (mapp questions). AI-offertflödets data:projekt:text-files-nod läser automatiskt dessa filer — svaren vägs in i offertgenereringen utan manuell handpåläggning.

Notifikationer

E-postmallar för formulärflödet hanteras under Inställningar → E-post → Mallar:

  • "Frågeformulär — länk till klient" — mallen för e-posten som skickas till kunden med formulärlänken
  • "Formulär besvarat — notifikation" — notifikation till företaget när kunden har svarat. Kan avaktiveras med toggle.
Tips: Formulärgeneratorn konfigureras under Inställningar → AI → Formulärgenerator. Du väljer AI-modell och kan justera systemprompt för att styra vilken typ av frågor som genereras.

Systemöversikt

open-crm är en Electron-app med strikt separation mellan React-renderer och Node.js main-process. Supabase-klienten är aldrig tillgänglig i renderer — all dataåtkomst sker via IPC-kanaler.

arkitektur
Renderer (React + TypeScript + Tailwind)
  └─ window.api.invoke('db:kunder:list')
        │ contextBridge
  Preload (src/preload/index.ts)
        │ ipcRenderer → ipcMain
  Main (src/main/ipc/*.ts)
        │
  Supabase SDK (src/main/supabase.ts)
        │
  PostgreSQL (Supabase Cloud / self-hosted)

Renderer

React 18 + TypeScript 5 + Tailwind CSS v4

Main

Node.js + Electron IPC handlers (src/main/ipc/)

Databas

Supabase PostgreSQL med RLS-policys

Viktigt: Renderer-processen får aldrig importera @supabase/supabase-js direkt. Alla anrop till databasen måste gå via window.api.invoke(). Detta säkerställer att service key och access token aldrig exponeras i renderer-kontexten.

IPC-mönster

Alla IPC-kanaler följer konventionen db:<entitet>:<åtgärd>.

typescript — renderer
// Hämta alla kunder
const kunder = await window.api.invoke('db:kunder:list') as Kund[]

// Skapa ny kund
const kund = await window.api.invoke('db:kunder:create', {
  namn: 'Acme AB',
  epost: 'info@acme.se',
}) as Kund

// Uppdatera
await window.api.invoke('db:kunder:update', { id: kund.id, namn: 'Acme AB (uppdaterad)' })
typescript — main handler
// src/main/ipc/kunder.ts
export function registerKunderHandlers(): void {
  ipcMain.handle('db:kunder:list', async () => {
    const { data, error } = await supabase
      .from('kunder')
      .select('*')
      .order('created_at', { ascending: false })
    if (error) throw new Error(error.message)
    return data
  })

  ipcMain.handle('db:kunder:create', async (_, input: CreateKundInput) => {
    const { data, error } = await supabase
      .from('kunder')
      .insert(input)
      .select()
      .single()
    if (error) throw new Error(error.message)
    return data
  })
}

Felhantering

Handlers kastar ett vanligt Error vid fel — inga wrapper-objekt. Renderer-komponenter fångar felet med try/catch och visar det i UI:t.

Databas & RLS

Tabellnomenklatur

Alla tabeller använder snake_case och pluralis. Kolumner är konsekvent snake_case. Primärnyckel är alltid id UUID DEFAULT gen_random_uuid().

Migrationssystem

filstruktur
supabase/
└── migrations/
    ├── 20240101120000_create_kunder.sql
    ├── 20240102120000_create_projekt.sql
    ├── 20240103120000_create_forslag.sql
    └── ...

Filer namnges YYYYMMDDHHMMSS_beskrivning.sql och appliceras i lexikografisk ordning. Varje fil körs exakt en gång — systemet spårar körda filer i tabellen _applied_migrations.

Hela migrationssetet för en fresh installation finns i rankgnar/open-crm-setup — ett separat repo med bootstrapscript för self-hosted Supabase (VPS).

Row-Level Security (RLS)

Alla tabeller har RLS aktiverat. Varje app i ekosystemet har sin egna åtkomstkontroll:

Desktop CRM

Kör med service_role — full åtkomst via main-processen. Aldrig exponerad i renderer.

Remote

is_app_admin() — kontrollerar om auth.uid() finns i app_admins-tabellen.

Anställdapp

Anställd-RLS — åtkomst begränsad till data kopplad till den inloggade medarbetarens personal-ID.

Kundportal

is_kund_user_for(kund_id) — en kund ser bara sin kund-ID:s data.

Signering

Token-baserad åtkomst utan auth — valideras server-side mot signeringstabellen.

Branding & tema

Visuell identitet (företagsnamn, logotype, primärfärg) lagras i tabellen app_installningar och hämtas vid appstart. Ändringar träder i kraft utan ny build.

Dark / Light-tema

Appen startar i dark mode som standard. Användaren kan växla tema via knappen i titelraden. Valet sparas lokalt och återställs vid nästa start.

Säkerhet — känsliga kolumner

Tabellen app_installningar innehåller både publika konfigurationsvärden och känsliga API-nycklar. Supabase RLS är konfigurerat med kolumn-nivå behörighet — anon-rollen kan bara läsa de kolumner som är icke-känsliga. Service-nycklar exponeras aldrig via PostgREST.

Integrationer

Zoho Mail

E-postintegrationen kräver ett Zoho Mail-konto. Alternativt kan vilken SMTP-server som helst konfigureras.

  • Konfigureras under Inställningar → E-post
  • Inkommande e-post kopplas till kunder via avsändar-e-postadress
  • Mallar för offerter, fakturabekräftelser och påminnelser
  • SMTP-alternativ: ange host, port, användarnamn och lösenord

Supabase Auth

Supabase Auth hanterar autentisering för Remote och Kundportalen. Desktop CRM autentiseras inte via Auth — den kör med service_role i main-processen.

Miljövariabler — referens

Komplett lista över alla miljövariabler som används i ekosystemet:

VariabelAppBeskrivning
SUPABASE_URLDesktopProject URL från Supabase → Settings → API
SUPABASE_ANON_KEYDesktopAnon/public key — begränsad åtkomst via RLS
SUPABASE_SERVICE_KEYDesktopService role key — full åtkomst, används bara i main-processen
SUPABASE_ACCESS_TOKENDesktopPersonal Access Token — kör SQL-migreringar via Management API
NEXT_PUBLIC_SUPABASE_URLRemote / App / PortalSamma URL som ovan, exponeras till webbläsaren
NEXT_PUBLIC_SUPABASE_ANON_KEYRemote / App / PortalAnon key för webb-apparna, RLS skyddar data
Viktigt: SUPABASE_SERVICE_KEY och SUPABASE_ACCESS_TOKEN får aldrig exponeras i webbläsaren eller i webb-apparna. De tillhör enbart Desktop CRM:s main-process och ska inte ha prefix NEXT_PUBLIC_.

Bidra till projektet

open-crm välkomnar bidrag. Öppna ett issue för buggrapporter eller funktionsförslag, eller skicka in en pull request direkt.

Kom igång

bash
# Forka repot på GitHub och klona din fork
git clone https://github.com/<ditt-namn>/open-crm
cd open-crm
npm install

# Skapa en feature-branch
git checkout -b feat/min-forbattring

# Gör dina ändringar och verifiera
npm run typecheck

# Skicka in pull request

Kodkonventioner

  • TypeScript strict — inga any-typer, inga @ts-ignore
  • IPC-kanaler följer mönstret db:<entitet>:<åtgärd>
  • Komponenter max ~200 rader — dela upp vid behov
  • Inga hårdkodade färger — använd CSS-tokens (bg-bg, text-muted osv.)
  • Inga kommentarer som förklarar VAD koden gör — bara VARFÖR när det inte är uppenbart
  • npm run typecheck måste passera innan PR öppnas
Tips: Fullständiga konventioner finns i CLAUDE.md i repots rot. Det är den auktoritativa referensen för kod- och arkitekturstandarder.

Licens

open-crm distribueras under MIT License. Du är fri att använda, modifiera och distribuera koden kommersiellt och icke-kommersiellt. Ingen attribution krävs, men uppskattas.

LICENSE
MIT License

Copyright (c) 2024 open-crm contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
provided to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.