CodeForPhilly / CodeForPhilly/codeforphilly-ng

Revive blog posts as a content-typed gitsheets sheet (revises the deferred decision)

Aperta
#45 1 commento 0 reazioni 0 assegnatari Vedi su GitHub
Lingua principale
TypeScript
Stelle
1
Fork
1
Merge medio
5g 3h
PR unite (30g)
9

Descrizione

[specs/deferred.md](https://github.com/CodeForPhilly/codeforphilly-ng/blob/main/specs/deferred.md) currently says blog posts get replaced by "staff-authored markdown files in the code repo at `apps/web/src/content/blog/.md`, shipped via PR." That decision predates [gitsheets v1.2](https://github.com/JarvusInnovations/gitsheets/releases/tag/v1.2.0)'s content-typed records.

With v1.2 we can give blog posts their own gitsheets sheet — markdown bodies + TOML frontmatter — and get a better outcome than files-in-code-repo:

## Why this beats the original deferral

| Concern | Files-in-code-repo | Content-typed sheet |
|---|---|---|
| PR-reviewable | ✅ | ✅ |
| Publish cadence | Tied to web deploys | Immediate on data-repo merge |
| Tags / cross-links | Ad-hoc frontmatter | Native `TagAssignment` |
| Author attribution | Hand-stamp in frontmatter | Native `Person` reference |
| Snapshot inclusion | Not in data snapshot | In the snapshot (pseudonymized) |
| API serving | Bespoke Vite handler | Existing read API pipeline |
| `/blog` index cost | Bundle every post into web build | `queryAll({ withBody: false })` |
| laddr-import revival | Out of scope | Resurrect `blog_posts` table on the existing one-shot import |

## Sheet shape

```toml
# .gitsheets/blog-posts.toml
[gitsheet]
root = 'blog-posts'
path = '${{ slug }}'

[gitsheet.format]
type = 'markdown'
body = 'body'

[gitsheet.schema]
$ref = './schemas/BlogPost.schema.json'
```

`BlogPost` entity (in `packages/shared/src/schemas/blog-post.ts`):
- `id` UUIDv7
- `legacyId` (laddr's `BlogPost.ID`, for the importer's idempotence)
- `slug` (kebab-case, slug-handle conventions)
- `title`
- `summary` (short markdown — stays in frontmatter)
- `authorId` → Person
- `postedAt` (iso8601)
- `editedAt` nullable
- `featuredImageKey` nullable (attachment via gitsheets)
- `deletedAt` nullable (soft-delete)
- `body` (the markdown body — the designated content field)
- standard `createdAt` / `updatedAt`

## Routing

Add to the SPA:
- `/blog` — index (paginated, optional tag filter)
- `/blog/:slug` — detail
- `/blog/tag/:namespace/:slug` — tag-filtered (reuse `TagsNamespace` pattern)

API:
- `GET /api/blog-posts` (list with facets, q, sort, page)
- `GET /api/blog-posts/:slug` (detail)
- `POST/PATCH/DELETE` — staff-only (per the original spec, blog wasn't a per-user-role CMS)

## laddr-import revival

The existing one-shot importer at `apps/api/scripts/import-laddr.ts` currently skips `blog_posts`. Re-add it as another translator in [`apps/api/scripts/import-laddr/translators.ts`](https://github.com/CodeForPhilly/codeforphilly-ng/blob/main/apps/api/scripts/import-laddr/translators.ts):

- Map `BlogPost.Slug` → `slug` (slugify-with-dedupe if invalid)
- Map `BlogPost.Title` → `title`
- Map `BlogPost.Body` → `body`
- Map `BlogPost.AuthorID` → resolve via the existing `idMaps.personByLegacy`
- Map `BlogPost.Published` (and similar) → `postedAt`
- Preserve `legacyId` so re-runs are idempotent

## Sequencing

- Depends on [#44](https://github.com/CodeForPhilly/codeforphilly-ng/issues/44) (content-typed gitsheets is the substrate) — or stand on its own as the first content-typed sheet in the project. Either order works since blog-posts is a brand-new sheet that doesn't conflict with the existing TOML-only ones.
- Sequenced after `cutover-prep` so existing migration paths stay valid through cutover.

## Spec updates needed

- `specs/deferred.md` — update the "Blog (`/blog`) as a user-facing CMS" entry from "files in code repo" to "content-typed sheet, see this issue."
- New spec files: `specs/api/blog.md`, `specs/screens/blog-index.md`, `specs/screens/blog-detail.md`.
- `specs/data-model.md` — add `BlogPost` entity.
- `specs/behaviors/legacy-id-mapping.md` — note the new `BlogPost.legacyId` axis.

Out of scope: comments, reactions, the multi-author "posts under a topic" workflow — keep it as simple as the original deferral imagined.

Guida per i contributori

Nessuna guida per i contributori indicizzata per questo repository

Valutazione

Questa issue non è ancora stata valutata.

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.