# ianmllr/tech-tilbud architecture

> Architecture diagram of the GitHub repository ianmllr/tech-tilbud, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-09-22). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/ianmllr/tech-tilbud
- Repository: https://github.com/ianmllr/tech-tilbud

## Overview

Tech-tilbud gathers Danish subscription-linked tech offers, compares their six-month costs with market prices, and lets users browse savings and request an expiry reminder. The main flow runs from provider and price scrapers through offer normalization into the searchable listing; reminders are a separate persistence-and-email flow. The sampled source confirms the listing filters, reminder endpoints, and market-price matching. Other scraper wiring and the reminder dispatch schedule are not shown, so those connections are left out.

Main entry points: [`src/hooks/useOffers.ts`](https://github.com/ianmllr/tech-tilbud/blob/master/src/hooks/useOffers.ts) (Search and filters), [`src/app/api/reminders/send/route.ts`](https://github.com/ianmllr/tech-tilbud/blob/master/src/app/api/reminders/send/route.ts) (Due reminder sender), [`src/lib/offers.ts`](https://github.com/ianmllr/tech-tilbud/blob/master/src/lib/offers.ts) (Offer catalog), [`src/app/page.tsx`](https://github.com/ianmllr/tech-tilbud/blob/master/src/app/page.tsx) (Offer listing)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_collection["Offer collection"]
  node_provider_scrapers["Provider scrapers"]
  node_shared_scraper["Scraper utilities<br/>[scraper_utils.py]"]
  node_market_scrapers["Market price scrapers"]
end

subgraph group_comparison["Offer comparison"]
  node_offer_data["Offer catalog<br/>[offers.ts]"]
  node_offer_types["Offer model<br/>[offer.ts]"]
end

subgraph group_web["Web experience"]
  node_listing_page["Offer listing<br/>[page.tsx]"]
  node_offer_filters["Search and filters<br/>[useOffers.ts]"]
  node_offer_card["Offer details<br/>[OfferCard.tsx]"]
  node_reminder_page["Reminder page<br/>[page.tsx]"]
  node_reminder_form["Reminder form<br/>[ReminderForm.tsx]"]
end

subgraph group_reminders["Reminder service"]
  node_reminder_api["Reminder registration<br/>[route.ts]"]
  node_reminder_db[("Reminder database<br/>[db.ts]")]
  node_send_api["Due reminder sender<br/>[route.ts]"]
end

node_user(("Visitor"))
node_price_sources(("PriceRunner / Prisjagt"))
node_email_service["Resend email"]

node_provider_scrapers -->|"use utilities"| node_shared_scraper
node_market_scrapers -.->|"scrape prices"| node_price_sources
node_offer_data -->|"maps offers"| node_offer_types
node_listing_page -->|"requests results"| node_offer_filters
node_offer_filters -->|"filters and sorts"| node_offer_data
node_offer_filters -->|"supplies offers"| node_offer_card
node_user -->|"browses offers"| node_listing_page
node_user -->|"requests reminder"| node_reminder_page
node_reminder_page -->|"renders form"| node_reminder_form
node_reminder_form -->|"submits reminder"| node_reminder_api
node_reminder_api -->|"stores reminder"| node_reminder_db
node_send_api -->|"reads due; deletes sent"| node_reminder_db
node_send_api -->|"sends email"| node_email_service

click node_provider_scrapers "https://github.com/ianmllr/tech-tilbud/tree/master/scrapers"
click node_shared_scraper "https://github.com/ianmllr/tech-tilbud/blob/master/scrapers/scraper_utils.py"
click node_market_scrapers "https://github.com/ianmllr/tech-tilbud/blob/master/scrapers/pricerunner_scraper.py"
click node_offer_data "https://github.com/ianmllr/tech-tilbud/blob/master/src/lib/offers.ts"
click node_offer_types "https://github.com/ianmllr/tech-tilbud/blob/master/src/types/offer.ts"
click node_listing_page "https://github.com/ianmllr/tech-tilbud/blob/master/src/app/page.tsx"
click node_offer_filters "https://github.com/ianmllr/tech-tilbud/blob/master/src/hooks/useOffers.ts"
click node_offer_card "https://github.com/ianmllr/tech-tilbud/blob/master/src/components/OfferCard.tsx"
click node_reminder_page "https://github.com/ianmllr/tech-tilbud/blob/master/src/app/reminder/page.tsx"
click node_reminder_form "https://github.com/ianmllr/tech-tilbud/blob/master/src/components/ReminderForm.tsx"
click node_reminder_api "https://github.com/ianmllr/tech-tilbud/blob/master/src/app/api/reminders/route.ts"
click node_reminder_db "https://github.com/ianmllr/tech-tilbud/blob/master/src/lib/db.ts"
click node_send_api "https://github.com/ianmllr/tech-tilbud/blob/master/src/app/api/reminders/send/route.ts"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_provider_scrapers,node_shared_scraper,node_market_scrapers toneBlue
class node_offer_data,node_offer_types toneAmber
class node_listing_page,node_offer_filters,node_offer_card,node_reminder_page,node_reminder_form toneMint
class node_reminder_api,node_reminder_db,node_send_api toneRose
class node_user,node_price_sources,node_email_service toneIndigo
```

## Components

### Offer collection

- [Provider scrapers](https://github.com/ianmllr/tech-tilbud/tree/master/scrapers): `scrapers`
- [Scraper utilities](https://github.com/ianmllr/tech-tilbud/blob/master/scrapers/scraper_utils.py): `scrapers/scraper_utils.py`
- [Market price scrapers](https://github.com/ianmllr/tech-tilbud/blob/master/scrapers/pricerunner_scraper.py): `scrapers/pricerunner_scraper.py`

### Offer comparison

- [Offer catalog](https://github.com/ianmllr/tech-tilbud/blob/master/src/lib/offers.ts): `src/lib/offers.ts`
- [Offer model](https://github.com/ianmllr/tech-tilbud/blob/master/src/types/offer.ts): `src/types/offer.ts`

### Web experience

- [Offer listing](https://github.com/ianmllr/tech-tilbud/blob/master/src/app/page.tsx): `src/app/page.tsx`
- [Search and filters](https://github.com/ianmllr/tech-tilbud/blob/master/src/hooks/useOffers.ts): `src/hooks/useOffers.ts`
- [Offer details](https://github.com/ianmllr/tech-tilbud/blob/master/src/components/OfferCard.tsx): `src/components/OfferCard.tsx`
- [Reminder page](https://github.com/ianmllr/tech-tilbud/blob/master/src/app/reminder/page.tsx): `src/app/reminder/page.tsx`
- [Reminder form](https://github.com/ianmllr/tech-tilbud/blob/master/src/components/ReminderForm.tsx): `src/components/ReminderForm.tsx`

### Reminder service

- [Reminder registration](https://github.com/ianmllr/tech-tilbud/blob/master/src/app/api/reminders/route.ts): `src/app/api/reminders/route.ts`
- [Reminder database](https://github.com/ianmllr/tech-tilbud/blob/master/src/lib/db.ts): `src/lib/db.ts`
- [Due reminder sender](https://github.com/ianmllr/tech-tilbud/blob/master/src/app/api/reminders/send/route.ts): `src/app/api/reminders/send/route.ts`

### Other components

- **Visitor**
- **PriceRunner / Prisjagt**
- **Resend email**

## Connections

- Provider scrapers → Scraper utilities: use utilities
- Market price scrapers → PriceRunner / Prisjagt: scrape prices
- Offer catalog → Offer model: maps offers
- Offer listing → Search and filters: requests results
- Search and filters → Offer catalog: filters and sorts
- Search and filters → Offer details: supplies offers
- Visitor → Offer listing: browses offers
- Visitor → Reminder page: requests reminder
- Reminder page → Reminder form: renders form
- Reminder form → Reminder registration: submits reminder
- Reminder registration → Reminder database: stores reminder
- Due reminder sender → Reminder database: reads due; deletes sent
- Due reminder sender → Resend email: sends email
