Modification à l'Exécution
Créez et modifiez les types de contenu sans changements de code ni reconstructions. Les non-développeurs peuvent concevoir leur modèle de contenu via l’interface d’administration.
EmDash utilise un modèle de contenu base de données d’abord où les définitions de schéma résident dans la base de données, et non dans le code. C’est un choix de conception fondamental qui permet la modification du schéma à l’exécution et une configuration accessible aux non-développeurs.
Les CMS traditionnels comme Strapi ou Keystatic vous obligent à définir le schéma dans le code :
// Traditional approach - schema in codeconst posts = collection({ fields: { title: text({ required: true }), content: richText(), },});EmDash stocke ces mêmes informations dans des tables de base de données :
-- _emdash_collections tableINSERT INTO _emdash_collections (slug, label)VALUES ('posts', 'Blog Posts');
-- Table _emdash_fieldsINSERT INTO _emdash_fields (collection_id, slug, type, required)VALUES ('coll_abc', 'title', 'string', true), ('coll_abc', 'content', 'portableText', false);Les deux approches définissent la même structure de contenu. La différence réside dans l’emplacement de cette structure et la façon dont elle peut être modifiée.
Modification à l'Exécution
Créez et modifiez les types de contenu sans changements de code ni reconstructions. Les non-développeurs peuvent concevoir leur modèle de contenu via l’interface d’administration.
Véritables Colonnes SQL
Contrairement au modèle EAV (Entité-Attribut-Valeur) de WordPress, chaque champ obtient une vraie colonne. Indexation appropriée, clés étrangères et optimisation des requêtes.
Auto-documenté
Les outils de base de données peuvent inspecter le schéma directement. Pas besoin d’analyser le code pour comprendre le modèle de contenu.
Chemin de Migration
Exportez le schéma en JSON pour le contrôle de version. Importez le schéma dans de nouveaux environnements.
Deux tables système définissent votre structure de contenu :
CREATE TABLE _emdash_collections ( id TEXT PRIMARY KEY, slug TEXT UNIQUE NOT NULL, -- "posts", "products" label TEXT NOT NULL, -- "Blog Posts" label_singular TEXT, -- "Post" description TEXT, icon TEXT, -- Lucide icon name supports JSON, -- ["drafts", "revisions", "preview"] source TEXT, -- How it was created created_at TEXT DEFAULT CURRENT_TIMESTAMP, updated_at TEXT);Le champ source indique comment la collection a été créée :
| Source | Description |
|---|---|
manual | Créée via l’interface d’administration |
template:blog | Créée par le fichier seed d’un modèle |
import:wordpress | Importée depuis WordPress |
discovered | Découverte automatiquement depuis des données existantes |
CREATE TABLE _emdash_fields ( id TEXT PRIMARY KEY, collection_id TEXT REFERENCES _emdash_collections(id), slug TEXT NOT NULL, -- Column name: "title", "price" label TEXT NOT NULL, -- Display label type TEXT NOT NULL, -- Field type column_type TEXT NOT NULL, -- SQLite type: TEXT, REAL, INTEGER, JSON required INTEGER DEFAULT 0, unique_field INTEGER DEFAULT 0, default_value TEXT, -- JSON-encoded default validation JSON, -- Validation rules widget TEXT, -- Custom widget identifier options JSON, -- Widget options sort_order INTEGER, created_at TEXT DEFAULT CURRENT_TIMESTAMP, UNIQUE(collection_id, slug));Chaque collection obtient sa propre table avec le préfixe ec_. Lorsque vous créez une collection “produits” avec des champs titre et prix :
CREATE TABLE ec_products ( -- System columns (always present) id TEXT PRIMARY KEY, slug TEXT UNIQUE, status TEXT DEFAULT 'draft', author_id TEXT, created_at TEXT DEFAULT (datetime('now')), updated_at TEXT DEFAULT (datetime('now')), published_at TEXT, deleted_at TEXT, -- Soft delete version INTEGER DEFAULT 1, -- Optimistic locking
-- Colonnes de contenu (définies par les champs) title TEXT NOT NULL, price REAL);Lorsque vous ajoutez un champ via l’interface d’administration, EmDash :
_emdash_fields 2. Exécute ALTER TABLE ec_collection ADD COLUMN nom_colonne TYPE 3. Régénère le schéma Zod pour la validationSQLite prend en charge ces opérations ALTER TABLE à l’exécution :
| Opération | Pris en charge |
|---|---|
| Ajouter une colonne | Oui |
| Renommer une colonne | Oui |
| Supprimer une colonne | Oui (SQLite 3.35+) |
| Changer le type de colonne | Non (nécessite une reconstruction de table) |
Pour les changements de type, EmDash gère la reconstruction de table de manière transparente : créer une nouvelle table → copier les données → supprimer l’ancienne table → renommer la nouvelle table.
EmDash maintient une séparation claire :
| Préoccupation | Emplacement | Tables |
|---|---|---|
| Schéma | Tables système | _emdash_collections, _emdash_fields |
| Contenu | Tables par collection | ec_posts, ec_products, etc. |
| Médias | Table séparée + stockage | Table media + R2/S3 |
| Paramètres | Table options | Table options avec préfixe site: |
Cette séparation signifie :
EmDash construit des schémas Zod à partir des définitions de champ de la base de données au démarrage :
// Simplified examplefunction buildSchema(fields: Field[]): ZodSchema { const shape: Record<string, ZodType> = {};
for (const field of fields) { let zodType = fieldTypeToZod(field.type);
if (field.required) { zodType = zodType.required(); }
if (field.validation?.min !== undefined) { zodType = zodType.min(field.validation.min); }
shape[field.slug] = zodType; }
return z.object(shape);}Le contenu est validé par rapport à ces schémas d’exécution lors de chaque opération de création et de mise à jour.
Générez des types TypeScript à partir du schéma de votre base de données :
# Fetch schema from database, generate typesnpx emdash typesCela génère .emdash/types.ts :
// .emdash/types.ts (generated)export interface Post { title: string; content: PortableTextBlock[]; excerpt?: string; featuredImage?: string;}
export interface Product { title: string; price: number; quantity: number;}
// Surcharges typées pour les fonctions de requêtedeclare module "emdash" { export function getEmDashCollection( type: "posts", ): Promise<{ entries: ContentEntry<Post>[]; error?: Error }>;
export function getEmDashEntry( type: "products", id: string, ): Promise<{ entry: ContentEntry<Product> | null; error?: Error; isPreview: boolean }>;}Les développeurs peuvent utiliser la CLI :
# Fetch schema, generate typesnpx emdash types
# Exporter le schéma en JSONnpx emdash export-seed > seed.jsonLes non-développeurs utilisent exclusivement l’interface d’administration :
Les deux approches modifient les mêmes tables de base de données sous-jacentes.
Les modèles et les exports utilisent des fichiers seed JSON pour des définitions de schéma portables :
{ "version": "1", "collections": [ { "slug": "posts", "label": "Articles de blog", "labelSingular": "Article", "supports": ["drafts", "revisions", "preview"], "fields": [ { "slug": "title", "type": "string", "required": true }, { "slug": "content", "type": "portableText" }, { "slug": "featuredImage", "type": "image" } ] } ], "taxonomies": [{ "name": "category", "label": "Catégories", "hierarchical": true }], "menus": [{ "name": "primary", "label": "Navigation principale" }]}Appliquez les fichiers seed de manière programmatique :
import { applySeed, validateSeed } from "emdash/seed";import seedData from "../../concepts/.emdash/seed.json";
// Validez d'abordconst { valid, errors } = validateSeed(seedData);
// Appliquez (idempotent - sûr à réexécuter)await applySeed(db, seedData, { includeContent: true, onConflict: "skip", // 'skip' | 'update' | 'error'});| Approche | Emplacement du Schéma | Modification à l’Exécution | Sécurité des Types |
|---|---|---|---|
| EmDash | Base de données | Oui (complète) | Générée depuis la BD |
| WordPress | Code PHP + EAV | Limitée (champs meta) | Aucune |
| Strapi | Fichiers code | Non (reconstruction requise) | Générée à la construction |
| Sanity | Fichiers code | Non (le schéma doit être déployé) | Intégrée |
| Directus | Base de données | Oui (complète) | Générée depuis la BD |
EmDash suit le modèle Directus : base de données d’abord avec génération de types optionnelle. Cela offre une flexibilité maximale tout en permettant un développement avec typage fort lorsque souhaité.
Collections
Découvrez les types de champs et la validation.
Panneau d'administration
Explorez l’architecture de l’admin.
Seeding
Configurez des sites avec des fichiers de seed.