Skip to content

Recipe-Based Projects Guide

CMS Planner provides special support for recipe-based architectures, particularly Drupal recipes. This guide covers patterns, best practices, and examples for planning recipe-based projects.

What are Recipe-Based Projects?

Recipe-based architecture uses self-contained configuration packages (recipes) that can be combined to create feature-rich applications. Each recipe bundles all the configuration entities needed for a specific feature.

Common in:

  • Drupal CMS - Drupal recipes and site templates
  • Laravel - Package-based features
  • Rails - Engine-based modules
  • Other CMS platforms - Modular feature packages

Drupal Recipes

Drupal recipes are the primary use case for CMS Planner's recipe-based support.

Recipe Structure

A typical Drupal recipe includes:

recipe_name/
├── recipe.yml                    # Recipe metadata and dependencies
├── config/                       # Configuration entities
│   ├── node.type.example.yml    # Content type
│   ├── field.storage.node.field_example.yml  # Field storage
│   ├── field.field.node.example.field_example.yml  # Field instance
│   ├── taxonomy.vocabulary.example.yml  # Taxonomy
│   ├── views.view.example.yml   # View
│   ├── pathauto.pattern.example.yml  # URL pattern
│   ├── metatag.metatag_defaults.node__example.yml  # Meta tags
│   └── image.style.example.yml  # Image style
└── README.md                     # Documentation

What Goes in a Recipe

Include (Configuration Entities): - Content types (node.type.*.yml) - Field storage (field.storage.*.yml) - Field instances (field.field.*.yml) - Taxonomies (taxonomy.vocabulary.*.yml) - Views (views.view.*.yml) - Pathauto patterns (pathauto.pattern.*.yml) - Metatag defaults (metatag.metatag_defaults.*.yml) - Image styles (image.style.*.yml) - Block types, paragraph types, etc.

Do NOT Include (Simple Config): - Module enablement (core.extension.yml) - Site configuration (system.site.yml) - System settings

Recipe Naming Convention

Use flat naming with project prefix:

Good: - saplings_person - saplings_service - vital (site template) - myproject_blog

Bad: - saplings/person (nested path) - vital/site_template (nested path) - person (no prefix)

Shared Field Storage

A critical pattern in recipe-based projects is shared field storage, where one field definition is reused across multiple content types.

Why Shared Fields?

Benefits: - Data consistency across content types - Easier site-wide changes - Better entity references - Simplified Views and relationships

Example:

# Created by saplings_person recipe
field.storage.node.field_phone:
  type: telephone

# Used by:
- Person content type
- Location content type
- Department content type

Planning Shared Fields

When generating an FRD for a recipe-based project, CMS Planner documents:

  1. Which recipe creates the shared field
  2. Which content types use the field
  3. Installation order dependencies
  4. Field reuse diagram

Example FRD Section

## FR-001: saplings_person Recipe [MUST HAVE]

**Creates Shared Field Storage:**
- `field_phone` - Used by: Person, Location, Department
- `field_services` - Used by: Person, Location, Department, News
- `field_department` - Used by: Person, Service, Event, Internal Resource

**Installation Requirement:** Must be installed BEFORE recipes that use these shared fields.

**Recipe Structure:**
saplings_person/
├── recipe.yml
├── config/
│   ├── node.type.person.yml
│   ├── field.storage.node.field_phone.yml (SHARED)
│   ├── field.field.node.person.field_phone.yml
│   ├── field.storage.node.field_services.yml (SHARED)
│   ├── field.storage.node.field_department.yml (SHARED)
│   ├── taxonomy.vocabulary.specialties.yml
│   ├── views.view.provider_directory.yml
│   └── pathauto.pattern.person.yml
└── README.md

Installation Order Dependencies

Recipe installation order matters when recipes share field storage.

Dependency Chain Example

1. saplings_person
   ├─ Creates: field_phone, field_services, field_department

2. saplings_service
   ├─ Uses: field_department (from saplings_person)
   ├─ Creates: field_locations

3. saplings_location
   ├─ Uses: field_phone, field_services (from saplings_person)
   ├─ Uses: field_locations (from saplings_service)

4. saplings_department
   ├─ Uses: field_phone, field_services, field_locations
   ├─ (uses fields from multiple recipes)

5. vital (site template)
   ├─ Installs: all saplings recipes
   ├─ Adds: demo content

FRD Dependency Diagram

CMS Planner includes a dependency diagram in the FRD appendix:

Appendix A: Recipe Dependency Graph

saplings_person (foundation)
saplings_service
├─→ saplings_location
├─→ saplings_event
├─→ saplings_news
├─→ saplings_alert
├─→ saplings_department
└─→ saplings_internal_resource
vital (site template)

Site Template Recipe

The master site template recipe installs all dependencies and demo content.

Example: vital Recipe

# vital/recipe.yml
name: 'Vital Healthcare Site Template'
description: 'Complete healthcare site with provider directory, services, locations, etc.'
type: 'Site template'
recipes:
  # Base platform
  - drupal_cms/admin_ui
  - drupal_cms/authentication
  - drupal_cms/seo

  # Saplings recipes (in order!)
  - saplings_person
  - saplings_service
  - saplings_location
  - saplings_event
  - saplings_news
  - saplings_alert
  - saplings_department
  - saplings_internal_resource

# Demo content integrated
install:
  - default_content

Demo Content Integration

Demo content is NOT a separate recipe—it's integrated into the site template:

vital/
├── recipe.yml
├── config/
└── content/           # Default Content module format
    ├── node/
    │   ├── person-1.json
    │   ├── service-1.json
    │   └── location-1.json
    ├── taxonomy_term/
    └── file/

Themes vs Recipes

Important: Themes are NOT recipes.

Theme Structure

vital_theme/           # Drupal theme (NOT a recipe)
├── vital_theme.info.yml
├── vital_theme.theme
├── templates/
├── css/
└── js/

The theme is installed by the site template recipe but is not itself a recipe.

FRD Generation for Recipe Projects

When using /functional-requirements for a recipe-based project:

1. Provide Recipe Context

/functional-requirements

Building Drupal site template with recipe-based architecture:

**Base:** Byte site template (fork)
**Platform:** Drupal CMS 2.0+, Drupal Core 11.3+
**Recipes:** Saplings collection (8 recipes)
**Features:**
- Provider directory (saplings_person)
- Services catalog (saplings_service)
- Locations (saplings_location)
- Events calendar (saplings_event)
- News/blog (saplings_news)
- Alerts (saplings_alert)
- Departments (saplings_department)
- Internal resources (saplings_internal_resource)

**Theme:** vital_theme (subtheme of Mercury)
**Demo Content:** Integrated into vital recipe

2. Generated FRD Includes

  • One FR per recipe (FR-001 through FR-008)
  • Recipe structure examples with config entities
  • Shared field storage matrix in appendix
  • Dependency diagram showing installation order
  • Installation instructions with proper ordering
  • Demo content specifications
  • Theme requirements (separate from recipes)

3. Story Point Estimation

Each recipe gets estimated separately:

  • Recipe creation - Export config, organize, test
  • Field storage planning - Identify shared fields
  • Configuration entities - Content types, views, etc.
  • Testing - Clean installation, dependency testing
  • Documentation - README, examples
  • Demo content - Create sample data

4. CSV Backlog

Organized by recipe:

Tasklist,Task,Tags
"Phase 2: Core Recipes","[EPIC] saplings_person Recipe [34 points]","SP-34,Phase-2"
"Phase 2: Core Recipes","- [STORY] Person Content Type [13 points]","SP-13,Phase-2"
"Phase 2: Core Recipes","-- [TASK] Define fields [5 points]","SP-5,Phase-2"
"Phase 2: Core Recipes","-- [TASK] Create shared storage [3 points]","SP-3,Phase-2"

Example Projects

Healthcare Site (Vital)

Recipes: 8 Saplings recipes + vital site template Shared Fields: field_phone, field_services, field_department, field_locations Installation Order: Critical due to shared field dependencies Demo Content: Integrated into vital recipe Story Points: 720 total across 8 phases

University Site

Recipes: faculty, courses, programs, departments, events, news Shared Fields: field_department, field_faculty, field_term Installation Order: faculty → courses → programs Story Points: ~600 points

E-commerce Site

Recipes: products, categories, reviews, shipping, payments Shared Fields: field_category, field_price, field_availability Installation Order: categories → products → reviews Story Points: ~800 points

Best Practices

Planning

  1. Identify shared fields early - Plan which recipe creates each shared field
  2. Document dependencies - Clear installation order requirements
  3. Group related functionality - Each recipe should be cohesive
  4. Plan demo content - Representative samples for all features

Estimation

  1. Recipe creation - 8-13 points per recipe (config export + testing)
  2. Shared field storage - Add 3-5 points for planning and testing
  3. Dependencies - Add buffer for dependency testing
  4. Demo content - 5-8 points per recipe for quality samples

Testing

  1. Clean installation - Test each recipe in isolation
  2. Dependency order - Verify installation order works
  3. Shared fields - Confirm field reuse works correctly
  4. Demo content - Validate content imports properly

Documentation

  1. README per recipe - Installation, dependencies, features
  2. Shared field matrix - Document all field reuse
  3. Installation guide - Step-by-step with proper order
  4. Architecture diagram - Visual dependency graph

Common Pitfalls

❌ Wrong: Nested Recipe Paths

recipes/
├── vital/
│   ├── site_template/
│   └── theme/

✅ Right: Flat Recipe Names

recipes/
├── vital/
├── vital_theme/  (this is a theme, not recipe!)
├── saplings_person/
└── saplings_service/

❌ Wrong: Simple Config in Recipes

# DON'T include core.extension.yml
system.modules:
  views: 0
  pathauto: 0

✅ Right: Only Config Entities

# DO include views.view.*.yml
views.view.provider_directory:
  display:
    default: ...

❌ Wrong: Optional Demo Content Recipe

recipes/
├── vital/
└── vital_demo_content/  # Separate recipe

✅ Right: Integrated Demo Content

vital/
├── recipe.yml
└── content/  # Part of vital recipe

Getting Help


Next: Story Point Estimation | Teamwork Import