# gnehs/home-dashboard architecture

> Architecture diagram of the GitHub repository gnehs/home-dashboard, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-13). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/gnehs/home-dashboard
- Repository: https://github.com/gnehs/home-dashboard

## Overview

1. **What this repo is**
   - A **Next.js App Router** service that renders **server-generated dashboard images** for an **e-paper / electronic ink display** use case.
   - The app is not primarily a traditional interactive web UI; its core product is a set of HTTP image endpoints.

2. **Main request flow**
   - A device or browser requests one of the image routes under `app/img/...`.
   - The route handler gathers live data from local utilities and external APIs.
   - The route returns a rendered image response, suitable for an ESPHome-driven display or any client that can fetch an image URL.

3. **Image endpoints**
   - Each dashboard variant lives in its own route folder:
     - `app/img/board-1/route.tsx`
     - `app/img/currency/route.tsx`
     - `app/img/currency-2/route.tsx`
     - `app/img/day-clock/route.tsx`
     - `app/img/weather/route.tsx`
   - This structure makes each dashboard an independently addressable image source with its own layout and data requirements.

4. **Rendering subsystem**
   - `utils/ImageResponse.ts` and `utils/font.ts` are the shared rendering layer.
   - These utilities likely wrap Next.js image generation primitives and provide consistent fonts/layout behavior across all routes.
   - `app/globals.css` and Tailwind config provide the visual styling foundation used by the rendered image compositions.

5. **Data integration layer**
   - The `utils/` directory contains the external-data adapters:
     - `utils/met-weather.ts` for weather
     - `utils/cryptocompare.ts` for crypto pricing
     - `utils/taifex.ts` for Taiwan futures market data
     - `utils/homeAssistant.ts` for Home Assistant entity/state data
     - `utils/stepStep.ts` for StepStep service data
     - `utils/bot-bank.ts` for bank/account-related data
   - These modules form the main boundary between the dashboard renderer and outside services.

6. **Dashboard-specific composition**
   - The “board” image (`board-1`) is the most integration-heavy dashboard and combines home automation / status data.
   - The currency dashboards focus on market data.
   - The weather dashboard is centered on location-based forecast data.
   - The day clock dashboard is likely mostly self-contained, relying on time and formatting rather than external services.

7. **Error handling**
   - `app/components/Error.tsx` is the shared failure-state component.
   - This is important because some routes depend on API connectivity and environment configuration; when those dependencies fail, the image still needs a controlled fallback instead of breaking the render.

8. **Configuration and environment**
   - The app is driven by environment variables declared in `.env.example`.
   - Key config inputs include:
     - `WEATHER_LAT` / `WEATHER_LON`
     - `NEXT_PUBLIC_INVERT_COLOR`
     - Home Assistant host/token
     - StepStep host/token
   - This means the runtime is highly environment-dependent, especially for dashboards that pull live home data.

9. **Consumer boundary**
   - `esphome.lilyt5.example.yaml` shows the downstream integration point: an **ESPHome** device that fetches the rendered images and displays them on an e-paper panel.
   - So the architecture includes both the Next.js render service and a separate hardware/display consumer.

10. **Deployment and delivery**
   - `Dockerfile` packages the app for container deployment.
   - `.github/workflows/build.yaml` automates Docker image builds on GitHub Actions.
   - The README indicates images are published to a container registry and then run via `docker run`, making the deployment model “build container, serve image endpoints, point device at them.”

11. **Public/static assets**
   - `public/` holds static files such as `robots.txt` and referenced preview images.
   - `app/img/*` is the runtime image surface, while `public/` is supporting static content.

12. **Overall architecture in one line**
   - This repository is a **server-side image rendering backend** composed of **Next.js route handlers + shared image utilities + external data adapters + containerized deployment**, with **ESPHome/e-paper devices as the primary consumers**.

Main entry points: [`app/img/board-1/route.tsx`](https://github.com/gnehs/home-dashboard/blob/main/app/img/board-1/route.tsx) (Board image), [`app/page.tsx`](https://github.com/gnehs/home-dashboard/blob/main/app/page.tsx) (Landing), [`app/img/currency/route.tsx`](https://github.com/gnehs/home-dashboard/blob/main/app/img/currency/route.tsx) (Currency image), [`app/img/weather/route.tsx`](https://github.com/gnehs/home-dashboard/blob/main/app/img/weather/route.tsx) (Weather image)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_group_app["Image service"]
  node_node_app_page["Landing<br/>Next page<br/>[page.tsx]"]
  node_node_app_layout["Root shell<br/>Next layout<br/>[layout.tsx]"]
  node_node_img_board["Board image<br/>route handler<br/>[route.tsx]"]
  node_node_img_currency["Currency image<br/>route handler<br/>[route.tsx]"]
  node_node_img_currency2["Currency alt<br/>route handler<br/>[route.tsx]"]
  node_node_img_clock["Day clock<br/>route handler<br/>[route.tsx]"]
  node_node_img_weather["Weather image<br/>route handler<br/>[route.tsx]"]
  node_node_error["Error card<br/>shared component<br/>[Error.tsx]"]
  node_node_css["Global styles<br/>styling<br/>[globals.css]"]
  node_node_tailwind["Tailwind config<br/>styling config<br/>[tailwind.config.ts]"]
end

subgraph group_group_utils["Rendering and data"]
  node_node_img_response["Image response<br/>render helper<br/>[ImageResponse.ts]"]
  node_node_font["Font setup<br/>render helper<br/>[font.ts]"]
  node_node_weather_api["Met weather<br/>weather adapter<br/>[met-weather.ts]"]
  node_node_crypto_api["Crypto compare<br/>market adapter<br/>[cryptocompare.ts]"]
  node_node_taifex_api["Taifex<br/>market adapter<br/>[taifex.ts]"]
  node_node_ha_api["Home Assistant<br/>home automation adapter<br/>[homeAssistant.ts]"]
  node_node_stepstep_api["StepStep<br/>service adapter<br/>[stepStep.ts]"]
  node_node_bank_api["Bank data<br/>finance adapter<br/>[bot-bank.ts]"]
end

subgraph group_group_delivery["Delivery"]
  node_node_env["Env example<br/>config<br/>[.env.example]"]
  node_node_docker["Dockerfile<br/>container build"]
  node_node_github_actions["Build workflow<br/>ci pipeline<br/>[build.yaml]"]
end

subgraph group_group_consumer["Consumer"]
  node_node_esphome["ESPHome display<br/>hardware consumer"]
end

node_node_app_page -->|"links to"| node_node_img_board
node_node_app_page -->|"links to"| node_node_img_currency
node_node_app_page -->|"links to"| node_node_img_currency2
node_node_app_page -->|"links to"| node_node_img_clock
node_node_app_page -->|"links to"| node_node_img_weather
node_node_img_board -->|"renders via"| node_node_img_response
node_node_img_board -->|"uses"| node_node_font
node_node_img_board -->|"reads"| node_node_ha_api
node_node_img_board -->|"reads"| node_node_stepstep_api
node_node_img_board -->|"reads"| node_node_bank_api
node_node_img_board -.->|"falls back to"| node_node_error
node_node_img_currency -->|"renders via"| node_node_img_response
node_node_img_currency -->|"uses"| node_node_font
node_node_img_currency -->|"reads"| node_node_crypto_api
node_node_img_currency -->|"reads"| node_node_taifex_api
node_node_img_currency2 -->|"renders via"| node_node_img_response
node_node_img_currency2 -->|"uses"| node_node_font
node_node_img_currency2 -->|"reads"| node_node_crypto_api
node_node_img_clock -->|"renders via"| node_node_img_response
node_node_img_clock -->|"uses"| node_node_font
node_node_img_weather -->|"renders via"| node_node_img_response
node_node_img_weather -->|"uses"| node_node_font
node_node_img_weather -->|"reads"| node_node_weather_api
node_node_app_layout -->|"includes"| node_node_css
node_node_app_layout -.->|"styled by"| node_node_tailwind
node_node_env -.->|"configures"| node_node_weather_api
node_node_env -.->|"configures"| node_node_ha_api
node_node_env -.->|"configures"| node_node_stepstep_api
node_node_env -.->|"configures"| node_node_img_board
node_node_docker -->|"built by"| node_node_github_actions
node_node_esphome -->|"fetches"| node_node_img_board
node_node_esphome -->|"fetches"| node_node_img_weather

click node_node_app_page "https://github.com/gnehs/home-dashboard/blob/main/app/page.tsx"
click node_node_app_layout "https://github.com/gnehs/home-dashboard/blob/main/app/layout.tsx"
click node_node_img_board "https://github.com/gnehs/home-dashboard/blob/main/app/img/board-1/route.tsx"
click node_node_img_currency "https://github.com/gnehs/home-dashboard/blob/main/app/img/currency/route.tsx"
click node_node_img_currency2 "https://github.com/gnehs/home-dashboard/blob/main/app/img/currency-2/route.tsx"
click node_node_img_clock "https://github.com/gnehs/home-dashboard/blob/main/app/img/day-clock/route.tsx"
click node_node_img_weather "https://github.com/gnehs/home-dashboard/blob/main/app/img/weather/route.tsx"
click node_node_error "https://github.com/gnehs/home-dashboard/blob/main/app/components/Error.tsx"
click node_node_img_response "https://github.com/gnehs/home-dashboard/blob/main/utils/ImageResponse.ts"
click node_node_font "https://github.com/gnehs/home-dashboard/blob/main/utils/font.ts"
click node_node_weather_api "https://github.com/gnehs/home-dashboard/blob/main/utils/met-weather.ts"
click node_node_crypto_api "https://github.com/gnehs/home-dashboard/blob/main/utils/cryptocompare.ts"
click node_node_taifex_api "https://github.com/gnehs/home-dashboard/blob/main/utils/taifex.ts"
click node_node_ha_api "https://github.com/gnehs/home-dashboard/blob/main/utils/homeAssistant.ts"
click node_node_stepstep_api "https://github.com/gnehs/home-dashboard/blob/main/utils/stepStep.ts"
click node_node_bank_api "https://github.com/gnehs/home-dashboard/blob/main/utils/bot-bank.ts"
click node_node_css "https://github.com/gnehs/home-dashboard/blob/main/app/globals.css"
click node_node_tailwind "https://github.com/gnehs/home-dashboard/blob/main/tailwind.config.ts"
click node_node_env "https://github.com/gnehs/home-dashboard/blob/main/.env.example"
click node_node_docker "https://github.com/gnehs/home-dashboard/tree/main/Dockerfile"
click node_node_github_actions "https://github.com/gnehs/home-dashboard/blob/main/.github/workflows/build.yaml"
click node_node_esphome "https://github.com/gnehs/home-dashboard/blob/main/esphome.lilyt5.example.yaml"

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_node_app_page,node_node_app_layout,node_node_img_board,node_node_img_currency,node_node_img_currency2,node_node_img_clock,node_node_img_weather,node_node_error,node_node_css,node_node_tailwind toneBlue
class node_node_img_response,node_node_font,node_node_weather_api,node_node_crypto_api,node_node_taifex_api,node_node_ha_api,node_node_stepstep_api,node_node_bank_api toneAmber
class node_node_env,node_node_docker,node_node_github_actions toneMint
class node_node_esphome toneRose
```

## Components

### Image service

Next.js app router surfaces that generate dashboard images.

- [Landing](https://github.com/gnehs/home-dashboard/blob/main/app/page.tsx): Next page · Top-level app entry and navigation surface. · `app/page.tsx`
- [Root shell](https://github.com/gnehs/home-dashboard/blob/main/app/layout.tsx): Next layout · App-wide HTML/layout wrapper and metadata boundary. · `app/layout.tsx`
- [Board image](https://github.com/gnehs/home-dashboard/blob/main/app/img/board-1/route.tsx): route handler · Integration-heavy dashboard image combining home and status data. · `app/img/board-1/route.tsx`
- [Currency image](https://github.com/gnehs/home-dashboard/blob/main/app/img/currency/route.tsx): route handler · Dashboard image focused on market and exchange-rate data. · `app/img/currency/route.tsx`
- [Currency alt](https://github.com/gnehs/home-dashboard/blob/main/app/img/currency-2/route.tsx): route handler · Second currency dashboard variant with a different composition. · `app/img/currency-2/route.tsx`
- [Day clock](https://github.com/gnehs/home-dashboard/blob/main/app/img/day-clock/route.tsx): route handler · Self-contained clock/date dashboard image. · `app/img/day-clock/route.tsx`
- [Weather image](https://github.com/gnehs/home-dashboard/blob/main/app/img/weather/route.tsx): route handler · Location-based weather dashboard image. · `app/img/weather/route.tsx`
- [Error card](https://github.com/gnehs/home-dashboard/blob/main/app/components/Error.tsx): shared component · Fallback failure state used when data sources or config are unavailable. · `app/components/Error.tsx`
- [Global styles](https://github.com/gnehs/home-dashboard/blob/main/app/globals.css): styling · Shared CSS foundation for rendered image compositions. · `app/globals.css`
- [Tailwind config](https://github.com/gnehs/home-dashboard/blob/main/tailwind.config.ts): styling config · Utility-first styling configuration used across the app. · `tailwind.config.ts`

### Rendering and data

Shared image rendering layer and external data adapters.

- [Image response](https://github.com/gnehs/home-dashboard/blob/main/utils/ImageResponse.ts): render helper · Shared wrapper around Next image generation response primitives. · `utils/ImageResponse.ts`
- [Font setup](https://github.com/gnehs/home-dashboard/blob/main/utils/font.ts): render helper · Shared font loading and typography configuration for image rendering. · `utils/font.ts`
- [Met weather](https://github.com/gnehs/home-dashboard/blob/main/utils/met-weather.ts): weather adapter · External weather data adapter used by weather-oriented routes. · `utils/met-weather.ts`
- [Crypto compare](https://github.com/gnehs/home-dashboard/blob/main/utils/cryptocompare.ts): market adapter · Crypto pricing adapter for currency dashboards. · `utils/cryptocompare.ts`
- [Taifex](https://github.com/gnehs/home-dashboard/blob/main/utils/taifex.ts): market adapter · Taiwan futures market data adapter. · `utils/taifex.ts`
- [Home Assistant](https://github.com/gnehs/home-dashboard/blob/main/utils/homeAssistant.ts): home automation adapter · Entity and state data adapter for smart-home dashboards. · `utils/homeAssistant.ts`
- [StepStep](https://github.com/gnehs/home-dashboard/blob/main/utils/stepStep.ts): service adapter · StepStep service data adapter used by the board dashboard. · `utils/stepStep.ts`
- [Bank data](https://github.com/gnehs/home-dashboard/blob/main/utils/bot-bank.ts): finance adapter · Bank or account-related data adapter used by the board dashboard. · `utils/bot-bank.ts`

### Delivery

Container and automation for building and running the service.

- [Env example](https://github.com/gnehs/home-dashboard/blob/main/.env.example): config · Documented runtime configuration for weather, home automation, and display settings. · `.env.example`
- [Dockerfile](https://github.com/gnehs/home-dashboard/tree/main/Dockerfile): container build · Container image definition for deployment. · `Dockerfile`
- [Build workflow](https://github.com/gnehs/home-dashboard/blob/main/.github/workflows/build.yaml): ci pipeline · GitHub Actions workflow that builds and publishes the container image. · `.github/workflows/build.yaml`

### Consumer

Downstream e-paper display integration.

- [ESPHome display](https://github.com/gnehs/home-dashboard/blob/main/esphome.lilyt5.example.yaml): hardware consumer · Example e-paper device configuration that fetches the generated images. · `esphome.lilyt5.example.yaml`

## Connections

- Landing → Board image: links to · Landing page points users toward the available image endpoints.
- Landing → Currency image: links to · Landing page points users toward the available image endpoints.
- Landing → Currency alt: links to · Landing page points users toward the available image endpoints.
- Landing → Day clock: links to · Landing page points users toward the available image endpoints.
- Landing → Weather image: links to · Landing page points users toward the available image endpoints.
- Board image → Image response: renders via · Board image is returned through the shared image response wrapper.
- Board image → Font setup: uses · Board image shares the common font setup.
- Board image → Home Assistant: reads · Board image pulls home automation state.
- Board image → StepStep: reads · Board image pulls StepStep service data.
- Board image → Bank data: reads · Board image pulls bank/account data.
- Board image → Error card: falls back to · Shared failure component for data or config issues.
- Currency image → Image response: renders via · Currency image is returned through the shared image response wrapper.
- Currency image → Font setup: uses · Currency image shares the common font setup.
- Currency image → Crypto compare: reads · Currency image pulls crypto pricing data.
- Currency image → Taifex: reads · Currency image pulls futures market data.
- Currency alt → Image response: renders via · Currency variant is returned through the shared image response wrapper.
- Currency alt → Font setup: uses · Currency variant shares the common font setup.
- Currency alt → Crypto compare: reads · Currency variant pulls crypto pricing data.
- Day clock → Image response: renders via · Clock image is returned through the shared image response wrapper.
- Day clock → Font setup: uses · Clock image shares the common font setup.
- Weather image → Image response: renders via · Weather image is returned through the shared image response wrapper.
- Weather image → Font setup: uses · Weather image shares the common font setup.
- Weather image → Met weather: reads · Weather image pulls forecast and location data.
- Root shell → Global styles: includes · Root layout applies the global stylesheet.
- Root shell → Tailwind config: styled by · Layout and routes rely on the Tailwind configuration.
- Env example → Met weather: configures · Weather latitude and longitude come from environment settings.
- Env example → Home Assistant: configures · Home Assistant host and token are environment-driven.
- Env example → StepStep: configures · StepStep host and token are environment-driven.
- Env example → Board image: configures · Dashboard behavior depends on runtime environment variables.
- Dockerfile → Build workflow: built by · The Docker image is assembled and published by CI.
- ESPHome display → Board image: fetches · ESPHome device consumes the board image endpoint.
- ESPHome display → Weather image: fetches · ESPHome device can consume weather image endpoints.
