Initial research ahahahah
This commit is contained in:
794
.planning/research/ARCHITECTURE.md
Normal file
794
.planning/research/ARCHITECTURE.md
Normal file
@@ -0,0 +1,794 @@
|
||||
# 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)
|
||||
388
.planning/research/FEATURES.md
Normal file
388
.planning/research/FEATURES.md
Normal file
@@ -0,0 +1,388 @@
|
||||
# Features Research: SummerCMS
|
||||
|
||||
**Domain:** Content Management Framework (CMF) for web developers, agencies, and freelancers
|
||||
**Researched:** 2026-02-04
|
||||
**Reference:** WinterCMS/OctoberCMS rewrite in Scala
|
||||
**Confidence:** HIGH (multiple authoritative sources cross-referenced)
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Modern CMFs in 2025-2026 have converged on a set of table-stakes features while differentiating through API-first architecture, real-time collaboration, and AI-powered capabilities. SummerCMS must nail the fundamentals (plugin system, YAML-driven forms, component architecture) while leveraging Scala's strengths for performance and type safety.
|
||||
|
||||
The WinterCMS reference provides a proven plugin architecture with 19 Golem15 plugins demonstrating the feature surface area. Key differentiators for SummerCMS: superior performance, type-safe plugin APIs, and modern frontend integration (Vue + HTMX).
|
||||
|
||||
---
|
||||
|
||||
## Table Stakes (Must Have)
|
||||
|
||||
Features users expect. Missing = product feels incomplete or unusable.
|
||||
|
||||
### Content Management
|
||||
|
||||
| Feature | Why Expected | Complexity | Notes |
|
||||
|---------|--------------|------------|-------|
|
||||
| Page/Post CRUD | Core CMS functionality | Medium | Hierarchical pages, slugs, SEO fields |
|
||||
| Rich text editor | Content creation baseline | Medium | Recommend headless editor (TipTap/ProseMirror) |
|
||||
| Media library | Asset management expected | High | Upload, organize, transform images |
|
||||
| Content versioning | Revision history standard | Medium | Track changes, rollback capability |
|
||||
| Content scheduling | Publish at future date | Low | Schedule publish/unpublish |
|
||||
| Draft/Published states | Basic workflow | Low | Minimum viable workflow |
|
||||
|
||||
**WinterCMS Reference:** Blog plugin, Pages plugin (Winter.Pages) provide these patterns.
|
||||
|
||||
### User & Authentication
|
||||
|
||||
| Feature | Why Expected | Complexity | Notes |
|
||||
|---------|--------------|------------|-------|
|
||||
| User registration/login | Basic access control | Medium | Email verification, password reset |
|
||||
| Role-based access (RBAC) | Permission management | High | Roles, permissions, resource scoping |
|
||||
| Backend admin auth | Separate from frontend users | Medium | Admin accounts with elevated privileges |
|
||||
| Session management | Security baseline | Low | Secure sessions, logout |
|
||||
| Password policies | Security compliance | Low | Strength requirements, expiration |
|
||||
|
||||
**WinterCMS Reference:** Golem15.User plugin with JWT, GDPR compliance, OAuth integration.
|
||||
|
||||
### Admin Backend
|
||||
|
||||
| Feature | Why Expected | Complexity | Notes |
|
||||
|---------|--------------|------------|-------|
|
||||
| YAML/JSON-driven forms | Core WinterCMS pattern | High | `fields.yaml`, `columns.yaml` equivalent |
|
||||
| List/table views | Data management | Medium | Sortable, filterable, searchable |
|
||||
| Form widgets | Extensible inputs | High | Text, dropdown, relation, file, etc. |
|
||||
| Dashboard | Admin landing page | Low | Widgets, stats, quick actions |
|
||||
| Settings management | Global configuration | Medium | Type-safe settings with UI |
|
||||
|
||||
**WinterCMS Reference:** Backend module, `fields.yaml`/`columns.yaml` pattern, Apparatus form widgets.
|
||||
|
||||
### Plugin System
|
||||
|
||||
| Feature | Why Expected | Complexity | Notes |
|
||||
|---------|--------------|------------|-------|
|
||||
| Plugin installation/removal | Extensibility baseline | High | Package management, migrations |
|
||||
| Plugin dependencies | Inter-plugin references | Medium | `$require` equivalent |
|
||||
| Plugin lifecycle hooks | Initialization/boot | Medium | Register, boot, update hooks |
|
||||
| Database migrations | Schema management | Medium | Per-plugin migrations |
|
||||
| Asset registration | CSS/JS injection | Low | Backend and frontend asset loading |
|
||||
|
||||
**WinterCMS Reference:** Plugin.php with `$require`, `registerComponents()`, `registerSchedule()`.
|
||||
|
||||
### Theme System
|
||||
|
||||
| Feature | Why Expected | Complexity | Notes |
|
||||
|---------|--------------|------------|-------|
|
||||
| Theme installation | Design customization | Medium | Theme packages, activation |
|
||||
| Layouts/partials | Template composition | Medium | Layout inheritance, partial reuse |
|
||||
| Template engine | HTML generation | Medium | Twig, Thymeleaf, or Scala templates |
|
||||
| Asset compilation | Build pipeline | Medium | Vite/Tailwind integration |
|
||||
| Child themes | Theme extension | Low | Override parent theme files |
|
||||
|
||||
**WinterCMS Reference:** CMS module, theme.yaml, layout/page/partial structure.
|
||||
|
||||
### Frontend Components
|
||||
|
||||
| Feature | Why Expected | Complexity | Notes |
|
||||
|---------|--------------|------------|-------|
|
||||
| CMS components | Reusable page elements | High | Similar to WinterCMS components |
|
||||
| Component parameters | Configuration | Medium | Define via theme/code |
|
||||
| Partial injection | Dynamic content areas | Low | Placeholders for components |
|
||||
|
||||
**WinterCMS Reference:** Component classes with `defineProperties()`, `onRun()` methods.
|
||||
|
||||
### Database & ORM
|
||||
|
||||
| Feature | Why Expected | Complexity | Notes |
|
||||
|---------|--------------|------------|-------|
|
||||
| Model layer | Data abstraction | High | Active Record or Repository pattern |
|
||||
| Relations | Associations | High | hasMany, belongsTo, morphTo |
|
||||
| Model events | Lifecycle hooks | Medium | beforeSave, afterCreate, etc. |
|
||||
| Query builder | Flexible queries | Medium | Type-safe query construction |
|
||||
| Soft deletes | Recoverable data | Low | Trash/restore pattern |
|
||||
|
||||
**WinterCMS Reference:** Storm library, model traits (SoftDelete, Nullable, etc.).
|
||||
|
||||
### CLI Tools
|
||||
|
||||
| Feature | Why Expected | Complexity | Notes |
|
||||
|---------|--------------|------------|-------|
|
||||
| Project scaffolding | Quick start | Medium | `summer:up`, `summer:down` equivalent |
|
||||
| Plugin creation | Developer productivity | Medium | `create:plugin`, `create:model` |
|
||||
| Migration commands | Database management | Low | Run, rollback, status |
|
||||
| Cache commands | Maintenance | Low | Clear, warm caches |
|
||||
|
||||
**WinterCMS Reference:** Artisan commands via Laravel foundation.
|
||||
|
||||
---
|
||||
|
||||
## Differentiators (Competitive Advantage)
|
||||
|
||||
Features that set SummerCMS apart. Not expected, but highly valued.
|
||||
|
||||
### Performance & Scalability
|
||||
|
||||
| Feature | Value Proposition | Complexity | Notes |
|
||||
|---------|-------------------|------------|-------|
|
||||
| JVM performance | 10-100x faster than PHP | - | Inherent Scala advantage |
|
||||
| Compile-time safety | Fewer runtime errors | - | Type system catches bugs |
|
||||
| Native async | Non-blocking I/O | Medium | Scala Futures, ZIO, Cats Effect |
|
||||
| Efficient caching | Sub-millisecond responses | High | Edge caching, smart invalidation |
|
||||
|
||||
**Rationale:** PHP CMSs (WinterCMS, WordPress) are slow. Scala on JVM with proper architecture delivers enterprise-grade performance.
|
||||
|
||||
### Modern Frontend Integration
|
||||
|
||||
| Feature | Value Proposition | Complexity | Notes |
|
||||
|---------|-------------------|------------|-------|
|
||||
| HTMX native support | No-JS interactivity | Medium | Server-driven UI updates |
|
||||
| Vue.js integration | Rich client components | Medium | When HTMX isn't enough |
|
||||
| SSR + hydration | Best of both worlds | High | Server render + client enhance |
|
||||
| Live Preview | Real-time editing preview | High | See changes before publish |
|
||||
|
||||
**Rationale:** HTMX + Vue provides flexibility without JavaScript fatigue. Most interactions via HTMX (fast, simple), Vue for complex widgets.
|
||||
|
||||
### API-First Architecture
|
||||
|
||||
| Feature | Value Proposition | Complexity | Notes |
|
||||
|---------|-------------------|------------|-------|
|
||||
| REST API built-in | Headless capability | Medium | First-class API alongside traditional |
|
||||
| GraphQL option | Flexible queries | High | Optional, for complex clients |
|
||||
| API documentation | Developer experience | Low | Auto-generated OpenAPI |
|
||||
| Versioned APIs | Stability | Medium | v1, v2 without breaking clients |
|
||||
|
||||
**Rationale:** Headless is the 2025 trend. SummerCMS should work as traditional CMS AND headless backend.
|
||||
|
||||
### Type-Safe Plugin Development
|
||||
|
||||
| Feature | Value Proposition | Complexity | Notes |
|
||||
|---------|-------------------|------------|-------|
|
||||
| Scala plugin API | Compile-time checks | High | Plugin interfaces with types |
|
||||
| IDE autocomplete | Developer productivity | - | Free with typed API |
|
||||
| Plugin testing framework | Quality assurance | Medium | Built-in test utilities |
|
||||
| Hot reload | Development speed | High | Detect plugin changes |
|
||||
|
||||
**Rationale:** PHP plugins fail at runtime with cryptic errors. Scala catches issues at compile time.
|
||||
|
||||
### Advanced Workflow
|
||||
|
||||
| Feature | Value Proposition | Complexity | Notes |
|
||||
|---------|-------------------|------------|-------|
|
||||
| Multi-stage approval | Enterprise workflows | High | Draft -> Review -> Approve -> Publish |
|
||||
| Content scheduling | Marketing campaigns | Medium | Time-based publish/unpublish |
|
||||
| Audit logging | Compliance | Medium | Who changed what, when |
|
||||
| Role-based workflows | Flexible processes | High | Different flows per content type |
|
||||
|
||||
**WinterCMS Reference:** Apparatus scenario system provides workflow patterns.
|
||||
|
||||
### Multisite & Multi-tenant
|
||||
|
||||
| Feature | Value Proposition | Complexity | Notes |
|
||||
|---------|-------------------|------------|-------|
|
||||
| Multiple sites | One install, many sites | High | Shared core, separate content |
|
||||
| Site cloning | Rapid deployment | Medium | Copy site structure |
|
||||
| Per-site themes | Design flexibility | Medium | Different look per site |
|
||||
| Shared content | Reuse across sites | High | Global assets/content |
|
||||
|
||||
**WinterCMS Reference:** Golem15.SiteManager plugin.
|
||||
|
||||
### AI Integration (2025+ trend)
|
||||
|
||||
| Feature | Value Proposition | Complexity | Notes |
|
||||
|---------|-------------------|------------|-------|
|
||||
| AI content assist | Writing help | Medium | Integration points for LLMs |
|
||||
| Auto-translation | Multilingual content | Medium | AI-powered i18n |
|
||||
| Smart tagging | Auto-categorization | Medium | AI metadata generation |
|
||||
| Content recommendations | Engagement | High | Related content suggestions |
|
||||
|
||||
**WinterCMS Reference:** Golem15.AI plugin with OpenAI/Perplexity integration.
|
||||
|
||||
---
|
||||
|
||||
## Anti-Features (Do NOT Build)
|
||||
|
||||
Features other CMFs do that are problematic. Deliberately avoid.
|
||||
|
||||
| Anti-Feature | Why Avoid | What to Do Instead |
|
||||
|--------------|-----------|-------------------|
|
||||
| Kitchen-sink core | Bloated, slow, hard to maintain | Minimal core + plugin ecosystem |
|
||||
| Visual page builders | Complex, fragile, poor performance | Component-based with good defaults |
|
||||
| Magic string configurations | Runtime errors, no IDE support | Typed configuration with validation |
|
||||
| Closed marketplace | Vendor lock-in | Open plugin format, community repos |
|
||||
| WordPress-style "hooks everywhere" | Spaghetti code, unpredictable | Explicit extension points, typed APIs |
|
||||
| Database-stored code | Security risk, hard to version | Code in filesystem, config in DB |
|
||||
| Monolithic frontend | Tightly coupled, hard to customize | Decoupled frontend, HTMX by default |
|
||||
| Real-time collaboration (Phase 1) | Complex, requires WebSocket infra | Defer to Phase 3+, use optimistic locking |
|
||||
| GraphQL by default | Over-engineering for most sites | REST default, GraphQL as optional plugin |
|
||||
|
||||
### Specific Patterns to Avoid
|
||||
|
||||
**God Object Plugin Architecture:**
|
||||
Don't create a single "Plugin" class that handles registration, boot, routing, events, and everything else. Instead, use composition with specific handlers.
|
||||
|
||||
**Inner Platform Effect:**
|
||||
Don't make the YAML configuration so flexible it becomes a programming language. Define clear boundaries for what's configurable vs. what requires code.
|
||||
|
||||
**Dead Code Accumulation:**
|
||||
Establish deprecation policies early. Don't ship deprecated features that linger forever.
|
||||
|
||||
---
|
||||
|
||||
## Feature Dependencies
|
||||
|
||||
Features must be built in order based on dependencies.
|
||||
|
||||
```
|
||||
[Foundation Layer]
|
||||
Database/ORM ──────────┐
|
||||
├──► Plugin System ──► Everything Else
|
||||
User/Auth ────────────┘
|
||||
|
||||
[Core CMS Layer]
|
||||
Plugin System ──► Theme System ──► Frontend Components
|
||||
│
|
||||
└──► Backend Admin ──► YAML Forms ──► Content Management
|
||||
|
||||
[Advanced Layer]
|
||||
Content Management ──► Versioning ──► Workflow ──► Scheduling
|
||||
│
|
||||
└──► API Layer ──► Headless Mode
|
||||
|
||||
[Extension Layer]
|
||||
All Core ──► Multisite
|
||||
│
|
||||
├──► AI Integration
|
||||
│
|
||||
└──► Real-time Collaboration
|
||||
```
|
||||
|
||||
### Critical Path for MVP
|
||||
|
||||
1. **Database/ORM** - Everything depends on data persistence
|
||||
2. **User/Auth** - Backend requires authentication
|
||||
3. **Plugin System** - All features are plugins
|
||||
4. **Backend Admin** - Content management UI
|
||||
5. **YAML Forms** - Backend forms for content
|
||||
6. **Theme System** - Frontend rendering
|
||||
7. **Content Management** - Pages, posts, media
|
||||
|
||||
---
|
||||
|
||||
## Complexity Assessment
|
||||
|
||||
Rough complexity for major features (effort in developer-weeks, assuming senior developer).
|
||||
|
||||
| Feature Category | Complexity | Estimated Effort | Risk |
|
||||
|------------------|------------|------------------|------|
|
||||
| Database/ORM Layer | High | 8-12 weeks | Medium (Scala ecosystem mature) |
|
||||
| Plugin System | Very High | 12-16 weeks | High (architectural decisions) |
|
||||
| Backend Admin UI | High | 10-14 weeks | Medium (Vue.js, established patterns) |
|
||||
| YAML Form Engine | High | 8-12 weeks | Medium (complex parsing + rendering) |
|
||||
| Theme/Template System | Medium | 6-8 weeks | Low (Scala templates exist) |
|
||||
| User/Auth System | Medium | 4-6 weeks | Low (standard patterns) |
|
||||
| Content Management | Medium | 6-8 weeks | Low (straightforward CRUD) |
|
||||
| Media Library | High | 8-10 weeks | Medium (file handling, transforms) |
|
||||
| CLI Tools | Low | 2-4 weeks | Low (standard tooling) |
|
||||
| API Layer (REST) | Medium | 4-6 weeks | Low (well-understood) |
|
||||
| Multisite | Very High | 12-16 weeks | High (data isolation complex) |
|
||||
| Workflow Engine | High | 8-12 weeks | Medium (state machines) |
|
||||
|
||||
### Total MVP Estimate
|
||||
|
||||
Core MVP (Plugin + Admin + Theme + Content): **40-60 weeks** of development effort.
|
||||
|
||||
---
|
||||
|
||||
## WinterCMS Feature Mapping
|
||||
|
||||
Key WinterCMS features and their SummerCMS equivalents.
|
||||
|
||||
### Core Modules
|
||||
|
||||
| WinterCMS | SummerCMS Equivalent | Notes |
|
||||
|-----------|----------------------|-------|
|
||||
| System module | `summer-core` | Plugin management, updates, settings |
|
||||
| Backend module | `summer-admin` | Admin panel, controllers, forms |
|
||||
| CMS module | `summer-cms` | Themes, pages, components |
|
||||
| Storm library | `summer-orm` | Database abstraction layer |
|
||||
|
||||
### Golem15 Plugins to Replicate
|
||||
|
||||
| Plugin | Priority | Complexity | Notes |
|
||||
|--------|----------|------------|-------|
|
||||
| **Apparatus** | P0 - Critical | Very High | Core DI, scenarios, backend utilities |
|
||||
| **User** | P0 - Critical | Medium | Auth, JWT, GDPR |
|
||||
| **Blog** | P1 - High | Medium | Content example, commonly needed |
|
||||
| **PaymentGateway** | P2 - Medium | Very High | Complex FSM, financial logic |
|
||||
| **Translate** | P1 - High | High | i18n infrastructure |
|
||||
| **Menu** | P1 - High | Low | Navigation builder |
|
||||
| **SEO** | P1 - High | Medium | Meta tags, sitemap |
|
||||
| **Sitemap** | P1 - High | Low | XML sitemap generation |
|
||||
| **SiteManager** | P2 - Medium | High | Multisite functionality |
|
||||
| **AI** | P3 - Low | Medium | AI integration patterns |
|
||||
| **WebSockets** | P3 - Low | High | Real-time features |
|
||||
| **Chat** | P3 - Low | High | Real-time messaging |
|
||||
| **FAQ** | P2 - Medium | Low | Simple content type |
|
||||
| **Quote** | P2 - Medium | Medium | Business logic example |
|
||||
|
||||
### Architectural Patterns to Preserve
|
||||
|
||||
| WinterCMS Pattern | SummerCMS Approach |
|
||||
|-------------------|-------------------|
|
||||
| `$require` plugin dependencies | Manifest-declared dependencies |
|
||||
| `fields.yaml` / `columns.yaml` | YAML/HOCON config files |
|
||||
| Component `defineProperties()` | Typed property definitions |
|
||||
| Model `$rules`, `$belongsTo`, etc. | Case class with validation, relations |
|
||||
| Event system (`Event::fire()`) | Typed event bus, pub/sub |
|
||||
| Backend behaviors (FormController, ListController) | Traits/mixins for controllers |
|
||||
| Twig templating | Scala templates or Thymeleaf |
|
||||
| AJAX Framework (Snowboard) | HTMX native, Vue for complex UI |
|
||||
|
||||
### Key Apparatus Framework Concepts
|
||||
|
||||
| Concept | Description | SummerCMS Equivalent |
|
||||
|---------|-------------|----------------------|
|
||||
| Scenario System | Event-driven workflow engine | Typed FSM with Akka or ZIO |
|
||||
| Dependency Injection | Auto-wiring components | Scala DI (MacWire, ZIO) |
|
||||
| Route Resolver | Custom route handling | Type-safe routing (http4s, Play) |
|
||||
| Backend Injector | CSS/JS injection | Asset pipeline with manifests |
|
||||
| Form Widgets | Custom form inputs | Widget component system |
|
||||
|
||||
---
|
||||
|
||||
## Sources
|
||||
|
||||
### Primary (HIGH confidence)
|
||||
- WinterCMS Official Documentation: https://wintercms.com/docs
|
||||
- WinterCMS Features: https://wintercms.com/features
|
||||
- October CMS Forms Documentation: https://docs.octobercms.com/3.x/backend/forms.html
|
||||
- Golem15 WinterCMS Starter CLAUDE.md (local reference)
|
||||
|
||||
### Secondary (MEDIUM confidence)
|
||||
- Craft CMS Features: https://craftcms.com/features
|
||||
- Statamic Documentation: https://statamic.com/
|
||||
- Strapi CMS Blog: https://strapi.io/blog/best-cms-2025
|
||||
- Payload CMS Documentation: https://payloadcms.com/docs
|
||||
|
||||
### Market Research (MEDIUM confidence)
|
||||
- CMS Feature Comparisons (2025): Multiple web search results
|
||||
- Headless CMS landscape: https://jamstack.org/headless-cms/
|
||||
- Plugin architecture patterns: https://www.dotcms.com/blog/plugin-achitecture
|
||||
|
||||
### Community (LOW confidence, patterns observed)
|
||||
- WinterCMS GitHub Discussions
|
||||
- Hacker News threads on CMS architecture
|
||||
- Various CMS comparison articles (2025)
|
||||
|
||||
---
|
||||
|
||||
## Gaps and Open Questions
|
||||
|
||||
1. **Scala CMS precedent?** No major Scala-based CMS exists. Research Scala web frameworks (Play, http4s, ZIO HTTP) for patterns.
|
||||
|
||||
2. **Template engine choice?** Twig is PHP-specific. Options: Twirl (Play), Thymeleaf, Scalate. Needs deeper research.
|
||||
|
||||
3. **Hot reload in Scala?** JVM startup is slow. Investigate JRebel, Bloop, or compile daemon for development experience.
|
||||
|
||||
4. **YAML parsing performance?** Scala YAML libraries need benchmarking for large config files.
|
||||
|
||||
5. **Plugin isolation?** How to safely load third-party plugins without security risks. Classloader isolation? Sandboxing?
|
||||
|
||||
These gaps should be addressed during phase-specific research.
|
||||
577
.planning/research/PITFALLS.md
Normal file
577
.planning/research/PITFALLS.md
Normal file
@@ -0,0 +1,577 @@
|
||||
# Pitfalls Research: SummerCMS
|
||||
|
||||
**Project:** SummerCMS - Scala/ZIO rewrite of WinterCMS
|
||||
**Researched:** 2026-02-04
|
||||
**Confidence:** MEDIUM-HIGH (verified via multiple sources)
|
||||
|
||||
## Executive Summary
|
||||
|
||||
This research identifies critical pitfalls across four dimensions: Scala/ZIO technical challenges, CMF rewrite patterns, scope/ambition management, and team/process dynamics. The most dangerous pitfalls are:
|
||||
|
||||
1. **The Big Rewrite Anti-Pattern** - Trying to achieve full parity before shipping anything
|
||||
2. **ZIO Learning Curve for Non-FP Developers** - 40.5% of teams report slowed onboarding
|
||||
3. **AI Agent Quality Debt** - Research shows AI assistance creates persistent technical debt
|
||||
4. **Plugin System Design Lock-in** - Getting the API wrong forces breaking changes
|
||||
|
||||
---
|
||||
|
||||
## Scala/ZIO Specific Pitfalls
|
||||
|
||||
### 1. Incorrectly Wrapping Async Code with ZIO.effect
|
||||
|
||||
**What goes wrong:** When wrapping legacy or third-party APIs, developers use `ZIO.effect` (now `ZIO.attempt`) for code that returns `Future`. The ZIO effect completes without waiting for the Future, causing race conditions and silent failures.
|
||||
|
||||
**Warning signs:**
|
||||
- Race conditions in async operations
|
||||
- "Impossible" null pointer exceptions
|
||||
- Tests passing locally but failing in CI
|
||||
- Side effects executing out of order
|
||||
|
||||
**Prevention strategy:**
|
||||
- Use `ZIO.fromFuture` for Future-returning code
|
||||
- Create team training on ZIO effect wrapping patterns
|
||||
- Add lint rules or code review checklist item
|
||||
- Establish wrapper utility library early
|
||||
|
||||
**Phase relevance:** Phase 1 (Core Framework) - must be addressed in initial architecture
|
||||
|
||||
---
|
||||
|
||||
### 2. FiberFailure Exception Wrapping
|
||||
|
||||
**What goes wrong:** When using `Runtime.unsafeRun`, ZIO throws `FiberFailure` wrapping the original exception. Code expecting to catch specific exceptions (e.g., `SQLException`) fails because only `FiberFailure` propagates.
|
||||
|
||||
**Warning signs:**
|
||||
- Exception handlers not triggering
|
||||
- Generic error messages losing original cause
|
||||
- Interop with Java libraries failing unexpectedly
|
||||
|
||||
**Prevention strategy:**
|
||||
- Use `Cause.squash` when extracting errors for interop
|
||||
- Document exception unwrapping patterns
|
||||
- Create standardized error handling utilities for Java interop
|
||||
|
||||
**Phase relevance:** Phase 1-2, especially when integrating database and external services
|
||||
|
||||
---
|
||||
|
||||
### 3. Unintentional Side Effects Outside ZIO
|
||||
|
||||
**What goes wrong:** Developers add `println` statements or other side effects in val definitions without wrapping in ZIO. These execute eagerly during effect construction, causing out-of-order execution.
|
||||
|
||||
**Warning signs:**
|
||||
- Log statements appearing in wrong order
|
||||
- "Debug" side effects happening at import time
|
||||
- Confusion about when code actually runs
|
||||
|
||||
**Prevention strategy:**
|
||||
- Use `ZIO.logDebug` instead of println
|
||||
- Configure linter to warn on println usage
|
||||
- Code review focus on val definitions
|
||||
|
||||
**Phase relevance:** All phases - cultural issue to address from day 1
|
||||
|
||||
---
|
||||
|
||||
### 4. ZIO HTTP Client Performance Overhead
|
||||
|
||||
**What goes wrong:** ZIO HTTP Client has ~2 second initialization overhead and ~300ms per-request overhead without connection pooling. Default configuration is not production-ready.
|
||||
|
||||
**Warning signs:**
|
||||
- API response times 300ms+ slower than expected
|
||||
- Memory growing with request count
|
||||
- Service restarts due to memory exhaustion
|
||||
|
||||
**Prevention strategy:**
|
||||
- Always use connection pooling (`Client.default` with pool)
|
||||
- Configure client initialization at app startup, not per-request
|
||||
- Monitor memory and finalizer counts
|
||||
- Set up production load testing early
|
||||
|
||||
**Phase relevance:** Phase 2-3 when building HTTP layer
|
||||
|
||||
**Sources:** [ZIO HTTP Client Performance Issue #2117](https://github.com/zio/zio-http/issues/2117), [Memory Leaks Issue #2956](https://github.com/zio/zio-http/issues/2956)
|
||||
|
||||
---
|
||||
|
||||
### 5. ZIO Quill Compile-Time Explosion
|
||||
|
||||
**What goes wrong:** Projects with many Quill queries see compile times grow exponentially. Single queries can take 5+ minutes and require 5GB+ heap. This kills developer productivity.
|
||||
|
||||
**Warning signs:**
|
||||
- Compile times increasing each sprint
|
||||
- CI builds timing out
|
||||
- Developers avoiding database code changes
|
||||
- "Slow inlining phase" in compiler output
|
||||
|
||||
**Prevention strategy:**
|
||||
- Split database layer into separate sbt subproject
|
||||
- Limit queries per file (suggested: 10-15 max)
|
||||
- Use `scalacOptions += "-Yretain-trees"` to avoid intermittent failures
|
||||
- Configure CI with sufficient memory (8GB+ for Quill projects)
|
||||
- Consider Doobie as alternative for complex query scenarios
|
||||
|
||||
**Phase relevance:** Phase 2 (Database Layer) - architecture decision point
|
||||
|
||||
**Sources:** [Quill Compilation Time #2737](https://github.com/zio/zio-quill/issues/2737), [ZIO Quill Compiler Performance](https://zio.dev/zio-quill/compiler-performance/)
|
||||
|
||||
---
|
||||
|
||||
### 6. Infinite Compile Time with ZLayer.fromFunction
|
||||
|
||||
**What goes wrong:** When `ZLayer.fromFunction` receives more type parameters than needed, the compiler enters infinite loop until heap exhaustion.
|
||||
|
||||
**Warning signs:**
|
||||
- Compilation never finishing
|
||||
- OutOfMemoryError during build
|
||||
- CI job killed after timeout
|
||||
|
||||
**Prevention strategy:**
|
||||
- Use `ZLayer.derive` for automatic layer construction
|
||||
- Provide explicit type annotations on ZLayer definitions
|
||||
- Code review for ZLayer boilerplate
|
||||
|
||||
**Phase relevance:** Phase 1 (Core Framework) - affects DI architecture
|
||||
|
||||
**Sources:** [ZIO Issue #8701](https://github.com/zio/zio/issues/8701)
|
||||
|
||||
---
|
||||
|
||||
### 7. Overlapping Routes with Tapir/ZIO-HTTP
|
||||
|
||||
**What goes wrong:** ZIO HTTP's routing implementation cannot correctly handle overlapping path shapes. Routes like `/users/{id}` and `/users/admin` conflict, causing 404 or 405 errors.
|
||||
|
||||
**Warning signs:**
|
||||
- Intermittent 404s on valid endpoints
|
||||
- Header-based versioning not working
|
||||
- First-listed route capturing all traffic
|
||||
|
||||
**Prevention strategy:**
|
||||
- Design non-overlapping URL structures
|
||||
- Avoid header-based routing for endpoint selection
|
||||
- Use path prefixes for API versioning (`/v1/`, `/v2/`)
|
||||
- Test all route combinations explicitly
|
||||
|
||||
**Phase relevance:** Phase 2-3 (API Layer) - design routing conventions early
|
||||
|
||||
**Sources:** [Tapir ZIO HTTP Docs](https://tapir.softwaremill.com/en/latest/server/ziohttp.html)
|
||||
|
||||
---
|
||||
|
||||
### 8. Misusing ZIO Environment for Service Passing
|
||||
|
||||
**What goes wrong:** Teams use ZIO's R environment to pass services around like a DI container, creating complex type signatures and making code hard to follow.
|
||||
|
||||
**Warning signs:**
|
||||
- ZIO effect types with 5+ services in R
|
||||
- Difficulty understanding what services are needed where
|
||||
- Excessive `provideSome` and type manipulation
|
||||
|
||||
**Prevention strategy:**
|
||||
- Use constructor injection for services
|
||||
- Reserve R environment for contextual needs (scopes, transactions)
|
||||
- Follow pattern: "constructors require, layers make"
|
||||
- Use `ZLayer.derive` for automatic wiring
|
||||
|
||||
**Phase relevance:** Phase 1 (Core Framework) - establish patterns before codebase grows
|
||||
|
||||
**Sources:** [Structuring ZIO 2 Applications](https://softwaremill.com/structuring-zio-2-applications/)
|
||||
|
||||
---
|
||||
|
||||
## CMF Rewrite Pitfalls
|
||||
|
||||
### 9. The Iceberg Underestimation
|
||||
|
||||
**What goes wrong:** Product managers and developers see the visible UI/UX of WinterCMS and assume that's the scope. But like an iceberg, only 10% is visible. The migration system, YAML parsing edge cases, plugin lifecycle hooks, and error recovery paths are the hidden 90%.
|
||||
|
||||
**Warning signs:**
|
||||
- Estimates based on feature count, not implementation depth
|
||||
- "It's just a CRUD form generator" mentality
|
||||
- Discovery of essential features mid-implementation
|
||||
- Timeline constantly extending
|
||||
|
||||
**Prevention strategy:**
|
||||
- Inventory ALL WinterCMS features before scoping (use reference implementation)
|
||||
- Weight estimates by implementation complexity, not user visibility
|
||||
- Build explicit unknown-unknowns buffer (30-50% for Phase 1)
|
||||
- Accept that Phase 1 will reveal scope for later phases
|
||||
|
||||
**Phase relevance:** All phases - especially Phase 1 planning
|
||||
|
||||
**Sources:** [Why Rewrites Fail](https://swizec.com/blog/you-can-t-stop-the-business-or-why-rewrites-fail/)
|
||||
|
||||
---
|
||||
|
||||
### 10. Moving Target Syndrome
|
||||
|
||||
**What goes wrong:** The original WinterCMS continues evolving while SummerCMS is built. Teams chase feature parity with a moving target, implementing features twice or falling perpetually behind.
|
||||
|
||||
**Warning signs:**
|
||||
- WinterCMS releases during development causing re-work
|
||||
- "We need to add X because they just added it" mid-sprint
|
||||
- Never reaching parity point
|
||||
- Demoralization from endless chase
|
||||
|
||||
**Prevention strategy:**
|
||||
- Define parity target against specific WinterCMS version (freeze reference)
|
||||
- Accept that SummerCMS 1.0 will differ from WinterCMS latest
|
||||
- Focus on core value proposition, not feature-for-feature matching
|
||||
- Plan "catch-up" sprints explicitly, not continuously
|
||||
|
||||
**Phase relevance:** Project-wide - establish as principle in Phase 0
|
||||
|
||||
---
|
||||
|
||||
### 11. Plugin API Lock-in
|
||||
|
||||
**What goes wrong:** The plugin system API is designed early but proves inadequate. Changing it later breaks all plugins, requiring mass rewrites or painful deprecation cycles.
|
||||
|
||||
**Warning signs:**
|
||||
- Plugin developers working around API limitations
|
||||
- Plugins accessing internal APIs
|
||||
- Feature requests that require plugin API changes
|
||||
- "We can't do X because of the plugin contract"
|
||||
|
||||
**Prevention strategy:**
|
||||
- Study multiple plugin system designs (WordPress, WinterCMS, Discourse, VSCode)
|
||||
- Build 3-5 diverse plugins before finalizing API
|
||||
- Use semantic versioning from day 1
|
||||
- Design for extension points (hooks, filters, traits)
|
||||
- Plan for plugin API v2 from the start (versioned endpoints)
|
||||
|
||||
**Phase relevance:** Phase 3-4 (Plugin System) - most critical architecture decision
|
||||
|
||||
---
|
||||
|
||||
### 12. YAML Parser Edge Cases
|
||||
|
||||
**What goes wrong:** WinterCMS's YAML-driven forms have subtle behaviors and edge cases. A naive reimplementation misses validation cascades, conditional visibility, custom widget loading, and translation lookups.
|
||||
|
||||
**Warning signs:**
|
||||
- Forms "mostly work" but have weird bugs
|
||||
- Copy-pasting YAML from WinterCMS requires modifications
|
||||
- Custom widgets not loading correctly
|
||||
- Translations missing in form contexts
|
||||
|
||||
**Prevention strategy:**
|
||||
- Create comprehensive test suite from WinterCMS YAML examples
|
||||
- Document all YAML features before implementation
|
||||
- Build incrementally with full test coverage at each step
|
||||
- Consider typed config format (HOCON, Dhall) as alternative
|
||||
|
||||
**Phase relevance:** Phase 2-3 (Backend/Admin System)
|
||||
|
||||
---
|
||||
|
||||
### 13. Authentication/Authorization Reimplementation
|
||||
|
||||
**What goes wrong:** Authentication seems simple until you hit: password reset flows, account lockout, session management, remember-me tokens, OAuth providers, JWT refresh, GDPR deletion requirements, and audit logging.
|
||||
|
||||
**Warning signs:**
|
||||
- "Just build login first, we'll add security later"
|
||||
- Security review finding critical issues
|
||||
- Edge cases discovered in production
|
||||
- Compliance requirements appearing late
|
||||
|
||||
**Prevention strategy:**
|
||||
- Use battle-tested library (ZIO-Auth, or wrap proven Java library)
|
||||
- Define security requirements before implementation
|
||||
- Include compliance checklist (GDPR, CCPA) in design
|
||||
- Penetration testing in Phase 2, not after launch
|
||||
|
||||
**Phase relevance:** Phase 2 (Auth/User System) - do not underestimate
|
||||
|
||||
---
|
||||
|
||||
### 14. Migration Tool Neglect
|
||||
|
||||
**What goes wrong:** Teams focus on new CMS but neglect the migration path from WinterCMS. Users can't adopt because they can't migrate their existing sites.
|
||||
|
||||
**Warning signs:**
|
||||
- "Migration is a post-launch concern"
|
||||
- Data model designed without migration in mind
|
||||
- Plugin compatibility assumptions
|
||||
- No testing with real WinterCMS sites
|
||||
|
||||
**Prevention strategy:**
|
||||
- Include migration as Phase 2/3 requirement, not post-launch
|
||||
- Test with 3-5 real WinterCMS sites during development
|
||||
- Document breaking changes and migration paths
|
||||
- Build automated migration tooling
|
||||
|
||||
**Phase relevance:** Phase 4-5 - but requires design consideration in Phase 1
|
||||
|
||||
---
|
||||
|
||||
## Scope/Ambition Pitfalls
|
||||
|
||||
### 15. The "Full Parity" Delusion
|
||||
|
||||
**What goes wrong:** Targeting "full WinterCMS parity" sounds achievable but is actually unbounded scope. WinterCMS has 15+ years of features, edge cases, and workarounds. Full parity could take 5+ years.
|
||||
|
||||
**Warning signs:**
|
||||
- Feature list keeps growing
|
||||
- No clear definition of "parity"
|
||||
- Blocking launch on nice-to-have features
|
||||
- Team fatigue from endless scope
|
||||
|
||||
**Prevention strategy:**
|
||||
- Define "Essential Parity" vs "Nice-to-Have Parity"
|
||||
- Create tiered launch criteria:
|
||||
- MVP: Build a new site
|
||||
- v1.0: Migrate simple WinterCMS site
|
||||
- v1.5: Migrate complex WinterCMS site
|
||||
- Accept 80/20 rule: 80% of value from 20% of features
|
||||
- Document what's explicitly NOT in v1.0
|
||||
|
||||
**Phase relevance:** Phase 0 (Planning) - critical scope decision
|
||||
|
||||
---
|
||||
|
||||
### 16. Second System Effect
|
||||
|
||||
**What goes wrong:** Having learned from WinterCMS's limitations, the team over-engineers SummerCMS with every feature they wished the original had. The result is bloated, slow, and late.
|
||||
|
||||
**Warning signs:**
|
||||
- "While we're at it, let's also..."
|
||||
- Architecture astronaut discussions
|
||||
- Features justified by "what if" scenarios
|
||||
- Premature optimization before working system
|
||||
|
||||
**Prevention strategy:**
|
||||
- Limit architectural innovations per phase (suggest: 1-2 max)
|
||||
- Require user story for every feature
|
||||
- "Build the simplest thing that could possibly work" as team mantra
|
||||
- Technical debt is acceptable in v1; perfection is not required
|
||||
|
||||
**Phase relevance:** All phases - ongoing discipline
|
||||
|
||||
**Sources:** The Mythical Man-Month (Fred Brooks)
|
||||
|
||||
---
|
||||
|
||||
### 17. Technology FOMO
|
||||
|
||||
**What goes wrong:** During multi-year development, new technologies emerge. Teams want to switch to the latest ZIO version, new HTTP libraries, or shiny new patterns. Constant upgrades destabilize the codebase.
|
||||
|
||||
**Warning signs:**
|
||||
- "ZIO X.Y just released, we should upgrade"
|
||||
- Multiple active branches for different tech stacks
|
||||
- Library upgrade PRs exceeding feature PRs
|
||||
- Breaking changes from dependency updates
|
||||
|
||||
**Prevention strategy:**
|
||||
- Freeze major dependencies for 6-month windows
|
||||
- Upgrade in dedicated sprints, not continuously
|
||||
- Maintain changelog awareness but resist immediate adoption
|
||||
- Prefer stable over bleeding-edge for core dependencies
|
||||
|
||||
**Phase relevance:** All phases - establish upgrade policy in Phase 1
|
||||
|
||||
---
|
||||
|
||||
### 18. Parallel Development Without Integration Points
|
||||
|
||||
**What goes wrong:** Teams work on plugin system, admin UI, and API layer in parallel but without regular integration. When they merge, nothing fits together.
|
||||
|
||||
**Warning signs:**
|
||||
- Long-running feature branches
|
||||
- Merge conflicts taking days to resolve
|
||||
- "Demo day" disasters
|
||||
- Differing assumptions about shared interfaces
|
||||
|
||||
**Prevention strategy:**
|
||||
- Weekly integration builds mandatory
|
||||
- Shared interface contracts (API specs, type definitions) before implementation
|
||||
- Vertical slices: build thin complete features, not horizontal layers
|
||||
- CI must run integration tests on all PRs
|
||||
|
||||
**Phase relevance:** All phases - process discipline
|
||||
|
||||
---
|
||||
|
||||
## Team/Process Pitfalls
|
||||
|
||||
### 19. AI Agent Quality Debt Accumulation
|
||||
|
||||
**What goes wrong:** Research shows AI-assisted coding creates "substantial but transient velocity gains alongside persistent increases in technical debt." The initial speed comes at the cost of code quality that compounds over time.
|
||||
|
||||
**Warning signs:**
|
||||
- PRs with unusual patterns or verbose code
|
||||
- Test coverage declining despite more code
|
||||
- Static analysis warnings increasing
|
||||
- Experienced developers spending time debugging AI code
|
||||
- "The agent wrote it, I don't fully understand it"
|
||||
|
||||
**Prevention strategy:**
|
||||
- Mandatory human review for all AI-generated code
|
||||
- AI agents work on tests FIRST, then implementation
|
||||
- Static analysis gates in CI (no warning increase allowed)
|
||||
- Limit AI to well-defined, isolated tasks
|
||||
- "Agent code" labeled for extra scrutiny
|
||||
|
||||
**Phase relevance:** All phases - process constraint
|
||||
|
||||
**Sources:** [Speed at Cost of Quality Study](https://arxiv.org/abs/2511.04427), [METR AI Developer Study](https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/)
|
||||
|
||||
---
|
||||
|
||||
### 20. AI Confirmation Bias
|
||||
|
||||
**What goes wrong:** AI agents affirm user premises even when wrong. Developers ask "Is this design correct?" and get "Yes!" even for flawed designs.
|
||||
|
||||
**Warning signs:**
|
||||
- Lack of pushback on technical decisions
|
||||
- Bugs in areas "validated" by AI
|
||||
- False confidence in untested approaches
|
||||
|
||||
**Prevention strategy:**
|
||||
- Use AI for implementation, not architecture validation
|
||||
- Human architect reviews all design decisions
|
||||
- Ask AI adversarial questions: "What could go wrong with this?"
|
||||
- Require AI to cite sources for technical claims
|
||||
|
||||
**Phase relevance:** All phases - especially architecture phases
|
||||
|
||||
**Sources:** [VentureBeat on AI Agent Limitations](https://venturebeat.com/ai/why-ai-coding-agents-arent-production-ready-brittle-context-windows-broken)
|
||||
|
||||
---
|
||||
|
||||
### 21. Scala Learning Curve for Web Developers
|
||||
|
||||
**What goes wrong:** Target users are "web developers who may not know Scala deeply," but the codebase uses advanced ZIO patterns, tagless final, and complex type signatures. Contributors can't understand or extend the system.
|
||||
|
||||
**Warning signs:**
|
||||
- External PRs take weeks to review due to errors
|
||||
- Same questions asked repeatedly in issues
|
||||
- Plugin developers working in different style than core
|
||||
- 40.5% onboarding slowdown (industry research)
|
||||
|
||||
**Prevention strategy:**
|
||||
- Create "SummerCMS Style Guide" limiting advanced patterns
|
||||
- Use simple, explicit types over clever abstractions
|
||||
- Extensive inline documentation for non-obvious code
|
||||
- "Stepping project" for new contributors (simple bugs first)
|
||||
- Consider Scala 3 direct-style syntax over ZIO everywhere
|
||||
|
||||
**Phase relevance:** Phase 1 - establish code style early
|
||||
|
||||
**Sources:** [Xebia: Onboarding Juniors into Scala](https://xebia.com/blog/6-tips-for-onboarding-juniors-into-scala/), [State of Scala Survey](https://www.jvm-weekly.com/p/the-state-of-scala-and-clojure-surveys)
|
||||
|
||||
---
|
||||
|
||||
### 22. Expert Blindness on Complexity
|
||||
|
||||
**What goes wrong:** The principal Scala developer builds elegant, idiomatic code that only they can maintain. When they're unavailable, development stops.
|
||||
|
||||
**Warning signs:**
|
||||
- Only one person can debug certain modules
|
||||
- Code reviews always require expert input
|
||||
- "Ask [expert]" as common answer to questions
|
||||
- Bus factor of 1 for critical systems
|
||||
|
||||
**Prevention strategy:**
|
||||
- Pair programming on complex modules
|
||||
- All code must be explainable to non-expert in 5 minutes
|
||||
- Rotate ownership of modules
|
||||
- Document "why" not just "what" in code comments
|
||||
|
||||
**Phase relevance:** All phases - team management
|
||||
|
||||
---
|
||||
|
||||
### 23. Cake Pattern and Implicit Abuse
|
||||
|
||||
**What goes wrong:** Teams use Scala's Cake pattern for dependency injection, creating unmaintainable "hairball" of traits. Or they overuse implicits until nobody can trace where values come from.
|
||||
|
||||
**Warning signs:**
|
||||
- Traits with 10+ dependencies
|
||||
- `implicit` parameters that could be explicit
|
||||
- IDE unable to find usages
|
||||
- New developers completely lost
|
||||
|
||||
**Prevention strategy:**
|
||||
- Use ZLayer for DI, not Cake pattern
|
||||
- Prefer explicit constructor parameters over implicits
|
||||
- Limit implicit scope to truly contextual needs
|
||||
- IDE-friendly code as explicit goal
|
||||
|
||||
**Phase relevance:** Phase 1 - architecture decision
|
||||
|
||||
**Sources:** [Scala Best Practices - Architecture](https://github.com/alexandru/scala-best-practices/blob/master/sections/3-architecture.md)
|
||||
|
||||
---
|
||||
|
||||
## Critical "Do Not" List
|
||||
|
||||
These are absolute no-gos that lead to project failure:
|
||||
|
||||
### DO NOT: Build Without a Working Prototype First
|
||||
Build a minimal end-to-end prototype (CLI -> HTTP -> DB -> Response) before any "real" development. This validates the stack integration and uncovers tooling issues.
|
||||
|
||||
### DO NOT: Design Plugin API in Isolation
|
||||
Build 3+ real plugins before finalizing the plugin API. Paper designs miss critical use cases.
|
||||
|
||||
### DO NOT: Skip Type Safety for "Simplicity"
|
||||
Scala's value is in type safety. Cutting corners with `Any` or stringly-typed code creates bugs that surface in production.
|
||||
|
||||
### DO NOT: Ignore Compile Time Budgets
|
||||
Set compile time budgets per module (e.g., 30 seconds). When exceeded, split the module. Slow compilation kills productivity.
|
||||
|
||||
### DO NOT: Let AI Agents Work Without Tests
|
||||
Require tests BEFORE implementation. AI-generated code without tests is tech debt disguised as velocity.
|
||||
|
||||
### DO NOT: Promise WinterCMS Compatibility Without Testing It
|
||||
Every compatibility claim must have a passing test against real WinterCMS artifacts.
|
||||
|
||||
### DO NOT: Defer Security to "After Launch"
|
||||
Authentication, authorization, and input validation are Phase 1 concerns, not Phase N polish.
|
||||
|
||||
### DO NOT: Build Horizontal Layers in Sequence
|
||||
Don't build all database layer, then all API layer, then all UI. Build vertical slices that prove integration works.
|
||||
|
||||
---
|
||||
|
||||
## Pitfall-to-Phase Mapping
|
||||
|
||||
| Pitfall | Primary Phase | Mitigation Phase |
|
||||
|---------|---------------|------------------|
|
||||
| ZIO.effect misuse | 1 | Code review from day 1 |
|
||||
| Fiber exception wrapping | 1-2 | Utility library in Phase 1 |
|
||||
| ZIO HTTP performance | 2-3 | Load testing in Phase 2 |
|
||||
| Quill compile times | 2 | Architecture decision |
|
||||
| Overlapping routes | 2-3 | URL convention in Phase 2 |
|
||||
| Plugin API lock-in | 3-4 | Build plugins before finalizing |
|
||||
| YAML edge cases | 2-3 | Test suite from WinterCMS |
|
||||
| Auth complexity | 2 | Use proven library |
|
||||
| AI quality debt | All | CI gates + review process |
|
||||
| Learning curve | All | Style guide + onboarding |
|
||||
| Moving target | All | Freeze reference version |
|
||||
| Full parity delusion | 0 | Scope discipline |
|
||||
|
||||
---
|
||||
|
||||
## Sources
|
||||
|
||||
### ZIO/Scala Technical
|
||||
- [5 More ZIO Pitfalls - Wix Engineering](https://medium.com/wix-engineering/5-more-pitfalls-to-avoid-when-starting-to-work-with-zio-d0cdd44fa439)
|
||||
- [ZIO in 2025 - Ziverge](https://www.ziverge.com/post/zio-in-2025)
|
||||
- [Structuring ZIO 2 Applications - SoftwareMill](https://softwaremill.com/structuring-zio-2-applications/)
|
||||
- [Tuning ZIO for High Performance](https://blog.pierre-ricadat.com/tuning-zio-for-high-performance/)
|
||||
- [ZIO Quill Compiler Performance](https://zio.dev/zio-quill/compiler-performance/)
|
||||
|
||||
### Rewrite/CMF
|
||||
- [Why Rewrites Fail - Swizec](https://swizec.com/blog/you-can-t-stop-the-business-or-why-rewrites-fail/)
|
||||
- [Software Rewrite Strategy - Amazing CTO](https://www.amazingcto.com/why-rewrites-fail-and-how-to-be-successful/)
|
||||
- [Big Rewrite Anti-Pattern - Joca Torres](https://jocatorres.medium.com/leadership-anti-patterns-94cc8634429a)
|
||||
|
||||
### AI Development
|
||||
- [Speed at Cost of Quality Study](https://arxiv.org/abs/2511.04427)
|
||||
- [METR AI Developer Productivity Study](https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/)
|
||||
- [AI Coding Reality - Addy Osmani](https://addyosmani.com/blog/ai-coding-workflow/)
|
||||
|
||||
### Scala DX/Onboarding
|
||||
- [Onboarding Juniors into Scala - Xebia](https://xebia.com/blog/6-tips-for-onboarding-juniors-into-scala/)
|
||||
- [State of Scala Survey](https://www.jvm-weekly.com/p/the-state-of-scala-and-clojure-surveys)
|
||||
- [Scala Best Practices](https://github.com/alexandru/scala-best-practices)
|
||||
456
.planning/research/STACK.md
Normal file
456
.planning/research/STACK.md
Normal file
@@ -0,0 +1,456 @@
|
||||
# Stack Research: SummerCMS
|
||||
|
||||
**Project:** SummerCMS - Scala CMF rewriting WinterCMS
|
||||
**Researched:** 2026-02-04
|
||||
**Overall Confidence:** HIGH (all major recommendations verified with official sources)
|
||||
|
||||
## Executive Summary
|
||||
|
||||
The ZIO ecosystem in 2025/2026 is mature and production-ready. ZIO HTTP 3.x is stable, Quill provides excellent PostgreSQL integration, and the tooling ecosystem (Mill, Besom) has reached 1.0 stability. The recommended stack prioritizes developer experience while maintaining the performance goals of the project.
|
||||
|
||||
**Key finding:** The ZIO ecosystem has consolidated around a smaller set of well-maintained libraries, with zio-sql and zio-jdbc deprecated in favor of Quill as the primary database library.
|
||||
|
||||
---
|
||||
|
||||
## Recommended Stack
|
||||
|
||||
### Language & Runtime
|
||||
|
||||
| Technology | Version | Purpose | Rationale |
|
||||
|------------|---------|---------|-----------|
|
||||
| Scala | 3.3.7 LTS | Core language | LTS provides stability for a multi-year project; 3.8.x requires JDK 17+ which may limit deployment options |
|
||||
| JDK | 17+ | Runtime | Required for Scala 3.3.x LTS, widely available, long-term support |
|
||||
| ZIO | 2.1.24 | Effect system | Latest stable with stream performance improvements, binary compatibility guaranteed in 2.x line |
|
||||
|
||||
**Confidence:** HIGH - Verified via [Scala releases](https://www.scala-lang.org/download/all.html), [ZIO releases](https://github.com/zio/zio/releases)
|
||||
|
||||
**Notes:**
|
||||
- Scala 3.3.7 LTS is recommended over 3.8.x bleeding edge - CMF needs stability over newest features
|
||||
- ZIO 2.1.x line has explicit binary compatibility guarantees, critical for plugin ecosystem
|
||||
|
||||
---
|
||||
|
||||
### Core Framework
|
||||
|
||||
| Technology | Version | Purpose | Rationale |
|
||||
|------------|---------|---------|-----------|
|
||||
| ZIO HTTP | 3.8.1 | HTTP server/client | Production-ready, built on Netty, native ZIO integration, OpenAPI support, built-in template DSL |
|
||||
|
||||
**Confidence:** HIGH - Verified via [ZIO HTTP releases](https://github.com/zio/zio-http/releases)
|
||||
|
||||
**Why ZIO HTTP over alternatives:**
|
||||
- **vs http4s:** ZIO HTTP is ZIO-native; http4s is Cats Effect-native. Mixing ecosystems adds complexity.
|
||||
- **vs Akka HTTP:** Licensing changes in Akka make it unsuitable for new projects.
|
||||
- **vs Play:** Too heavyweight for a CMF, brings its own conventions that conflict with our plugin architecture.
|
||||
|
||||
**Key ZIO HTTP 3.x features for CMF:**
|
||||
- Declarative endpoint definitions (maps to YAML-driven form generation)
|
||||
- Built-in OpenAPI generation (API documentation for plugins)
|
||||
- Middleware composition (authentication, logging, metrics)
|
||||
- WebSocket support (future real-time features)
|
||||
- Datastar SDK (new in 3.6.0 - alternative to HTMX, evaluate later)
|
||||
|
||||
---
|
||||
|
||||
### Database Layer
|
||||
|
||||
| Technology | Version | Purpose | Rationale |
|
||||
|------------|---------|---------|-----------|
|
||||
| ZIO Quill | 4.8.6 | Query DSL & ORM-like features | Compile-time query generation, ZIO-native contexts, PostgreSQL-specific features |
|
||||
| PostgreSQL Driver | 42.7.5 | JDBC driver | Latest version compatible with Quill |
|
||||
| HikariCP | 5.x | Connection pooling | Industry standard, ZIO integration via Quill contexts |
|
||||
| Flyway | 10.x | Database migrations | Industry standard, straightforward ZIO integration |
|
||||
|
||||
**Confidence:** HIGH - Verified via [Quill documentation](https://zio.dev/zio-quill/), [Quill releases](https://github.com/zio/zio-quill/releases)
|
||||
|
||||
**Why Quill:**
|
||||
- **zio-sql deprecated:** Per [Ziverge 2025 roadmap](https://www.ziverge.com/post/zio-in-2025), zio-sql and zio-jdbc are deprecated. Quill is the endorsed solution.
|
||||
- **Compile-time queries:** SQL errors caught at compile time, critical for plugin ecosystem stability
|
||||
- **ZIO contexts:** `PostgresZioJdbcContext` provides native ZIO effect integration
|
||||
- **ProtoQuill:** Full Scala 3 support via zio-protoquill
|
||||
|
||||
**Installation:**
|
||||
```scala
|
||||
libraryDependencies ++= Seq(
|
||||
"io.getquill" %% "quill-jdbc-zio" % "4.8.6",
|
||||
"org.postgresql" % "postgresql" % "42.7.5",
|
||||
"org.flywaydb" % "flyway-core" % "10.22.0",
|
||||
"org.flywaydb" % "flyway-database-postgresql" % "10.22.0"
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Template Engine
|
||||
|
||||
| Technology | Version | Purpose | Rationale |
|
||||
|------------|---------|---------|-----------|
|
||||
| ScalaTags | 0.13.1 | Primary HTML generation | Type-safe, 4x faster than Twirl, pure Scala |
|
||||
| Twirl | 2.0.9 | Theme templates (fallback) | Familiar syntax for theme developers, Play-compatible |
|
||||
|
||||
**Confidence:** MEDIUM - ScalaTags is well-documented; theme developer experience needs validation
|
||||
|
||||
**Primary approach: ScalaTags**
|
||||
- Type-safe HTML construction
|
||||
- [Almost 4x faster than Twirl](https://com-lihaoyi.github.io/scalatags/)
|
||||
- Pure Scala - IDE support, refactoring works
|
||||
- Integrates with ZIO HTTP's built-in template DSL
|
||||
- Good for component rendering where type-safety matters
|
||||
|
||||
**Secondary approach: Twirl for themes**
|
||||
- Theme developers expect template syntax, not Scala code
|
||||
- Twirl's `@` syntax is intuitive for non-Scala developers
|
||||
- Can be compiled at build time for performance
|
||||
- Familiar to WinterCMS/Laravel Blade developers
|
||||
|
||||
**Hybrid strategy:**
|
||||
- Core components and admin backend: ScalaTags (developer maintains, type-safety critical)
|
||||
- Theme partials and layouts: Twirl (theme developers, simplicity matters)
|
||||
- Consider: Custom template language (like Twig) parsed to ScalaTags at compile time
|
||||
|
||||
**Open question:** Should we invest in a Twig-to-ScalaTags compiler for WinterCMS theme compatibility?
|
||||
|
||||
---
|
||||
|
||||
### Frontend Integration
|
||||
|
||||
| Technology | Version | Purpose | Rationale |
|
||||
|------------|---------|---------|-----------|
|
||||
| HTMX | 2.x (latest) | Data-attribute driven interactions | Captures OctoberCMS data-attributes spirit, no build step, server-rendered |
|
||||
| htmx4s | 0.3.0 | Scala HTMX integration | Type-safe HTMX attributes, ZIO HTTP compatible |
|
||||
| Vue.js | 3.x | Complex interactive components | For forms, media manager, admin UI where HTMX insufficient |
|
||||
|
||||
**Confidence:** HIGH - htmx4s verified via [Scaladex](https://index.scala-lang.org/eikek/htmx4s), patterns validated via [Rock the JVM demo](https://github.com/rockthejvm/scalatags-htmx-demo)
|
||||
|
||||
**htmx4s modules:**
|
||||
```scala
|
||||
libraryDependencies ++= Seq(
|
||||
"com.github.eikek" %% "htmx4s-constants" % "0.3.0", // HTMX vocabulary as Scala values
|
||||
"com.github.eikek" %% "htmx4s-scalatags" % "0.3.0", // ScalaTags integration
|
||||
// Note: htmx4s-http4s is for http4s - we'll need ZIO HTTP equivalent
|
||||
)
|
||||
```
|
||||
|
||||
**HTMX strategy:**
|
||||
- Primary interaction model for CMS frontend
|
||||
- Server returns HTML fragments, not JSON
|
||||
- Reduces JavaScript complexity significantly
|
||||
- Aligns with OctoberCMS's original data-attributes philosophy
|
||||
|
||||
**Vue.js strategy:**
|
||||
- Reserved for complex admin UI components (media manager, form builder)
|
||||
- Mounts on specific DOM elements, not full SPA
|
||||
- Communicates via JSON API endpoints
|
||||
- Themes can declare Vue components for complex interactivity
|
||||
|
||||
**What NOT to use:**
|
||||
- Alpine.js: WinterCMS's messy Snowboard+Alpine was explicitly called out as a problem. HTMX is simpler.
|
||||
- React/Angular: Overkill for CMS, adds build complexity for theme developers.
|
||||
- Full SPA mode: Server-rendered with progressive enhancement is better for SEO and initial load.
|
||||
|
||||
---
|
||||
|
||||
### Configuration & Serialization
|
||||
|
||||
| Technology | Version | Purpose | Rationale |
|
||||
|------------|---------|---------|-----------|
|
||||
| ZIO Config | 4.0.5 | Configuration loading | YAML/HOCON support, type-safe config derivation |
|
||||
| ZIO Schema | 1.7.5 | Schema derivation | JSON/Protobuf/Avro codecs, form field validation |
|
||||
| ZIO JSON | 0.7.x | JSON serialization | Schema-based, high performance |
|
||||
|
||||
**Confidence:** HIGH - Verified via [ZIO Config docs](https://zio.dev/zio-config/), [ZIO Schema docs](https://zio.dev/zio-schema/)
|
||||
|
||||
**Why ZIO Schema is critical for CMF:**
|
||||
- **YAML-driven forms:** Schema can describe form fields, validation rules
|
||||
- **Automatic codec derivation:** Plugin data models get JSON APIs for free
|
||||
- **Migration support:** Schema evolution for plugin updates
|
||||
|
||||
```scala
|
||||
libraryDependencies ++= Seq(
|
||||
"dev.zio" %% "zio-config" % "4.0.5",
|
||||
"dev.zio" %% "zio-config-yaml" % "4.0.5",
|
||||
"dev.zio" %% "zio-config-magnolia" % "4.0.5", // Derivation
|
||||
"dev.zio" %% "zio-schema" % "1.7.5",
|
||||
"dev.zio" %% "zio-schema-json" % "1.7.5",
|
||||
"dev.zio" %% "zio-json" % "0.7.45"
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Logging & Observability
|
||||
|
||||
| Technology | Version | Purpose | Rationale |
|
||||
|------------|---------|---------|-----------|
|
||||
| ZIO Logging | 2.5.3 | Structured logging | ZIO-native, SLF4J bridge for Java libraries |
|
||||
| ZIO Metrics | (ZIO Core) | Metrics collection | Built into ZIO 2.1, no separate library needed |
|
||||
|
||||
**Confidence:** HIGH - Verified via [ZIO Logging releases](https://github.com/zio/zio-logging/releases)
|
||||
|
||||
```scala
|
||||
libraryDependencies ++= Seq(
|
||||
"dev.zio" %% "zio-logging" % "2.5.3",
|
||||
"dev.zio" %% "zio-logging-slf4j2-bridge" % "2.5.3" // For Java libs
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Testing
|
||||
|
||||
| Technology | Version | Purpose | Rationale |
|
||||
|------------|---------|---------|-----------|
|
||||
| ZIO Test | 2.1.24 | Core testing | Part of ZIO core, property-based testing, test containers |
|
||||
| TestContainers | 0.41.x | Integration tests | PostgreSQL containers for database tests |
|
||||
|
||||
**Confidence:** HIGH - ZIO Test is part of ZIO Core
|
||||
|
||||
```scala
|
||||
libraryDependencies ++= Seq(
|
||||
"dev.zio" %% "zio-test" % "2.1.24" % Test,
|
||||
"dev.zio" %% "zio-test-sbt" % "2.1.24" % Test,
|
||||
"com.dimafeng" %% "testcontainers-scala-postgresql" % "0.41.4" % Test
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Build & Tooling
|
||||
|
||||
| Technology | Version | Purpose | Rationale |
|
||||
|------------|---------|---------|-----------|
|
||||
| Mill | 1.0.0+ | Build tool | 3-7x faster than sbt, simpler mental model, better IDE support |
|
||||
| Scala CLI | 1.x | Scripts & utilities | Quick prototyping, migration scripts |
|
||||
|
||||
**Confidence:** HIGH - Verified via [Mill 1.0.0 announcement](https://mill-build.org/blog/13-mill-build-tool-v1-0-0.html)
|
||||
|
||||
**Why Mill over sbt:**
|
||||
- **Performance:** Native launcher starts in ~100ms, 3-7x faster builds
|
||||
- **Simplicity:** Standard Scala OOP model, not sbt's task/setting matrix
|
||||
- **IDE support:** Jump-to-definition works, easier debugging
|
||||
- **Zero-install JVM:** Launcher can download required JDK
|
||||
- **Module scaling:** Handles hundreds of modules without slowdown (critical for plugin ecosystem)
|
||||
|
||||
**sbt considered but rejected:**
|
||||
- Larger ecosystem BUT complex mental model
|
||||
- Plugin developers would need to understand sbt deeply
|
||||
- Performance degrades with many subprojects (each plugin = subproject)
|
||||
|
||||
**Mill build structure for plugins:**
|
||||
```scala
|
||||
// build.mill
|
||||
import mill._
|
||||
import mill.scalalib._
|
||||
|
||||
object core extends ScalaModule {
|
||||
def scalaVersion = "3.3.7"
|
||||
// Core CMF
|
||||
}
|
||||
|
||||
object plugins extends Module {
|
||||
object blog extends ScalaModule {
|
||||
def moduleDeps = Seq(core)
|
||||
// Blog plugin
|
||||
}
|
||||
object user extends ScalaModule {
|
||||
def moduleDeps = Seq(core)
|
||||
// User plugin
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Deployment
|
||||
|
||||
| Technology | Version | Purpose | Rationale |
|
||||
|------------|---------|---------|-----------|
|
||||
| Besom | 0.5.0 | Pulumi Scala SDK | Pure Scala IaC, type-safe infrastructure |
|
||||
| Docker | Latest | Containerization | Standard deployment format |
|
||||
| GraalVM Native Image | Optional | Native binaries | CLI tools, faster startup for serverless |
|
||||
|
||||
**Confidence:** MEDIUM - Besom verified via [GitHub](https://github.com/VirtusLab/besom), production patterns need validation
|
||||
|
||||
**Why Besom for Pulumi:**
|
||||
- Pure Scala 3, not Java SDK wrapper
|
||||
- Type-safe infrastructure definitions
|
||||
- Functional, lazy evaluation semantics
|
||||
- Can share types with application code
|
||||
|
||||
```scala
|
||||
// Besom dependency (via Scala CLI or Mill)
|
||||
//> using dep org.virtuslab::besom-core:0.5.0
|
||||
//> using dep org.virtuslab::besom-aws:6.0.0
|
||||
```
|
||||
|
||||
**Docker strategy:**
|
||||
- Primary deployment target
|
||||
- Multi-stage builds: compile with Mill, run with JRE
|
||||
- Consider distroless base images for security
|
||||
|
||||
**GraalVM Native Image:**
|
||||
- For CLI tools (scaffolding, migrations)
|
||||
- Faster cold starts
|
||||
- NOT for main server (reflection in Quill, ZIO may have issues)
|
||||
|
||||
---
|
||||
|
||||
## Complete Dependency Overview
|
||||
|
||||
```scala
|
||||
// build.mill - Mill build file
|
||||
import mill._
|
||||
import mill.scalalib._
|
||||
|
||||
trait SummerCMSModule extends ScalaModule {
|
||||
def scalaVersion = "3.3.7"
|
||||
|
||||
override def ivyDeps = Agg(
|
||||
// ZIO Core
|
||||
ivy"dev.zio::zio:2.1.24",
|
||||
ivy"dev.zio::zio-streams:2.1.24",
|
||||
|
||||
// HTTP
|
||||
ivy"dev.zio::zio-http:3.8.1",
|
||||
|
||||
// Database
|
||||
ivy"io.getquill::quill-jdbc-zio:4.8.6",
|
||||
ivy"org.postgresql:postgresql:42.7.5",
|
||||
ivy"org.flywaydb:flyway-core:10.22.0",
|
||||
ivy"org.flywaydb:flyway-database-postgresql:10.22.0",
|
||||
|
||||
// Template
|
||||
ivy"com.lihaoyi::scalatags:0.13.1",
|
||||
|
||||
// HTMX
|
||||
ivy"com.github.eikek::htmx4s-constants:0.3.0",
|
||||
ivy"com.github.eikek::htmx4s-scalatags:0.3.0",
|
||||
|
||||
// Config & Schema
|
||||
ivy"dev.zio::zio-config:4.0.5",
|
||||
ivy"dev.zio::zio-config-yaml:4.0.5",
|
||||
ivy"dev.zio::zio-config-magnolia:4.0.5",
|
||||
ivy"dev.zio::zio-schema:1.7.5",
|
||||
ivy"dev.zio::zio-schema-json:1.7.5",
|
||||
ivy"dev.zio::zio-json:0.7.45",
|
||||
|
||||
// Logging
|
||||
ivy"dev.zio::zio-logging:2.5.3",
|
||||
ivy"dev.zio::zio-logging-slf4j2-bridge:2.5.3"
|
||||
)
|
||||
|
||||
override def testIvyDeps = Agg(
|
||||
ivy"dev.zio::zio-test:2.1.24",
|
||||
ivy"dev.zio::zio-test-sbt:2.1.24"
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## What NOT to Use
|
||||
|
||||
### Deprecated/Abandoned Libraries
|
||||
|
||||
| Library | Status | Use Instead |
|
||||
|---------|--------|-------------|
|
||||
| ZIO SQL | Deprecated | Quill |
|
||||
| ZIO JDBC | Deprecated | Quill |
|
||||
| Akka HTTP | License changed | ZIO HTTP |
|
||||
| Slick | Lightbend ecosystem | Quill |
|
||||
|
||||
### Wrong Ecosystem
|
||||
|
||||
| Library | Issue | Use Instead |
|
||||
|---------|-------|-------------|
|
||||
| http4s | Cats Effect-native | ZIO HTTP |
|
||||
| Doobie | Cats Effect-native | Quill |
|
||||
| Circe | Cats-based JSON | ZIO JSON |
|
||||
| fs2 | Cats Effect streams | ZIO Streams |
|
||||
| Cats Effect | Different effect system | ZIO |
|
||||
|
||||
### Overkill for CMF
|
||||
|
||||
| Library | Issue | Use Instead |
|
||||
|---------|-------|-------------|
|
||||
| Play Framework | Too opinionated, heavyweight | ZIO HTTP + custom routing |
|
||||
| Spring Boot | Java-centric, not idiomatic Scala | ZIO ecosystem |
|
||||
| Tapir | Adds abstraction layer we don't need | ZIO HTTP declarative endpoints |
|
||||
|
||||
### Frontend Anti-Patterns
|
||||
|
||||
| Approach | Issue | Use Instead |
|
||||
|----------|-------|-------------|
|
||||
| Full SPA | SEO problems, complex build | HTMX + progressive enhancement |
|
||||
| Alpine.js | WinterCMS's messy pattern | HTMX for simple, Vue for complex |
|
||||
| Snowboard.js | WinterCMS-specific, deprecated | HTMX |
|
||||
|
||||
---
|
||||
|
||||
## Confidence Levels Summary
|
||||
|
||||
| Area | Level | Notes |
|
||||
|------|-------|-------|
|
||||
| ZIO Core (2.1.24) | HIGH | Production-proven, official releases verified |
|
||||
| ZIO HTTP (3.8.1) | HIGH | Stable 3.x line, verified Feb 2025 release |
|
||||
| Quill (4.8.6) | HIGH | Endorsed as only maintained ZIO RDBMS library |
|
||||
| ScalaTags (0.13.1) | HIGH | Stable, well-maintained by Li Haoyi |
|
||||
| htmx4s (0.3.0) | MEDIUM | Small but functional library, may need custom ZIO HTTP integration |
|
||||
| Mill (1.0.0) | HIGH | Just hit 1.0, production-ready |
|
||||
| Besom (0.5.0) | MEDIUM | Pre-1.0 but stable-candidate, VirtusLab maintained |
|
||||
| Template strategy | MEDIUM | ScalaTags + Twirl hybrid needs validation with theme developers |
|
||||
|
||||
---
|
||||
|
||||
## Open Questions
|
||||
|
||||
### Requires Further Investigation
|
||||
|
||||
1. **Twirl vs custom template language:** Should we support Twig syntax for WinterCMS theme migration?
|
||||
|
||||
2. **htmx4s ZIO HTTP integration:** htmx4s has http4s module but not ZIO HTTP. Need to build adapter or use constants-only module.
|
||||
|
||||
3. **Plugin hot-reload:** Can Mill's watch mode + ZIO HTTP dev mode enable WinterCMS-like plugin hot-reload?
|
||||
|
||||
4. **WebSocket scaling:** Project context mentions "websockets scale poorly." ZIO HTTP has WebSocket support - research SSE as alternative for real-time features.
|
||||
|
||||
5. **GraalVM native compatibility:** Full server as native image may have issues with Quill/ZIO reflection. Validate if important for deployment.
|
||||
|
||||
6. **Datastar SDK:** ZIO HTTP 3.6+ includes Datastar SDK - evaluate as HTMX alternative for even simpler frontend patterns.
|
||||
|
||||
### Architecture Decisions Pending
|
||||
|
||||
- Plugin dependency resolution algorithm (WinterCMS uses PHP Composer-like)
|
||||
- Theme rendering pipeline (compile-time vs runtime templates)
|
||||
- Admin backend component system (Vue vs HTMX vs hybrid)
|
||||
|
||||
---
|
||||
|
||||
## Sources
|
||||
|
||||
### Official Documentation
|
||||
- [ZIO HTTP Documentation](https://zio.dev/zio-http/)
|
||||
- [ZIO Quill Getting Started](https://zio.dev/zio-quill/getting-started/)
|
||||
- [ZIO Schema Documentation](https://zio.dev/zio-schema/)
|
||||
- [ZIO Config Documentation](https://zio.dev/zio-config/)
|
||||
- [Mill Build Tool](https://mill-build.org/mill/index.html)
|
||||
- [Besom Pulumi Scala SDK](https://virtuslab.github.io/besom/)
|
||||
- [ScalaTags Documentation](https://com-lihaoyi.github.io/scalatags/)
|
||||
|
||||
### Release Pages
|
||||
- [ZIO Releases](https://github.com/zio/zio/releases) - v2.1.24
|
||||
- [ZIO HTTP Releases](https://github.com/zio/zio-http/releases) - v3.8.1
|
||||
- [Scala All Versions](https://www.scala-lang.org/download/all.html) - 3.3.7 LTS
|
||||
|
||||
### Strategy & Roadmap
|
||||
- [Ziverge: ZIO in 2025](https://www.ziverge.com/post/zio-in-2025) - Ecosystem direction
|
||||
- [Mill 1.0.0 Release](https://mill-build.org/blog/13-mill-build-tool-v1-0-0.html)
|
||||
|
||||
### Integration Examples
|
||||
- [Rock the JVM ScalaTags + HTMX Demo](https://github.com/rockthejvm/scalatags-htmx-demo)
|
||||
- [htmx4s GitHub](https://github.com/eikek/htmx4s)
|
||||
- [ZIO Flyway DB Migrator](https://github.com/DenisNovac/zio-flyway-db-migrator)
|
||||
|
||||
---
|
||||
|
||||
*Stack research completed: 2026-02-04*
|
||||
Reference in New Issue
Block a user