# BOC v2 — Architecture Proposal ## Nuvarande Problem (v1.0) - 13K rader Go i ett enda monolit-paket - 20 handlers i samma package, delar `*sql.DB` - Ingen repository pattern — SQL direkt i handlers - Ingen service layer — affärslogik i HTTP-handlers - Ledger-integration är en pass-through proxy - Ingen event sourcing trots Kafka-definitioner - Frontend: 12 HTML-filer med copy-paste ## V2 Vision: Clean Architecture ``` ┌─────────────────────────────────────────┐ │ Transport (HTTP / WebSocket / CLI) │ │ - handlers/ chi routers │ │ - middleware/ auth, cors, rate │ │ - dto/ request/response │ ├─────────────────────────────────────────┤ │ Application (Use Cases) │ │ - services/ business logic │ │ - commands/ CQRS write │ │ - queries/ CQRS read │ ├─────────────────────────────────────────┤ │ Domain (Core Business) │ │ - models/ entities, value obj │ │ - events/ domain events │ │ - repositories/ interfaces │ ├─────────────────────────────────────────┤ │ Infrastructure │ │ - db/ PostgreSQL impl │ │ - cache/ Redis impl │ │ - events/ Kafka impl │ │ - email/ Resend impl │ │ - pdf/ gofpdf impl │ │ - ledger/ aamos-ledger client │ └─────────────────────────────────────────┘ ``` ## V2 Förändringar ### 1. Repository Pattern ```go // domain/repositories/customer.go type CustomerRepository interface { FindByID(ctx context.Context, id uuid.UUID) (*models.Customer, error) FindByTenant(ctx context.Context, tenantID uuid.UUID, opts ListOptions) ([]*models.Customer, error) Create(ctx context.Context, c *models.Customer) error Update(ctx context.Context, c *models.Customer) error Delete(ctx context.Context, id uuid.UUID) error } // infrastructure/db/customer_repo.go type PostgresCustomerRepo struct { db *sql.DB } ``` ### 2. Service Layer (Transactions) ```go // application/services/quote_service.go func (s *QuoteService) ConvertToOrder(ctx context.Context, quoteID uuid.UUID) (*models.Order, error) { return s.db.WithTx(ctx, func(tx *sql.Tx) error { quote, err := s.quotes.FindByIDTx(ctx, tx, quoteID) if err != nil { return err } order := quote.ToOrder() if err := s.orders.CreateTx(ctx, tx, order); err != nil { return err } quote.Status = models.QuoteConverted return s.quotes.UpdateTx(ctx, tx, quote) }) } ``` ### 3. Domain Events (Kafka aktiverad) ```go // domain/events/customer_events.go type CustomerCreated struct { CustomerID uuid.UUID TenantID uuid.UUID Email string } // application/event_publisher.go func (p *KafkaPublisher) Publish(ctx context.Context, event domain.Event) error { // Actually uses Kafka now, not just defined } ``` ### 4. Ledger Integration med Circuit Breaker ```go // infrastructure/ledger/client.go type LedgerClient struct { baseURL string httpClient *http.Client circuitBreaker *gobreaker.CircuitBreaker cache cache.Cache } func (c *LedgerClient) GetBalanceSheet(ctx context.Context) (*BalanceSheet, error) { // Cache-first, circuit breaker, fallback to stale data } ``` ### 5. CQRS för Analytics ```go // application/queries/dashboard_query.go type DashboardQuery struct { readDB *sql.DB // Read replica or materialized view } func (q *DashboardQuery) GetKPIs(ctx context.Context, tenantID uuid.UUID) (*KPIs, error) { // Optimized read query, no business logic } ``` ## V2 Teknisk Stack | Komponent | Nu | V2 | |-----------|-----|-----| | Router | chi | chi (behåll) | | DB | database/sql | sqlx eller pgx | | Migrations | custom | golang-migrate | | Validation | manual | go-playground/validator | | Testing | testify | testify + sqlmock + dockertest | | Events | Kafka stub | Kafka aktiverad | | Cache | Redis wrapper | Redis + cache-aside pattern | | Frontend | 12 HTML | Vanilla JS SPA (se FRONTEND_REFACTOR_PROPOSAL.md) | ## V2 Migreringsplan ### Fas 1: Foundation (1 vecka) 1. Refactor till Clean Architecture packages 2. Implementera Repository pattern för CRM + Sales 3. Lägg till service layer med transaktioner 4. Riktiga integrationstester med dockertest ### Fas 2: Events + Cache (1 vecka) 1. Aktivera Kafka publishing från services 2. Implementera cache-aside för analytics 3. Circuit breaker för ledger ### Fas 3: Frontend (3 dagar) 1. Vanilla JS SPA shell 2. Konvertera moduler en i taget 3. Ta bort gamla HTML-filer ### Fas 4: Polish (2 dagar) 1. OpenAPI/Swagger docs 2. Health checks för alla dependencies 3. Metrics (Prometheus) 4. Structured logging med trace IDs ## V2 "Inte Nu" - GraphQL (YAGNI) - Microservices (för tidigt) - Kubernetes operators (overkill) - React/Vue (för tungt) ## Sammanfattning V2 handlar inte om nya features. V2 handlar om att **det vi har faktiskt fungerar pålitligt**. Nuvarande v1.0 är en demo som ser komplett ut men har: - Säkerhetshål (fixade idag) - Tysta databasfel (fixade idag) - Ingen transaktionssäkerhet - Död kod (Rust, C, Kafka) - Noll testtäckning V2 = produktionsklar.