--- name: emdash-integration-guide description: Lessons learned when integrating EmDash CMS into an existing Astro static site — seed file pitfalls, template data access patterns, image/media handling fixes, and database reset procedures. Use when setting up EmDash CMS, debugging seed failures, or fixing 404 images. --- # EmDash CMS Integration Guide ## Overview This document summarizes the problems encountered and solutions when integrating EmDash CMS into an existing Astro static site, covering seed file setup, template design, and image/media handling. --- ## 1. Database & Seed File ### 1.1 Reserved Field Slugs **Problem**: Adding `slug` or `published_at` as collection fields in `seed.json` causes the seed to fail. The `ec_blog` table is created but custom fields (like `excerpt`, `body`, `featured_image`) never get their columns added, resulting in errors like: ``` SqliteError: table ec_blog has no column named excerpt ``` **Root Cause**: EmDash has a `RESERVED_FIELD_SLUGS` set in `node_modules/emdash/src/schema/types.ts` that includes: - `id`, `slug`, `status`, `author_id`, `primary_byline_id` - `created_at`, `updated_at`, `published_at`, `scheduled_at`, `deleted_at` - `version`, `live_revision_id`, `draft_revision_id`, `locale`, `translation_group` - Plus runtime-hydrated fields: `terms`, `bylines`, `byline` When `createField()` encounters a reserved slug, it **throws a SchemaError**, which stops the transaction and prevents all subsequent fields from being created. **Fix**: Do NOT include reserved slugs in the `fields` array of your collection definition. The system already creates these columns automatically in the content table (e.g., `ec_blog`). ```json // ❌ WRONG - slug and published_at are reserved "fields": [ { "slug": "title", "type": "string" }, { "slug": "slug", "type": "slug" }, { "slug": "excerpt", "type": "text" }, { "slug": "published_at", "type": "datetime" } ] // ✅ CORRECT - only define custom fields "fields": [ { "slug": "title", "type": "string" }, { "slug": "excerpt", "type": "text" }, { "slug": "body", "type": "portableText" }, { "slug": "featured_image", "type": "image" }, { "slug": "tags", "type": "string" } ] ``` ### 1.2 Database Reset **Problem**: The old database (`data.db`) caches schema and seed data. Changes to `seed.json` aren't reflected unless the database is fully deleted. **Fix**: Remove all database files before restarting: ```bash cd /path/to/project rm -f data.db data.db-shm data.db-wal npm run dev ``` The `npx emdash dev` command hardcodes port 4321 and ignores `astro.config.mjs`'s `server.port` setting. Always use `npm run dev` for daily development. ### 1.3 Seed Content Data Format **Problem**: Content entries in the seed file must only include non-system fields in `data`. System fields like `slug`, `status`, `published_at` are stored as direct columns on the `ec_*` table — they go at the same level as `data`, not inside it. ```json // ✅ CORRECT structure { "id": "my-post", "slug": "my-slug", "status": "published", "data": { "title": "My Title", "excerpt": "Description", "featured_image": { "src": "/images/photo.jpg", "alt": "Photo description" }, "body": [ { "_type": "block", "style": "normal", "children": [ { "_type": "span", "text": "Hello world" } ] } ], "tags": "news" } } ``` --- ## 2. Template Data Access ### 2.1 Date Field Name (published_at -> publishedAt) **Problem**: In templates, `article.data.published_at` returns `undefined`, showing "Invalid Date". **Root Cause**: EmDash's loader (`mapRowToData` in `node_modules/emdash/src/loader.ts`) maps system date columns to **camelCase** using an `INCLUDE_IN_DATA` map: ```js const INCLUDE_IN_DATA = { published_at: "publishedAt", created_at: "createdAt", updated_at: "updatedAt", scheduled_at: "scheduledAt", }; ``` **Fix**: Use camelCase property names in templates: ```astro {/* ❌ WRONG */}