Sikkerhet
Hva som skjer med avtalene dere laster opp
Tre spørsmål kommer før den første PDF-en: hvor havner filen, hvem kan åpne den, og hva gjør språkmodellen med den. Svarene står her, ledd for ledd.
Alt på denne siden beskriver hvordan produktet er bygget i dag. Det vi ikke kan vise til, har vi latt stå usagt framfor å skrive det pent.
Veien filen tar
En signert avtale er ikke en fil du vil måtte lete etter, og ikke en fil du vil finne igjen på en åpen lenke. Her er hvert ledd fra du slipper den i nettleseren til den vises fram igjen.
- Filen
- Selve PDF-en legges i en privat Vercel Blob-store, «dealpilot-documents», i regionen fra1. Privat betyr her at objektet ikke har noen offentlig adresse i det hele tatt — ikke at vi har skrudd av deling på noe som ellers ville vært åpent.
- Feltene
- Sidetekst, funn, frister og logg ligger i Neon Postgres i eu-central-1, altså Frankfurt. Serverfunksjonene som leser dem kjører i fra1, rett ved siden av. Begge deler er innenfor EU.
- Visningen
- Hver gang en fil vises eller lastes ned, går den gjennom /api/documents/[id]/file. Ruten sjekker innlogging og arbeidsområde før den i det hele tatt spør lagringen, og svaret sendes med «Cache-Control: private, no-store».
- Teksten
- Sideteksten hentes ut på vår egen server med unpdf og lagres side for side, med sidetall. Det er den lagrede sideteksten sitatene senere sjekkes mot. DOCX konverteres i samme prosess, uten sideinndeling.
- Den samme filen to ganger
- Hver opplasting får en sha256-sum før den lagres. Er summen fra før i arbeidsområdet, spør vi om det er meningen i stedet for å legge de samme bytene der en gang til.
- Det vi ikke tar imot
- Passordbeskyttede PDF-er avvises ved opplasting, og det samme gjør filer over 25 MB. Vi prøver ikke å låse opp noe som er låst.
Skillet mellom to kunder ligger i hver eneste spørring, ikke i grensesnittet
Hver tabell som eier kundedata har en workspace_id, og den er indeksert. Avtaler, dokumenter, sidetekst, funn, frister, varsler og logg — alle sammen. Et arbeidsområde er ikke et filter vi legger på i visningen; det er en kolonne spørringen ikke kommer utenom.
Alle serverlesninger går gjennom requireWorkspaceContext(). Den henter sesjonen og slår deretter opp medlemskapet i databasen. Arbeidsområdet sesjonen peker på er et hint, aldri et bevis, og en id som kommer fra nettleseren er aldri noe vi legger til grunn.
Det gjelder leddene nedover også. Laster du opp til et selskap, slås selskapet opp på både id og arbeidsområde før avtalen opprettes — hører det ikke hjemme hos deg, stopper det der. Ber du om en avtale som finnes, men ikke hos deg, får du 404 eller 403. Ikke innholdet.
Innenfor arbeidsområdet er det derimot ikke noe skille: alle medlemmer ser alle avtalene. Rollene eier og administrator styrer hvem som kan endre innstillinger, selskapsstruktur og invitasjoner — ikke hvem som kan lese. Skal to deler av konsernet ikke se hverandres avtaler, må de ha hvert sitt arbeidsområde.
Hva modellen får, og hva vi gjør med svaret
- Det som sendes
- Sideteksten fra avtalen, med sidemarkører, gjennom Vercel AI Gateway. Har PDF-en ikke noe brukbart tekstlag — en skanning, typisk — sendes selve filen i stedet, fordi det er den eneste måten å lese den på. Utover avtalen sendes filnavnet og navnet på ditt eget selskap, så modellen vet hvilken av partene som er dere.
- Det som kommer tilbake
- Svaret må passe et Zod-skjema før vi ser på det: modellen kan bare svare i den formen vi har definert, felt for felt. Gjør den ikke det, får den ett forsøk til med beskjed om å svare på skjemaform — og feiler det også, feiler kjøringen synlig i stedet for å gjette seg videre.
- Sitatet
- Hvert funn skal peke på et ordrett sitat og en side. Sitatet slås opp i den lagrede sideteksten — først på siden modellen oppga, så på alle de andre. Sto det et annet sted, rettes sidetallet. Finnes det ikke i dokumentet i det hele tatt, står funnet uten kilde og med lavere sikkerhet enn modellen selv oppga.
- Det modellen ikke fant
- Felt modellen ikke fant blir null, og vises som «Ikke funnet i avtalen» — ikke som en tom strek du må tolke selv. Modellen har dessuten beskjed om ikke å regne ut noe: den henter sluttdato og oppsigelsestid, mens siste frist for oppsigelse regnes ut i kode etterpå.
Ingenting av dette er et faktum før et menneske har sett på det. Avtalen står i «gjennomgang» til noen godkjenner den, og det du retter er det som gjelder etterpå. Hver kjøring lagres i extraction_run med modell, promptversjon og skjemaversjon, og godkjenninger og endringer skrives til audit_event og vises som historikk på avtalen.
Spørsmål vi får før første opplasting
- Har dere ISO 27001 eller SOC 2?
- Nei, ingen av delene. Vi har ingen sikkerhetssertifisering, og vi kommer ikke til å antyde at vi har en. Det du får i stedet er beskrivelsen over: hvor dataene ligger, hvordan de skilles og hva som sendes videre.
- Forlater avtalene infrastrukturen deres?
- Avtaleteksten går ett sted: til språkmodellen, gjennom Vercel AI Gateway. Varsler sendes med Resend, og de inneholder avtaletittel, dato, selskapsnavn og en lenke inn i DealPilot — ikke avtaleteksten, og aldri dokumentet som vedlegg.
- Brukes avtalene våre til å trene en modell?
- Ikke av oss. Avtaleteksten din ligger i ditt eget arbeidsområde, og vi trener eller finjusterer ingenting på den. Hva leverandøren av språkmodellen gjør med et kall som går gjennom gatewayen, avgjøres av deres vilkår, og vi vil ikke love noe på deres vegne.
- Hvordan er innloggingen sikret?
- Better Auth med e-post og passord på minst åtte tegn, sesjoner som varer i fjorten dager, og maks åtte innloggingsforsøk i minuttet i produksjon. Omdirigeringen i kanten er bare et hint — den virkelige kontrollen gjøres på nytt i hver side, hver rute og hver serverhandling.
Begynn med den avtalen du er mest usikker på
Last opp én PDF og se hva DealPilot finner. Tar under et minutt, og du trenger ikke legge inn kortnummer.
Opprett konto