- JavaScript 83.8%
- CSS 8.2%
- TypeScript 4.7%
- HTML 2.1%
- Dockerfile 1.2%
| api | ||
| data | ||
| scripts | ||
| src | ||
| .dockerignore | ||
| .gitignore | ||
| bun.lock | ||
| docker-compose.yml | ||
| Dockerfile | ||
| index.html | ||
| package.json | ||
| README.md | ||
| server.js | ||
| tsconfig.json | ||
| vite.config.ts | ||
Homebase
A friendly "Start Page" or "Homebase" for your family homelab built with Preact + Vite, served by a Bun backend.
Requirements
- Bun 1.3+
Install
bun install
Run
- Dev (Vite + API middleware on
http://localhost:4001)
bun run dev
- Production-style server (serves
dist/+ API onhttp://localhost:4000)
bun run build
bun run start
Environment
Create a .env file in the repo root:
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GOOGLE_REFRESH_TOKEN=
GOOGLE_CALENDAR_ID=
The calendar API returns [] when these variables are missing.
Google Calendar OAuth2 Setup
This project uses Google Calendar API with OAuth2 refresh tokens (no public iCal URL).
- Ensure your Google OAuth client allows redirect URI:
http://localhost:8085/callback
- Run the one-time auth helper:
bun scripts/google-auth.js
- Sign in and grant access.
- Copy the printed
GOOGLE_REFRESH_TOKENinto.env. - Set
GOOGLE_CALENDAR_IDto the target calendar ID.
Notes:
- The script requests
https://www.googleapis.com/auth/calendar.events.readonly. - It uses
access_type=offlineandprompt=consentso Google returns a refresh token.
API Endpoints
GET /api/servicesGET /api/statsGET /api/calendar
/api/calendar returns:
[
{
"id": "event-id",
"title": "Event name",
"time": "2:30 PM",
"date": "Wed, Mar 4",
"color": "#3B82F6",
"icon": "ri-calendar-event-line"
}
]
For all-day events, time is "All day".
Service Data (data/services.json)
The service cards are driven by data/services.json, which is served by GET /api/services and rendered by ServiceGrid + ServiceTile.
How it works:
ServiceGridgroups bycategory, sorts each group byorder, and renders one tile per item.ServiceTilerenders links for normal services and a non-link info card whentype: "info".- For
type: "info", the optionaldetailsobject is shown as extra rows (currently used for Minecraft host/ports).
Typical service item fields:
name(string): display name and React key.icon(string): Remix Icon class, e.g.ri-server-line.category(string): category bucket used byServiceGrid(must match a key inCATEGORY_THEMES).color(string): tile accent color (hex recommended).description(string): subtitle text.order(number): ascending sort order within category.url(string, optional): target URL; omitted for info-only cards.type(string, optional): use"info"for non-clickable informational tiles.details(object, optional): additional structured content for info tiles.
Example:
{
"name": "Proxmox",
"icon": "ri-server-line",
"url": "http://proxmox.home.local",
"category": "infrastructure",
"color": "#E97627",
"description": "Virtualization",
"order": 2
}
System Stats (systeminformation)
Server stats come from systeminformation in api/stats.js and are exposed via GET /api/stats.
Collected metrics:
- CPU current load (
si.currentLoad) ->cpu - Memory usage (
si.mem) ->ram.used,ram.total - Filesystem usage (
si.fsSize) ->disk.used,disk.total - CPU temperature (
si.cpuTemperature) ->temp - System uptime (
si.time) ->uptime
Dashboard behavior:
useStatspolls every 3 seconds and computescpuPercent,ramPercent, anddiskPercent.StatsPanelshows:- Uptime chip (
Xd Yh) - Service count chip (based on loaded services)
- CPU, RAM, Disk, and Temp bars/values
- Uptime chip (
- Disk source:
- If
HOST_FSis set (Docker uses/hostfs), the API uses that mount when available. - Otherwise it falls back to
/.
- If
Docker
docker-compose.yml passes the Google Calendar env vars into the container.
The app is exposed on http://localhost:5000.
docker compose up -d --build