9.0 KiB
9.0 KiB
SummerCMS Technology Stack
Philosophy
Direct-style Scala 3 on JDK 21 virtual threads. No monadic effect systems (no ZIO, no Cats Effect). Virtual threads make blocking IO cheap, so you write normal imperative-looking code that scales. This is the simplest possible modern Scala stack.
Core Stack
| Layer | Technology | Why |
|---|---|---|
| Language | Scala 3.3+ LTS | VirtusLab maintains the compiler. Scala 3 has cleaner syntax, given/using for DI, extension methods, enums, union types |
| Runtime | JDK 21+ with Project Loom | Virtual threads = millions of lightweight threads, no async/callback hell |
| HTTP Server | Tapir + JDK HttpServer | Tapir gives type-safe endpoint definitions with auto-generated OpenAPI docs. JDK HttpServer with Executors.newVirtualThreadPerTaskExecutor() is the lightest possible server |
| Concurrency | Ox | Structured concurrency, Go-like channels, error supervision, retries, rate limiting. Built on virtual threads |
| Database | Magnum | Scala 3 native, typesafe SQL interpolator, auto-generated CRUD, no dependencies, works with any JDBC database |
| Migrations | Flyway | Industry standard, JVM-native, works with any JDBC database |
Supporting Libraries
| Concern | Library | Notes |
|---|---|---|
| JSON | uPickle or Circe | Serialization/deserialization for API + config |
| Config | Typesafe Config (HOCON) | Industry standard JVM config, supports YAML-like nesting, env var substitution |
| Logging | SLF4J + Logback | Standard JVM logging — used directly, no wrapper needed |
| Caching | Caffeine (in-memory) + Jedis/Lettuce (Redis) | Caffeine is the fastest JVM cache; Redis for distributed |
| Hashing | jBCrypt + JDK crypto | Password hashing + general encryption |
| Jakarta Mail | Standard JVM email | |
| Admin Frontend | Vue.js 3 + TypeScript | SPA admin panel consuming Tapir API |
| OpenAPI codegen | Tapir -> OpenAPI -> openapi-typescript | Auto-generated TS types for Vue frontend |
| Template Engine | Scalate (Mustache/SSP) or Twirl | Server-rendered public-facing themes |
| CLI | Decline or Scopt | Console command parsing for scaffolding |
| Testing | MUnit or ScalaTest + Tapir test utils | Unit + integration testing |
| Build (project) | sbt | Multi-module build for the subprojects |
| Build (scripts) | scala-cli | Quick scripts, prototyping, dev tooling. VirtusLab maintains it |
Module Mapping: Laravel Illuminate -> SummerCMS
Each module = separate sbt subproject, publishable independently (like Illuminate packages).
| Illuminate Package | SummerCMS Module | Implementation Approach |
|---|---|---|
| Container | summer-backpack |
Scala 3 given/using for compile-time DI + lightweight runtime registry for plugins |
| Contracts | summer-pact |
Scala traits — all public APIs defined here |
| Support | summer-towel |
Extension methods, utility types, base classes |
| Config | summer-compass |
Typesafe Config wrapper, HOCON files, standardized access across all modules |
| Events | summer-festival |
Simple event bus with typed events + Ox channels for async |
| Http | summer-surf |
Tapir endpoint definitions, request/response wrappers, routing (Tapir endpoints are type-safe routes) |
| Database | summer-lagoon |
Magnum repos + case class models + query builder + pagination |
| Auth | summer-bouncer |
JWT tokens (for API) + session cookies (for admin), guards as traits, session management |
| Validation | summer-lifeguard |
Compile-time via Scala types + runtime rules engine (inspired by fields.yaml) |
| Cache | summer-cooler |
Caffeine + Redis, driver-based via trait |
| Queue | summer-conga |
Ox channels + virtual threads for workers, persistent queue via DB or Redis |
summer-postcard |
Jakarta Mail wrapper with template support | |
| Console | summer-bonfire |
CLI command framework for scaffolding (summer create:plugin, etc.) |
| Filesystem | summer-sandcastle |
java.nio.file + pluggable storage providers (S3, etc.) via driver trait |
| Translation | summer-phrasebook |
i18n with HOCON/JSON locale files |
| View | summer-sunset |
Template engine for admin panel rendering |
Illuminate Packages Not Ported (and why)
| Illuminate Package | Why not needed | Where it lives instead |
|---|---|---|
| Pipeline | Function composition is native to Scala (f andThen g). Laravel needs a Pipeline class because PHP lacks first-class functions. In Scala this is a one-liner, not a module. |
Inline wherever needed |
| Routing | Tapir endpoint definitions ARE routes — defining an endpoint and defining a route is the same thing. No separate routing layer needed. | Merged into summer-surf (http) |
| Session | For an API-first CMS with JWT, sessions are thin — only needed for admin panel cookies. Not enough to justify a standalone module. | Merged into summer-bouncer (auth) |
| Log | SLF4J is already a logging facade. Wrapping a facade with another facade adds zero value. Just use SLF4J + Logback directly. | Direct SLF4J usage |
| Collections | Scala stdlib collections are already excellent — List, Map, Seq, Vector with map, filter, fold, etc. No wrapper needed. |
Scala stdlib |
| Pagination | A paginator is a case class + a few helper methods. Too small for a standalone module. | Merged into summer-lagoon (database) |
Plugin & Theme System
Plugins
Each plugin = a directory with a Plugin.scala descriptor (same lifecycle as WinterCMS).
- Descriptor declares: models, controllers, components, console commands, event listeners, navigation items
- Plugins discovered at boot via classpath scanning or manifest
- Plugins can extend other plugins' models via Scala 3 extension methods + event hooks
- Plugin lifecycle:
register()->boot()
Components
- Components are defined in plugins and placed in theme templates (like WinterCMS)
- Each component = a class with
onRun(), properties, and a partial template - Components handle their own data fetching and expose variables to templates
- Registered via plugin descriptor, auto-discovered by the theme engine
Themes
- Theme = directory of templates + assets + config
- Templates rendered server-side (Scalate/Twirl) or served as SPA shell
- Components (from plugins) can be placed in theme templates
Admin Backend
- Tapir endpoints serve as the admin API
- YAML/JSON-driven forms — same concept as WinterCMS
fields.yaml/columns.yaml:- Plugin defines
fields.yamlfor model forms - Backend returns form schema as JSON, Vue frontend renders it
- Field types: text, textarea, dropdown, relation, repeater, etc.
- Plugin defines
- Admin frontend: Full SPA in Vue.js 3 + TypeScript — consumes Tapir-generated typed API
- TypeScript types auto-generated from Tapir OpenAPI spec
- Vue components for form builder, list columns, relation managers, etc.
Frontend-Backend Communication
- Tapir-generated typed API — all communication is via typed JSON endpoints
- OpenAPI spec auto-generated from Tapir endpoint definitions
- TypeScript client types generated from OpenAPI for the Vue admin SPA
- Public-facing sites can use the same API (headless mode) or server-rendered templates
- Headless mode: admin panel + API controllers serve as a superuser data presentation layer, frontend is fully decoupled
Scaffolding Commands
summer create:plugin vendor.pluginname
summer create:model vendor.pluginname ModelName
summer create:controller vendor.pluginname ControllerName
summer create:component vendor.pluginname ComponentName
summer create:command vendor.pluginname CommandName
summer create:job vendor.pluginname JobName
summer create:migration vendor.pluginname description
Project Structure
summercms/
build.sbt # Multi-project sbt build
modules/
summer-backpack/ # DI container + plugin registry
summer-pact/ # Contracts (traits)
summer-towel/ # Support utilities
summer-compass/ # Config
summer-festival/ # Events
summer-surf/ # HTTP + routing (Tapir)
summer-lagoon/ # Database + pagination (Magnum)
summer-bouncer/ # Auth + sessions
summer-lifeguard/ # Validation
summer-cooler/ # Cache
summer-conga/ # Queue (Ox)
summer-postcard/ # Mail
summer-bonfire/ # Console / CLI
summer-sandcastle/ # Filesystem + storage providers
summer-phrasebook/ # Translation / i18n
summer-sunset/ # View / templates
app/ # Full CMS application (depends on all modules)
summer-cms/ # Assembled CMS with admin panel
plugins/ # Example/core plugins
summer-plugin-user/
summer-plugin-blog/
summer-plugin-pages/