Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

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

Open
#45 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
35/100
Issue type
Feature
Clarity
Mostly clear
Activity status
Quiet
Tech stack
markdown, typescript
Domain
api, backend, data, frontend

Research direction

Start by reading issue #44 and the deferred decision in specs/deferred.md, then inspect the existing gitsheet patterns and apps/api/scripts/import-laddr.ts. Trace apps/api/scripts/import-laddr/translators.ts and the referenced BlogPost schema and routing requirements. Done means the content-typed blog-post sheet, API, SPA routes, importer revival, and listed spec updates are implemented without the excluded workflows.

Written by the indexing model from the issue text.

Description

specs/deferred.md currently says blog posts get replaced by "staff-authored markdown files in the code repo at apps/web/src/content/blog/<slug>.md, shipped via PR." That decision predates gitsheets v1.2'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

# .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:

  • Map BlogPost.Slugslug (slugify-with-dedupe if invalid)
  • Map BlogPost.Titletitle
  • Map BlogPost.Bodybody
  • 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 (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.

Dominant language
TypeScript
Stars
1
Forks
1
Avg merge
1d 20h
Merged PRs (30d)
25

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from CodeForPhilly/codeforphilly-ng

All issues in CodeForPhilly/codeforphilly-ng

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.