# 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 |

