πŸ—οΈ Arkitektur

← Tilbage til forsiden

πŸ—οΈ PepsiMax Indekset

Teknisk arkitekturoversigt

Systemdiagram

flowchart TB
    subgraph Frontend["πŸ–₯️ Frontend (Browser)"]
        UI[index.html
Brugerinterface] JS[main.js
JavaScript Logic] Map[Leaflet
Kortvisning] Charts[Chart.js
Prisgrafer] end subgraph CloudflarePages["☁️ Cloudflare Pages"] API["/api/*
REST API"] Static[Statiske filer
HTML/CSS/JS] Images["/images/*
Billedserver"] end subgraph Workers["⚑ Cloudflare Workers"] Products["/api/products
Produkter + Priser"] Stores["/api/stores
Butikker"] Admin["/api/admin/*
Administration"] Cron["/api/cron/*
Automatisering"] end subgraph External["🌐 Eksterne Services"] Turso[(Turso SQLite
Database)] R2[Cloudflare R2
Billeder] Firecrawl[Firecrawl API
Web Scraping] Salling[Salling API
Prisdata] Discord[Discord
Notifikationer] end UI --> JS JS --> Map JS --> Charts JS --> API API --> Products API --> Stores API --> Admin Products --> Turso Stores --> Turso Admin --> Turso Cron --> Firecrawl Cron --> Salling Cron --> Discord Cron --> Turso Images --> R2 Static --> UI

Datamodel

erDiagram
    PRODUCTS ||--o{ PRICE_HISTORY : has
    CHAINS ||--o{ PRICE_HISTORY : has
    CHAINS ||--o{ STORES : has
    PRODUCT_TYPES ||--o{ PRODUCTS : categorizes

    PRODUCT_TYPES {
        string id PK
        string name
        string description
    }

    PRODUCTS {
        string id PK
        string product_type_id FK
        string display_name
        int bundle_size
        int unit_volume_ml
        int total_volume_ml
        boolean is_active
    }

    CHAINS {
        string id PK
        string name
        string logo_url
        boolean is_active
    }

    STORES {
        string id PK
        string chain_id FK
        string name
        string address
        float latitude
        float longitude
    }

    PRICE_HISTORY {
        string id PK
        string product_id FK
        string chain_id FK
        float price
        boolean is_promotion
        date valid_from
        date valid_until
        boolean is_current
    }
            

Request Flow

sequenceDiagram
    participant U as πŸ‘€ Bruger
    participant B as πŸ–₯️ Browser
    participant CF as ☁️ Cloudflare
    participant W as ⚑ Worker
    participant DB as πŸ—„οΈ Turso DB

    U->>B: Γ…bner pepsimax.slambert.com
    B->>CF: GET /index.html
    CF-->>B: HTML + CSS + JS

    B->>CF: GET /api/products
    CF->>W: KΓΈr products.js
    W->>DB: SELECT products, prices, chains
    DB-->>W: Resultater
    W-->>CF: JSON response
    CF-->>B: Produktdata med priser

    B->>U: Vis priser i UI
            

Automatiseret Prisindsamling

flowchart LR
    subgraph Trigger["⏰ Trigger"]
        Schedule[Kl. 07:00 dagligt]
        Manual[Manuel kΓΈrsel]
    end

    subgraph Scraper["πŸ” Scraping"]
        FC[Firecrawl API]
        Parse[Parser]
    end

    subgraph Sources["πŸ“° Kilder"]
        ETilbud[etilbudsavis.dk]
    end

    subgraph Process["βš™οΈ Processering"]
        Match[Match til produkter]
        Validate[ValidΓ©r priser]
        Import[ImportΓ©r til DB]
    end

    subgraph Notify["πŸ“’ Notifikation"]
        Discord2[Discord webhook]
    end

    Schedule --> FC
    Manual --> FC
    FC --> ETilbud
    ETilbud --> Parse
    Parse --> Match
    Match --> Validate
    Validate --> Import
    Import --> Discord2
            

Tech Stack

Komponent Teknologi FormΓ₯l
Frontend Vanilla JS, HTML5, CSS3 Brugerinterface
Kort Leaflet.js Butikskort
Grafer Chart.js Prishistorik
Backend Cloudflare Workers Serverless API
Database Turso (SQLite) Datalagring
Billeder Cloudflare R2 Objektlagring
Scraping Firecrawl Automatisk prisindsamling
Hosting Cloudflare Pages CDN + Deployment

Sikkerhed

flowchart TB
    subgraph Public["🌍 Offentlige endpoints"]
        GET1[GET /api/products]
        GET2[GET /api/stores]
        GET3[GET /images/*]
    end

    subgraph Protected["πŸ” Beskyttede endpoints"]
        Admin1[POST /api/admin/*]
        Admin2[DELETE /api/admin/*]
        Cron1[POST /api/cron/*]
    end

    subgraph Auth["πŸ”‘ Autentificering"]
        GitHub[GitHub OAuth]
        Session[Session Token]
        AdminPW[ADMIN_PASSWORD]
    end

    Public --> |Ingen auth| Response1[βœ… Data]
    Protected --> Auth
    Auth --> |Valideret| Response2[βœ… Handling]
    Auth --> |Afvist| Response3[❌ 401/403]
            

Mappestruktur

pepsimax-index/
β”œβ”€β”€ functions/              # Cloudflare Workers
β”‚   β”œβ”€β”€ api/
β”‚   β”‚   β”œβ”€β”€ products.js     # Produkter + priser
β”‚   β”‚   β”œβ”€β”€ stores.js       # Butikker
β”‚   β”‚   β”œβ”€β”€ admin/          # Admin endpoints
β”‚   β”‚   └── cron/           # Automatisering
β”‚   └── utils/              # HjΓ¦lpefunktioner
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ admin/              # Admin dashboard
β”‚   └── lib/                # Frontend biblioteker
β”œβ”€β”€ js/
β”‚   └── main.js             # Hovedlogik
β”œβ”€β”€ css/
β”‚   └── styles.css          # Styling
β”œβ”€β”€ docs/                   # Dokumentation
└── scripts/                # VΓ¦rktΓΈjsscripts

Bygget med ❀️ og Cloudflare