# Guestbook — Implementation Notes ## Architecture summary The guestbook extends the Astro site with **hybrid SSR** mode using the `@astrojs/node` standalone adapter. - Existing content pages remain static. - Guestbook and admin pages are server-rendered (`export const prerender = false`). - API routes handle submissions, moderation, and token-based admin login. - SQLite (`better-sqlite3`) stores entries, sessions, rate-limit data, and audit logs. ## Relevant files ``` src/ lib/ db.ts — SQLite singleton + schema guestbook.ts — Entry CRUD, pagination, moderation reads auth.ts — Session management + cookie policy spam.ts — Validation + heuristic spam scoring pages/ guestbook.astro — Public guestbook page admin/ index.astro — Moderation portal (session-gated) login.astro — Token login form pages/api/ guestbook/submit.ts — POST: public guestbook submission admin/token-login.ts — POST: token authentication + session creation admin/moderate.ts — POST: approve / reject / spam admin/logout.ts — POST: end admin session layouts/ AdminLayout.astro — Minimal admin UI layout ``` ## Environment variables Copy `.env.example` to `.env` and set: | Variable | Required | Description | |---|---|---| | `SECRET_KEY` | **Yes** | Random secret for IP-hash salting and session-related values | | `ADMIN_SECRET_TOKEN` | **Yes** | Shared secret token for `/admin/login` | | `COOKIE_SECURE` | No | Force secure cookies (`true`/`false`). If unset, `NODE_ENV=production` => secure cookies | | `DB_PATH` | No | SQLite path (default: `./data/guestbook.db`) | | `PORT` | No | Server port (default: `3000`) | | `HOST` | No | Bind host (default: `0.0.0.0`) | Generate secrets: ```bash openssl rand -hex 32 # SECRET_KEY openssl rand -hex 32 # ADMIN_SECRET_TOKEN ``` ## Admin setup 1. Set `ADMIN_SECRET_TOKEN` in your environment. 2. Open `/admin/login`. 3. Enter token. 4. After success, you are redirected to `/admin`. If token is missing, `/admin/login` shows a configuration warning and login is disabled. ## Local development ```bash npm install cp .env.example .env # set at minimum: # SECRET_KEY=... # ADMIN_SECRET_TOKEN=... # DB_PATH=./data/guestbook.db # COOKIE_SECURE=false # for local http npm run dev # guestbook: http://localhost:4321/guestbook # admin: http://localhost:4321/admin/login ``` ## Docker deployment ```bash docker compose up -d --build docker compose logs -f cozy-den ``` The `guestbook_data` Docker volume persists the SQLite database. ## Moderation flow 1. Visitor submits message at `/guestbook`. 2. Entry is saved as `pending`. 3. Admin logs in at `/admin/login` with token. 4. Admin approves/rejects/marks spam in `/admin`. 5. Approved entries are shown publicly. ## Privacy decisions - IP addresses are never stored directly. - A truncated salted hash is stored only for rate limiting. - No tracking scripts or third-party analytics. - Admin session cookie is `httpOnly` and `SameSite=Strict`. - User content is stored as plain text (HTML stripped server-side). ## Database tables | Table | Purpose | |---|---| | `guestbook_entries` | Submissions + moderation status | | `admin_sessions` | Active admin sessions | | `rate_limit` | Submission throttling by IP hash | | `audit_log` | Moderation actions |