docs(11.2): reshape into the Alpha 0.1 landing page and split the newsletter into 11.3

This commit is contained in:
Jakub Zych
2026-10-01 14:33:50 +02:00
parent 79116a2e03
commit 59122d53c1
7 changed files with 446 additions and 15 deletions

View File

@@ -568,28 +568,50 @@ Plans:
**Wave 7** *(gap closure, blocked on Wave 6 completion)*
- [x] 11.1-07-PLAN.md — Checkers fail closed: AST fence discovery (nested and README src= refused, captions only on verified fences, Go-lexer aliases need src=), go test roots and go/build membership for src= targets, `go doc -c`, env/flag/go run/bin command forms; planted fixtures and unit tests for every hole
### Phase 11.2: Ready to share: summercms.io website and newsletter plugin (INSERTED)
### Phase 11.2: summercms.io Alpha 0.1 landing page on SummerCMS (INSERTED)
**Goal:** summercms.io is ready to share publicly. A fresh Nuxt 4 website in English and Polish runs on a SummerCMS binary. Visitors subscribe for updates through the initial Go version of the Golem15 Newsletter plugin, which confirms each email by double opt-in. The Phase 11.1 docs are served at `/docs` and linked from the site.
**Goal:** summercms.io replaces its "Under construction" page with the Alpha 0.1 landing page from the claude.ai/design handoff. The page is a Nuxt 4 static site, English only and i18n-ready, embedded in and served by a SummerCMS binary that also serves the Phase 11.1 docs at `/docs`. It deploys behind nginx with supervisor using documented steps. This is a quick phase of 2-3 plans; newsletter signup moved to Phase 11.3.
**Requirements**: TBD
**Depends on:** Phase 11.1
**Repos:** four new repos under `git.golem15.com/golem15/`: (1) `sm-summercms-app`, the root app that builds the binary and wires the plugins; (2) `vue-summercms-app`, the Nuxt 4 site, held inside the root app; (3) `sm-summercms-plugin`, the site plugin that serves the embedded site at `/`, the docs at `/docs` and any site-specific data, the WinterCMS site-plugin pattern; (4) `sm-newsletter-plugin`, the reusable signup plugin. `summercms.go` changes only if the site needs a framework feature that is missing.
**Repos:** three new repos under `git.golem15.com/golem15/`: (1) `sm-summercms-app`, the root app that builds the binary and wires the plugins; (2) `vue-summercms-app`, the Nuxt 4 site, held inside the root app; (3) `sm-summercms-plugin`, the site plugin that serves the embedded site at `/`, the docs at `/docs` and any site-specific data, the WinterCMS site-plugin pattern. `summercms.go` changes only if the site needs a framework feature that is missing.
**Naming convention:** the same as OctoberCMS (`oc-`) and WinterCMS (`wn-`), with the `sm-` prefix: root app `sm-<name>-app`, Vue frontend `vue-<name>-app`, plugin `sm-<name>-plugin`, theme `sm-<name>-theme`. The Go package inside a plugin keeps its plain name (`newsletter`). The meta root `summercms.io` and the framework `summercms.go` keep their names. `fonoteka.go` becomes `sm-fonoteka-app`.
**Port source:** Golem15.Newsletter, `github.com/golem15com/wn-newsletter-plugin`, checked out at `/media/nvme/dev/golem15/horoskopia.eu/plugins/golem15/newsletter`. The PHP plugin is work in progress. Its audience comes from registered users (it requires `Golem15.User`), and its only public routes are unsubscribe. It has no public subscriber model or signup widget, so this phase adds those in Go. The PHP original is not changed.
**Design source:** `.planning/phases/11.2-ready-to-share-summercms-io-website-and-newsletter-plugin/design/` (handoff `README.md`, `SummerCMS Landing.dc.html`, `assets/sun-crop.png`). The design is high fidelity: colors, type, spacing and copy are final. The handoff supersedes 11.2-CONTEXT D-06 (English only for now), D-08, D-10 and D-11 (no signup, "Alpha 0.1 is out", Source links allowed).
**Success Criteria** (what must be TRUE):
1. The newsletter plugin repo exists and ships an initial stub: a public signup endpoint (validated, honeypot and rate-limited, with required consent), double opt-in confirmation mail with a tokenized confirm link, a welcome mail, unsubscribe, and subscriber add, edit and delete in the admin SPA. Composing and sending newsletters is out of scope.
2. The website repo exists and ships a prerendered English and Polish summercms.io landing page with a signup widget. The widget calls the plugin's API on the same origin and covers the pending, confirmed and error states.
3. The Phase 11.1 docs are served at `summercms.io/docs`, the landing page links to them, and every link resolves.
4. The site deploys as one binary with the Nuxt build and the docs embedded, with documented build and run steps.
1. `nuxt generate` in `vue-summercms-app` produces the landing page matching the handoff: sticky header with scroll-spy, hero, the Why, Features, From WinterCMS and Get started sections, a terminal card with a working Copy button, and a footer. It is responsive down to phone width, and the section links hide at 720px or less.
2. One `sm-summercms-app` binary embeds the Nuxt output and the Phase 11.1 docs build. It serves `/` and `/docs` with indexable responses (no admin `noindex`/CSP) and with cache headers: immutable for hashed assets, no-cache for HTML.
3. Every link on the page resolves, including the eight feature-tile `/docs/...` links and the WinterCMS concept-map link. They are verified against the built docs, not assumed.
4. A scripted build (`nuxt generate`, then `summer docs:build`, then `go build`) and a `DEPLOY.md` in the root app cover building, uploading, a supervisor program config, and an nginx site config (TLS, proxy to the binary, gzip). Following it on a clean server brings the site up.
5. The new Go code has unit tests, delivered in the phase's last plan.
**Context:** `.planning/phases/11.2-ready-to-share-summercms-io-website-and-newsletter-plugin/11.2-CONTEXT.md`
**Context:** `.planning/phases/11.2-ready-to-share-summercms-io-website-and-newsletter-plugin/11.2-CONTEXT.md` (D-01 to D-05, D-07, D-09 and D-12 still apply; see its supersession note)
**Plans:** 0 plans
Plans:
- [ ] TBD (run /gsd-plan-phase 11.2 to break down)
### Phase 11.3: Newsletter plugin and signup on summercms.io (INSERTED)
**Goal:** Visitors to summercms.io subscribe for updates through the initial Go version of the Golem15 Newsletter plugin, which confirms each email by double opt-in. The signup widget is added to the Phase 11.2 landing page, and the site gains Polish alongside English.
**Requirements**: TBD
**Depends on:** Phase 11.2
**Repos:** `sm-newsletter-plugin` (new, under `git.golem15.com/golem15/`, Go package `newsletter`), plus changes to the Phase 11.2 repos (`vue-summercms-app` for the widget and Polish locale, `sm-summercms-app` to wire the plugin). `summercms.go` changes only if a framework feature is missing.
**Port source:** Golem15.Newsletter, `github.com/golem15com/wn-newsletter-plugin`, checked out at `/media/nvme/dev/golem15/horoskopia.eu/plugins/golem15/newsletter`. The PHP plugin is work in progress. Its audience comes from registered users (it requires `Golem15.User`), and its only public routes are unsubscribe. It has no public subscriber model or signup widget, so this phase adds those in Go. The PHP original is not changed.
**Success Criteria** (what must be TRUE):
1. The newsletter plugin repo exists and ships an initial stub: a public signup endpoint (validated, honeypot and rate-limited, with required consent), double opt-in confirmation mail with a tokenized confirm link, a welcome mail, unsubscribe, and subscriber add, edit and delete in the admin SPA. Composing and sending newsletters is out of scope.
2. The landing page has a signup widget that calls the plugin's API on the same origin and covers the pending, confirmed and error states, with localized result pages.
3. The site is prerendered in English and Polish, and the confirmation and welcome mails follow the subscriber's locale.
4. The new code has unit tests, delivered in the phase's last plan.
**Context:** decisions D-13 to D-22 in `.planning/phases/11.2-ready-to-share-summercms-io-website-and-newsletter-plugin/11.2-CONTEXT.md` (carried over from the original 11.2 discussion).
**Plans:** 0 plans
Plans:
- [ ] TBD (run /gsd-plan-phase 11.3 to break down)
### Phase 12: Płytarium API — Collections and Albums
**Goal**: Collections and Albums endpoints are ported with byte-compatible request/response shapes, including active-context switching, editor invitations, ratings, reservations, cover handling and search.
@@ -678,7 +700,8 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 →
| 10. Admin Vue SPA | 5/5 | Complete | 2026-09-27 |
| 11. Jobs, realtime and search infrastructure | 8/8 | In Progress| |
| 11.1. SummerCMS documentation for humans and AI agents | 7/7 | In Progress| |
| 11.2. Ready to share: summercms.io website and newsletter plugin | 0/TBD | Not started | - |
| 11.2. summercms.io Alpha 0.1 landing page on SummerCMS | 0/TBD | Not started | - |
| 11.3. Newsletter plugin and signup on summercms.io | 0/TBD | Not started | - |
| 12. Płytarium API — Collections and Albums | 0/TBD | Not started | - |
| 13. Płytarium API — wishlist, notifications, CSV, credentials, public routes | 0/TBD | Not started | - |
| 14. Domain jobs and external integrations | 0/TBD | Not started | - |

View File

@@ -5,12 +5,12 @@ current_phase: "11.1"
current_phase_name: SummerCMS documentation for humans and AI agents (INSERTED)
status: verifying
stopped_at: Completed 11.1-07-PLAN.md
last_updated: "2026-10-01T06:58:29.387Z"
last_updated: "2026-10-01T11:49:35.390Z"
last_activity: 2026-10-01
last_activity_desc: Phase 11.1 execution started
state_head: ce5dcec7e4e0733b07676b36abb26188d7150501
state_head: 79116a2e036d36614819ed60276886f62556235b
progress:
total_phases: 19
total_phases: 20
completed_phases: 9
total_plans: 93
completed_plans: 93
@@ -158,6 +158,8 @@ Progress: [██████░░░░] 60%
- Phase 10.2 inserted after Phase 10: Nest framework packages under modules and write run docs (URGENT)
- Phase 11.1 inserted after Phase 11: SummerCMS documentation for humans and AI agents, modelled on wintercms.com/docs; after core framework, before Płytarium API port
- Phase 11.2 inserted after Phase 11.1: Ready to share: summercms.io website (sm-summercms-app + vue-summercms-app), sm-newsletter-plugin stub with double opt-in, 11.1 docs at /docs
- Phase 11.2 edited: edited fields: title, goal, repos, design source, success_criteria — reshaped into the Alpha 0.1 landing page (Nuxt 4 on SummerCMS, nginx + supervisor deploy); newsletter moved to 11.3
- Phase 11.3 inserted after Phase 11.2: Newsletter plugin and signup on summercms.io (split out of the original 11.2)
### Decisions

View File

@@ -0,0 +1,182 @@
# Handoff: SummerCMS Alpha 0.1 Landing Page
## Overview
A single-page marketing landing for **summercms.io**, launching with Alpha 0.1. It has a sticky header with section anchors and a link to `/docs`, a hero, four content sections (Why, Features, From WinterCMS, Get started) and a footer. It replaces the current "Under construction" page and keeps its navy, yellow and sun identity.
## About the Design Files
`SummerCMS Landing.dc.html` is a **design reference built in HTML**. It shows the intended look and behavior and is not production code. Recreate it in the target site's stack. If the site has no stack yet, a static-site setup (Astro, Hugo, or a plain HTML/CSS page) is enough: the page is static apart from two small scripts (scroll-spy and copy-to-clipboard). The file loads a design-runtime script (`support.js`) for previewing; ignore it.
## Fidelity
**High-fidelity.** Colors, type, spacing and copy are final. Match them exactly.
## Global
- Page background `#233148`. Text `#e9edf3`.
- Fonts: **Roboto** (300/400/500/700) and **Roboto Mono** (400/500), from Google Fonts.
- `html { scroll-behavior: smooth; scroll-padding-top: 72px }` so anchor jumps clear the sticky header.
- Content container: `max-width: 1120px; margin: 0 auto; padding: 0 24px`.
- Section vertical padding: `96px` top and bottom.
- Default link color `#f5c55a`; hover `#fbe3a6`. Selection: background `#f5c55a`, text `#1d2940`.
## Sections
### 1. Header (sticky)
- `position: sticky; top: 0; z-index: 10`. Height 64px. Background `rgba(29,41,64,0.82)` with `backdrop-filter: blur(12px)`. Bottom border `1px solid rgba(255,255,255,0.07)`.
- Row is flex, `align-items: center`, `gap: 16px`. Logo, the "ALPHA 0.1" pill and the Docs button all have `flex-shrink: 0` and `white-space: nowrap`.
- **Logo** (links to `#top`): a 30px sun icon (masked to a circle, scaled 1.35) next to the wordmark "Summer" + "CMS". Roboto 700, 18px, letter-spacing -0.01em. "Summer" `#fff`, "CMS" `#fbd77e`.
- **Pill** "ALPHA 0.1": 11px/500, letter-spacing 0.12em, color `#f5c55a`, border `1px solid rgba(245,197,90,0.35)`, radius 999px, padding 3px 9px.
- **Section links**: Why `#why` · Features `#features` · From WinterCMS `#winter` · Get started `#start`.
- Right-aligned in a `flex: 1; min-width: 0; overflow-x: auto` wrapper; the inner row has `margin-left: auto`.
- Each link: 14px/500, padding 8px 12px, radius 999px, color `#c5ccd6`.
- Active link: color `#f5c55a`, background `rgba(245,197,90,0.1)`.
- **Hidden at viewport ≤ 720px.** Below that width the header shows only logo, pill and Docs.
- **Docs button** → `/docs`: label "Docs →". Background `#f5c55a`, text `#1d2940`, 14px/500, padding 9px 16px, radius 999px. Hover background `#fbd77e`.
### 2. Hero (`#top`)
- Padding 120px 24px 128px. Centered column, `text-align: center`, `overflow: hidden`.
- **Rays** (behind everything, can be turned off): an absolutely positioned layer at `inset: -40% -20%`.
- `background: repeating-conic-gradient(from 0deg at 50% 50%, rgba(255,255,255,0.035) 0deg 7deg, transparent 7deg 15deg)`
- `mask: radial-gradient(circle, #000 10%, transparent 62%)`
- **Glow**: a 520px circle centered 210px from the top, `radial-gradient(circle, rgba(245,197,90,0.16), transparent 60%)`.
- **Sun badge**: 180px circle with border `1px solid rgba(255,255,255,0.12)` and background `#29344a`, containing the sun image.
- **H1** "Summer" + "CMS": `clamp(44px, 7vw, 76px)`, weight 700, line-height 1, letter-spacing -0.02em, margin-top 28px.
- "Summer" is `#fff`.
- "CMS" uses a gradient text fill: `linear-gradient(180deg, #fde9b4, #f5c55a)`.
- **Tagline** "A new dawn in content management": `clamp(18px, 2.2vw, 22px)`, weight 300, color `#c5ccd6`, margin-top 16px.
- **Description**: max-width 600px, 17px, line-height 1.6, color `#a3adbd`, margin-top 24px. Copy: "A content management framework for Go, inspired by WinterCMS. Plugins, the admin SPA and console commands compile into a single binary."
- **CTAs**: margin-top 40px, flex row, gap 12px, wraps on narrow screens.
- Primary "Read the docs" → `/docs`: background `#f5c55a`, text `#1d2940`, 15px/500, padding 14px 26px, pill shape. Hover background `#fbd77e`.
- Secondary "Alpha 0.1 is out" → `#start`: 8px `#f5c55a` dot before the label. Background `rgba(255,255,255,0.06)`, border `1px solid rgba(255,255,255,0.14)`, padding 13px 24px. Hover background `rgba(255,255,255,0.1)`.
### Section heading pattern (used in every content section)
- Eyebrow: 12px/500, letter-spacing 0.16em, uppercase, `#f5c55a`.
- H2: `clamp(30px, 4vw, 42px)`, weight 700, line-height 1.15, letter-spacing -0.015em, `#fff`, margin-top 12px.
### 3. Why (`#why`)
- Eyebrow "WHY SUMMER". H2 "What you tested is exactly what you deploy." (max-width 720px).
- Card grid: `repeat(auto-fit, minmax(260px, 1fr))`, gap 20px, margin-top 48px.
- Cards: background `#29344a`, border `1px solid rgba(255,255,255,0.08)`, radius 16px, padding 28px.
- Number: Roboto Mono 13px, `#f5c55a`.
- Title: 20px/500, `#fff`, margin 16px 0 8px.
- Body: 15px, line-height 1.6, `#a3adbd`.
- Card copy:
1. **One binary**: "Plugins are Go packages compiled in at build time. Nothing is scanned, loaded or installed at runtime."
2. **YAML-driven admin**: "Describe lists and forms in `fields.yaml` and `columns.yaml`. An embedded SPA renders them." The file names use inline code: Roboto Mono 13px, `#e9edf3`.
3. **Headless by design**: "A JSON API declared route by route, plus realtime channels. Build the public site in whatever frontend you like."
### 4. Features (`#features`)
- Full-bleed band: background `#1f2b42`, top and bottom borders `1px solid rgba(255,255,255,0.07)`.
- Eyebrow "WHAT'S IN THE BOX". H2 "The services a content app needs."
- Grid: `repeat(auto-fill, minmax(240px, 1fr))`. The 1px dividers come from `gap: 1px` over a `rgba(255,255,255,0.08)` grid background. Outer border is the same color, radius 16px, `overflow: hidden`.
- Each tile is a link: background `#1f2b42`, padding 24px, flex column, gap 6px. Hover background `#253350`.
- Title: 16px/500, `#e9edf3`.
- Body: 14px, line-height 1.5, `#a3adbd`.
| Title | Body | Link |
|---|---|---|
| Admin SPA | Embedded in the binary, driven by each plugin's YAML. | /docs/backend/admin-spa |
| Models & migrations | GORM structs with fill, validation and pagination helpers. | /docs/database/models |
| Routing & auth | Route groups, named middleware, tokens and OAuth. | /docs/services/routing |
| Queued jobs | Dispatched inside the caller's transaction. | /docs/services/jobs |
| Realtime | Broadcast model changes to subscribed clients. | /docs/services/realtime |
| Search | Searchable models, synced after commit. | /docs/services/search |
| Mail & push | Plugin mail templates and push notifications. | /docs/services/mail |
| Console | Scaffolding, scheduler, workers and your own commands. | /docs/console/introduction |
*Doc URLs were derived from the docs folder structure. Confirm them against the built docs site.*
### 5. From WinterCMS (`#winter`)
- Two columns: `repeat(auto-fit, minmax(300px, 1fr))`, gap 48px, `align-items: start`.
- **Left column**
- Eyebrow "COMING FROM WINTERCMS". H2 "Same shape. Compiled and typed."
- Paragraph (16px, line-height 1.65, `#a3adbd`, margin-top 20px): "Plugins still register and boot, require each other, ship migrations and admin YAML. A plugin ports file by file."
- Link "See the full concept map →" (15px/500) → `/docs/setup/coming-from-wintercms`.
- **Right column: concept table**
- Container: background `#29344a`, border `rgba(255,255,255,0.08)`, radius 16px.
- Header row "WINTERCMS | SUMMERCMS": 12px/500, letter-spacing 0.12em, `#8a94a3`.
- Rows: grid `1fr 1.3fr`, padding 14px 20px, Roboto Mono 13px, divider `rgba(255,255,255,0.06)`. Left cell `#a3adbd`, right cell `#fbe3a6`.
- Row content:
| WinterCMS | SummerCMS |
|---|---|
| Plugin.php | party.Plugin |
| version.yaml + updates/ | pact.HasMigrations |
| Eloquent models | GORM + lagoon |
| fields.yaml / columns.yaml | Same YAML, compiled at boot |
| routes.php | pact.HasRoutes |
| Event::listen / fire | festival.Bus |
| Artisan commands | bonfire.Command |
### 6. Get started (`#start`)
- Full-bleed band: background `#1f2b42`, top border `rgba(255,255,255,0.07)`.
- Two columns, same grid as the WinterCMS section, `align-items: center`.
- **Left column**
- Eyebrow "GET STARTED". H2 "Build your first app."
- Requirement chips "Go 1.27" and "PostgreSQL 16": 13px, `#c5ccd6`, background `rgba(255,255,255,0.06)`, border `rgba(255,255,255,0.1)`, pill shape, padding 6px 12px.
- Note: "Alpha 0.1 is for early adopters. APIs may change before 1.0."
- Buttons:
- "Installation guide" (primary style) → `/docs/setup/installation`.
- "Source" (outline style) → `https://git.golem15.com/golem15/summercms`.
- **Right column: terminal card**
- Background `#18223a`, border `rgba(255,255,255,0.08)`, radius 16px.
- Title bar: label "terminal" (Roboto Mono 12px, `#8a94a3`) and a **Copy** button (12px/500, `#c5ccd6`, background `rgba(255,255,255,0.06)`, border `rgba(255,255,255,0.1)`, radius 6px, padding 5px 10px).
- Body: padding 22px 20px, Roboto Mono 14px, line-height 1.9.
- **Each line is its own block element.** Comments are `#8a94a3`. The `$ ` prompt is `#f5c55a`. A 16px gap separates the two groups.
```
# install the summer CLI
$ go install ./cmd/summer
# build and run the example app
$ cd examples/hello
$ summer build
$ ./bin/hello greeter:hello
```
### 7. Footer
- Top border `rgba(255,255,255,0.07)`. Padding 32px 24px. 13px, `#8a94a3`.
- Left: "© 2026 SummerCMS. Something bright is here."
- Right links (`#a3adbd`, hover `#f5c55a`, gap 20px):
- Docs → `/docs`
- Source → `https://git.golem15.com/golem15/summercms`
- Back to top ↑ → `#top`
## Interactions & Behavior
- **Scroll-spy**: on window scroll, the active section is the last of `why`, `features`, `winter`, `start` whose top is less than 140px from the viewport top. That link gets the active style. Above the first section, no link is active.
- **Copy button**: writes the four commands (without `$` or comments) to the clipboard. The label changes to "Copied" for 1.5s, then reverts.
- **Responsive**: every grid uses auto-fit/auto-fill and collapses to one column on its own. Section links hide at ≤ 720px. Hero type scales with `clamp()`.
- **Transitions**: none are specified. Hover changes are instant; a 150ms ease on background and color is fine.
## State
- `activeSection: string`
- `copied: boolean`
- `isWide: boolean` (matchMedia `min-width: 721px`)
The prototype also has two config flags: `showRays` (default true) and `scrollSpy` (default true).
## Design Tokens
| Token | Hex | Used for |
|---|---|---|
| navy-900 | `#18223a` | terminal background |
| navy-850 | `#1d2940` | header base, text on yellow |
| navy-800 | `#1f2b42` | alternate bands |
| navy-700 | `#233148` | page background |
| navy-650 | `#253350` | feature tile hover |
| navy-600 | `#29344a` | cards |
| yellow-500 | `#f5c55a` | accent |
| yellow-400 | `#fbd77e` | accent hover, "CMS" in logo |
| yellow-200 | `#fbe3a6` | link hover, code values |
| yellow-100 | `#fde9b4` | top of the "CMS" gradient |
| text | `#e9edf3` | body text |
| text-2 | `#c5ccd6` | tagline, nav links |
| text-3 | `#a3adbd` | body copy |
| text-4 | `#8a94a3` | captions, comments |
- Borders: white at 6, 7, 8, 10, 12 and 14% alpha.
- Radius: 6px (small button), 16px (cards), 999px (pills).
- Spacing in use: 4, 6, 8, 12, 16, 20, 24, 28, 32, 40, 48, 96 and 120px.
## Assets
- `assets/sun-crop.png` (180×180): **a placeholder cropped from a screenshot** of the current under-construction page. Replace it with the original sun artwork from the existing summercms.io site. A transparent PNG or SVG is best; the hero badge then provides the circle and border.
## Files
- `SummerCMS Landing.dc.html`: the full design reference.
- `assets/sun-crop.png`: the placeholder sun icon.

View File

@@ -0,0 +1,223 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700;900&family=Roboto+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
html{scroll-behavior:smooth;scroll-padding-top:72px}
body{margin:0;background:#233148;color:#e9edf3;font-family:Roboto,system-ui,sans-serif;-webkit-font-smoothing:antialiased}
a{color:#f5c55a;text-decoration:none}
a:hover{color:#fbe3a6}
::selection{background:#f5c55a;color:#1d2940}
</style>
</helmet>
<div style="min-height:100vh;background:#233148;overflow-x:hidden">
<header style="position:sticky;top:0;z-index:10;background:rgba(29,41,64,0.82);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border-bottom:1px solid rgba(255,255,255,0.07)">
<nav style="max-width:1120px;margin:0 auto;padding:0 24px;height:64px;display:flex;align-items:center;gap:16px">
<a href="#top" style="flex-shrink:0;white-space:nowrap;display:flex;align-items:center;gap:10px;color:#fff;font-weight:700;font-size:18px;letter-spacing:-0.01em">
<img src="assets/sun-crop.png" alt="" style="width:30px;height:30px;-webkit-mask-image:radial-gradient(circle,#000 52%,transparent 70%);mask-image:radial-gradient(circle,#000 52%,transparent 70%);transform:scale(1.35)">
<span>Summer<span style="color:#fbd77e">CMS</span></span>
</a>
<span style="flex-shrink:0;white-space:nowrap;font-size:11px;font-weight:500;letter-spacing:0.12em;color:#f5c55a;border:1px solid rgba(245,197,90,0.35);border-radius:999px;padding:3px 9px">ALPHA 0.1</span>
<div style="flex:1;display:flex;min-width:0;overflow-x:auto;scrollbar-width:none">
<sc-if value="{{ wide }}" hint-placeholder-val="{{ true }}">
<div style="display:flex;gap:4px;flex-wrap:nowrap;margin-left:auto">
<sc-for list="{{ navItems }}" as="n" hint-placeholder-count="4">
<a href="{{ n.href }}" style="{{ n.style }}">{{ n.label }}</a>
</sc-for>
</div>
</sc-if>
</div>
<a href="/docs" style="flex-shrink:0;white-space:nowrap;display:flex;align-items:center;gap:8px;background:#f5c55a;color:#1d2940;font-weight:500;font-size:14px;padding:9px 16px;border-radius:999px" style-hover="background:#fbd77e;color:#1d2940">Docs <span>→</span></a>
</nav>
</header>
<section id="top" data-screen-label="Hero" style="position:relative;padding:120px 24px 128px;display:flex;flex-direction:column;align-items:center;text-align:center;overflow:hidden">
<sc-if value="{{ showRays }}" hint-placeholder-val="{{ true }}">
<div style="position:absolute;inset:-40% -20%;background:repeating-conic-gradient(from 0deg at 50% 50%,rgba(255,255,255,0.035) 0deg 7deg,rgba(255,255,255,0) 7deg 15deg);-webkit-mask-image:radial-gradient(circle at 50% 50%,#000 10%,transparent 62%);mask-image:radial-gradient(circle at 50% 50%,#000 10%,transparent 62%);pointer-events:none"></div>
</sc-if>
<div style="position:absolute;left:50%;top:210px;width:520px;height:520px;transform:translate(-50%,-50%);background:radial-gradient(circle,rgba(245,197,90,0.16),transparent 60%);pointer-events:none"></div>
<div style="position:relative;width:180px;height:180px;border-radius:50%;border:1px solid rgba(255,255,255,0.12);display:flex;align-items:center;justify-content:center;background:#29344a">
<img src="assets/sun-crop.png" alt="SummerCMS sun" style="width:180px;height:180px;border-radius:50%">
</div>
<h1 style="position:relative;margin:28px 0 0;font-size:clamp(44px,7vw,76px);line-height:1;font-weight:700;letter-spacing:-0.02em;color:#fff">Summer<span style="background:linear-gradient(180deg,#fde9b4,#f5c55a);-webkit-background-clip:text;background-clip:text;color:transparent">CMS</span></h1>
<p style="position:relative;margin:16px 0 0;font-size:clamp(18px,2.2vw,22px);font-weight:300;letter-spacing:0.01em;color:#c5ccd6">A new dawn in content management</p>
<p style="position:relative;margin:24px 0 0;max-width:600px;font-size:17px;line-height:1.6;color:#a3adbd;text-wrap:pretty">A content management framework for Go, inspired by WinterCMS. Plugins, the admin SPA and console commands compile into a single binary.</p>
<div style="position:relative;margin-top:40px;display:flex;gap:12px;flex-wrap:wrap;justify-content:center">
<a href="/docs" style="background:#f5c55a;color:#1d2940;font-weight:500;font-size:15px;padding:14px 26px;border-radius:999px" style-hover="background:#fbd77e;color:#1d2940">Read the docs</a>
<a href="#start" style="display:flex;align-items:center;gap:10px;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.14);color:#e9edf3;font-weight:500;font-size:15px;padding:13px 24px;border-radius:999px" style-hover="background:rgba(255,255,255,0.1);color:#fff"><span style="width:8px;height:8px;border-radius:50%;background:#f5c55a"></span>Alpha 0.1 is out</a>
</div>
</section>
<section id="why" data-screen-label="Why" style="max-width:1120px;margin:0 auto;padding:96px 24px">
<div style="font-size:12px;font-weight:500;letter-spacing:0.16em;color:#f5c55a">WHY SUMMER</div>
<h2 style="margin:12px 0 0;max-width:720px;font-size:clamp(30px,4vw,42px);line-height:1.15;font-weight:700;letter-spacing:-0.015em;color:#fff;text-wrap:pretty">What you tested is exactly what you deploy.</h2>
<div style="margin-top:48px;display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:20px">
<div style="background:#29344a;border:1px solid rgba(255,255,255,0.08);border-radius:16px;padding:28px">
<div style="font-family:'Roboto Mono',monospace;font-size:13px;color:#f5c55a">01</div>
<h3 style="margin:16px 0 8px;font-size:20px;font-weight:500;color:#fff">One binary</h3>
<p style="margin:0;font-size:15px;line-height:1.6;color:#a3adbd;text-wrap:pretty">Plugins are Go packages compiled in at build time. Nothing is scanned, loaded or installed at runtime.</p>
</div>
<div style="background:#29344a;border:1px solid rgba(255,255,255,0.08);border-radius:16px;padding:28px">
<div style="font-family:'Roboto Mono',monospace;font-size:13px;color:#f5c55a">02</div>
<h3 style="margin:16px 0 8px;font-size:20px;font-weight:500;color:#fff">YAML-driven admin</h3>
<p style="margin:0;font-size:15px;line-height:1.6;color:#a3adbd;text-wrap:pretty">Describe lists and forms in <code style="font-family:'Roboto Mono',monospace;font-size:13px;color:#e9edf3">fields.yaml</code> and <code style="font-family:'Roboto Mono',monospace;font-size:13px;color:#e9edf3">columns.yaml</code>. An embedded SPA renders them.</p>
</div>
<div style="background:#29344a;border:1px solid rgba(255,255,255,0.08);border-radius:16px;padding:28px">
<div style="font-family:'Roboto Mono',monospace;font-size:13px;color:#f5c55a">03</div>
<h3 style="margin:16px 0 8px;font-size:20px;font-weight:500;color:#fff">Headless by design</h3>
<p style="margin:0;font-size:15px;line-height:1.6;color:#a3adbd;text-wrap:pretty">A JSON API declared route by route, plus realtime channels. Build the public site in whatever frontend you like.</p>
</div>
</div>
</section>
<section id="features" data-screen-label="Features" style="border-top:1px solid rgba(255,255,255,0.07);border-bottom:1px solid rgba(255,255,255,0.07);background:#1f2b42">
<div style="max-width:1120px;margin:0 auto;padding:96px 24px">
<div style="font-size:12px;font-weight:500;letter-spacing:0.16em;color:#f5c55a">WHAT'S IN THE BOX</div>
<h2 style="margin:12px 0 0;max-width:720px;font-size:clamp(30px,4vw,42px);line-height:1.15;font-weight:700;letter-spacing:-0.015em;color:#fff">The services a content app needs.</h2>
<div style="margin-top:48px;display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:1px;background:rgba(255,255,255,0.08);border:1px solid rgba(255,255,255,0.08);border-radius:16px;overflow:hidden">
<sc-for list="{{ features }}" as="f" hint-placeholder-count="8">
<a href="{{ f.href }}" style="display:flex;flex-direction:column;gap:6px;background:#1f2b42;padding:24px;color:#e9edf3" style-hover="background:#253350;color:#fff">
<span style="font-size:16px;font-weight:500">{{ f.title }}</span>
<span style="font-size:14px;line-height:1.5;color:#a3adbd">{{ f.body }}</span>
</a>
</sc-for>
</div>
</div>
</section>
<section id="winter" data-screen-label="From WinterCMS" style="max-width:1120px;margin:0 auto;padding:96px 24px;display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:48px;align-items:start">
<div>
<div style="font-size:12px;font-weight:500;letter-spacing:0.16em;color:#f5c55a">COMING FROM WINTERCMS</div>
<h2 style="margin:12px 0 0;font-size:clamp(30px,4vw,42px);line-height:1.15;font-weight:700;letter-spacing:-0.015em;color:#fff;text-wrap:pretty">Same shape. Compiled and typed.</h2>
<p style="margin:20px 0 0;font-size:16px;line-height:1.65;color:#a3adbd;text-wrap:pretty">Plugins still register and boot, require each other, ship migrations and admin YAML. A plugin ports file by file.</p>
<a href="/docs/setup/coming-from-wintercms" style="display:inline-flex;margin-top:24px;font-weight:500;font-size:15px">See the full concept map →</a>
</div>
<div style="border:1px solid rgba(255,255,255,0.08);border-radius:16px;overflow:hidden;background:#29344a">
<div style="display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.3fr);padding:14px 20px;font-size:12px;font-weight:500;letter-spacing:0.12em;color:#8a94a3;border-bottom:1px solid rgba(255,255,255,0.08)">
<span>WINTERCMS</span><span>SUMMERCMS</span>
</div>
<sc-for list="{{ concepts }}" as="c" hint-placeholder-count="6">
<div style="display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.3fr);gap:12px;padding:14px 20px;border-bottom:1px solid rgba(255,255,255,0.06);font-family:'Roboto Mono',monospace;font-size:13px;line-height:1.5">
<span style="color:#a3adbd">{{ c.w }}</span>
<span style="color:#fbe3a6">{{ c.s }}</span>
</div>
</sc-for>
</div>
</section>
<section id="start" data-screen-label="Get started" style="border-top:1px solid rgba(255,255,255,0.07);background:#1f2b42">
<div style="max-width:1120px;margin:0 auto;padding:96px 24px;display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:48px;align-items:center">
<div>
<div style="font-size:12px;font-weight:500;letter-spacing:0.16em;color:#f5c55a">GET STARTED</div>
<h2 style="margin:12px 0 0;font-size:clamp(30px,4vw,42px);line-height:1.15;font-weight:700;letter-spacing:-0.015em;color:#fff">Build your first app.</h2>
<div style="margin-top:24px;display:flex;gap:8px;flex-wrap:wrap">
<span style="font-size:13px;color:#c5ccd6;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);border-radius:999px;padding:6px 12px">Go 1.27</span>
<span style="font-size:13px;color:#c5ccd6;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);border-radius:999px;padding:6px 12px">PostgreSQL 16</span>
</div>
<p style="margin:20px 0 0;font-size:16px;line-height:1.65;color:#a3adbd;text-wrap:pretty">Alpha 0.1 is for early adopters. APIs may change before 1.0.</p>
<div style="margin-top:28px;display:flex;gap:12px;flex-wrap:wrap">
<a href="/docs/setup/installation" style="background:#f5c55a;color:#1d2940;font-weight:500;font-size:15px;padding:13px 24px;border-radius:999px" style-hover="background:#fbd77e;color:#1d2940">Installation guide</a>
<a href="https://git.golem15.com/golem15/summercms" style="border:1px solid rgba(255,255,255,0.14);color:#e9edf3;font-weight:500;font-size:15px;padding:12px 22px;border-radius:999px" style-hover="background:rgba(255,255,255,0.08);color:#fff">Source</a>
</div>
</div>
<div style="background:#18223a;border:1px solid rgba(255,255,255,0.08);border-radius:16px;overflow:hidden">
<div style="display:flex;align-items:center;justify-content:space-between;padding:12px 18px;border-bottom:1px solid rgba(255,255,255,0.07)">
<span style="font-family:'Roboto Mono',monospace;font-size:12px;color:#8a94a3">terminal</span>
<button onClick="{{ copy }}" style="font:500 12px Roboto,sans-serif;color:#c5ccd6;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);border-radius:6px;padding:5px 10px;cursor:pointer">{{ copyLabel }}</button>
</div>
<div style="padding:22px 20px;font-family:'Roboto Mono',monospace;font-size:14px;line-height:1.9;color:#e9edf3;overflow-x:auto;display:flex;flex-direction:column">
<span style="color:#8a94a3;white-space:pre"># install the summer CLI</span>
<span style="white-space:pre"><span style="color:#f5c55a">$ </span>go install ./cmd/summer</span>
<span style="color:#8a94a3;white-space:pre;margin-top:16px"># build and run the example app</span>
<span style="white-space:pre"><span style="color:#f5c55a">$ </span>cd examples/hello</span>
<span style="white-space:pre"><span style="color:#f5c55a">$ </span>summer build</span>
<span style="white-space:pre"><span style="color:#f5c55a">$ </span>./bin/hello greeter:hello</span>
</div>
</div>
</div>
</section>
<footer style="border-top:1px solid rgba(255,255,255,0.07)">
<div style="max-width:1120px;margin:0 auto;padding:32px 24px;display:flex;gap:24px;align-items:center;flex-wrap:wrap;font-size:13px;color:#8a94a3">
<span>© 2026 SummerCMS. Something bright is here.</span>
<div style="flex:1"></div>
<div style="display:flex;gap:20px">
<a href="/docs" style="color:#a3adbd" style-hover="color:#f5c55a">Docs</a>
<a href="https://git.golem15.com/golem15/summercms" style="color:#a3adbd" style-hover="color:#f5c55a">Source</a>
<a href="#top" style="color:#a3adbd" style-hover="color:#f5c55a">Back to top ↑</a>
</div>
</div>
</footer>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{&quot;showRays&quot;:{&quot;editor&quot;:&quot;boolean&quot;,&quot;default&quot;:true,&quot;tsType&quot;:&quot;boolean&quot;},&quot;scrollSpy&quot;:{&quot;editor&quot;:&quot;boolean&quot;,&quot;default&quot;:true,&quot;tsType&quot;:&quot;boolean&quot;}}">
class Component extends DCLogic {
state = { active: '', copied: false, wide: window.innerWidth > 720 };
sections = [['why','Why'],['features','Features'],['winter','From WinterCMS'],['start','Get started']];
componentDidMount() {
this.onScroll = () => {
let a = '';
for (const [id] of this.sections) {
const el = document.getElementById(id);
if (el && el.getBoundingClientRect().top < 140) a = id;
}
if (a !== this.state.active) this.setState({ active: a });
};
window.addEventListener('scroll', this.onScroll, { passive: true });
this.mq = window.matchMedia('(min-width: 721px)');
this.onMq = () => this.setState({ wide: this.mq.matches });
this.mq.addEventListener('change', this.onMq);
this.onScroll();
}
componentWillUnmount() { window.removeEventListener('scroll', this.onScroll); this.mq?.removeEventListener('change', this.onMq); }
renderVals() {
const spy = this.props.scrollSpy ?? true;
return {
showRays: this.props.showRays ?? true,
wide: this.state.wide,
navItems: this.sections.map(([id, label]) => {
const on = spy && this.state.active === id;
return { href: '#' + id, label, style: `white-space:nowrap;flex-shrink:0;font-size:14px;font-weight:500;padding:8px 12px;border-radius:999px;color:${on ? '#f5c55a' : '#c5ccd6'};background:${on ? 'rgba(245,197,90,0.1)' : 'transparent'}` };
}),
features: [
{ title: 'Admin SPA', body: 'Embedded in the binary, driven by each plugin’s YAML.', href: '/docs/backend/admin-spa' },
{ title: 'Models & migrations', body: 'GORM structs with fill, validation and pagination helpers.', href: '/docs/database/models' },
{ title: 'Routing & auth', body: 'Route groups, named middleware, tokens and OAuth.', href: '/docs/services/routing' },
{ title: 'Queued jobs', body: 'Dispatched inside the caller’s transaction.', href: '/docs/services/jobs' },
{ title: 'Realtime', body: 'Broadcast model changes to subscribed clients.', href: '/docs/services/realtime' },
{ title: 'Search', body: 'Searchable models, synced after commit.', href: '/docs/services/search' },
{ title: 'Mail & push', body: 'Plugin mail templates and push notifications.', href: '/docs/services/mail' },
{ title: 'Console', body: 'Scaffolding, scheduler, workers and your own commands.', href: '/docs/console/introduction' },
],
concepts: [
{ w: 'Plugin.php', s: 'party.Plugin' },
{ w: 'version.yaml + updates/', s: 'pact.HasMigrations' },
{ w: 'Eloquent models', s: 'GORM + lagoon' },
{ w: 'fields.yaml / columns.yaml', s: 'Same YAML, compiled at boot' },
{ w: 'routes.php', s: 'pact.HasRoutes' },
{ w: 'Event::listen / fire', s: 'festival.Bus' },
{ w: 'Artisan commands', s: 'bonfire.Command' },
],
copyLabel: this.state.copied ? 'Copied' : 'Copy',
copy: () => {
navigator.clipboard?.writeText('go install ./cmd/summer\ncd examples/hello\nsummer build\n./bin/hello greeter:hello');
this.setState({ copied: true });
setTimeout(() => this.setState({ copied: false }), 1500);
},
};
}
}
</script>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View File

@@ -65,7 +65,7 @@
},
{
"number": "11.2",
"name": "Ready to share: summercms.io website and newsletter plugin",
"name": "summercms.io Alpha 0.1 landing page on SummerCMS",
"status": "pending"
},
{
@@ -94,5 +94,5 @@
"label": "Advance to the next step (verify)",
"reason": "Phase 11.1 of 19 · ready to verify"
},
"updated_at": "2026-10-01T06:58:29.408Z"
"updated_at": "2026-10-01T11:49:17.622Z"
}