--- type: database title: Blog Post Table description: blog_post table — draft/published Markdown posts surfaced on the public landing page. tags: [database, blog, markdown] timestamp: 2026-07-21T18:28:00Z --- # Schema | Column | Type | Description | |----------------|------------------|--------------------------------------------------------------| | `id` | TEXT PK | UUID v4 (set by the service, not auto-generated). | | `title` | TEXT | Post title. | | `body_md` | TEXT (default `''`) | Markdown body. | | `status` | TEXT (default `'draft'`) | One of `draft` or `published`. | | `created_at` | TEXT | ISO 8601 (TypeORM `@CreateDateColumn`). | | `updated_at` | TEXT | ISO 8601 (TypeORM `@UpdateDateColumn`). | | `published_at` | TEXT, nullable | ISO 8601 timestamp the post was published (set when status flips). | # Indexes | Index | Columns | Purpose | |------------------------------------|----------------------------------|------------------------------------------------------------| | `idx_blog_status_published` | `(status, published_at)` | Lets `GET /api/v1/blog/posts` filter to `status='published'` and order by `published_at DESC` cheaply. | # Behavior * Only rows with `status = 'published'` are exposed through the public endpoint `GET /api/v1/blog/posts` (see [REST API Overview](/api/rest-overview.md)). Drafts are hidden. * `BlogService.listPublished()` orders by `published_at DESC`, falling back to `created_at` when `published_at` is null. # See also - [Database Schema Overview](/database/schema.md) - [Landing Page Guide](/guides/landing-page.md)