- Implemented user notification preferences table for managing default notification settings. - Created sag_reminders table to define reminder rules with various trigger types and recipient configurations. - Developed sag_reminder_queue for processing reminder events triggered by status changes or scheduled times. - Added sag_reminder_logs to track reminder notifications and user interactions. - Introduced frontend notification system using Bootstrap 5 Toast for displaying reminders. - Created email template for sending reminders with case details and action links. - Implemented rate limiting for user notifications to prevent spamming. - Added triggers and functions for automatic updates and reminder processing.
13 KiB
GitHub Copilot Instructions - BMC Webshop (Frontend)
Project Overview
BMC Webshop er en kunde-styret webshop løsning, hvor BMC Hub ejer indholdet, API Gateway (apigateway.bmcnetworks.dk) styrer logikken, og Webshoppen (dette projekt) kun viser og indsamler input.
Tech Stack: React/Next.js/Vue.js (vælg én), TypeScript, Tailwind CSS eller Bootstrap 5
3-Lags Arkitektur
┌─────────────────────────────────────────────────────────┐
│ TIER 1: BMC HUB (Admin System) │
│ - Administrerer webshop-opsætning │
│ - Pusher data til Gateway │
│ - Poller Gateway for nye ordrer │
│ https://hub.bmcnetworks.dk │
└─────────────────────────────────────────────────────────┘
▼ (Push config)
┌─────────────────────────────────────────────────────────┐
│ TIER 2: API GATEWAY (Forretningslogik + Database) │
│ - Modtager og gemmer webshop-config fra Hub │
│ - Ejer PostgreSQL database med produkter, priser, ordrer│
│ - Håndterer email/OTP login │
│ - Beregner priser og filtrerer varer │
│ - Leverer sikre API'er til Webshoppen │
│ https://apigateway.bmcnetworks.dk │
└─────────────────────────────────────────────────────────┘
▲ (API calls)
┌─────────────────────────────────────────────────────────┐
│ TIER 3: WEBSHOP (Dette projekt - Kun Frontend) │
│ - Viser logo, tekster, produkter, priser │
│ - Shopping cart (kun i frontend state) │
│ - Sender ordre som payload til Gateway │
│ - INGEN forretningslogik eller datapersistering │
└─────────────────────────────────────────────────────────┘
Webshoppens Ansvar
✅ Hvad Webshoppen GØR
- Viser kundens logo, header-tekst, intro-tekst (fra Gateway)
- Viser produktkatalog med navn, beskrivelse, pris (fra Gateway)
- Samler kurv i browser state (localStorage/React state)
- Sender ordre til Gateway ved checkout
- Email/OTP login flow (kalder Gateway's auth-endpoint)
❌ Hvad Webshoppen IKKE GØR
- Gemmer INGEN data (hverken kurv, produkter, eller ordrer)
- Beregner INGEN priser eller avance
- Håndterer INGEN produkt-filtrering (Gateway leverer klar liste)
- Snakker IKKE direkte med Hub eller e-conomic
- Håndterer IKKE betalingsgateway (Gateway's ansvar)
API Gateway Kontrakt
Base URL: https://apigateway.bmcnetworks.dk
1. Login med Email + Engangskode
Step 1: Anmod om engangskode
POST /webshop/auth/request-code
Content-Type: application/json
{
"email": "kunde@firma.dk"
}
Response 200:
{
"success": true,
"message": "Engangskode sendt til kunde@firma.dk"
}
Step 2: Verificer kode og få JWT token
POST /webshop/auth/verify-code
Content-Type: application/json
{
"email": "kunde@firma.dk",
"code": "123456"
}
Response 200:
{
"success": true,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"customer_id": 42,
"expires_at": "2026-01-13T15:00:00Z"
}
2. Hent Webshop Context (Komplet Webshop-Data)
GET /webshop/{customer_id}/context
Authorization: Bearer {jwt_token}
Response 200:
{
"customer_id": 42,
"company_name": "Advokatfirma A/S",
"config_version": "2026-01-13T12:00:00Z",
"branding": {
"logo_url": "https://apigateway.bmcnetworks.dk/assets/logos/42.png",
"header_text": "Velkommen til vores webshop",
"intro_text": "Bestil nemt og hurtigt direkte her.",
"primary_color": "#0f4c75",
"accent_color": "#3282b8"
},
"products": [
{
"id": 101,
"ean": "5711045071324",
"product_number": "FIRE-001",
"name": "Cisco Firewall ASA 5506-X",
"description": "Next-generation firewall med 8 porte",
"unit": "stk",
"base_price": 8500.00,
"calculated_price": 9350.00,
"margin_percent": 10.0,
"currency": "DKK",
"stock_available": true,
"category": "Network Security"
},
{
"id": 102,
"ean": "5704174801740",
"product_number": "SW-024",
"name": "TP-Link 24-Port Gigabit Switch",
"description": "Managed switch med VLAN support",
"unit": "stk",
"base_price": 2100.00,
"calculated_price": 2310.00,
"margin_percent": 10.0,
"currency": "DKK",
"stock_available": true,
"category": "Switches"
}
],
"allowed_payment_methods": ["invoice", "card"],
"min_order_amount": 500.00,
"shipping_cost": 0.00
}
3. Opret Ordre
POST /webshop/orders
Authorization: Bearer {jwt_token}
Content-Type: application/json
{
"customer_id": 42,
"order_items": [
{
"product_id": 101,
"quantity": 2,
"unit_price": 9350.00
},
{
"product_id": 102,
"quantity": 5,
"unit_price": 2310.00
}
],
"shipping_address": {
"company_name": "Advokatfirma A/S",
"street": "Hovedgaden 1",
"postal_code": "1000",
"city": "København K",
"country": "DK"
},
"delivery_note": "Levering til bagsiden, ring på døren",
"total_amount": 30250.00
}
Response 201:
{
"success": true,
"order_id": "ORD-2026-00123",
"status": "pending",
"total_amount": 30250.00,
"created_at": "2026-01-13T14:30:00Z",
"message": "Ordre modtaget. Du vil modtage en bekræftelse på email."
}
4. Hent Mine Ordrer (Optional)
GET /webshop/orders?customer_id=42
Authorization: Bearer {jwt_token}
Response 200:
{
"orders": [
{
"order_id": "ORD-2026-00123",
"created_at": "2026-01-13T14:30:00Z",
"status": "pending",
"total_amount": 30250.00,
"item_count": 7
}
]
}
Frontend Krav
Mandatory Features
-
Responsive Design
- Mobile-first approach
- Breakpoints: 576px (mobile), 768px (tablet), 992px (desktop)
- Brug CSS Grid/Flexbox eller framework grid system
-
Dark Mode Support
- Toggle mellem light/dark theme
- Gem præference i localStorage
- CSS Variables for farver
-
Shopping Cart
- Gem kurv i localStorage (persist ved page reload)
- Vis antal varer i header badge
- Real-time opdatering af total pris
- Slet/rediger varer i kurv
-
Login Flow
- Email input → Send kode
- Vis countdown timer (5 minutter)
- Verificer kode → Få JWT token
- Gem token i localStorage
- Auto-logout ved token expiry
-
Product Catalog
- Vis produkter i grid layout (3-4 kolonner på desktop)
- Filtrer produkter efter kategori (hvis Gateway leverer kategorier)
- Søgning i produktnavn/beskrivelse
- "Tilføj til kurv" knap med antal-vælger
-
Checkout Flow
- Vis kurv-oversigt
- Leveringsadresse (kan være pre-udfyldt fra Gateway)
- Leveringsnotat (textarea)
- "Bekræft ordre" knap
- Loading state under ordre-oprettelse
- Success/error feedback
Design Guidelines
Stil: Minimalistisk, clean, "Nordic" æstetik (inspireret af BMC Hub's Nordic Top design)
Farver (kan overskrives af Gateway's branding config):
- Primary:
#0f4c75(Deep Blue) - Accent:
#3282b8(Bright Blue) - Success:
#27ae60 - Warning:
#f39c12 - Danger:
#e74c3c
Typografi:
- Font: System font stack (
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, ...) - Headings: 500-600 weight
- Body: 400 weight
Components:
- Cards med subtil shadow/border
- Buttons med hover states
- Input fields med focus outline
- Loading spinners (ikke lange tekst-beskeder)
State Management
Local Storage Keys
// Authentication
webshop_jwt_token // JWT token fra Gateway
webshop_customer_id // Customer ID
webshop_token_expires_at // ISO timestamp
// Shopping Cart
webshop_cart // JSON array af cart items
webshop_theme // "light" eller "dark"
// Cache (optional)
webshop_context // Cached webshop context (TTL: 5 minutter)
Cart Item Format
{
product_id: 101,
ean: "5711045071324",
name: "Cisco Firewall ASA 5506-X",
unit_price: 9350.00,
quantity: 2,
total: 18700.00
}
Error Handling
Gateway API Errors
// Eksempel på error response fra Gateway
{
"success": false,
"error": "invalid_code",
"message": "Ugyldig engangskode. Prøv igen."
}
Error Codes (forventet fra Gateway):
invalid_email- Email ikke fundet eller ikke whitelistedinvalid_code- Forkert engangskodecode_expired- Engangskode udløbet (>5 min)token_expired- JWT token udløbetunauthorized- Manglende/ugyldig Authorization headerproduct_not_found- Produkt ID findes ikkemin_order_not_met- Ordre under minimum beløbout_of_stock- Produkt ikke på lager
Handling:
- Vis brugervenlig fejlbesked i UI (ikke tekniske detaljer)
- Log tekniske fejl til console (kun i development)
- Redirect til login ved
token_expiredellerunauthorized
Security
-
HTTPS Only
- Al kommunikation med Gateway over HTTPS
- Ingen hardcoded credentials
-
JWT Token
- Gem i localStorage (ikke cookie)
- Send i
Authorization: Bearer {token}header - Check expiry før hver API call
- Auto-logout ved expiry
-
Input Validation
- Validér email format (client-side)
- Validér antal > 0 ved "Tilføj til kurv"
- Validér leveringsadresse udfyldt ved checkout
- Sanitize input (brug library som DOMPurify hvis nødvendigt)
-
CORS
- Gateway skal have
Access-Control-Allow-Originheader - Webshoppen kalder altid Gateway (ikke Hub direkte)
- Gateway skal have
Deployment
Environment Variables
# .env.production
NEXT_PUBLIC_API_GATEWAY_URL=https://apigateway.bmcnetworks.dk
NEXT_PUBLIC_WEBSHOP_NAME="BMC Networks Webshop"
Build Process
# Development
npm run dev
# Production build
npm run build
npm run start
# Docker (optional)
docker build -t bmc-webshop .
docker run -p 3000:3000 bmc-webshop
Static Hosting (Anbefalet)
- Vercel, Netlify, eller Cloudflare Pages
- Deploy fra Git repository
- Automatisk HTTPS og CDN
- Environment variables i hosting provider UI
Testing
Manual Testing Checklist
- Login med email/OTP virker
- Token gemmes og bruges i efterfølgende API calls
- Webshop context hentes og vises korrekt
- Produkter vises i grid
- "Tilføj til kurv" opdaterer cart badge
- Cart viser korrekte varer og total pris
- Checkout sender korrekt payload til Gateway
- Success message vises ved succesfuld ordre
- Error handling virker (test med ugyldig kode, udløbet token)
- Dark mode toggle virker
- Responsive design på mobil/tablet/desktop
Common Pitfalls to Avoid
- Gem IKKE data i Webshoppen - alt kommer fra Gateway
- Beregn IKKE priser selv - Gateway leverer
calculated_price - Snakker IKKE direkte med Hub - kun via Gateway
- Gem IKKE kurv i database - kun localStorage
- Hardcode IKKE customer_id - hent fra JWT token
- Valider IKKE produkter selv - Gateway filtrerer allerede
- Implementer IKKE betalingsgateway - Gateway's ansvar
Quick Reference
API Endpoints
POST /webshop/auth/request-code # Anmod engangskode
POST /webshop/auth/verify-code # Verificer kode → JWT
GET /webshop/{customer_id}/context # Hent webshop data
POST /webshop/orders # Opret ordre
GET /webshop/orders?customer_id={id} # Hent mine ordrer
Typical Flow
1. User indtaster email → POST /auth/request-code
2. User indtaster kode → POST /auth/verify-code → Gem JWT token
3. App henter webshop context → GET /context (med JWT header)
4. User browser produkter, tilføjer til kurv (localStorage)
5. User går til checkout → POST /orders (med cart data)
6. Gateway behandler ordre → Success message vises
Support & Documentation
Hub Repository: /Users/christianthomas/DEV/bmc_hub_dev
Hub API Docs: https://hub.bmcnetworks.dk/api/docs
Gateway API Docs: https://apigateway.bmcnetworks.dk/docs (når implementeret)
Kontakt: ct@bmcnetworks.dk