ποΈ 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