CodeForPhilly / CodeForPhilly/codeforphilly-ng

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

Ouverte
#45 1 commentaire 0 réactions 0 personnes assignées Voir sur GitHub
Langage dominant
TypeScript
Étoiles
1
Forks
1
Merge moyen
5 j 3 h
PR mergées (30 j)
9

Description

[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.

Guide de contribution

Aucun guide de contribution indexé pour ce dépôt

Évaluation

Cette issue n'a pas encore été évaluée.

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.