# Architecture Research: SummerCMS

**Domain:** Scala/ZIO-based Content Management Framework (CMF)
**Researched:** 2026-02-04
**Overall Confidence:** MEDIUM-HIGH

This document defines the recommended architecture for SummerCMS, a Scala rewrite of WinterCMS using the ZIO ecosystem. The architecture leverages ZIO's effect system and layer-based dependency injection to create a modular, extensible CMF.

---

## High-Level Architecture

```
                                    +------------------+
                                    |   HTMX/Vue       |
                                    |   Frontend       |
                                    +--------+---------+
                                             |
                                             v
+-----------------------------------------------------------------------------------+
|                              HTTP LAYER (ZIO HTTP)                                 |
|  +-------------+  +-------------+  +-------------+  +------------------+          |
|  | Public      |  | Admin       |  | API         |  | Static Assets    |          |
|  | Routes      |  | Routes      |  | Routes      |  | Handler          |          |
|  +------+------+  +------+------+  +------+------+  +------------------+          |
|         |                |                |                                        |
|         +----------------+----------------+                                        |
|                          |                                                         |
|                          v                                                         |
|  +--------------------------------------------------------------------+           |
|  |                    MIDDLEWARE STACK                                 |           |
|  |  Auth | CORS | Logging | Metrics | Error | Rate Limit | Plugin     |           |
|  +--------------------------------------------------------------------+           |
+-----------------------------------------------------------------------------------+
                                             |
                                             v
+-----------------------------------------------------------------------------------+
|                           REQUEST PIPELINE                                         |
|  +-------------+  +-------------+  +-------------+  +------------------+          |
|  | Route       |  | Theme       |  | Component   |  | Response         |          |
|  | Resolver    |  | Resolver    |  | Resolver    |  | Builder          |          |
|  +------+------+  +------+------+  +------+------+  +------------------+          |
+-----------------------------------------------------------------------------------+
                                             |
                                             v
+-----------------------------------------------------------------------------------+
|                           CORE SERVICES LAYER                                      |
|  +-----------+  +-----------+  +-----------+  +-----------+  +-----------+        |
|  | Plugin    |  | Theme     |  | Config    |  | Event     |  | Cache     |        |
|  | Registry  |  | Engine    |  | Service   |  | Bus       |  | Service   |        |
|  +-----------+  +-----------+  +-----------+  +-----------+  +-----------+        |
|                                                                                    |
|  +-----------+  +-----------+  +-----------+  +-----------+  +-----------+        |
|  | Template  |  | Form      |  | Auth      |  | Media     |  | Queue     |        |
|  | Engine    |  | Builder   |  | Service   |  | Manager   |  | Service   |        |
|  +-----------+  +-----------+  +-----------+  +-----------+  +-----------+        |
+-----------------------------------------------------------------------------------+
                                             |
                                             v
+-----------------------------------------------------------------------------------+
|                           DOMAIN LAYER (Pure Business Logic)                       |
|  +-----------+  +-----------+  +-----------+  +-----------+  +-----------+        |
|  | Models    |  | Commands  |  | Queries   |  | Validators|  | Transforms|        |
|  +-----------+  +-----------+  +-----------+  +-----------+  +-----------+        |
+-----------------------------------------------------------------------------------+
                                             |
                                             v
+-----------------------------------------------------------------------------------+
|                           DATA ACCESS LAYER                                        |
|  +-----------+  +-----------+  +-----------+  +-----------+                       |
|  | Repository|  | Query     |  | Migration |  | Schema    |                       |
|  | Interfaces|  | Builder   |  | System    |  | Registry  |                       |
|  +-----------+  +-----------+  +-----------+  +-----------+                       |
|                          |                                                         |
|                          v                                                         |
|  +--------------------------------------------------------------------+           |
|  |                    ZIO Quill (PostgreSQL)                          |           |
|  +--------------------------------------------------------------------+           |
+-----------------------------------------------------------------------------------+
```

---

## Core Components

### 1. Request Pipeline

**Responsibility:** Routes incoming HTTP requests through theme/component resolution to response generation.

```scala
// Conceptual flow
Request
  -> RouteResolver      // Determines page/route from URL
  -> ThemeResolver      // Loads theme and layout
  -> ComponentResolver  // Instantiates page components
  -> PageRenderer       // Renders template with component data
  -> Response
```

**Key Types:**
```scala
trait RouteResolver {
  def resolve(path: Path, method: Method): ZIO[Any, RouteError, ResolvedRoute]
}

sealed trait ResolvedRoute
case class PageRoute(page: Page, params: Map[String, String]) extends ResolvedRoute
case class ApiRoute(handler: Handler, params: Map[String, String]) extends ResolvedRoute
case class StaticRoute(asset: Asset) extends ResolvedRoute
case class RedirectRoute(target: String, permanent: Boolean) extends ResolvedRoute
```

**Build Order:** 2nd (after Plugin System foundation)

---

### 2. Plugin System

**Responsibility:** Plugin discovery, lifecycle management, dependency resolution, and extension point registry.

This is the foundational component. Everything else builds on top of it.

```scala
// Plugin definition (similar to WinterCMS Plugin.php)
trait Plugin {
  def pluginDetails: PluginDetails
  def require: List[PluginId] = Nil  // Dependencies

  // Lifecycle hooks
  def register: ZIO[PluginEnvironment, Nothing, Unit]
  def boot: ZIO[PluginEnvironment, PluginError, Unit]

  // Registration methods
  def registerComponents: Map[String, ComponentFactory] = Map.empty
  def registerNavigation: List[NavigationItem] = List.empty
  def registerSettings: List[SettingsPage] = List.empty
  def registerPermissions: List[Permission] = List.empty
  def registerMailTemplates: List[MailTemplate] = List.empty
  def registerSchedule: List[ScheduledTask] = List.empty
}

// Plugin registry service
trait PluginRegistry {
  def discover: ZIO[Any, PluginError, List[PluginManifest]]
  def load(id: PluginId): ZIO[Any, PluginError, Plugin]
  def enable(id: PluginId): ZIO[Any, PluginError, Unit]
  def disable(id: PluginId): ZIO[Any, PluginError, Unit]
  def getEnabled: ZIO[Any, Nothing, List[Plugin]]
  def resolveDependencies(id: PluginId): ZIO[Any, PluginError, List[PluginId]]
}
```

**Plugin Extension Mechanism (replicating WinterCMS patterns):**

```scala
// 1. Event-based extension (primary mechanism)
trait EventBus {
  def emit[E](event: E): ZIO[Any, Nothing, Unit]
  def subscribe[E: Tag](handler: E => ZIO[Any, Nothing, Unit]): ZIO[Any, Nothing, Subscription]
}

// Events plugins can emit/subscribe to
case class ModelCreated[M](model: M)
case class ModelUpdated[M](model: M, changes: Map[String, Any])
case class FormExtending(formWidget: FormWidget, model: Any, context: String)
case class ListExtending(listWidget: ListWidget, model: Any)

// 2. Model extension via type classes
trait ModelExtensions[M] {
  def relations: Map[String, Relation[_, _]] = Map.empty
  def attributes: Map[String, Attribute[_]] = Map.empty
  def behaviors: List[Behavior[M]] = List.empty
}

// 3. Form field injection
trait FormFieldExtension {
  def extendFields(form: FormDefinition, model: Any, context: String): FormDefinition
}
```

**ZIO Layer Structure:**
```scala
val pluginRegistryLayer: ZLayer[Config & Database, PluginError, PluginRegistry] =
  ZLayer.fromFunction(PluginRegistryLive.apply _)

val eventBusLayer: ZLayer[Any, Nothing, EventBus] =
  ZLayer.succeed(EventBusLive())
```

**Build Order:** 1st (foundation for everything)

---

### 3. Theme Engine

**Responsibility:** Theme loading, template rendering, asset management, layout composition.

```scala
trait ThemeEngine {
  def getActive: ZIO[Any, ThemeError, Theme]
  def setActive(id: ThemeId): ZIO[Any, ThemeError, Unit]
  def render(page: Page, data: PageData): ZIO[Any, RenderError, Html]
  def renderPartial(name: String, data: Map[String, Any]): ZIO[Any, RenderError, Html]
}

trait Theme {
  def id: ThemeId
  def pages: ZIO[Any, ThemeError, List[PageDefinition]]
  def layouts: ZIO[Any, ThemeError, List[LayoutDefinition]]
  def partials: ZIO[Any, ThemeError, List[PartialDefinition]]
  def assets: AssetManager
}

// Template definition (parsed from .htm files with YAML frontmatter)
case class PageDefinition(
  url: String,
  layout: Option[String],
  title: Option[String],
  description: Option[String],
  components: Map[String, ComponentConfig], // Component alias -> config
  markup: String
)
```

**Template Rendering Options:**

| Option | Recommendation | Rationale |
|--------|---------------|-----------|
| ScalaTags | **Recommended** | Type-safe, fast (2x Twirl), Scala-native, HTMX-friendly |
| Twirl | Alternative | Play Framework standard, familiar syntax |
| Custom Parser | For WinterCMS .htm compat | Parse YAML frontmatter + Twig-like syntax |

For maximum WinterCMS compatibility, implement a custom template parser that:
1. Parses YAML frontmatter for page config
2. Translates Twig-like syntax to ScalaTags calls
3. Supports component embedding via `{% component 'alias' %}`

**Build Order:** 4th (needs Plugin System, Config, Components)

---

### 4. Component System

**Responsibility:** Reusable UI components with lifecycle, properties, and AJAX handlers.

```scala
// Component definition (mirrors WinterCMS components)
trait Component {
  def componentDetails: ComponentDetails
  def defineProperties: List[PropertyDefinition] = Nil

  // Lifecycle
  def init: ZIO[ComponentEnv, ComponentError, Unit] = ZIO.unit
  def onRun: ZIO[ComponentEnv, ComponentError, Unit] = ZIO.unit

  // Data for template
  def data: ZIO[ComponentEnv, ComponentError, Map[String, Any]]

  // AJAX/HTMX handlers (replaces WinterCMS onXxx methods)
  def handlers: Map[String, Handler] = Map.empty
}

// Handler for HTMX requests
type Handler = Request => ZIO[ComponentEnv, ComponentError, Response]

// Component factory for registration
trait ComponentFactory {
  def create(config: ComponentConfig): ZIO[Any, ComponentError, Component]
}

// Property definition (for admin UI)
case class PropertyDefinition(
  name: String,
  title: String,
  description: Option[String],
  `type`: PropertyType, // string, dropdown, checkbox, etc.
  default: Option[Any],
  options: Option[Map[String, String]], // For dropdowns
  required: Boolean = false,
  validation: List[Validator] = Nil
)
```

**HTMX Integration:**
```scala
// Component can define HTMX handlers
trait Component {
  // Traditional handler approach
  def onLoadMore(request: Request): ZIO[ComponentEnv, ComponentError, Response] = ???

  // These become routes: POST /component/{alias}/onLoadMore
  // HTMX attributes: hx-post="/component/posts/onLoadMore" hx-target="#posts-list"
}
```

**Build Order:** 3rd (needs Plugin System, Config)

---

### 5. Admin Backend

**Responsibility:** Backend administration interface with YAML-driven forms and lists.

```scala
// Backend controller (mirrors WinterCMS Backend\Classes\Controller)
trait BackendController {
  def actions: Map[String, Action] = Map.empty

  // Standard CRUD actions
  def index: Action = listAction
  def create: Action = formAction(FormMode.Create)
  def update(id: Id): Action = formAction(FormMode.Update, Some(id))
  def preview(id: Id): Action = formAction(FormMode.Preview, Some(id))
}

// Form configuration (parsed from fields.yaml)
case class FormConfig(
  fields: Map[String, FieldDefinition],
  tabs: Option[TabsConfig],
  secondaryTabs: Option[TabsConfig]
)

case class FieldDefinition(
  label: String,
  `type`: FieldType,          // text, textarea, dropdown, relation, etc.
  span: Span = Span.Auto,     // left, right, full, auto
  required: Boolean = false,
  placeholder: Option[String] = None,
  options: Option[FieldOptions] = None,
  dependsOn: List[String] = Nil,
  trigger: Option[TriggerConfig] = None
)

// List configuration (parsed from columns.yaml)
case class ListConfig(
  columns: Map[String, ColumnDefinition],
  recordUrl: Option[String],
  perPage: Int = 20,
  showCheckboxes: Boolean = true,
  toolbar: ToolbarConfig
)
```

**YAML Parsing:**
```scala
// Use zio-json-yaml or yaml4s for parsing
val formConfig: ZIO[Any, ParseError, FormConfig] =
  YamlParser.parse[FormConfig](yamlContent)
```

**Build Order:** 6th (needs most other components)

---

### 6. Database Layer

**Responsibility:** Type-safe database access, migrations, model definitions.

**Recommendation: ZIO Quill** because:
- Compile-time query generation (catches SQL errors at compile time)
- Native ZIO integration via `quill-jdbc-zio`
- Excellent PostgreSQL support
- Minimal runtime overhead

```scala
// Model definition (case class + schema)
case class Post(
  id: Long,
  title: String,
  slug: String,
  content: Option[String],
  publishedAt: Option[Instant],
  authorId: Long,
  createdAt: Instant,
  updatedAt: Instant
)

object Post {
  implicit val schema: Schema[Post] = DeriveSchema.gen[Post]

  // Quill query definitions
  inline def posts = quote { query[Post] }
  inline def bySlug(slug: String) = quote { posts.filter(_.slug == lift(slug)) }
  inline def published = quote { posts.filter(_.publishedAt.isDefined) }
}

// Repository pattern with ZIO
trait PostRepository {
  def findById(id: Long): ZIO[Any, RepositoryError, Option[Post]]
  def findBySlug(slug: String): ZIO[Any, RepositoryError, Option[Post]]
  def findPublished(page: Int, perPage: Int): ZIO[Any, RepositoryError, Page[Post]]
  def create(post: Post): ZIO[Any, RepositoryError, Post]
  def update(post: Post): ZIO[Any, RepositoryError, Post]
  def delete(id: Long): ZIO[Any, RepositoryError, Unit]
}

// Implementation using Quill
class PostRepositoryLive(quill: Quill.Postgres[SnakeCase]) extends PostRepository {
  import quill._

  def findById(id: Long): ZIO[Any, RepositoryError, Option[Post]] =
    run(quote { Post.posts.filter(_.id == lift(id)) })
      .map(_.headOption)
      .mapError(RepositoryError.fromThrowable)
}
```

**Migration System:**
```scala
// Migrations as versioned ZIO effects
trait Migration {
  def version: MigrationVersion
  def description: String
  def up: ZIO[Database, MigrationError, Unit]
  def down: ZIO[Database, MigrationError, Unit]
}

// Plugin migrations
trait Plugin {
  def migrations: List[Migration] = List.empty
}
```

**Build Order:** 1st-parallel (can be built alongside Plugin System foundation)

---

### 7. Authentication & Authorization

**Responsibility:** User authentication, JWT tokens, permissions, access control.

```scala
// Auth service
trait AuthService {
  def authenticate(credentials: Credentials): ZIO[Any, AuthError, User]
  def validateToken(token: JwtToken): ZIO[Any, AuthError, User]
  def generateToken(user: User): ZIO[Any, AuthError, JwtToken]
  def refreshToken(token: JwtToken): ZIO[Any, AuthError, JwtToken]
  def hasPermission(user: User, permission: Permission): ZIO[Any, Nothing, Boolean]
}

// Middleware for protected routes
val authMiddleware: Middleware[AuthService] =
  Middleware.interceptIncomingHandler { request =>
    for {
      token <- extractBearerToken(request)
      user  <- ZIO.serviceWithZIO[AuthService](_.validateToken(token))
    } yield (request, Context(user))
  }

// Permission-based access control
val requirePermission: Permission => Middleware[AuthService] = permission =>
  Middleware.interceptIncomingHandler { (request, ctx: Context) =>
    ZIO.serviceWithZIO[AuthService](_.hasPermission(ctx.user, permission))
      .filterOrFail(identity)(AuthError.Forbidden)
      .as((request, ctx))
  }
```

**Build Order:** 5th (needs Database, Plugin System, Config)

---

### 8. Configuration Service

**Responsibility:** Hierarchical configuration from files, database, environment.

```scala
trait ConfigService {
  def get[A: Schema](key: String): ZIO[Any, ConfigError, A]
  def getOpt[A: Schema](key: String): ZIO[Any, ConfigError, Option[A]]
  def set[A: Schema](key: String, value: A): ZIO[Any, ConfigError, Unit]
}

// Configuration sources (in priority order)
// 1. Environment variables
// 2. Database (system_settings table)
// 3. Plugin config files (config/*.yaml)
// 4. Theme config files
// 5. Defaults
```

**Build Order:** 1st-parallel (early foundation)

---

## Component Boundaries

| Component | Owns | Does NOT Own |
|-----------|------|--------------|
| **Plugin System** | Plugin lifecycle, dependencies, discovery, extension registry | Specific plugin logic |
| **Theme Engine** | Template loading, rendering, layouts, assets | Page data (components provide this) |
| **Component System** | Component lifecycle, properties, handlers | Database access (uses Repository) |
| **Admin Backend** | Form/list rendering, CRUD scaffolding | Business logic (delegates to services) |
| **Database Layer** | Connections, queries, migrations, schemas | Business rules (pure domain layer) |
| **Auth Service** | Authentication, tokens, permissions | User registration flows (User plugin) |
| **Config Service** | Config loading, caching, hierarchy | Config UI (Admin Backend) |
| **Event Bus** | Event dispatch, subscriptions | Event definitions (plugins define these) |

---

## Data Flow

### Frontend Page Request

```
1. Browser: GET /blog/my-post
   |
2. ZIO HTTP: Route matching
   |
3. RouteResolver: Lookup page by URL pattern
   |-- Database: pages table (or theme file scan)
   |-- Returns: PageDefinition { url: "/blog/:slug", components: ["blogPost"] }
   |
4. ThemeResolver: Load theme, layout, page template
   |-- Filesystem: themes/mytheme/pages/blog-post.htm
   |-- Returns: LayoutDefinition, PageTemplate
   |
5. ComponentResolver: Instantiate components
   |-- PluginRegistry: Get component factories
   |-- For each component in page:
   |   |-- Factory.create(config)
   |   |-- Component.init()
   |   |-- Component.onRun()
   |   |-- Component.data() -> Map[String, Any]
   |
6. PageRenderer: Render template with component data
   |-- Merge: layout + page + partial templates
   |-- Inject: component data into template scope
   |-- Execute: ScalaTags/template -> Html
   |
7. Response: HTML with HTMX attributes
```

### HTMX Handler Request

```
1. Browser: POST /component/blogPosts/onLoadMore (HTMX)
   |-- Headers: HX-Request: true, HX-Trigger: load-more-btn
   |
2. ZIO HTTP: Component handler route
   |
3. ComponentResolver:
   |-- Load component by alias from session/page context
   |-- Component.handlers("onLoadMore")
   |
4. Handler execution:
   |-- Handler(request) -> ZIO[ComponentEnv, Error, Response]
   |-- Returns: HTML fragment
   |
5. Response: HTML fragment
   |-- HTMX swaps into target element
```

### Admin Form Save

```
1. Admin: POST /backend/blog/posts/update/5
   |-- Body: form data (multipart or JSON)
   |
2. BackendController.update(5):
   |-- FormWidget.load(fields.yaml)
   |-- Validate input against field definitions
   |-- Event: FormSaving(widget, model, data)  // Plugins can modify
   |
3. Model save:
   |-- Repository.update(model)
   |-- Event: ModelUpdated(model, changes)  // Plugins react
   |
4. Response: Redirect to list or show success flash
```

---

## ZIO Patterns

### Layer Architecture

```scala
// Application layers (bottom-up)
val dataLayer: ZLayer[Any, Nothing, Database & Cache] =
  ZLayer.make[Database & Cache](
    PostgresDatabase.layer,
    RedisCache.layer
  )

val coreServicesLayer: ZLayer[Database & Cache, Nothing, Services] =
  ZLayer.make[Services](
    ConfigServiceLive.layer,
    EventBusLive.layer,
    AuthServiceLive.layer,
    PluginRegistryLive.layer
  )

val domainLayer: ZLayer[Services & Database, Nothing, Repositories] =
  ZLayer.make[Repositories](
    PostRepositoryLive.layer,
    UserRepositoryLive.layer,
    // ... more repositories
  )

val httpLayer: ZLayer[Services & Repositories, Nothing, HttpApp] =
  ZLayer.make[HttpApp](
    PublicRoutes.layer,
    AdminRoutes.layer,
    ApiRoutes.layer,
    MiddlewareStack.layer
  )

// Full application
val appLayer: ZLayer[Any, AppError, HttpApp] =
  dataLayer >>> coreServicesLayer >>> domainLayer >>> httpLayer
```

### Effect Organization

```scala
// Pure business logic (no effects)
object PostLogic {
  def generateSlug(title: String): String =
    title.toLowerCase.replaceAll("[^a-z0-9]+", "-")

  def validatePost(post: Post): Validated[ValidationError, Post] = ???
}

// Effectful operations wrapped in ZIO
trait PostService {
  def createPost(input: CreatePostInput): ZIO[Any, PostError, Post]
}

class PostServiceLive(
  repo: PostRepository,
  events: EventBus,
  auth: AuthService
) extends PostService {

  def createPost(input: CreatePostInput): ZIO[Any, PostError, Post] =
    for {
      _       <- auth.requirePermission(Permission.CreatePost)
      slug    <- ZIO.succeed(PostLogic.generateSlug(input.title))
      valid   <- ZIO.fromEither(PostLogic.validatePost(input.toPost(slug)))
      created <- repo.create(valid)
      _       <- events.emit(PostCreated(created))
    } yield created
}
```

### Resource Safety

```scala
// Database transactions
def withTransaction[R, E, A](zio: ZIO[R & Transaction, E, A]): ZIO[R & Database, E, A] =
  ZIO.scoped {
    for {
      tx     <- Database.beginTransaction
      result <- zio.provideSome[R](ZLayer.succeed(tx))
      _      <- tx.commit
    } yield result
  }

// Plugin lifecycle with proper cleanup
def loadPlugins: ZIO[Scope & PluginRegistry, PluginError, List[Plugin]] =
  for {
    registry <- ZIO.service[PluginRegistry]
    plugins  <- registry.discover
    sorted   <- registry.topologicalSort(plugins)  // Dependency order
    loaded   <- ZIO.foreach(sorted) { manifest =>
      ZIO.acquireRelease(
        registry.load(manifest.id).tap(_.boot)
      )(plugin => plugin.shutdown.ignore)
    }
  } yield loaded
```

### Error Handling

```scala
// Domain errors as sealed traits
sealed trait PostError
object PostError {
  case class NotFound(id: Long) extends PostError
  case class SlugTaken(slug: String) extends PostError
  case class ValidationFailed(errors: List[ValidationError]) extends PostError
  case class DatabaseError(cause: Throwable) extends PostError
}

// Error recovery and mapping
def findOrCreate(slug: String, default: => Post): ZIO[PostService, Nothing, Post] =
  ZIO.serviceWithZIO[PostService](_.findBySlug(slug))
    .catchSome { case PostError.NotFound(_) =>
      ZIO.serviceWithZIO[PostService](_.create(default))
    }
    .orDie  // Defect if still fails
```

---

## Build Order

Based on dependencies, build in this order:

### Phase 1: Foundation (Parallel)
| Component | Dependencies | Effort |
|-----------|--------------|--------|
| Database Layer | None | Medium |
| Config Service | None | Low |
| Event Bus | None | Low |

### Phase 2: Core Services
| Component | Dependencies | Effort |
|-----------|--------------|--------|
| Plugin System | Config, Event Bus, Database | High |

### Phase 3: Domain Components
| Component | Dependencies | Effort |
|-----------|--------------|--------|
| Component System | Plugin System, Config | Medium |
| Auth Service | Database, Config | Medium |

### Phase 4: Rendering
| Component | Dependencies | Effort |
|-----------|--------------|--------|
| Theme Engine | Plugin System, Component System, Config | High |
| Template Parser | Theme Engine | Medium |

### Phase 5: HTTP Layer
| Component | Dependencies | Effort |
|-----------|--------------|--------|
| Request Pipeline | All above | Medium |
| Public Routes | Request Pipeline | Low |
| API Routes | Request Pipeline, Auth | Low |

### Phase 6: Admin
| Component | Dependencies | Effort |
|-----------|--------------|--------|
| Admin Backend | All above | High |
| Form Widget System | Admin Backend | High |
| List Widget System | Admin Backend | Medium |

### Phase 7: Core Plugins
| Component | Dependencies | Effort |
|-----------|--------------|--------|
| User Plugin | All core | High |
| Blog Plugin | All core | Medium |
| Pages Plugin | All core | Medium |

---

## WinterCMS Architecture Comparison

| Aspect | WinterCMS | SummerCMS |
|--------|-----------|-----------|
| **Language** | PHP (Laravel) | Scala (ZIO) |
| **Effect System** | None (exceptions) | ZIO effects (typed errors) |
| **DI** | Laravel Container | ZIO Layers |
| **HTTP** | Laravel Router | ZIO HTTP |
| **Database** | Eloquent ORM | ZIO Quill (compile-time) |
| **Templates** | Twig | ScalaTags + custom parser |
| **Events** | Laravel Events | ZIO Event Bus |
| **Config** | PHP arrays/YAML | YAML + ZIO Config |
| **Plugin Discovery** | Filesystem scan | Filesystem + SPI |
| **Model Extension** | Dynamic `extend()` | Type classes + events |
| **Frontend** | AJAX (Snowboard) | HTMX + Vue optional |

### Key Architectural Differences

1. **Type Safety:** SummerCMS gains compile-time query validation (Quill) and typed errors (ZIO) that WinterCMS lacks.

2. **Concurrency:** ZIO fibers enable true async/concurrent plugin loading and request handling vs PHP's request-per-process model.

3. **Resource Safety:** ZIO's `Scope` ensures database connections, file handles, and plugin resources are properly released even on errors.

4. **Model Extension:** WinterCMS uses runtime `extend()` calls. SummerCMS uses compile-time type classes for static extensions, plus events for runtime extensions.

5. **Testing:** ZIO's layer system enables true dependency injection for testing. Mock any layer by providing a test implementation.

---

## Sources

- [ZIO Architectural Patterns](https://zio.dev/reference/architecture/architectural-patterns/)
- [ZIO Service Pattern](https://zio.dev/reference/service-pattern/)
- [ZIO Layers](https://zio.dev/reference/contextual/zlayer/)
- [Structuring ZIO 2 Applications](https://softwaremill.com/structuring-zio-2-applications/)
- [ZIO HTTP Introduction](https://zio.dev/zio-http/)
- [ZIO HTTP HTMX Integration](https://index.scala-lang.org/zio/zio-http/artifacts/zio-http-htmx/3.3.0)
- [ZIO Quill Getting Started](https://zio.dev/zio-quill/getting-started/)
- [ZIO Schema](https://zio.dev/zio-schema/)
- [ZIO JSON](https://zio.dev/zio-json/)
- [ScalaTags Documentation](https://com-lihaoyi.github.io/scalatags/)
- [WinterCMS Plugin Extension](https://wintercms.com/docs/v1.2/docs/plugin/extending)
- [WinterCMS Plugin Registration](https://wintercms.com/docs/v1.2/docs/plugin/registration)
- [Tapir ZIO HTTP4s Integration](https://tapir.softwaremill.com/en/latest/server/zio-http4s.html)
- [Plugin Architecture Patterns](https://www.dotcms.com/blog/plugin-achitecture)
