Commit a2ad1338 by PLN (Algolia)

docs: content model blog/pipeline + deploy is self-hosted now

parent b4267163
...@@ -28,12 +28,11 @@ yarn test:e2e # Playwright e2e (auto-starts dev server) ...@@ -28,12 +28,11 @@ yarn test:e2e # Playwright e2e (auto-starts dev server)
yarn test:e2e:ui # Playwright UI mode yarn test:e2e:ui # Playwright UI mode
``` ```
Deploy is Vercel, **preview-first** (after the hoist, Vercel "Root Directory" must be `.` / repo root — update in the Vercel UI): Deploy is **self-hosted since 2026-09-06** (Vercel exited): `yarn build` with `output: 'export'``rsync out/` to erable `/var/www/me.nech.pl/` → nginx serves flat files (`try_files $uri $uri.html $uri/`, certbot webroot TLS, HTTP 301). Canonical vhost + runbook: SRE repo `nechpl-www/me/` (vhost `deploy/nginx/me.nech.pl.conf`, `runbook-cutover.md`). The `yarn deploy:*` Vercel scripts are rollback-era residue — deprecated, keep only until the Vercel project is decommissioned:
```bash ```bash
yarn deploy:preview # vercel --yes (every branch/PR) yarn build # static export → out/ (the deploy artifact)
yarn deploy:prod # vercel --prod --yes (only from main, after review) # rsync out/ → erable:/var/www/me.nech.pl/ (see SRE runbook for the copy-paste steps)
yarn preview:env:pull # vercel env pull .env.local (first-time local setup)
``` ```
## Non-obvious conventions (enforced — see `.cursor/rules/`) ## Non-obvious conventions (enforced — see `.cursor/rules/`)
...@@ -47,17 +46,19 @@ yarn preview:env:pull # vercel env pull .env.local (first-time local ...@@ -47,17 +46,19 @@ yarn preview:env:pull # vercel env pull .env.local (first-time local
## Content model ## Content model
Markdown sections are loaded server-side at build via `gray-matter` (frontmatter) + `remark`/`remark-html` (body → HTML). The single loader is **`lib/content/index.ts`**, which holds two collection shapes on purpose (not one forced shape): Markdown sections are loaded server-side at build via `gray-matter` (frontmatter) + a unified remark→rehype chain (**`lib/markdown.ts`** — remark-parse, remark-gfm, remark-directive escape-hatch stub for future Hydra/Strudel islands, rehype-pretty-code/shiki build-time highlighting, custom rehype-figure for centered `<figure>`/`<figcaption>`). The single loader is **`lib/content/index.ts`**, which holds two collection shapes on purpose (not one forced shape):
*Flat Markdown collections* (posts, poems, talks, hydras — one `.md` per item under `content/SECTION/`): *Flat Markdown collections* (blog, poems, talks, hydras — one `.md` per item under `content/SECTION/`):
- `getAllContentData(section, sorted)` — list with frontmatter only (index/listing pages). - `getAllContentData(section, sorted)` — list with frontmatter only (index/listing pages). Carries `slug`, `draft`, `description`, `tags`. **`draft: true` posts are filtered out of production builds** (visible in dev via SHOW_DRAFTS).
- `getAllContentIds(section)` — plain `string[]`; dynamic pages map it to params via `.map((id) => ({ id }))`. - `getAllContentIds(section)` — plain `string[]`; dynamic pages map it to params via `.map((id) => ({ id }))`.
- `getContentData(section, id)` — single item with rendered `contentHtml`. - `getContentData(section, id)` — single item with rendered `contentHtml`.
Thin per-section wrappers (`lib/posts.js`, `lib/hydras.js`, `lib/poems.js`, `lib/talks.js`) just re-export from `@/lib/content`, binding a section name. Dynamic content pages (`app/post/[id]/page.js`, `app/poesie/[id]/page.js`, `app/hydra/[id]/page.js`) are async server components that pair `generateStaticParams()` + a `params`-driven fetch (`params` is a Promise — `await` it). Thin per-section wrappers (`lib/blog.js`, `lib/hydras.js`, `lib/poems.js`, `lib/talks.js`) just re-export from `@/lib/content`, binding a section name. Dynamic content pages (`app/blog/[slug]/page.js`, `app/poesie/[id]/page.js`, `app/hydra/[id]/page.js`) are async server components that pair `generateStaticParams()` + a `params`-driven fetch (`params` is a Promise — `await` it).
*ParVagues "lives"* — a richer collection in the SAME module: Markdown organized by year under `content/lives/YYYY/slug.md`, with optional `content/lives/YYYY/slug/tracks.json` and gig photos under `public/images/parvagues/lives/YYYY/slug/`. Frontmatter carries gig metadata (date, time, location, audio/video/instagram/archive links, tags). `getAllLives()` aggregates across all year folders, sorted newest-first; `getLiveData`/`getLiveTracks`/`getLivesImages` resolve a single gig. The ParVagues pages import these directly from `@/lib/content`. *ParVagues "lives"* — a richer collection in the SAME module: Markdown organized by year under `content/lives/YYYY/slug.md`, with optional `content/lives/YYYY/slug/tracks.json` and gig photos under `public/images/parvagues/lives/YYYY/slug/`. Frontmatter carries gig metadata (date, time, location, audio/video/instagram/archive links, tags). `getAllLives()` aggregates across all year folders, sorted newest-first; `getLiveData`/`getLiveTracks`/`getLivesImages` resolve a single gig. The ParVagues pages import these directly from `@/lib/content`.
*Editoring*: `yarn post <slug>` scaffolds `content/blog/YYYY-MM-DD-slug.md` (frontmatter stub, `draft: true`); `yarn post:image <slug> <file>` copies into `public/images/blog/<slug>/` and prints the markdown snippet. Blog prose is the owner's via git — content committed under `content/blog/` ships as committed (no prose generation).
**Presence seam:** `lib/content/parvagues-presence.ts` is the single place ParVagues platform links live. It's a thin typed stub (no schema, no invented links) so a future tooling-emitted `presence.json` can swap in without touching components — components are not yet wired to it. **Presence seam:** `lib/content/parvagues-presence.ts` is the single place ParVagues platform links live. It's a thin typed stub (no schema, no invented links) so a future tooling-emitted `presence.json` can swap in without touching components — components are not yet wired to it.
## Architecture notes ## Architecture notes
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment