# homepage Personal site built with [Astro 7](https://docs.astro.build). Currently a read-only showcase of the public images on a Harbor registry; built to grow into a blog/portfolio with more backends (e.g. Gitea). ## How it works - **Static where possible, live where it matters.** The home and 404 pages are prerendered. The registry pages (`/registry/…`) render on request through the Node adapter, reading Harbor via a [live content collection](https://docs.astro.build/en/guides/content-collections/#live-content-collections) (`src/live.config.ts`, loader in `src/loaders/harbor.ts`). No credentials or API calls reach the browser. - **Cached.** Rendered registry pages are kept in Astro's in-memory route cache for 60 s and served stale for up to 10 min while a fresh copy renders in the background (`REGISTRY_CACHE` in `src/consts.ts`). The listing also reuses a repository's artifacts for up to 5 min while its `update_time` is unchanged. - **No rebuilds for new images.** Pushing to Harbor shows up within about a minute. Rebuild only after code changes. - **Harbor unreachable?** The listing shows a notice and detail pages return `503`; neither is cached. - Repository descriptions are rendered as Markdown with raw HTML escaped and unsafe link schemes removed. ## Develop ```sh cp .env.example .env # set HARBOR_URL pnpm install pnpm dev # http://localhost:4321 pnpm check # type-check pnpm build # -> dist/ pnpm start # run the production server (reads .env) ``` Without `HARBOR_URL` the registry is simply empty. ## Deploy (Docker Compose) ```sh cp .env.example .env # set HARBOR_URL etc. docker compose up -d --build ``` Harbor settings are passed to the container at runtime, so changing them needs a restart (`docker compose up -d`), not a rebuild. Served on `${PORT:-8080}`. ## Container (plain Docker) ```sh docker build -t homepage --build-arg SITE_URL=https://example.com . docker run -p 8080:8080 \ -e HARBOR_URL=https://registry.example.com \ homepage # optional robot account for non-public projects: # -e HARBOR_USERNAME='robot$showcase' -e HARBOR_PASSWORD=... ``` A small Node server (`server.mjs`) runs Astro's standalone handler, adds security headers, and serves hashed `/_astro/` assets with long-lived caching. The server build is self-contained, so the image ships no `node_modules`.