BC02 - TEKNISK ARKITEKTUR
BC02 - AI-Dokumentanalys för Offerter (Optimate Core)
Projektkod: AIDA-2025-BC2
Version: 1.0
Datum: 2025-11-01
Arkitekt: Lars Diethelm
Status: För godkännande
Sammanfattning
Arkitekturval
Plattform: Optimate Core - Hub-and-Spoke Architecture
- Motivering: Modularitet och separation av capability (core engines) från configuration (n8n workflows för BC02). Beprövad arkitektur med återanvändbara komponenter.
AI-plattform: Anthropic Claude Sonnet 4 (primär) + Ollama (lokal backup/embeddings)
- Motivering: Claude excellent för multi-document analysis, teknisk dokumentförståelse och svensk text. Vision API för ritningsanalys. Ollama för embeddings och fallback.
Orkestrering (Hub): n8n
- Motivering: BC02-specifika workflows för dokumenthantering, beslutspunkter, CRM-integration. Visuell design för enkel anpassning.
Capability Layer (Spokes): Optimate Core Engines (FastAPI Microservices)
- Ingestion Engine: ZIP-fil parsing, dokumentidentifiering, ritningsanalys
- Agentic Engine: Multi-document RAG, krav-extrahering, motstridighetsdetektering, Go/No-go rekommendation
Deployment: Render (Cloud) - REKOMMENDERAT
- Motivering: Snabb setup för Fas 4. Managed infrastructure. Auto-scaling för varierande offertvolym (550/år = ~10-12/vecka, ojämnt fördelat).
Säkerhet: Render Private Network + Keycloak SSO (future)
- Motivering: Säker kommunikation mellan services. Multi-user access (Mattias, Karin, Emil, Liza).
Klassificering: Konfidentiell affärsdata + Kunddokument
- Kryptering: TLS 1.3 för transit, AES-256 för lagring. GDPR-compliance för kunddata.
Huvudkomponenter (Optimate Core)
Hub Layer:
- n8n: BC02-specifika workflows (dokumentintag, analys-pipeline, CRM-uppdatering)
Capability Layer (Core Spokes):
- Ingestion Engine (FastAPI): ZIP-parsing, PDF-extrahering, ritningsanalys (Blue Beam integration)
- Agentic Engine (FastAPI): Multi-document RAG, krav-extrahering, motstridighetsdetektering, Go/No-go AI
- PostgreSQL (Render Managed): Förfrågningslog, AI-beslut, historiska projekt, kunddata-cache
- Qdrant: Vektordatabas för semantisk sökning i dokumentation och historiska offerter
- Ollama: Lokal LLM för embeddings och backup-inferens
- Django HIL Portal: Mattias/Karins gränssnitt för granskning av AI-analys och beslutsstöd
External Integrations:
- WorkCloud CRM API (registrering av affärsmöjlighet)
- UC API (kreditkontroll)
- Email (mottagande och utskick av offerter)
- Blue Beam (future: direktintegration för ritningsanalys)
1. Arkitekturöversikt
Konceptuell arkitektur (Optimate Core - Hub-and-Spoke)
┌──────────────────────────────────────────────────────────┐
│ PRESENTATION LAYER │
│ Django HIL Portal (Mattias, Karin, Emil) │
│ - Förfrågningslista med AI-rekommendationer │
│ - Dokumentvisning med AI-highlights │
│ - Go/No-go beslutsstöd med motivering │
│ - Historisk projektjämförelse │
└─────────────────┬────────────────────────────────────────┘
│ HTTPS (Render Private Network)
│
┌─────────────────▼────────────────────────────────────────┐
│ HUB LAYER (BC02 Configuration) │
│ n8n │
│ │
│ BC02-specifika workflows: │
│ 1. Förfrågningsmottagning (Email → ZIP-parsing) │
│ 2. Dokumentanalys-pipeline (orchestration) │
│ 3. Go/No-go beslutsstöd │
│ 4. CRM-registrering (WorkCloud) │
│ 5. Kreditkontroll (UC API) │
│ 6. Offertgenerering och utskick │
└──┬────────┬─────────┬──────────┬──────────────────────────┘
│ │ │ │
│ API │ API │ API │ API
│ │ │ │
┌──▼────────▼─────────▼──────────▼──────────────────────────┐
│ CAPABILITY LAYER (Core Spokes) │
│ Optimate Core Engines │
│ │
│ ┌────────────────────┐ ┌──────────────────────┐ │
│ │ Ingestion Engine │ │ Agentic Engine │ │
│ │ (FastAPI) │ │ (FastAPI) │ │
│ │ │ │ │ │
│ │ • ZIP parsing │ │ • Multi-doc RAG │ │
│ │ • PDF extraction │ │ • Krav-extrahering │ │
│ │ • Dokumenttyp ID │ │ • Motstridigheter │ │
│ │ • Ritningsanalys │ │ • Go/No-go AI │ │
│ │ • OCR (Claude) │ │ • Historisk jämför. │ │
│ └────────────────────┘ └──────────────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌────────────┐ │
│ │ Claude API │ │ Ollama │ │ Qdrant │ │
│ │ │ │ │ │ │ │
│ │ • Doc analys │ │ • Embeddings │ │ • Historik │ │
│ │ • Vision API │ │ • Backup AI │ │ • Semantisk│ │
│ │ • Multi-doc │ │ │ │ sökning │ │
│ └──────────────┘ └──────────────┘ └────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ PostgreSQL (Render Managed) │ │
│ │ • Förfrågningslog (550/år) │ │
│ │ • AI-beslut och rekommendationer │ │
│ │ • Historiska projekt (vunna/förlorade) │ │
│ │ • Kunddata-cache (WorkCloud sync) │ │
│ │ • Dokument-metadata │ │
│ └──────────────────────────────────────────────────┘ │
└───────────────────┬─────────────────────────────────────┘
│
┌───────────────────▼─────────────────────────────────────┐
│ EXTERNAL INTEGRATIONS │
│ (anropas via Ingestion/Agentic Engines) │
│ │
│ WorkCloud CRM │ UC Kreditkontroll │ Email (SMTP) │
└──────────────────────────────────────────────────────────┘
Dataflöde - Komplett offertprocess:
[1. Email med ZIP-länk]
↓
[n8n: Ladda ner ZIP] → [Ingestion Engine: Extrahera filer]
↓
[Ingestion Engine: Identifiera dokumenttyper]
→ AF-del, AFD-1, AFD.472, K-ritningar, A-ritningar,
teknisk beskrivning (25-60 sidor)
↓
[Agentic Engine: Multi-document RAG-analys]
→ Extrahera: Omfattning, garantitider, entreprenadform,
tekniska krav, motstridigheter
→ Jämför med Qdrant: 5 liknande historiska projekt
↓
[Agentic Engine: Go/No-go AI-rekommendation]
Input: Projektstorlek, kund, geografi, komplexitet, historik
Output: Rekommendation (Go/No-go) + konfidensgrad + motivering
↓
[Django Portal: Mattias/Emil ser AI-sammanfattning]
- 1-sida sammanfattning (från 25-60 sidor)
- Kritiska krav highlighted
- Motstridigheter flaggade
- Go/No-go rekommendation med motivering
- Jämförelse med historiska projekt
↓
[Manuellt beslut: Go/No-go]
↓
IF Go:
├─► [n8n → UC API: Kreditkontroll]
├─► [n8n → WorkCloud: Registrera affärsmöjlighet]
├─► [n8n → OneNote: Uppdatera]
└─► [Fortsätt med mängdning och kalkyl]
ELSE No-go:
└─► [n8n → CRM: Markera som avböjd + skäl]
Teknisk stack (Optimate Core)
| Lager | Teknologi | Produkt/Ramverk | Version | Motivering |
|---|---|---|---|---|
| Hub (Configuration) | ||||
| Orkestrering | n8n | n8n | Latest | Visuell workflow för BC02-specifik offertprocess |
| Capability (Core Spokes) | ||||
| Core Engines | FastAPI | Optimate Ingestion Engine | 1.x | ZIP-parsing, dokumentidentifiering, ritningsanalys |
| Core Engines | FastAPI | Optimate Agentic Engine | 1.x | Multi-doc RAG, krav-extrahering, Go/No-go AI |
| AI - Primär | Claude API | Anthropic Sonnet 4 | Latest | Multi-document analysis, Vision för ritningar |
| AI - Lokal | Ollama | Llama 3.1/Mistral | Latest | Embeddings för Qdrant, backup-inferens |
| Vektordatabas | Qdrant | Qdrant | Latest | Semantisk sökning i historik + dokumentation |
| Databas (Cloud) | PostgreSQL | Render Managed | 15.x | Förfrågningslog, AI-beslut, kundcache |
| Presentation | ||||
| Frontend | Django | Django HIL Portal | 4.x | Mattias/Karin/Emils gränssnitt för beslutsstöd |
| Infrastructure | ||||
| Cloud Deployment | Render | Render | - | Managed infrastructure, private network |
| Identity | Keycloak | Keycloak | Latest | SSO för multi-user (Mattias, Karin, Emil, Liza) |
| Observability | LangSmith | LangSmith | Latest | AI decision tracking, quality monitoring |
| Containerisering | Docker | Docker Compose | Latest | Local dev + on-premise option |
| Version Control | Git | GitHub | Latest | Three-repo strategy (core, template, customer) |
2. AI-komponenter (Optimate Core)
Capability Architecture för BC02
BC02 använder följande Optimate Core engines:
1. Ingestion Engine - BC02-specifika endpoints
Ansvar: Förfrågningsintag, dokumentparsing, initial klassificering
BC02-funktioner:
- ZIP-fil hantering: Ladda ner från email-länk, extrahera alla filer
- Dokumenttyp-identifiering: Känna igen AF, AFD, K-ritningar, A-ritningar, teknisk beskrivning
- PDF-extrahering: Text + struktur från multi-page dokument (25-60 sidor)
- Ritningsanalys: OCR via Claude Vision för littrering, ytor, detaljer
- Metadata-extrahering: Projektstorlek, byggare, plats, typ från dokumentnamn och innehåll
API-endpoints för BC02:
POST /api/v1/ingest/tender-zip
Input: {url: "https://port.se/download/xxx.zip"}
Output: {
files: [
{filename: "AF-del.pdf", type: "af", pages: 28, ...},
{filename: "AFD-1.pdf", type: "afd1", pages: 3, ...},
{filename: "K-ritning_01.pdf", type: "k_drawing", ...},
...
],
metadata: {
project_name: "Stender VB 1966",
builder: "Stender Fastigheter",
location: "Uppsala",
estimated_size: "2.5 MSEK"
}
}
POST /api/v1/ingest/identify-document-type
Input: {filename: "...", content_sample: "first 1000 chars"}
Output: {type: "afd472", confidence: 0.95, reasoning: "..."}
POST /api/v1/ingest/extract-drawing-info
Input: {drawing_pdf_base64: "..."}
Output: {
area_sqm: 1250,
material_distribution: {"plåt": 800, "papp": 450},
littering: ["A1", "A2", "B3"],
complexity: "medium"
}
Prestanda:
- ZIP-extrahering: <30s för typisk förfrågan (10-30 filer)
- Dokumenttyp-ID: <2s per dokument (95%+ accuracy)
- Ritningsanalys: <10s per ritning med Claude Vision
2. Agentic Engine - BC02-specifika endpoints
Ansvar: Intelligent dokumentanalys, RAG-pipeline, beslutsstöd
BC02-funktioner:
- Multi-document RAG: Läsa och förstå 10-30 dokument tillsammans (totalt 25-60 sidor)
- Krav-extrahering: AFD-1 Omfattning, AFD.472 Garantitider, tekniska krav från teknisk beskrivning
- Motstridighetsdetektering: Jämföra AFD, teknisk beskrivning, ritningar - flagga konflikter
- Entreprenadform-identifiering: AB vs ABT + implikationer för risk och ansvar
- Historisk jämförelse: Söka i Qdrant för 5 liknande projekt baserat på typ, storlek, kund
- Go/No-go AI: Rekommendera baserat på prioriteringsmatris + historik
API-endpoints för BC02:
POST /api/v1/agent/analyze-tender
Input: {
documents: [
{type: "af", content: "...", metadata: {...}},
{type: "afd1", content: "...", metadata: {...}},
{type: "technical_description", content: "...", pages: 52},
...
],
project_metadata: {...}
}
Output: {
summary: "1-page executive summary",
scope: {
extracted_from: "AFD-1 page 2",
requirements: ["Takarbeten 1250 kvm", "Plåt + papp", ...],
exclusions: ["Ställning ingår ej", ...]
},
guarantees: {
standard: "2 år",
special: ["Täthet 10 år", "Färg 5 år"],
source: "AFD.472 section 3.2"
},
contract_form: {
type: "ABT",
implications: ["Byggherren ansvarar för...", ...],
source: "AF-del page 1"
},
conflicts: [
{
description: "Teknisk beskrivning säger 'plåt endast', ritning visar papp",
documents: ["technical_description p.15", "drawing_02.pdf"],
severity: "high"
}
],
technical_requirements: [
"Brandklass REI 60",
"U-värde max 0.15",
...
],
confidence: 0.88,
processing_time_ms: 25000
}
POST /api/v1/agent/go-no-go-recommendation
Input: {
project_summary: {...}, # From analyze-tender
customer_info: {name: "...", history: [...], credit_rating: ...},
prioritization_matrix: {
size_threshold: 500000, # SEK
margin_min: 0.15,
geography_max_km: 200,
customer_tier: "A/B/C"
}
}
Output: {
recommendation: "GO",
confidence: 0.87,
reasoning: [
"Project size 2.5 MSEK exceeds threshold (500k)",
"Customer A-tier with good payment history",
"Within 150km (Uppsala)",
"Similar project won 3 months ago with 22% margin"
],
similar_projects: [
{
name: "Stender AB 2024-08",
won: true,
margin: 0.22,
similarity_score: 0.91
},
...
],
risk_factors: [
"AFD.472 guarantees 10 years (above standard 2y)",
"ABT contract form (more responsibility)"
],
sources: [
"Historical project DB: 5 matches",
"Customer tier from WorkCloud",
"AFD.472 from tender documents"
]
}
POST /api/v1/agent/summarize-requirements
Input: {technical_description_pdf: "...", page_count: 52}
Output: {
one_page_summary: "Markdown formatted, ~500 words",
critical_requirements: [
{requirement: "...", source: "page 15", priority: "high"},
...
],
materials: ["Plåt Prelaq Nova", "Papp SBS", ...],
estimated_complexity: "medium-high"
}
Prestanda:
- Multi-document analysis: <30s för 25-60 sidor
- Go/No-go recommendation: <5s (efter dokumentanalys)
- Motstridighetsdetektering: <10s
- Historisk jämförelse (Qdrant): <2s
AI-modeller och strategi
Modell 1: Claude Sonnet 4 (Primär för dokumentanalys)
Användning i BC02:
- Multi-document understanding (AF, AFD, teknisk beskrivning tillsammans)
- Svensk textförståelse (byggdokumentation är på svenska)
- Vision API för ritningsanalys (K-ritningar, takplaner)
- Sammanfattning av långa dokument (52 sidor → 1 sida)
- Motstridighetsdetektering mellan dokument
Prompt-strategi:
System: Du är en expert på svensk byggdokumentation och offertkalkylering
för tak- och fasadarbeten. Din uppgift är att analysera förfrågningsunderlag
och extrahera kritisk information för kalkylering.
Context: [10-30 dokument i full-text eller excerpts]
Task: Analysera samtliga dokument och:
1. Extrahera omfattning från AFD-1
2. Identifiera speciella garantikrav från AFD.472
3. Lista alla tekniska krav från teknisk beskrivning
4. Flagga motstridigheter mellan dokument
5. Sammanfatta i max 1 sida
Format: JSON enligt schema {...}
Träningsdata:
- 10 kompletta förfrågningsunderlag från Mattias
- 50+ historiska projekt med outcome (vunna/förlorade)
- Dokumentation av common pitfalls (missade krav)
Prestanda target:
- Krav-extrahering: >95% accuracy
- Motstridighetsdetektering: >85% recall
- Sammanfattning: Läsbar och användbar för Mattias/Karin
Modell 2: Ollama (Lokal LLM för embeddings + backup)
Modeller:
- nomic-embed-text: Embeddings för Qdrant
- Llama 3.1 8B: Backup-inferens vid Claude API-fel
Användning i BC02:
- Embeddings av historiska projekt (typ, krav, outcome)
- Embeddings av tekniska krav för semantisk matching
- Backup om Claude API är nere (lägre quality men operational continuity)
Prestanda:
- Embeddings: <500ms per document
- Inference: 5-10s per request (CPU), <2s med GPU
RAG-pipeline för BC02
Vad lagras i Qdrant:
- Historiska projekt (550/år = 2750 projekt över 5 år)
- Projektnamn, typ, storlek, kund
- Tekniska krav (embedded)
- Outcome (vunnet/förlorat, marginal)
- Kalkylatorns anteckningar
- Dokumentation och kunskapsbas
- AFF och AMA-definitioner (svenska byggstandarder)
- Tidigare feltolkningar och "lessons learned"
- Materialspecifikationer och priser
Retrieval-strategi:
Query: Nytt projekt "Stender VB 1966, tak 1250 kvm, plåt + papp"
Qdrant search:
- Embedding av projektsummary
- Metadata filter: type="tak", size_range=[1000, 1500]
- Return: Top 5 most similar projects
For each returned project:
- Margin, outcome, customer, challenges
- Feed to Claude as context for Go/No-go decision
3. Systemintegration
Integrationspunkter
| System | Typ | Protokoll | Frekvens | Datavolym | Kritikalitet |
|---|---|---|---|---|---|
| Email (inbound) | Källa | IMAP/POP3 | Continuous | 550 emails/år | Hög |
| WorkCloud CRM | Mål | REST API | Per offert | 550 updates/år | Hög |
| UC Kreditkontroll | Tjänst | REST API | Per Go-beslut | ~400/år | Medium |
| Email (outbound) | Mål | SMTP | Per offert | ~220/år | Medium |
| Blue Beam | Future | Plugin/API | Optional | - | Låg |
API-specifikationer
API 1: WorkCloud CRM - Registrera affärsmöjlighet
endpoint: /api/opportunities
method: POST
authentication: API Key (Header)
request body:
{
"customer_id": "12345",
"project_name": "Stender VB 1966",
"estimated_value": 2500000,
"probability": 0.5,
"stage": "tender_analysis",
"responsible": "Mattias Svensson",
"notes": "AI-analyserad, Go-beslut, ABT-kontrakt",
"documents": ["af_del.pdf", "technical_desc.pdf"],
"source": "BC02_AI_System"
}
response: 200 OK
{
"opportunity_id": "OPP-2025-1234",
"created_at": "2025-11-01T10:30:00Z"
}
API 2: UC Kreditkontroll
endpoint: /api/v1/creditcheck
method: POST
authentication: API Key
request body:
{
"org_number": "556789-1234",
"company_name": "Stender Fastigheter AB"
}
response:
{
"rating": "AAA",
"credit_limit": 5000000,
"payment_remarks": 0,
"recommendation": "approve",
"report_url": "https://uc.se/report/..."
}
API 3: Email Integration (via n8n)
n8n har inbyggda Email-nodes:
- Email Trigger: Poll IMAP inbox var 5:e minut för nya förfrågningar
- Email Send: SMTP för utskick av offerter
4. Dataarkitektur
Datamodell
Tabell 1: tender_requests
| Attribut | Typ | Beskrivning | Constraint |
|---|---|---|---|
| id | UUID | Unik identifierare | PRIMARY KEY |
| received_at | TIMESTAMP | Mottagen tidpunkt | NOT NULL |
| email_from | VARCHAR(255) | Avsändare | NOT NULL |
| email_subject | VARCHAR(500) | Ämnesrad | |
| zip_url | TEXT | Länk till ZIP-fil | |
| project_name | VARCHAR(255) | Projektnamn (AI-extraherat) | |
| customer_name | VARCHAR(255) | Kundnamn | |
| estimated_value | DECIMAL(12,2) | Uppskattat projektvärde | |
| complexity | ENUM | simple, medium, complex | |
| status | ENUM | received, analyzing, decided, calculating, sent | NOT NULL |
| decision | ENUM | go, no_go, pending | |
| decided_by | VARCHAR(100) | Mattias, Karin, Emil | |
| decided_at | TIMESTAMP | Beslutstidpunkt | |
| workcloud_opp_id | VARCHAR(50) | WorkCloud opportunity ID |
Tabell 2: tender_documents
| Attribut | Typ | Beskrivning | Constraint |
|---|---|---|---|
| id | UUID | Unik identifierare | PRIMARY KEY |
| tender_id | UUID | Referens till tender_requests | FOREIGN KEY |
| filename | VARCHAR(255) | Originalfilnamn | NOT NULL |
| document_type | ENUM | af, afd1, afd472, k_drawing, a_drawing, technical_desc, other | NOT NULL |
| page_count | INTEGER | Antal sidor | |
| file_size_kb | INTEGER | Filstorlek | |
| content_text | TEXT | Extraherad text (för RAG) | |
| metadata | JSONB | PDF metadata, AI-extraherad info | |
| storage_path | TEXT | S3/Supabase path |
Tabell 3: ai_analysis
| Attribut | Typ | Beskrivning | Constraint |
|---|---|---|---|
| id | UUID | Unik identifierare | PRIMARY KEY |
| tender_id | UUID | Referens till tender_requests | FOREIGN KEY |
| analysis_type | ENUM | full, scope, guarantees, conflicts, summary | NOT NULL |
| result | JSONB | AI output (strukturerad JSON) | NOT NULL |
| confidence | DECIMAL(3,2) | AI confidence (0.00-1.00) | |
| processing_time_ms | INTEGER | Tid för analys | |
| model_used | VARCHAR(50) | claude-sonnet-4, llama-3.1, etc | |
| prompt_version | VARCHAR(20) | Prompt version för reproducerbarhet | |
| created_at | TIMESTAMP | Analystidpunkt | DEFAULT NOW() |
Tabell 4: go_no_go_decisions
| Attribut | Typ | Beskrivning | Constraint |
|---|---|---|---|
| id | UUID | Unik identifierare | PRIMARY KEY |
| tender_id | UUID | Referens till tender_requests | FOREIGN KEY |
| ai_recommendation | ENUM | go, no_go | NOT NULL |
| ai_confidence | DECIMAL(3,2) | AI confidence | NOT NULL |
| ai_reasoning | TEXT | AI:s motivering | |
| similar_projects | JSONB | Array av liknande historiska projekt | |
| risk_factors | JSONB | Array av identifierade risker | |
| human_decision | ENUM | go, no_go, NULL | |
| human_decided_by | VARCHAR(100) | Mattias, Emil, etc | |
| human_decision_at | TIMESTAMP | Beslutstidpunkt | |
| override_reason | TEXT | Om skiljer från AI-rekommendation |
Tabell 5: historical_projects
| Attribut | Typ | Beskrivning | Constraint |
|---|---|---|---|
| id | UUID | Unik identifierare | PRIMARY KEY |
| project_name | VARCHAR(255) | Projektnamn | NOT NULL |
| customer_name | VARCHAR(255) | Kund | NOT NULL |
| project_type | VARCHAR(100) | Tak, fasad, etc | |
| project_value | DECIMAL(12,2) | Värde i SEK | |
| won | BOOLEAN | Vunnet eller förlorat | NOT NULL |
| margin | DECIMAL(4,3) | Marginal (0.15 = 15%) | |
| completion_date | DATE | Färdigställt | |
| key_requirements | JSONB | Tekniska krav | |
| challenges | TEXT | Utmaningar och lärdomar | |
| embedding | VECTOR(768) | Qdrant embedding |
Tabell 6: credit_checks
| Attribut | Typ | Beskrivning | Constraint |
|---|---|---|---|
| id | UUID | Unik identifierare | PRIMARY KEY |
| tender_id | UUID | Referens till tender_requests | FOREIGN KEY |
| org_number | VARCHAR(20) | Organisationsnummer | NOT NULL |
| uc_rating | VARCHAR(10) | UC-rating | |
| credit_limit | DECIMAL(12,2) | Kreditlimit | |
| approved | BOOLEAN | Godkänd eller ej | NOT NULL |
| checked_at | TIMESTAMP | Kontrolltidpunkt | DEFAULT NOW() |
| checked_by | VARCHAR(100) | Liza, etc |
Datalagring
| Datatyp | Lagring | Retention | Backup | Kryptering |
|---|---|---|---|---|
| Tender requests | PostgreSQL | 7 år | Daglig | AES-256 at rest |
| PDF-dokument | Supabase Storage / S3 | 7 år | Veckovis | TLS + AES-256 |
| AI-beslut | PostgreSQL | 7 år | Daglig | AES-256 |
| Historiska projekt | PostgreSQL + Qdrant | Permanent | Daglig | AES-256 |
| Qdrant vectors | Qdrant (disk) | Permanent | Veckovis snapshot | TLS in transit |
5. Säkerhetsarkitektur
Säkerhetslager
Render Cloud:
[Internet] → [Render Load Balancer + TLS] → [Private Network]
↓
[n8n] ← Private → [Ingestion Engine] ← Private → [Agentic Engine]
↓ ↓ ↓
[Django Portal] [PostgreSQL] [Qdrant]
On-Premise (future):
[Internet] → [Cloudflare Tunnel] → [Docker Network]
Autentisering och auktorisering
Fas 4: Basic auth i n8n + Django Fas 5: Keycloak SSO
Roller:
- Kalkylator (Mattias, Karin): Full åtkomst, beslut på standardprojekt
- Projektchef (Emil): Full åtkomst, beslut på stora/strategiska projekt
- Ekonomi (Liza): Read-only + kreditkontroll-beslut
- Admin (Rebecka, Lars): Systemadministration
Datasäkerhet
| Aspekt | Implementation | Standard |
|---|---|---|
| Kryptering i vila | AES-256 för Postgres/Qdrant | FIPS 140-2 |
| Kryptering i transit | TLS 1.3 för alla API-calls | RFC 8446 |
| Nyckelhantering | Render Secrets / .env (encrypted) | Principle of least privilege |
| GDPR Compliance | Kunddata pseudonymiserad vid behov | GDPR Article 25 |
| Access logs | All AI-access loggad i PostgreSQL | ISO 27001 |
6. Infrastruktur (Optimate Core - Render Deployment)
Deployment Model: Render (Cloud) - REKOMMENDERAT FAS 4
Arkitektur (Render):
# render.yaml - BC02 AI-Dokumentanalys
services:
# n8n - Workflow Hub
- type: web
name: bc02-n8n
env: docker
dockerfilePath: ./Dockerfile.n8n
envVars:
- key: N8N_ENCRYPTION_KEY
sync: false
- key: DATABASE_URL
fromDatabase:
name: bc02-postgres
property: connectionString
plan: standard # $25/mån
# Ingestion Engine (Core)
- type: web
name: bc02-ingestion-engine
env: docker
dockerCommand: uvicorn ingestion_engine.main:app --host 0.0.0.0 --port 8000
envVars:
- key: WORKCLOUD_API_KEY
sync: false
- key: UC_API_KEY
sync: false
- key: DATABASE_URL
fromDatabase:
name: bc02-postgres
property: connectionString
plan: standard # $25/mån
# Agentic Engine (Core)
- type: web
name: bc02-agentic-engine
env: docker
dockerCommand: uvicorn agentic_engine.main:app --host 0.0.0.0 --port 8000
envVars:
- key: ANTHROPIC_API_KEY
sync: false
- key: QDRANT_URL
value: http://bc02-qdrant:6333
- key: DATABASE_URL
fromDatabase:
name: bc02-postgres
property: connectionString
- key: LANGSMITH_API_KEY
sync: false
plan: standard # $25/mån
# Qdrant Vector Database
- type: web
name: bc02-qdrant
env: docker
disk:
name: bc02-qdrant-data
mountPath: /qdrant/storage
sizeGB: 10
plan: starter # $7/mån
# Django HIL Portal
- type: web
name: bc02-django-portal
env: python
buildCommand: pip install -r requirements.txt && python manage.py migrate
startCommand: gunicorn bc02_portal.wsgi:application
envVars:
- key: DATABASE_URL
fromDatabase:
name: bc02-postgres
property: connectionString
- key: N8N_WEBHOOK_URL
value: http://bc02-n8n:5678/webhook
plan: starter # $7/mån
databases:
- name: bc02-postgres
databaseName: dokumentanalys
user: bc02_user
plan: starter # $7/mån
Kostnad Render (Fas 4):
- n8n: $25/mån
- Ingestion Engine: $25/mån
- Agentic Engine: $25/mån
- Qdrant: $7/mån
- Django Portal: $7/mån
- PostgreSQL: $7/mån
- Total production: ~$96/mån (~$1150/år = 13 450 SEK/år)
- Med staging: ~$150/mån (~$1800/år = 21 000 SEK/år)
Cost-benefit:
- Årlig besparing BC02: 340 490 kr
- Render-kostnad År 1: 21 000 kr (6% av besparing)
- Nettobesparing: 319 490 kr/år
Miljöer
| Miljö | Deployment | Användning | Användare |
|---|---|---|---|
| Development | Lokal Docker Compose | Lars utveckling | Lars |
| Staging | Render (separate services) | Test med real data | Mattias, Lars |
| Production | Render | Live offerthantering | Mattias, Karin, Emil, Liza |
Skalbarhet
| Komponent | Start | Max | Skalningsstrategi |
|---|---|---|---|
| Ingestion Engine | Standard | Pro | Horizontal scaling vid >20 offerter/vecka |
| Agentic Engine | Standard | Pro + GPU | GPU för Ollama om Claude-kostnad hög |
| Qdrant | Starter | Standard | RAM upgrade för >10k historiska projekt |
| PostgreSQL | Starter | Pro | Storage + connection pool vid >1000 offerter/år |
7. Prestanda och SLA
Prestandakrav
| Metrik | Krav | Mätmetod | Frekvens |
|---|---|---|---|
| ZIP-extraction | <30s | Backend timer | Per request |
| Document analysis | <45s för 25-60 sidor | Backend timer | Per request |
| Go/No-go recommendation | <5s | Backend timer | Per request |
| Portal response time | <500ms p95 | Browser metrics | Kontinuerlig |
| System availability | >99% | Render uptime monitor | Kontinuerlig |
Service Level Agreement (SLA)
Tillgänglighet: 99% (43.8h downtime/år acceptabelt)
- Underhållsfönster: Lördagar 06:00-08:00
Response tider:
- Email → ZIP-download → Analys klar: <2 minuter
- Mattias ser AI-sammanfattning: <3 minuter från mottagande
- Total tid steg 2-8: <45 minuter (från 100-255 min)
Dataförlust:
- RPO (Recovery Point Objective): 24h (dagliga backups)
- RTO (Recovery Time Objective): 4h (restore från Render backup)
Support:
- Kontorstid (08:00-17:00): Rebecka primär, Lars sekundär
- Utanför kontorstid: Email-support, 24h respons
- Kritiska fel: 4h responstid
8. Monitoring och observability
LangSmith Integration (AI Observability)
Vad trackas:
- Varje Claude API-anrop (prompt + response)
- Processing time och cost per request
- Confidence scores per AI-beslut
- User feedback (Mattias override av AI-rekommendation)
Dashboard KPI:er:
- AI träffsäkerhet Go/No-go: Target >85%
- Krav-extrahering accuracy: Target >95%
- Motstridighetsdetektering recall: Target >85%
- Average processing time: <45s
- Cost per offert: <$5
Alert Workflows (n8n)
[n8n Schedule: Var 5:e minut]
↓
[Check AI error rate senaste timmen]
↓
IF error_rate > 10%:
→ Email alert till Lars + Rebecka
[n8n Schedule: Daglig 08:00]
↓
[Query PostgreSQL: AI-decisions senaste 24h]
↓
[Generate performance report]
↓
[Email till Mattias + Emil]:
- Antal förfrågningar analyzerade
- AI Go/No-go träffsäkerhet
- Genomsnittlig processing time
- Identifierade motstridigheter
9. Disaster Recovery
Backup-strategi (Render Managed)
Automatiska backups:
- PostgreSQL: Daglig automatisk backup (Render managed)
- Qdrant: Veckovis snapshot via n8n workflow
- n8n workflows: Daglig export till GitHub
n8n Backup Workflow:
[Schedule: 03:00 daglig]
↓
[n8n API: Export all workflows → JSON]
↓
[Qdrant API: Create snapshot]
↓
[Git: Commit + push to customer-site repo]
↓
[Email notification: Backup completed]
DR-plan
| Scenario | RTO | RPO | Procedur |
|---|---|---|---|
| Render region failure | 4h | 24h | Restore från backup till annan region |
| Database corruption | 4h | 24h | Restore från Render automatic backup |
| Qdrant data loss | 2h | 7 dagar | Re-import från veckovis snapshot |
| Accidental workflow deletion | 1h | 1 dag | Restore från Git history |
10. Utvecklingsmiljö
Development Setup
# Klona customer site repository
git clone https://github.com/optimate/customer-prolux-bc02-site.git
cd customer-prolux-bc02-site
# Setup environment
cp .env.example .env
# Edit .env med API-nycklar
# Starta full stack lokalt
docker-compose up -d
# Services tillgängliga:
# n8n: http://localhost:5678
# Django Portal: http://localhost:8000
# Ingestion Engine: http://localhost:8001
# Agentic Engine: http://localhost:8002
# Qdrant: http://localhost:6333
# PostgreSQL: localhost:5432
CI/CD Pipeline
GitHub Actions - Deploy to Render:
name: Deploy BC02 to Production
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Deploy to Render
run: |
curl -X POST "https://api.render.com/deploy/srv-xxx" \
-H "Authorization: Bearer ${{ secrets.RENDER_API_KEY }}"
Bilagor
Bilaga A: BC02 Site Repository Struktur
customer-prolux-bc02-site/
├── infra/
│ ├── render.yaml # Render deployment config
│ └── docker-compose.yml # Local dev setup
├── n8n/
│ ├── workflows/
│ │ ├── 01-email-intake.json
│ │ ├── 02-document-analysis-pipeline.json
│ │ ├── 03-go-no-go-decision.json
│ │ ├── 04-crm-registration.json
│ │ ├── 05-credit-check.json
│ │ └── 06-backup-workflow.json
│ └── credentials/ # Encrypted credentials
├── django_portal/
│ ├── bc02_app/
│ │ ├── views.py # Tender list, detail, decision
│ │ ├── models.py # Django ORM models
│ │ ├── templates/
│ │ │ ├── tender_list.html
│ │ │ ├── tender_detail.html
│ │ │ └── go_no_go_decision.html
│ │ └── api.py # REST API for n8n webhooks
│ ├── requirements.txt
│ └── manage.py
├── config/
│ ├── ingestion-engine.yml # BC02-specific endpoints config
│ ├── agentic-engine.yml # RAG settings, prompts
│ ├── document-types.json # AF, AFD, K, A definitions
│ └── prioritization-matrix.json # Go/No-go criteria from Emil
├── data/
│ ├── training_tenders/ # 10 example tenders from Mattias
│ │ ├── stender_vb_1966/
│ │ ├── nibbleskolan_2024/
│ │ └── ...
│ └── historical_projects.csv # Historical project data for Qdrant
├── prompts/
│ ├── analyze_tender.txt # Claude prompt for full analysis
│ ├── extract_scope_afd1.txt
│ ├── detect_conflicts.txt
│ └── go_no_go_recommendation.txt
├── backup/
│ ├── postgres/
│ ├── qdrant/
│ └── n8n/
├── site-docs/
│ ├── BC02-Setup.md
│ ├── BC02-User-Guide-Mattias.md
│ └── BC02-Teknisk-Arkitektur.md # This document
└── .env # Secrets (not in Git)
Bilaga B: Kostnadsanalys
Initial Investering (År 1):
| Post | Kostnad |
|---|---|
| Core Engine Development (BC02 endpoints) | 80 000 kr |
| n8n Workflows Development | 40 000 kr |
| Django Portal Development | 30 000 kr |
| Data prep + Training (10 examples) | 20 000 kr |
| Testing + Deployment | 15 000 kr |
| Total År 1 | 185 000 kr |
Årlig Drift (År 2+):
| Post | Kostnad |
|---|---|
| Render Cloud Hosting | 21 000 kr |
| Claude API (550 × $3) | 19 200 kr |
| LangSmith Observability | 7 200 kr |
| Maintenance (20h/år) | 40 000 kr |
| Total År 2+ | 87 400 kr |
ROI-kalkyl (uppdaterad):
- Årlig besparing BC02: 340 490 kr
- Investering År 1: 185 000 kr
- Drift År 2+: 87 400 kr
- Nettobesparing År 1: 155 490 kr
- Nettobesparing År 2+: 253 090 kr/år
- ROI: 6,5 månader
- NPV 3 år (5% diskontering): ~540 000 kr
Dokumentinformation
Version: 1.0
Arkitekt: Lars Diethelm
Platform: Optimate Core (Hub-and-Spoke Architecture)
Deployment: Render (Cloud) primär
Granskad av: Rebecka Englund (IT), Mattias Svensson (Process)
Godkänd av: Emil Gråberg (Processägare)
Datum: 2025-11-01
Nästa revision: Efter BP3 (vecka 43)
Repositories:
- Core:
github.com/optimate/optimate-core(Ingestion + Agentic Engines) - Template:
github.com/optimate/optimate-customer-template - Customer Site:
github.com/optimate/customer-prolux-bc02-site
Signering och Godkännande
Detta dokument utgör den tekniska grunden för implementation av BC02 Fas 4.
| Roll | Namn | Signatur | Datum |
|---|---|---|---|
| Processägare | Emil Gråberg | ____________ | ______ |
| Processexpert | Mattias Svensson | ____________ | ______ |
| Kalkylator | Karin Asp | ____________ | ______ |
| IT-ansvarig | Rebecka Englund | ____________ | ______ |
| Arkitekt/Utvecklare | Lars Diethelm | ____________ | ______ |
Nästa steg:
- Godkännande av detta dokument (Vecka 43)
- Uppföljningsmöte med Emil: Prioriteringsmatris + KPI:er (1 timme)
- Setup Render deployment + customer-site repository (Vecka 43)
- Utveckling av BC02-endpoints i Core Engines (Vecka 43-44)
- Import av 10 träningsexempel till Qdrant (Vecka 44)
- BP3-beslut (Vecka 43)
- Pilot med 5 förfrågningar (Vecka 45-46)
- Full utrullning (Vecka 47+)