* chore(analytics): configure posthog session replay masking Move session replay from the mask-everything default to pattern-based masking in lib/analytics/replay-masking.ts: currency-shaped text, person-/organisationsnummer (rendered and typed) and password inputs are masked; other interface text and typed input is recorded for debugging. data-ph-mask keeps force-masking tagged PII and data-ph-unmask is still honored for chrome. Privacy policy, RoPA and decision log updated to match. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore(analytics): address review comments on replay masking PR Bump the privacy policy's visible last-updated date to 2026-08-06 and add the conventional vi.clearAllMocks() beforeEach to the replay-masking tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
771 lines
33 KiB
YAML
771 lines
33 KiB
YAML
# Record of Processing Activities (GDPR Art. 30)
|
|
#
|
|
# Each entry documents one processing activity. Field shape follows EDPB
|
|
# Guidelines 9/2022 §3 (controller-side RoPA): purposes, lawful basis,
|
|
# data subject + data category, recipients, transfer mechanism, retention,
|
|
# security measures. Add an entry whenever a new flow ships that touches
|
|
# personal data: onboarding, integrations, support, or regulator filings.
|
|
|
|
processing_activities:
|
|
|
|
- id: invoices.delivery_history
|
|
name: Leveranshistorik för kundfakturor
|
|
purpose: >-
|
|
Dokumentera att en kundfaktura skickades, när leveransförsöket skedde,
|
|
vilken mottagardomän som användes och vilken exakt PDF som skickades.
|
|
Dashboardens listvy visar endast maskerade mottagardomäner och
|
|
driftmetadata. Fullständigt meddelandeinnehåll stannar på serversidan.
|
|
lawful_basis: art_6_1_b_and_c
|
|
special_category_basis: null
|
|
controller: gnubok-tenant
|
|
processor: supabase_and_resend
|
|
data_subjects:
|
|
- customer_contact
|
|
- company_member
|
|
data_categories:
|
|
- user.contact.email
|
|
- user.communication_content
|
|
- user.activity_timestamp
|
|
- user.document
|
|
recipients:
|
|
- name: Supabase
|
|
country: EU
|
|
role: processor
|
|
- name: Resend
|
|
country: US
|
|
role: processor
|
|
international_transfers:
|
|
applicable: true
|
|
mechanism: scc_2021_c2p
|
|
note: Resend processes the outbound delivery under SCC Module 2.
|
|
retention:
|
|
duration: through_seventh_calendar_year_after_fiscal_year_end
|
|
basis: bfl_7_kap_and_gdpr_storage_limitation
|
|
stored_in:
|
|
- invoice_deliveries
|
|
- document_attachments
|
|
security_measures:
|
|
- active_company_route_context
|
|
- rls_company_scoped
|
|
- masked_recipient_domains_in_list_api
|
|
- no_message_content_in_browser_list_api
|
|
- exact_sent_pdf_worm_protection
|
|
- metadata_only_immutable_audit_log
|
|
- daily_post_retention_pii_redaction
|
|
- signed_provider_delivery_webhook_only
|
|
- masked_recipient_addresses_in_provider_reason_text
|
|
|
|
- id: customer.private_identity
|
|
name: Personnummer för privatkund
|
|
purpose: >-
|
|
Identifiera en privatkund när företagets avtal, fakturering eller
|
|
kundadministration kräver en entydig identitet. Personnumret får endast
|
|
sparas på kundtypen privatkund. Samtliga listnings- och exportytor i API
|
|
och UI exponerar det endast maskerat (fyra sista siffrorna). Undantaget är
|
|
en enskild uppslagsyta (GET /api/customers/{id}/personal-number) som
|
|
returnerar hela värdet för en kund i taget, kräver skrivroll och loggas
|
|
med aktör men aldrig med värdet, så att den som registrerat ett
|
|
personnummer kan kontrollera vad som faktiskt sparats.
|
|
lawful_basis: art_6_1_b
|
|
special_category_basis: null
|
|
controller: gnubok-tenant
|
|
processor: supabase
|
|
data_subjects:
|
|
- customer
|
|
data_categories:
|
|
- user.government_id
|
|
recipients:
|
|
- name: Supabase
|
|
country: EU
|
|
role: processor
|
|
international_transfers:
|
|
applicable: false
|
|
mechanism: null
|
|
note: EU-only processor.
|
|
retention:
|
|
duration: customer_relationship_or_7y_if_accounting_record
|
|
basis: contract_and_bfl_7_kap
|
|
stored_in:
|
|
- customers.personal_number
|
|
- retained_invoice_documents_when_required
|
|
security_measures:
|
|
- aes_256_gcm_field_encryption
|
|
- masked_api_and_ui_output_last4_only
|
|
- write_role_required
|
|
- rls_company_scoped
|
|
# Replaces the previous `no_full_value_read_endpoint`. A single explicit
|
|
# drill-in now exists (GET /api/customers/{id}/personal-number): the
|
|
# value was otherwise write-only, so a user could store a personnummer
|
|
# and never verify what had been stored. Every listing surface still
|
|
# masks; the drill-in requires the write role, returns one customer at a
|
|
# time, and logs actor + customer id without the value.
|
|
- full_value_read_only_via_single_customer_drill_in
|
|
- full_value_read_requires_write_role
|
|
- full_value_read_logged_with_actor_never_value
|
|
|
|
- id: agi.submit
|
|
name: AGI inlämning till Skatteverket
|
|
purpose: >-
|
|
Lämna in lagstadgad arbetsgivardeklaration på individnivå (AGI) till
|
|
Skatteverket varje månad (Skatteförfarandelagen 26 kap.). Innefattar
|
|
huvuduppgift (HU) och individuppgifter (IU) per anställd. Skatteverkets
|
|
kvittens sparas i response_data inklusive signeradAv: personnummer för
|
|
den som BankID-signerade inlämningen. Ändamålet är bevis för vem som
|
|
juridiskt undertecknade deklarationen samt behandlingshistorik; BFL
|
|
5 kap. 6 § och BFNAR 2013:2 kap. 8 kräver att räkenskapsinformationen
|
|
bevarar den faktiska ingivaren, medan själva inlämningen styrs av SFL.
|
|
lawful_basis: art_6_1_c # legal obligation
|
|
special_category_basis: null
|
|
controller: gnubok-tenant
|
|
processor: anthropic-na # software supplier; Skatteverket is recipient, not processor
|
|
data_subjects:
|
|
- employee
|
|
- company_signatory # firmatecknare/deklarationsombud (BankID-signerare av kvittensen)
|
|
data_categories:
|
|
- user.government_id # personnummer (anställda i IU; signerarens i response_data.signeradAv)
|
|
- user.name
|
|
- user.financial.employment # gross salary, tax withheld, benefits
|
|
- user.financial.tax # avgifter, sjuklönekostnad
|
|
recipients:
|
|
- name: Skatteverket
|
|
country: SE
|
|
role: legal_recipient
|
|
international_transfers:
|
|
applicable: false
|
|
mechanism: null
|
|
note: >-
|
|
Sweden-to-Sweden processor-to-public-authority flow. Adequacy decision
|
|
not applicable; no third-country transfer.
|
|
retention:
|
|
duration: 7y
|
|
basis: bfl_7_kap # BFL 7 kap. 2 §: räkenskapsinformation
|
|
stored_in:
|
|
- agi_declarations.xml_content
|
|
- agi_declarations.individuppgifter
|
|
- agi_declarations.response_data # SKV kvittens incl. signeradAv (signerarens pnr); access via company-membership RLS
|
|
- skatteverket_api_audit_log
|
|
security_measures:
|
|
- encryption_at_rest_supabase
|
|
- rls_company_scoped
|
|
- tls_1_3_to_skatteverket
|
|
- bankid_signing_required_for_filing
|
|
- immutable_audit_log
|
|
- personnummer_at_rest_encryption
|
|
|
|
- id: agi.kontrollera.preflight
|
|
name: AGI pre-flight kontrollera (HU/IU)
|
|
purpose: >-
|
|
Skicka enskild HU eller IU som JSON till Skatteverkets kontrollera-
|
|
ändpunkt (v1.7 §7/§8) för dry-run-validering av felmeddelanden och
|
|
STOPP-/AVVISANDE-status innan ett fullständigt underlag laddas upp.
|
|
Skatteverket lagrar inget från denna kontroll; svaret driver vår UI
|
|
som låter användaren rätta felaktigheter i lönekörningen lokalt.
|
|
lawful_basis: art_6_1_c # legal obligation (ancillary to AGI filing)
|
|
special_category_basis: null
|
|
controller: gnubok-tenant
|
|
processor: anthropic-na
|
|
data_subjects:
|
|
- employee
|
|
data_categories:
|
|
- user.government_id # personnummer (BetalningsmottagarId)
|
|
- user.financial.employment # gross salary, tax withheld, benefits
|
|
recipients:
|
|
- name: Skatteverket
|
|
country: SE
|
|
role: legal_recipient
|
|
international_transfers:
|
|
applicable: false
|
|
mechanism: null
|
|
note: Sweden-to-Sweden flow; no third-country transfer.
|
|
retention:
|
|
# Skatteverket retains nothing for kontrollera calls. Our outbound
|
|
# audit row in skatteverket_api_audit_log records who-called-what-when
|
|
# but NOT the payload body, minimising at-rest footprint.
|
|
duration: 7y
|
|
basis: bfl_7_kap
|
|
stored_in:
|
|
- skatteverket_api_audit_log
|
|
security_measures:
|
|
- strict_zod_allow_list_input_validation
|
|
- request_size_cap_64kb
|
|
- rbac_company_member_role_check
|
|
- rls_company_scoped
|
|
- tls_1_3_to_skatteverket
|
|
- immutable_audit_log
|
|
- no_payload_body_persisted
|
|
|
|
- id: moms.declaration
|
|
name: Momsdeklaration till Skatteverket
|
|
purpose: >-
|
|
Lämna in lagstadgad momsdeklaration (utkast, lås och signering) till
|
|
Skatteverkets momsdeklaration-API (Mervärdesskattelagen 17 kap. 24 §).
|
|
lawful_basis: art_6_1_c
|
|
special_category_basis: null
|
|
controller: gnubok-tenant
|
|
processor: anthropic-na
|
|
data_subjects:
|
|
- business_owner
|
|
data_categories:
|
|
- user.government_id # orgnummer (juridiska personer) eller pnr
|
|
- user.financial.tax # rutor 05-62
|
|
recipients:
|
|
- name: Skatteverket
|
|
country: SE
|
|
role: legal_recipient
|
|
international_transfers:
|
|
applicable: false
|
|
mechanism: null
|
|
note: Sweden-to-Sweden flow; no third-country transfer.
|
|
retention:
|
|
duration: 7y
|
|
basis: bfl_7_kap
|
|
stored_in:
|
|
- extension_data (utkast metadata)
|
|
- skatteverket_api_audit_log
|
|
security_measures:
|
|
- rls_company_scoped
|
|
- tls_1_3_to_skatteverket
|
|
- bankid_signing_required_for_filing
|
|
- immutable_audit_log
|
|
|
|
- id: psd2.cash_account_mirror
|
|
name: PSD2-konton speglas till cash_accounts
|
|
purpose: >-
|
|
När en bank-anslutning via Enable Banking returnerar kontolista efter
|
|
lyckad PSD2-consent kopieras kontometadata (IBAN, valuta, kontonamn,
|
|
external_uid) till cash_accounts så att avstämning, motkontoresolver
|
|
och __PRIMARY_SEK__-sentinel kan rutta verifikat utan att läsa JSONB
|
|
från bank_connections.accounts_data vid varje fråga.
|
|
lawful_basis: art_6_1_b # contract (PSD2 consent + bookkeeping service)
|
|
special_category_basis: null
|
|
controller: gnubok-tenant
|
|
processor: anthropic-na
|
|
data_subjects:
|
|
- business_owner
|
|
data_categories:
|
|
- user.financial.bank_account # IBAN
|
|
- user.contact # account name (kontotitel)
|
|
recipients:
|
|
- name: Supabase
|
|
country: EU
|
|
role: processor
|
|
international_transfers:
|
|
applicable: false
|
|
mechanism: null
|
|
note: EU-only processor; no third-country transfer.
|
|
retention:
|
|
duration: consent_lifetime
|
|
basis: psd2_consent
|
|
stored_in:
|
|
- cash_accounts
|
|
- bank_connections.accounts_data
|
|
security_measures:
|
|
- rls_company_scoped
|
|
- data_minimization_no_balance_on_callback
|
|
- failure_emitted_to_event_log
|
|
|
|
- id: transactions.counterparty_iban
|
|
name: Motpartens IBAN på transaktioner
|
|
purpose: >-
|
|
Spara motpartens IBAN på transaktionsraden så att own-account-detector
|
|
kan identifiera överföringar mellan företagets egna konton (1930 → 1932
|
|
etc.) och bokföra båda benen automatiskt istället för att felbokföra
|
|
utflödet som extern kostnad. Krävs även för payment-matchning mot
|
|
leverantörsfakturor.
|
|
lawful_basis: art_6_1_b # contract (bookkeeping service)
|
|
special_category_basis: null
|
|
controller: gnubok-tenant
|
|
processor: anthropic-na
|
|
data_subjects:
|
|
- business_owner
|
|
- counterparty
|
|
data_categories:
|
|
- user.financial.bank_account # counterparty IBAN
|
|
recipients:
|
|
- name: Supabase
|
|
country: EU
|
|
role: processor
|
|
international_transfers:
|
|
applicable: false
|
|
mechanism: null
|
|
note: EU-only processor.
|
|
retention:
|
|
duration: 7y
|
|
basis: bfl_7_kap
|
|
stored_in:
|
|
- transactions.counterparty_iban
|
|
security_measures:
|
|
- rls_company_scoped
|
|
- immutable_after_post
|
|
|
|
- id: skattekonto.drift_alert
|
|
name: Skattekonto-drift via e-post
|
|
purpose: >-
|
|
Underrätta företagets kontaktadress när det cachade Skatteverket-saldot
|
|
avviker från GL 1630 utöver konfigurerad tolerans (> 1 SEK), så
|
|
bokföraren kan granska skattekonto-raderna. E-postmeddelandet
|
|
innehåller ingen finansiell siffra utan en länk till autentiserad
|
|
dashboard; mottagaren valideras mot company_members innan utskick.
|
|
lawful_basis: art_6_1_f # legitimate interest (bookkeeping accuracy)
|
|
special_category_basis: null
|
|
controller: gnubok-tenant
|
|
processor: resend
|
|
data_subjects:
|
|
- business_owner
|
|
- company_member
|
|
data_categories:
|
|
- user.contact.email
|
|
recipients:
|
|
- name: Resend
|
|
country: US
|
|
role: processor
|
|
international_transfers:
|
|
applicable: true
|
|
mechanism: scc_2021_c2p
|
|
note: >-
|
|
Resend (US): SCC Module 2 (controller-to-processor). Outbound
|
|
payload limited to ett notifieringsmail utan finansiella belopp;
|
|
TIA dokumenterad i .compliance/tia/resend.md.
|
|
retention:
|
|
duration: 30d
|
|
basis: event_log_ttl
|
|
stored_in:
|
|
- event_log
|
|
security_measures:
|
|
- recipient_membership_check_before_send
|
|
- no_financial_figures_in_body
|
|
- tls_to_resend
|
|
- rls_company_scoped
|
|
|
|
- id: ai.inference
|
|
name: AI-inferens (kategorisering + dokumenttolkning) via Amazon Bedrock
|
|
purpose: >-
|
|
Föreslå bokföringskategori för banktransaktioner och tolka/extrahera
|
|
uppladdade underlag (kvitton, leverantörsfakturor) med Anthropic
|
|
Claude-modeller körda i Amazon Bedrock. Endast aktiv när tenanten
|
|
uttryckligen aktiverat AI-funktioner: kärntjänsten (bokföring, fakturor,
|
|
moms, rapporter) fungerar fullt ut utan AI.
|
|
lawful_basis: art_6_1_a # consent: opt-in, AI features off by default
|
|
special_category_basis: null
|
|
controller: gnubok-tenant
|
|
processor: aws-bedrock
|
|
data_subjects:
|
|
- business_owner
|
|
- counterparty # namn/belopp på uppladdade underlag
|
|
data_categories:
|
|
- user.financial # transaktionsdata skickad för kategorisering
|
|
- user.document # uppladdade kvitton/fakturor för OCR/extraktion
|
|
recipients:
|
|
- name: Amazon Web Services (Amazon Bedrock)
|
|
country: EU
|
|
role: processor
|
|
international_transfers:
|
|
applicable: false
|
|
mechanism: null
|
|
note: >-
|
|
Inferens körs i AWS-regionen eu-north-1 (Stockholm): ingen överföring
|
|
till tredje land. AWS DPA + SCC + DPF-certifiering finns som
|
|
skyddsmekanism. Prompter lagras ej hos Bedrock efter anropet och används
|
|
ej till modellträning.
|
|
retention:
|
|
duration: none_at_processor
|
|
basis: no_retention_bedrock # prompt not persisted by Bedrock post-inference
|
|
stored_in:
|
|
- ai_usage_tracking # usage metadata only (tokens/cost), no payload body
|
|
security_measures:
|
|
- opt_in_consent_required
|
|
- eu_region_inference_eu_north_1
|
|
- prompts_not_retained_after_inference
|
|
- not_used_for_model_training
|
|
- rls_company_scoped
|
|
- tls_to_bedrock
|
|
|
|
- id: mcp.telemetry
|
|
name: MCP/agent-telemetri i event_log
|
|
purpose: >-
|
|
Varje MCP-verktygsanrop loggar metadata (verktygsnamn, felkod,
|
|
felmeddelande max 500 tecken, latens, aktör, session, frivillig
|
|
distributionskanal-markör, t.ex. 'openclaw' via X-Gnubok-Client-header
|
|
eller ?client=-parameter, sanerad mot allow-list och aldrig använd för
|
|
auktorisation) och varje skill-laddning loggar slug/tier till event_log.
|
|
Syftet är tillförlitlighetsanalys av agentgränssnittet: felfrekvens per
|
|
verktyg, adoption per distributionskanal, korrelation mellan laddade
|
|
skills och efterföljande fel, samt agenters egenrapporterade feedback
|
|
(agent.feedback). Inga verktygsargument eller verktygsresultat
|
|
persisteras.
|
|
lawful_basis: art_6_1_f # legitimate interest (service reliability/improvement)
|
|
special_category_basis: null
|
|
controller: gnubok-tenant
|
|
processor: supabase
|
|
data_subjects:
|
|
- business_owner
|
|
data_categories:
|
|
- user.unique_id # userId, actorId (API-nyckel-id), sessionId
|
|
- user.contact # actorLabel (användarvald API-nyckeletikett)
|
|
recipients:
|
|
- name: Supabase
|
|
country: EU
|
|
role: processor
|
|
international_transfers:
|
|
applicable: false
|
|
mechanism: null
|
|
note: EU-only processor; no third-country transfer.
|
|
retention:
|
|
# Differentiated TTL via /api/events/cleanup/cron: mcp.*/agent.*-rader
|
|
# behålls 180 dagar (felfrekvens-trender kräver mer än leveransfönstret);
|
|
# övriga event_log-rader (leveranshändelser) 30 dagar.
|
|
duration: 180d
|
|
basis: legitimate_interest_reliability
|
|
stored_in:
|
|
- event_log
|
|
security_measures:
|
|
- rls_user_scoped_select # event_log SELECT: auth.uid() = user_id
|
|
- service_role_only_writes
|
|
- error_message_truncated_500_chars
|
|
- no_tool_args_or_results_persisted
|
|
|
|
- id: mcp.company_customer_tools
|
|
name: MCP-verktyg för företagsinställningar och kunder
|
|
purpose: >-
|
|
Låta en uttryckligen behörig användare läsa nödvändiga företags- och
|
|
kunduppgifter samt förbereda ändringar för användarens godkännande.
|
|
Verktygssökningen gnubok_search_tools returnerar endast verktygsmetadata
|
|
och JSON-schema, aldrig företags- eller kundposter. Läsresultat begränsas
|
|
till det aktiva företaget och till verktygets dokumenterade fält.
|
|
lawful_basis: art_6_1_b
|
|
special_category_basis: null
|
|
controller: gnubok-tenant
|
|
processor: supabase
|
|
data_subjects:
|
|
- business_owner
|
|
- company_member
|
|
- customer
|
|
data_categories:
|
|
- user.name
|
|
- user.contact
|
|
- user.financial.bank_account
|
|
recipients:
|
|
- name: Supabase
|
|
country: EU
|
|
role: processor
|
|
international_transfers:
|
|
applicable: false
|
|
mechanism: null
|
|
note: EU-only processor.
|
|
retention:
|
|
duration: pending_operation_lifecycle
|
|
basis: contract_and_user_approval
|
|
stored_in:
|
|
- pending_operations
|
|
security_measures:
|
|
- api_key_scope_companies_read_or_write
|
|
- api_key_scope_customers_read_or_write
|
|
- active_company_filter_on_every_query
|
|
- rls_company_scoped
|
|
- search_returns_tool_metadata_only
|
|
- writes_staged_for_explicit_user_approval
|
|
- plaintext_personnummer_blocked_from_staging
|
|
|
|
- id: mcp.async_task_handles
|
|
name: MCP-uppgiftshandtag för långkörande verktygsanrop
|
|
purpose: >-
|
|
Låta en behörig MCP-klient hämta resultatet av ett långkörande
|
|
verktygsanrop (t.ex. generering av arkivpaket) via ett hållbart
|
|
uppgifts-id i stället för att hålla anslutningen öppen. Raden lagrar
|
|
verktygets svar tills klienten hämtat det; endast den skapande
|
|
användaren kan läsa, och utgångna rader rensas löpande vid nya anrop.
|
|
lawful_basis: art_6_1_b
|
|
special_category_basis: null
|
|
controller: gnubok-tenant
|
|
processor: supabase
|
|
data_subjects:
|
|
- business_owner
|
|
- company_member
|
|
data_categories:
|
|
- user.financial
|
|
- user.activity_timestamp
|
|
recipients:
|
|
- name: Supabase
|
|
country: EU
|
|
role: processor
|
|
international_transfers:
|
|
applicable: false
|
|
mechanism: null
|
|
note: EU-only processor.
|
|
retention:
|
|
duration: 1h
|
|
basis: transient_tool_call_state_storage_limitation
|
|
stored_in:
|
|
- mcp_tasks
|
|
security_measures:
|
|
- rls_user_scoped_select # mcp_tasks SELECT: auth.uid() = user_id
|
|
- service_role_only_writes
|
|
- creator_scoped_task_polling # tasks/get requires the creating user
|
|
- expired_rows_purged_on_creation
|
|
|
|
- id: arsredovisning.signature_evidence
|
|
name: Underskriftsbevis för årsredovisning
|
|
purpose: >-
|
|
Bevara vem som undertecknade en låst årsredovisningsversion, i vilken
|
|
roll, med vilken metod och på vilket datum. Bevisreferensen är endast en
|
|
ogenomskinlig identifierare med prefix archive:, document: eller receipt:.
|
|
Den får inte innehålla namn, e-post, personnummer eller fritext.
|
|
lawful_basis: art_6_1_c
|
|
special_category_basis: null
|
|
controller: gnubok-tenant
|
|
processor: supabase
|
|
data_subjects:
|
|
- company_signatory
|
|
data_categories:
|
|
- user.name
|
|
- user.professional_role
|
|
- user.activity_timestamp
|
|
recipients:
|
|
- name: Supabase
|
|
country: EU
|
|
role: processor
|
|
international_transfers:
|
|
applicable: false
|
|
mechanism: null
|
|
note: EU-only processor.
|
|
retention:
|
|
duration: 7y
|
|
basis: bfl_7_kap_and_arl_signing_evidence
|
|
stored_in:
|
|
- arsredovisning_signature_requests
|
|
- annual_report_versions
|
|
security_measures:
|
|
- rls_company_scoped
|
|
- service_role_only_signature_transitions
|
|
- version_company_period_and_state_validation
|
|
- signed_rows_immutable
|
|
- structured_opaque_evidence_reference
|
|
- future_and_pre_finalization_dates_rejected
|
|
|
|
- id: arsredovisning.bolagsverket.submit
|
|
name: Digital inlämning av årsredovisning till Bolagsverket
|
|
purpose: >-
|
|
Lämna in årsredovisningen (iXBRL) digitalt till Bolagsverkets eget
|
|
utrymme (ÅRL 8 kap.). Avsändarens och undertecknarens personnummer
|
|
krävs av Bolagsverkets API (skapa-inlamningtoken, lamna-in) och
|
|
används endast transient i anropen. Varken personnummer eller hash av
|
|
personnummer sparas i inlämningsposten. Fastställelseintyget signeras
|
|
med e-legitimation hos Bolagsverket, aldrig i appen.
|
|
lawful_basis: art_6_1_c # legal obligation (ÅRL filing duty)
|
|
special_category_basis: null
|
|
controller: gnubok-tenant
|
|
processor: anthropic-na # software supplier; Bolagsverket is recipient, not processor
|
|
data_subjects:
|
|
- business_owner # avsändare/undertecknare (styrelseledamot, VD)
|
|
data_categories:
|
|
- user.government_id # personnummer, endast transient till Bolagsverket
|
|
- user.name # undertecknarens namn
|
|
- user.contact # undertecknarens/kvittens e-post
|
|
- user.financial # årsredovisningens finansiella innehåll
|
|
recipients:
|
|
- name: Bolagsverket
|
|
country: SE
|
|
role: legal_recipient
|
|
international_transfers:
|
|
applicable: false
|
|
mechanism: null
|
|
note: Sweden-to-Sweden flow to a public authority; no third-country transfer.
|
|
retention:
|
|
duration: 7y
|
|
basis: bfl_7_kap # filed .xhtml archived as räkenskapsinformation
|
|
stored_in:
|
|
- arsredovisning_submissions # status, idnummer and checksums, no PNR values or hashes
|
|
- document_attachments # the exact filed iXBRL bytes (WORM)
|
|
security_measures:
|
|
- mtls_client_certificate_to_bolagsverket
|
|
- mtls_key_env_only_injected_from_secret_manager # never in settings/DB; see .env.example custody note
|
|
- pinned_endpoint_allowlist_per_environment # HOSTS map in client.ts; not env-configurable
|
|
- personnummer_and_hash_never_persisted
|
|
- personnummer_never_logged
|
|
- webhook_secret_constant_time_validation
|
|
- rls_company_scoped
|
|
- immutable_status_machine_trigger
|
|
|
|
- id: product.analytics
|
|
name: Produktanalys, sessionsinspelning, felrapportering, enkäter och supportärenden (PostHog)
|
|
purpose: >-
|
|
Förstå hur tjänsten faktiskt används (var användare fastnar i
|
|
onboarding, vilka flöden som avbryts), fånga klientfel och serverfel så
|
|
de kan åtgärdas, och ställa riktade produktfrågor. Endast hostad drift:
|
|
self-hosted-installationer laddar aldrig PostHog (isAnalyticsEnabled()
|
|
kortsluter på NEXT_PUBLIC_SELF_HOSTED, och ingen token bakas in i
|
|
Docker-imagen). Sandbox-/demoföretag identifieras aldrig.
|
|
lawful_basis: art_6_1_f # legitimate interest (produktförbättring och felsökning)
|
|
special_category_basis: null
|
|
controller: gnubok-tenant
|
|
processor: posthog-eu
|
|
data_subjects:
|
|
- business_owner
|
|
- company_member
|
|
data_categories:
|
|
- user.contact.email # person property via identify(), aldrig i event-properties
|
|
- user.name # profiles.full_name
|
|
# Sessionsinspelningen visar synlig text och tangentbordsinmatning,
|
|
# förutom maskerade fält (belopp, person-/orgnummer, lösenord samt
|
|
# data-ph-mask-taggade element), se security_measures nedan.
|
|
- user.behavior # sidvisningar, klick, händelser, sessionsinspelning
|
|
- user.device # user agent, skärmstorlek, IP (trunkeras av PostHog)
|
|
# Supportärenden: fritext som användaren SJÄLV skriver till supporten via
|
|
# in-app-dialogen (components/ui/support-link.tsx). Till skillnad från
|
|
# analysdata bär ärendet meddelandetexten, eftersom det är hela poängen
|
|
# med att skriva till supporten. Kan i praktiken innehålla bokförings-
|
|
# detaljer som användaren väljer att beskriva. Widgeten är avstängd:
|
|
# endast vår egen dialog kan öppna ärenden.
|
|
- user.content.support # fritext i supportmeddelanden, användarinitierat
|
|
# EJ organisationsnummer: för enskild firma ÄR orgnr innehavarens
|
|
# personnummer. buildGroupProperties() vägrar skicka det och ett
|
|
# enhetstest låser fast beteendet.
|
|
recipients:
|
|
- name: PostHog
|
|
country: DE
|
|
role: processor
|
|
international_transfers:
|
|
applicable: false
|
|
mechanism: null
|
|
note: >-
|
|
PostHog Cloud EU (Frankfurt). EU-baserat biträde; ingen
|
|
tredjelandsöverföring. DPA tecknat; SCCs gäller för eventuella
|
|
underbiträden utanför EES.
|
|
retention:
|
|
duration: posthog_project_retention
|
|
basis: processor_configured # sätts i PostHog-projektet, ej i denna kodbas
|
|
stored_in:
|
|
- posthog_eu # externt hos biträdet; inget lagras i vår databas
|
|
security_measures:
|
|
# Mönsterbaserad maskering (2026-08-06, ersätter maskera-allt-läget):
|
|
# belopp (valutaformaterad text), person-/organisationsnummer (text och
|
|
# inmatning) och lösenord maskeras; övrig text och tangentbordsinmatning
|
|
# syns i inspelningen för felsökning. data-ph-mask tvingar maskering av
|
|
# utpekade PII-element; låst av test i lib/analytics/__tests__.
|
|
- session_replay_masks_amounts_and_identity_numbers # lib/analytics/replay-masking.ts
|
|
- session_replay_masks_password_inputs
|
|
- org_number_never_transmitted_as_group_property # låst av test i lib/analytics/__tests__
|
|
- no_pii_in_event_properties # PII endast som person properties via identify()
|
|
# persistence: 'memory' -> ingen analysdata och inga kakor på enheten.
|
|
# TVÅ undantag, båda funktionell UI-state utan personuppgifter, båda
|
|
# skrivna direkt till localStorage av PostHogs egna moduler förbi
|
|
# persistence-inställningen: seenSurvey_<id> ("visa inte igen") och
|
|
# ph_conv_<token> = {"widgetSessionId": uuid} (hitta tillbaka till sitt
|
|
# eget ärende i samma webbläsare). ph_conv skapas vid sidladdning, alltså
|
|
# innan användaren faktiskt kontaktar supporten. Verifierat i prod.
|
|
- no_analytics_data_or_cookies_on_device
|
|
- only_functional_ui_state_persisted # seenSurvey_*, ph_conv_* (uuid, ingen PII)
|
|
# Radering (A.8.10), se .compliance/Data_Classification_Handling.md:
|
|
# ph_conv_* raderas vid utloggning (resetAnalyticsIdentity ->
|
|
# posthog.reset() -> conversations-managerns egen reset). seenSurvey_*
|
|
# har ingen raderingstrigger: ingen PostHog-bundle itererar över
|
|
# localStorage, så SDK:n kan inte hitta nycklarna. Accepterat: värdet är
|
|
# "true" under ett ogenomskinligt survey-id, utan personuppgifter.
|
|
- ph_conv_cleared_on_logout # hindrar delad enhet från att ärva ärendesession
|
|
- same_origin_reverse_proxy # /rl-rewrite; ingen tredjepartsvärd i CSP
|
|
- sandbox_companies_never_identified
|
|
- disabled_entirely_when_self_hosted
|
|
- server_side_payloads_redacted_before_send # lib/observability/redact.ts
|
|
- support_widget_disabled # endast egen UI via conversations-API
|
|
- support_ticket_identity_hmac_signed # POSTHOG_SECRET_API_KEY, serverside
|
|
- support_message_body_never_in_event_properties # breadcrumb bär endast subject
|
|
- email_remains_the_delivery_guarantee # ärendet är ett komplement, ej leveransväg
|
|
|
|
- id: whatsapp.receipt_intake
|
|
name: Kvittoinlämning och klargörande dialog via WhatsApp
|
|
purpose: >-
|
|
Ta emot kvitton som foto eller PDF skickade till Accounteds delade
|
|
WhatsApp-nummer och landa dem i dokumentinkorgen (Underlag) som
|
|
räkenskapsinformation, samt föra en kort klargörande dialog i samma
|
|
chatt: bekräfta mottagning, fråga vilket företag underlaget tillhör och
|
|
samla in de representationsuppgifter Skatteverket kräver (deltagarnas
|
|
namn och företag samt syfte). Avsändare är enbart befintliga
|
|
Accounted-användare som själva knutit sitt nummer med en engångskod;
|
|
okända nummer får ett enda begränsat standardsvar och behandlas aldrig
|
|
vidare (ingen AI, ingen mediahämtning, inget innehåll sparas).
|
|
Deltagarnamn i representationssvar är tredjepartsuppgifter som samlas
|
|
in från användaren, inte från de registrerade själva; individuell
|
|
information till varje deltagare vore oproportionerlig i förhållande
|
|
till den lagstadgade dokumentationsplikten och undantaget i art.
|
|
14.5 b tillämpas (uppgifterna framgår av verifikationen, som bevaras
|
|
enligt BFL).
|
|
# art 6.1 b: tjänsten (mottagning, dialog, inkorgsleverans).
|
|
# art 6.1 c: BFL 7 kap: kvittot bevaras 7 år som räkenskapsinformation.
|
|
# art 6.1 f: tredjeparts deltagarnamn i representationssvar (med
|
|
# art 14.5 b-undantaget dokumenterat i purpose ovan).
|
|
lawful_basis: art_6_1_b_c_and_f
|
|
special_category_basis: null
|
|
controller: gnubok-tenant
|
|
processor: supabase_and_meta
|
|
data_subjects:
|
|
- business_owner
|
|
- company_member
|
|
- representation_attendee # tredjepart: namn + företag i representationssvar
|
|
data_categories:
|
|
- user.contact.phone_number # HMAC-hash med peppar + AES-256-GCM + mask; aldrig i klartext i DB
|
|
- user.communication_content # chattext och webhook-payload utan avsändarnummer, 90 dagars retention
|
|
- user.document # kvittofiler, 7 år WORM enligt BFL 7 kap
|
|
- user.name # deltagarnamn i representationssvar (tredjepart)
|
|
- user.activity_timestamp
|
|
recipients:
|
|
- name: Meta Platforms Ireland Ltd (WhatsApp Business Platform, Cloud API)
|
|
country: IE
|
|
role: processor
|
|
- name: Supabase
|
|
country: EU
|
|
role: processor
|
|
# AI-tolkningen av kvittobilder och fritextsvar sker via Amazon Bedrock
|
|
# och täcks av den befintliga aktiviteten ai.inference ovan.
|
|
international_transfers:
|
|
applicable: true
|
|
mechanism: scc_2021_c2p
|
|
note: >-
|
|
Meta Platforms Ireland behandlar meddelandena under WhatsApp Business
|
|
dataskyddsvillkor med EU SCC-addendum (Module 2) för vidareöverföring
|
|
till Meta Platforms Inc. (US). Cloud API Local Storage är aktiverat
|
|
med region DE, så meddelandeinnehåll lagras i vila inom EU hos Meta.
|
|
retention:
|
|
# Differentierad per datakategori; verkställs dagligen av
|
|
# /api/extensions/whatsapp-inbox/retention/cron:
|
|
# chattranskript (body_text, raw_payload) 90 dagar, sedan rensas
|
|
# innehållet men radskelettet (wamid, riktning, tidsstämplar,
|
|
# status, inbox-koppling) bevaras som behandlingsspår
|
|
# okända avsändares rader 30 dagar, sedan radering
|
|
# engångskoder 24 h efter utgång, radering
|
|
# telefonkoppling (phone_enc) tills användaren återkallar,
|
|
# därefter kryptoshredning 90 dagar efter revokering (phone_hash och
|
|
# phone_masked bevaras för unikhetshistorik respektive visning)
|
|
# kvittofilen 7 år, WORM (BFL 7 kap),
|
|
# hanteras av dokumentarkivet, ej av denna cron
|
|
# kontoradering (art 17) omedelbart, inte via cron:
|
|
# anonymize_user_account revokerar och kryptoshreddar kopplingen,
|
|
# nollställer body_text/raw_payload på kopplingens meddelanden och
|
|
# raderar engångskoder (migration 20260803090000). auth.users
|
|
# gravsätts i stället för att raderas, så tabellens ON DELETE
|
|
# CASCADE utlöses aldrig av sig själv
|
|
duration: differentiated_per_data_category
|
|
basis: gdpr_storage_limitation_and_bfl_7_kap
|
|
stored_in:
|
|
- whatsapp_messages
|
|
- whatsapp_phone_links
|
|
- whatsapp_link_codes
|
|
- whatsapp_sender_rate_counters
|
|
- whatsapp_conversations
|
|
- invoice_inbox_items.channel_context
|
|
- document_attachments # kvittofilen, WORM
|
|
security_measures:
|
|
- phone_number_hmac_peppered_hash_lookup_only
|
|
- phone_number_aes_256_gcm_at_rest
|
|
- phone_number_masked_in_ui
|
|
- dedicated_whatsapp_key_material_not_bankid_keys
|
|
- webhook_signature_verified_over_raw_body
|
|
- service_role_only_tables_rls_no_policies
|
|
- unknown_senders_no_content_persistence_no_llm
|
|
- pre_binding_sender_rate_limits
|
|
- daily_retention_cron_with_crypto_shred
|
|
- llm_reads_answers_as_untrusted_data_no_tools
|
|
- receipt_files_worm_protected_bfl
|
|
- opt_out_stop_keyword_honored
|
|
- muted_senders_no_content_persistence
|
|
- account_deletion_revokes_and_shreds_whatsapp_link
|