# Den

Private productivity app for the FearTheWild team — live at **https://den.fearthewild.com**.

Den combines a **daily dashboard** (tasks + recurring habits with streaks and reminders) with a **projects tracker** (status, scheduling, quotes, and multi-stream time-tracking / retainer invoicing). It has accounts with **admin approval**, **password reset**, **Google sign-in**, and **Free / Pro / Epic tiers**.

## Stack

| Layer | Tech |
|---|---|
| Frontend | Vue 3 + Vite + TypeScript (SPA in `web/`) |
| API | Node.js 22 + Fastify 5 (TypeScript, `api/`) |
| Database | SQLite via `better-sqlite3` (file-based, schema migrations on boot) |
| Auth | Session cookies (httpOnly, SameSite=Lax) + Argon2id hashing |
| Email | Resend (password reset + approval emails) |
| Hosting | Single DigitalOcean droplet — Apache reverse proxy + systemd + Let's Encrypt |

## Repo layout

```
api/                 # Fastify backend (TypeScript)
  src/               # server, db + migrations, auth, tiers, email, google, routes/
web/                 # Vue 3 + Vite frontend
  src/               # views/, components/, composables/, utils/, data/
scripts/deploy.sh    # production build + restart + health check
docs/                # design notes (e.g. boards-plan.md)
.github/workflows/   # deploy.yml — auto-deploy on push to main
```

## Local development

Requires **Node 22+**. Run the API and the frontend in two terminals.

```bash
# Terminal 1 — API (http://127.0.0.1:3000)
cd api
npm install
npm run dev          # tsx watch; auto-restarts on change

# Terminal 2 — frontend (http://localhost:5173)
cd web
npm install
npm run dev          # Vite; proxies /api → 127.0.0.1:3000
```

Then open **http://localhost:5173**.

- **Database:** dev uses a local `data/dev.db` (gitignored) — never touches production. On first boot, if no admin exists, one is seeded for `art@fearthewild.com` and the **one-time password is printed to the API terminal** (look for `SEEDED ADMIN`). Copy it to log in.
- **Optional env (local):** features degrade gracefully if unset — reset/approval emails just print the link to the API console instead of sending, and the "Continue with Google" button hides. To exercise them locally, set `RESEND_API_KEY`, and/or `GOOGLE_CLIENT_ID` + `GOOGLE_CLIENT_SECRET`, before `npm run dev`.

### Build / type-check

```bash
cd api && npm run build       # tsc
cd web && npm run build       # vue-tsc + vite
# type-check only:
cd api && npm run typecheck
cd web && npm run typecheck
```

## Deploy

**Push to `main` → it deploys automatically.** A GitHub Actions workflow SSHes into the droplet and runs `scripts/deploy.sh`, which:

1. `git reset --hard origin/main` (self-healing — wipes any drift on the droplet)
2. `npm ci && npm run build` for both `api/` and `web/`
3. `systemctl restart den-api`
4. health-checks `https://den.fearthewild.com/api/health`

Watch progress in the repo's **Actions** tab. Database migrations run automatically on API boot.

Manual deploy (e.g. if Actions is down), run on the droplet:

```bash
bash /var/www/den.fearthewild.com/scripts/deploy.sh
```

## Production environment

The droplet is already provisioned (Apache vhost proxying `/api/*` → `127.0.0.1:3000`, `den-api.service` systemd unit running as the `den` user, SQLite at `/var/lib/den/den.db`, TLS via Let's Encrypt).

**Service config** lives in systemd drop-ins at `/etc/systemd/system/den-api.service.d/` (so it survives deploys). These env vars enable the optional integrations:

| Var | Purpose |
|---|---|
| `RESEND_API_KEY`, `MAIL_FROM`, `APP_BASE_URL` | Transactional email (reset + approval); `APP_BASE_URL` builds the links |
| `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET` | Google OAuth sign-in |

After editing a drop-in: `sudo systemctl daemon-reload && sudo systemctl restart den-api`.

**Handy ops:**

```bash
journalctl -u den-api -f          # live API logs
systemctl restart den-api         # restart the API
curl -s https://den.fearthewild.com/api/health   # full-stack health check
```
