Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
22
26
15 changes: 12 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
# AGENTS.md — WebDevBlogsite Living Hub

**Project:** WebDevBlogsite — `/home/hermes/Projects/WebDevBlogsite` · Next.js 16.3.3 · Bun 1.3.10 · Drizzle 0.45.2 · LibSQL/Turso · NextAuth 4.24.15
**Project:** WebDevBlogsite — `/home/hermes/Projects/WebDevBlogsite` · Next.js 16.3.4 · Bun 1.3.10 · Drizzle 0.45.2 · LibSQL 0.18.0/Turso · NextAuth 4.24.15 · Vitest 5.0.0
**Branch contract:** `main` is the modernized line (stale `feature/phase1-baseline`/`safety/phase1-baseline` deleted 2026-08-28, worktree `.worktrees/t_bf5e500e` removed). Work on new branches off `main`.
**Last verified:** 2026-08-28 20:35 UTC — `main@06350d5` all 4 CI jobs SUCCESS (`ci`/`sast`/`secrets-scan`/`dependency-scan`, run 33208912835) · gates `tsc 0` `eslint 0` `prettier pass` `vitest 89/89` `next build 23/23`.
**Last verified:** 2026-10-15 (docs audit) on branch `chore/deps-wave2-webdev` — gates `tsc 0` `eslint 0` `prettier pass` `vitest 89/89`. `next build` NOT run during this audit (out of scope); CI runs it on `bun run build`.

## Table of Contents (entry point — keep updated)

| Doc | Path | Purpose |
| ------------------ | ----------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| Handoff / scores | `/home/hermes/PROJECT_STATUS.md:1` (mirrors `/home/jevonx/PROJECT_STATUS.md:1`, `/tmp/PROJECT_STATUS.md:1`) | 12-repo snapshot, 0–100 scores, TDD gates, T1–T12, evidence |
| Modernization TODO | `./MODERNIZATION_TODO.md:1` | CSP, IP trust, RL store, query projection, serverActions — checklist |
| Plan (historical) | `./docs/PLAN.md:1` | Superseded 2026-08-25 plan (Cloudinary + publish API); read banner |
| Rate limit | `./docs/RATE_LIMIT.md:1` | In-memory Map vs Upstash, rightmost-XFF, cost |
| CI fix | `./docs/CI_FIX.md:1` | Zod dummy env + `trivy@v0.36.0` root cause |
| Vuln fix | `./docs/VULN_FIX.md:1` | `next`/`drizzle` 13 HIGH Honest fix (`06350d5`) |
Expand All @@ -25,6 +26,14 @@

- [2026-08-28T20:00:00Z] Always apply Dependabot fixes by adopting suggestions, then close the PR — never merge. (canonical in `./agents.md:1` + `~/.opencode/agents.md:1`; log `remember <rule>` here with timestamp)

## Gotchas (read before editing code or docs)

- **`src/proxy.ts` is correct — do NOT rename it to `middleware.ts`.** Next.js 16 deprecated the `middleware.ts` convention in favor of `proxy.ts` exporting `proxy()`. Docs written before 2026-08-25 (e.g. `docs/PLAN.md`, `docs/ASSESSMENT.md` item #1, `MODERNIZATION_TODO.md` QoL row) still describe the old name — those are historical.
- **Bun is canonical** (`packageManager: bun@1.3.10`, scripts like `bun run db:migrate`). `bun` is not installed on every host; `npx`/`./node_modules/.bin/*` equivalents work (`vitest run`, `tsc --noEmit`, `eslint .`, `prettier --check .`).
- **Env file is `.env`** (gitignored). `README.md` historically said `.env.local` — both are gitignored; either works, `.env.example` is the template.
- **`src/lib/env.ts` only falls back in `NODE_ENV=development|test`.** CI `next build` runs production mode and needs real/dummy env (see `docs/CI_FIX.md`).
- **`MODERNIZATION_TODO.md` and `docs/PLAN.md` are point-in-time snapshots** — several items are already resolved (prettier config added, `@auth/core` removed, XFF rightmost fix). Verify against source before acting on them.

## How to Work Here (TDD + Orchestrator — 5 steps)

1. **RED before GREEN:** Define acceptance criteria + failing check first — no code without pass criteria.
Expand All @@ -37,7 +46,7 @@

> Lean by design — details in `PROJECT_STATUS` + `docs/*`, not duplicated here.

- **Status:** `main` green and push-safe — see `/home/hermes/PROJECT_STATUS.md:1` §Current + `./docs/VULN_FIX.md:1` / `./docs/CI_FIX.md:1`.
- **Status:** gates green on the working branch (`tsc 0` `eslint 0` `prettier pass` `vitest 89/89`, verified 2026-10-15); `main` CI status last recorded in `PROJECT_STATUS` — see `/home/hermes/PROJECT_STATUS.md:1` §Current + `./docs/VULN_FIX.md:1` / `./docs/CI_FIX.md:1`. Note: `chore/deps-wave2-webdev` (vitest 5.0.0, Node 26) is the current working line.
- **Blockers:** P0 CSP hydration + P0 rate-limit deferred are in `./MODERNIZATION_TODO.md:1` → tracked as T1–T12 in `PROJECT_STATUS`.
- **Dependabot/other repos:** See `PROJECT_STATUS` evidence (2026-08-28 batch: 10 adopted, 2 reverted; 7 PRs pushed 19:46 UTC).

Expand Down
5 changes: 5 additions & 0 deletions MODERNIZATION_TODO.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# WebDevBlogsite — Modernization Todo List

> ⚠️ **HISTORICAL (audit date 2026-08-24) — PARTIALLY RESOLVED.** Changes verified against current source:
> `.prettierrc` + `format`/`format:check` scripts exist; `@auth/core` no longer in `package.json` (NextAuth v4 only);
> `getClientIp` now takes the **rightmost** `X-Forwarded-For` hop (`src/proxy.ts`); `@types/node@26` matches `engines.node 26.x`.
> Other items below were never resolved — verify each against current source before acting. See `AGENTS.md` §Gotchas.

**Project:** Next.js 16.1.6 App Router blog/portfolio · Bun 1.3.10 · Drizzle ORM · LibSQL/Turso · NextAuth v4
**Audit date:** 2026-08-24
**Re-audited (Phase 2):** `main` @ `fd0907235580255d68a564f3ec277a6c572f602b` — see `/tmp/second-audit-WebDev.md` and `/tmp/baseline-WebDev.md`.
Expand Down
111 changes: 65 additions & 46 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,20 @@ A production Next.js application combining a public portfolio with a database-ba
- GitHub OAuth — single-admin model via `ADMIN_GITHUB_ID`
- SEO: metadata, sitemap, robots.txt, and RSS feed
- Markdown rendering with Shiki syntax highlighting and table of contents
- Security: rate limiting, CSP headers, and input validation via middleware
- Security: rate limiting, CSP headers, and input validation via `src/proxy.ts`

## Tech stack

| Layer | Technology |
| ---------- | --------------------------------- |
| Framework | Next.js `16.3.3` (App Router) |
| Framework | Next.js `16.3.4` (App Router) |
| Language | TypeScript `5.9.3` |
| Styles | Tailwind CSS `4.2.1` |
| ORM | Drizzle ORM `0.45.1` |
| Database | LibSQL / Turso |
| Auth | NextAuth `4.24.13` + GitHub OAuth |
| Validation | Zod `4.3.6` |
| Styles | Tailwind CSS `4.3.3` |
| ORM | Drizzle ORM `0.45.2` |
| Database | LibSQL `0.18.0` / Turso |
| Auth | NextAuth `4.24.15` + GitHub OAuth |
| Validation | Zod `4.5.4` |
| Testing | Vitest `5.0.0` |
| Runtime | Bun `1.3.10` |
| Hosting | Vercel |

Expand All @@ -41,13 +42,11 @@ bun install
### 2. Create your local env file

```bash
# Mac/Linux
cp .env.example .env.local

# PowerShell
Copy-Item .env.example .env.local
cp .env.example .env
```

(Next.js loads `.env` automatically. `.env.local` is gitignored too if you prefer it.)

### 3. Fill in environment variables

```env
Expand Down Expand Up @@ -113,19 +112,22 @@ public/ # Static assets

### Key routes

| Route | Description |
| ------------------------- | --------------------------- |
| `/` | Homepage |
| `/blog` | Blog index |
| `/blog/[slug]` | Blog post |
| `/projects` | Projects index |
| `/projects/[slug]` | Project detail |
| `/about` | About page |
| `/admin` | Admin dashboard (protected) |
| `/admin/blog/new` | Create post (protected) |
| `/admin/blog/[slug]/edit` | Edit post (protected) |
| `/feed.xml` | RSS feed |
| `/sitemap.xml` | Sitemap |
| Route | Description |
| ------------------------- | ---------------------------------------------------- |
| `/` | Homepage |
| `/blog` | Blog index |
| `/blog/[slug]` | Blog post |
| `/projects` | Projects index |
| `/projects/[slug]` | Project detail |
| `/about` | About page |
| `/admin` | Admin dashboard (protected) |
| `/admin/blog/new` | Create post (protected) |
| `/admin/blog/[slug]/edit` | Edit post (protected) |
| `/feed.xml` | RSS feed |
| `/sitemap.xml` | Sitemap |
| `/api/publish` | Programmatic post creation (bearer token, protected) |

> **Note:** In Next.js 16 the `middleware.ts` file convention is deprecated in favor of `proxy.ts` exporting `proxy()`. This repo uses `src/proxy.ts` (rate limiting + CSP nonce). Do not rename it back — see `docs/RATE_LIMIT.md`.

## Authentication

Expand All @@ -149,20 +151,22 @@ Auth files:

Single `posts` table managed through Drizzle ORM and LibSQL.

| Field | Type |
| ------------ | -------------------- |
| `id` | integer, primary key |
| `title` | text |
| `slug` | text, unique |
| `content` | text (markdown) |
| `excerpt` | text |
| `category` | text |
| `coverImage` | text, nullable |
| `published` | boolean |
| `createdAt` | text (ISO 8601) |
| `updatedAt` | text (ISO 8601) |

Schema: `drizzle/schema.ts`
| Field | Type |
| ------------- | ----------------------------------------- |
| `id` | integer, primary key |
| `title` | text |
| `slug` | text, unique |
| `content` | text (markdown) |
| `excerpt` | text |
| `category` | text |
| `coverImage` | text, nullable |
| `published` | boolean |
| `toc` | json text (precomputed table of contents) |
| `readingTime` | integer (minutes) |
| `createdAt` | text (ISO 8601) |
| `updatedAt` | text (ISO 8601) |

Schema: `drizzle/schema.ts` (migrations `0000_initial`, `0001_post_query_indexes`, `0002_post_toc_reading_time` in `drizzle/migrations/`)

Migrations run automatically on `bun run dev` and `bun run build`. Applied migrations are tracked in `__migrations` so re-runs are safe.

Expand All @@ -183,12 +187,22 @@ Projects are statically defined in `content/projects.ts`. This is intentional

### Database

| Variable | Description |
| --------------------- | ------------------------------------------------------ |
| `DATABASE_URL` | SQLite file path or hosted LibSQL URL |
| `DATABASE_AUTH_TOKEN` | Required for hosted Turso with token auth |
| `TURSO_DATABASE_URL` | Vercel Turso integration variable (supported natively) |
| `TURSO_AUTH_TOKEN` | Vercel Turso integration token (supported natively) |
| Variable | Description |
| --------------------- | ------------------------------------------------------- |
| `DATABASE_URL` | SQLite file path or hosted LibSQL URL |
| `DATABASE_AUTH_TOKEN` | Required for hosted Turso with token auth |
| `TURSO_DATABASE_URL` | Vercel Turso integration variable (supported natively) |
| `TURSO_AUTH_TOKEN` | Vercel Turso integration token (supported natively) |
| `ALLOWED_IMAGE_HOSTS` | Comma-separated allowlist for `next/image` remote hosts |

### Media & API

| Variable | Description |
| ----------------------- | -------------------------------------------- |
| `CLOUDINARY_CLOUD_NAME` | Cloudinary cloud name (image CDN) |
| `CLOUDINARY_API_KEY` | Cloudinary API key |
| `CLOUDINARY_API_SECRET` | Cloudinary API secret |
| `PUBLISH_TOKEN` | Bearer token required by `POST /api/publish` |

### App

Expand Down Expand Up @@ -234,9 +248,10 @@ DATABASE_URL="libsql://your-db.turso.io" DATABASE_AUTH_TOKEN="your-token" bun ru
## Local development notes

- `local.db` is created automatically and is gitignored
- `.env.local` is gitignored — never commit real secrets
- `.env` / `.env.local` are gitignored — never commit real secrets
- Development mode provides fallback env values so the app starts without all variables set
- Production requires all variables to be present; missing values throw a validation error at startup
- Rate limiting + CSP nonce run from `src/proxy.ts` (Next.js 16 proxy convention)

## Git remotes

Expand All @@ -260,6 +275,10 @@ git log origin/main --oneline -1

## Extra docs

- [`docs/INDEX.md`](docs/INDEX.md) — full documentation index
- [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) — detailed codebase walkthrough
- [`docs/DEPLOYMENT.md`](docs/DEPLOYMENT.md) — full deployment and auth/database setup reference
- [`docs/ASSESSMENT.md`](docs/ASSESSMENT.md) — project assessment checklist with prioritized improvements
- [`docs/RATE_LIMIT.md`](docs/RATE_LIMIT.md) — rate limiting design and Upstash proposal
- [`docs/PLAN.md`](docs/PLAN.md) — historical implementation plan (superseded; see banner)
- [`MODERNIZATION_TODO.md`](MODERNIZATION_TODO.md) — point-in-time audit checklist (historical; see banner)
4 changes: 3 additions & 1 deletion agents.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# agents.md — WebDevBlogsite (local, per-repo)

**Mirror of AGENTS.md (uppercase) — this lowercase file is the canonical per instruction.**
**Last updated:** 2026-08-28 20:00 UTC
**Last updated:** 2026-10-15 (docs audit — see AGENTS.md §Gotchas for the `src/proxy.ts` note)

## Persistent Rules

Expand All @@ -11,6 +11,8 @@

- Canonical hub: ./AGENTS.md
- Project status: /home/hermes/PROJECT_STATUS.md
- Docs index: ./docs/INDEX.md
- Rate limit: ./docs/RATE_LIMIT.md
- CI fix: ./docs/CI_FIX.md
- Vuln fix: ./docs/VULN_FIX.md
- Plan (historical): ./docs/PLAN.md
Loading
Loading