22 KiB
Phase 11.2: summercms.io Alpha 0.1 landing page on SummerCMS - Context
Gathered: 2026-09-29 Updated: 2026-10-01 (phase reshaped into the Alpha 0.1 landing page; newsletter moved to 11.3) Status: Ready for planning
## Phase BoundaryHow to read this file. Decision numbers are stable because ROADMAP.md cites them. The decisions that apply to 11.2 are D-01 to D-05 (three repos only), D-07, D-09 and D-12 from the 2026-09-29 discussion, plus D-23 to D-45 from 2026-10-01. D-06, D-08, D-10 and D-11 are superseded and kept only as one-line stubs. D-13 to D-22 belong to Phase 11.3 and are kept verbatim in the
<phase_11_3_handoff>section at the end. The 11.2 planner ignores that section.
summercms.io replaces its "Under construction" page with the Alpha 0.1 landing page from the claude.ai/design handoff in design/. The page is a Nuxt 4 static site, English only and i18n-ready. It is embedded in one SummerCMS binary that also serves the Phase 11.1 docs at /docs. It deploys to the rome server behind nginx and supervisor, following a documented and scripted procedure.
Three new repos: sm-summercmsio-app, vue-summercmsio-app and sm-summercmsio-plugin. The framework (summercms.go) gets three small, scoped changes: Postgres 15 support verified and documented (D-25), an optional docs-to-site link (D-41) and a v0.1.0 tag (D-42).
Out of scope: newsletter signup, the Polish locale and the subscriber admin. These are Phase 11.3.
## Implementation DecisionsRepos and layout (2026-09-29, still in force)
-
D-01: Three new repos follow the
sm-naming convention (oc-/wn-in October/Winter):sm-summercmsio-appis the root app. It builds the binary, holds the other pieces and wires the plugins.vue-summercmsio-appis the Nuxt 4 site, held inside the root app asvue-fonoteka-appis in the fonoteka project.sm-summercmsio-pluginis the site plugin. It holds everything specific to summercms.io: serving the embedded Nuxt build at/, mounting the 11.1 docs output at/docs, and any site-specific data or routes. This is the proven WinterCMS pattern fromfigs.org.pl(figs/website) and golem15.com.
Public static-site serving goes in
sm-summercmsio-plugin, not in a new framework module. (The fourth repo,sm-newsletter-plugin, moved to 11.3.) — Reversibility: costly — repo names and module paths are referenced by the go.work/replace wiring and every import. -
D-02: Go module paths live under
git.golem15.com/golem15/, like the framework (git.golem15.com/golem15/summercms): for examplegit.golem15.com/golem15/sm-summercmsio-plugin. — Reversibility: one-way — a published Go module path is baked into every importer. -
D-03: The root app wires the framework and the site plugin the way
fonoteka.godoes today (a go.work workspace with a local replace during development).
Website build and hosting (2026-09-29, still in force)
- D-04: The site is Nuxt 4 with
nuxt generate(static output), the same stack asvue-fonoteka-app. Every route is real prerendered HTML, so link previews and search engines see content. - D-05: The generated site and the 11.1 docs output are embedded in the Go binary with
go:embed. One binary serves/and/docs. The build order (nuxt generate, thensummer docs:build, thengo build) is documented and scripted in the root app. - D-06: Superseded. The site is English only for now (see D-33); Polish moves to 11.3.
- D-07: The site's served responses must be indexable. The admin-only
boardwalkbehaviour (noindex, nofollow, admin CSP, base-path rewrite) must not apply to the public site. The site plugin sets its own cache headers: immutable for hashed assets, no-cache for HTML.
Landing page content (2026-09-29)
- D-08: Superseded by the design handoff's section list: header, hero, Why, Features, From WinterCMS, Get started and footer.
- D-09: The "From WinterCMS" section carries the seasons lineage: it started in October (OctoberCMS), went through Winter (WinterCMS), and now it's time for Summer. The handoff's copy is final. The theme lives in the brand (sun, "A new dawn", "Something bright is here") and is not added as extra copy.
- D-10: Superseded. The tone is "Alpha 0.1 is out", per the handoff.
- D-11: Superseded. Source links are on the page (see D-38).
- D-12: A "Built by Golem15" credit links to golem15.com. It is an addition to the handoff's footer, styled as a footer link.
Design handoff
- D-23: The handoff in
design/(README.md,SummerCMS Landing.dc.html) is high fidelity. Colors, type, spacing, copy, breakpoints and the two interactions (scroll-spy and copy-to-clipboard) are matched exactly. The only copy deviations are those decided here: D-12 (credit), D-39 (clone line) and D-26 (the Postgres chip).
Database at runtime
- D-24: The binary keeps the stock
summer servepath, which opens Postgres unconditionally (modules/surf/serve.go:40). There is no framework change to make the DB optional.romealready runs PostgreSQL 15.19 (Debian 12). - D-25: Verify the framework on PostgreSQL 15. Run the framework's database test suites (lagoon, conga and the rest that use
postgres:16-alpine) against apostgres:15image. If they pass, change the documented requirement from "PostgreSQL 16" to "PostgreSQL 15 or newer" in the rootREADME.md,docs/setup/installation.mdand any other page that states it (the docs checker must stay green). If any test fails on 15, stop and ask the user. Do not quietly work around it or upgrade rome. - D-26: The "PostgreSQL 16" chip in the Get started section follows D-25 and reads "PostgreSQL 15+".
- D-27: The app uses a dedicated Postgres role (
summercms) that owns a dedicated database (summercms_io). The password lives in the app's config or env on the server, never in git. DEPLOY.md documentscreateuser/createdb, and every deploy runs the app'smigratecommand before restarting.
Server and deploy flow
- D-28: The binary is built locally for linux/amd64 by a script in
sm-summercmsio-app(nuxt generate, thensummer docs:build --base-url /docs, thengo build), then rsynced to rome with its config. The server needs neither Go nor Node. - D-29:
/backendand the admin API are not exposed publicly. nginx proxies only/and/docsto the binary and denies the admin paths. Nothing needs administering until 11.3. - D-30: TLS uses rome's existing certbot / Let's Encrypt setup. DEPLOY.md shows the nginx server block with the certbot-managed certificate paths, HTTP to HTTPS redirect, gzip and proxy headers.
- D-31: Cutover replaces the existing summercms.io nginx server block in place. The current "Under construction" block is saved in DEPLOY.md (or alongside it) as the rollback.
- D-32: The binary runs under supervisor as a dedicated system user on a localhost-only port. The user, port and paths are Claude's discretion and are written down in DEPLOY.md and the supervisor program config.
Design to Nuxt
- D-33: The site is i18n-ready.
@nuxtjs/i18nis installed and configured with the single localeen, and all page copy lives inlocales/en.json. 11.3 addspl.jsonand a switcher without touching component markup. - D-34: Roboto (300/400/500/700) and Roboto Mono (400/500) are self-hosted through
@nuxt/fonts, the same module asvue-fonoteka-app. They are downloaded at build time and embedded, so visitors make no request to Google. - D-35: Styles are plain CSS. The handoff tokens are CSS custom properties on
:root, used by scoped component styles. No Tailwind. - D-36: The sun artwork is the original from the live site,
http://summercms.io/logo.png(746×744 transparent RGBA PNG, 513 KB). It replaces the handoff'ssun-crop.pngplaceholder. Resized and compressed copies are made for the hero badge (180px), the header logo (30px), the favicon set and the OG image. - D-37: SEO uses the full
@nuxtjs/seomodule, asvue-fonoteka-appdoes: meta, Open Graph and Twitter tags, OG image, schema.org, sitemap and robots. Whatever it generates must work withnuxt generateand be embedded (no runtime OG rendering in the Go binary). - D-45: The prototype's
showRaysandscrollSpyflags become Nuxt app config, both defaulting totrue.
Planning-session decisions (2026-10-01, after research)
- D-46: D-41 is extended.
docs/site.yamlgets an optionalsite_urland an optionalsite_label.summer docs:buildandsummer docs:serveaccept--site-urland--site-labelflags that override them, the same way--base-urloverridesbase_url. The framework's ownsite.yamlsets neither, so its docs output is unchanged. Ifsite_labelis unset, the label is the URL's host, or "Home" for a relative URL. The summercms.io build passes--site-url /and--site-label summercms.io, so the header reads "← summercms.io". - D-47: The landing page keeps the handoff's extension-less
/docs/...hrefs exactly as written (for example/docs/backend/admin-spa).sm-summercmsio-pluginanswers an extension-less/docs/xwith a 301 to/docs/x.htmlwhen that page exists. The SC3 link check follows the redirect and requires the final 200. - D-48: (2026-10-01, after plan 11.2-01) The site's repositories are named
summercmsio, notsummercms, to tell the website apart from the framework on Gitea. The user created the remotesgit@git.golem15.com:golem15/vue-summercmsio-app.git,git@git.golem15.com:golem15/sm-summercmsio-app.gitandgit@git.golem15.com:golem15/sm-summercmsio-plugin.git. Local directories, Go module paths (git.golem15.com/golem15/sm-summercmsio-app,git.golem15.com/golem15/sm-summercmsio-plugin), submodule URLs and the npm package name follow. Unchanged: the framework modulegit.golem15.com/golem15/summercms, the Go packagesummercms, the plugin IDgolem15.summercms, the plugin directoryplugins/golem15/summercmsand the binarysummercms-io. Each new repository getsoriginset to its remote at creation; nothing is pushed during the phase, and DEPLOY.md's step changes from creating the remotes to pushing them. Supersedes the repository names in D-01, D-02 and D-43. — Reversibility: one-way once pushed (module paths).
Get started accuracy
- D-38: Both Source links point to
https://git.golem15.com/golem15/summercms. The repo currently requires login, so making it public is a launch checklist item in DEPLOY.md, done manually by the user before cutover. The link check (roadmap criterion 3) verifies anonymous access at cutover time. - D-39: The terminal card gets a clone step so it works when pasted into a fresh shell: a
# get the frameworkcomment, then$ git clone https://git.golem15.com/golem15/summercmsand$ cd summercms, before the existinggo install ./cmd/summergroup. The Copy button copies every command line in order (now six), without$or comments. - D-40: A scripted check proves the terminal commands work verbatim. It runs them in a temp clone with a temp
GOBIN, ending with./bin/hello greeter:hello. If that command needs a database or other setup, the check provides it, and the copy is not changed again without asking. The command list lives in one place shared by the page and the check, or the check asserts that the two match, so they cannot drift.
Docs and release
- D-41: Framework change: an optional
site_urlkey indocs/site.yamladds a link back to the main site in the docs header (internal/docsite/theme/templates/header.html), for example "← summercms.io". When the key is unset, the output is unchanged. The change also updates the docs page that describessite.yaml, andsummer docs:build --checkandTestDocsTreestay green. summercms.io sets it to/. - D-42: The framework is tagged
v0.1.0(Alpha 0.1).sm-summercmsio-apprequiresgit.golem15.com/golem15/summercms v0.1.0(with the local replace during development), and the embedded docs are built from that tag, so the page, the docs and the code agree. The user confirms before the tag is created and pushed. — Reversibility: one-way — a pushed Go module version tag is cached by proxies and cannot be reused. - D-43: The new repos live as siblings of
summercms.goin the meta repo directory (summercms/sm-summercmsio-app/, likefonoteka.go).vue-summercmsio-appandsm-summercmsio-pluginare submodules insidesm-summercmsio-app. Creating the remotes on git.golem15.com is a manual step the plan lists for the user. - D-44: Every link on the page is verified against the built docs output (roadmap criterion 3), not assumed. As of 2026-10-01 all ten
/docs/...targets in the handoff exist as pages indocs/.
Claude's Discretion
- The system user, port and filesystem paths on rome (D-32).
- Whether the Nuxt build and the docs are embedded by
sm-summercmsio-pluginor by the root app, and how the plugin mounts/docs. - The 404 handling for unknown paths (for example Nuxt's generated
404.htmlwith a 404 status). - Image formats and sizes derived from the sun artwork, and the OG image layout within the brand.
- Where the D-40 command check lives (root app script or test) and how it shares the command list with the page.
- How
prefers-reduced-motionaffects smooth scrolling.
<canonical_refs>
Canonical References
Downstream agents MUST read these before planning or implementing.
Phase scope and design
.planning/ROADMAP.md§ Phase 11.2: goal, repos, naming convention, design source and success criteria..planning/phases/11.2-ready-to-share-summercms-io-website-and-newsletter-plugin/design/README.md: the high-fidelity handoff (layout, tokens, copy, interactions). Must read..planning/phases/11.2-ready-to-share-summercms-io-website-and-newsletter-plugin/design/SummerCMS Landing.dc.html: the HTML design reference. Ignore itssupport.jsruntime.http://summercms.io/logo.png: the original sun artwork (D-36).
Docs build (Phase 11.1)
.planning/phases/11.1-summercms-documentation-for-humans-and-ai-agents/11.1-CONTEXT.md: how the docs are built (summer docs:build, static output,internal/docsite).docs/site.yaml: docs config (base_url, and the newsite_urlfrom D-41).cmd/summer/docs.goandinternal/docsite/load.go: the--base-urlflag and how it overridesbase_url.internal/docsite/theme/templates/header.html: the docs header that D-41 changes.
Framework touch points
modules/surf/serve.go:serveopens the database unconditionally (D-24).README.md,docs/setup/installation.mdanddocs/plugins/testing.md: where "PostgreSQL 16" is stated (D-25).modules/boardwalk/README.md: the embedding and cache-header reference. Its admin security headers must not be reused (D-07).examples/hello: the app the terminal card builds and runs (D-40).
App wiring and frontend references
../fonoteka.go(main.go,go.work,summer.yaml,config/): the reference for app wiring (D-03)./media/nvme/dev/golem15/fonoteka/vue-fonoteka-app(nuxt.config.ts,package.json): Nuxt 4 with@nuxt/fonts,@nuxtjs/i18nv10 and@nuxtjs/seo, the setup to mirror (D-33, D-34, D-37). Note its comments about i18n on static builds (_i18n/**/*.json)./media/nvme/dev/golem15/figs.org.pl/plugins/figs/website: the WinterCMS site-plugin pattern (D-01).
</canonical_refs>
<code_context>
Existing Code Insights
Reusable Assets
boardwalk: itsgo:embedhandling and its hashed-asset versus HTML cache headers are a pattern to copy intosm-summercmsio-plugin. Itsnoindex, admin CSP and base-path rewrite are not.summer docs:build --base-url /docs: already emits docs with the right link prefix for mounting under/docs.summer build: generates the app'smain.goandplugins.gen.gofromsummer.yaml, as infonoteka.go.- The 11.1 docs checker (
TestDocsTree,docs:build --check): it already verifies internal links and commands acrossdocs/, so the D-41 change must keep it green.
Established Patterns
- Plugins are compiled Go modules registered at build time (no runtime loading).
- Every application repo is a go.work workspace that requires the framework with a local replace.
- Framework READMEs and docs never name a consuming application, so the D-41 docs use a neutral example URL, not summercms.io.
- Unit tests are the last plan of the phase.
go vetandgo test ./...stay green in every repo.
Integration Points
sm-summercmsio-appregisterssm-summercmsio-plugin, and the plugin's routes serve/(Nuxt output) and/docs(docs output) from the surf mux.- nginx on rome proxies
/and/docsto the binary on localhost and denies the admin paths (D-29). - Phase 11.2 depends on 11.1 being executed, because the docs build output feeds the embed step.
</code_context>
## Specific Ideas- The page must look exactly like the handoff. "Final" means final, apart from the decided deviations (D-12, D-26, D-39).
- One visual identity across summercms.io,
/docsand the admin: Direction C v2, dark navy and sunny yellow, with the sun. - The terminal card must work when pasted into a fresh shell (D-39, D-40).
- Composing and sending newsletters, templates and the campaign CLI, ported from the PHP plugin in a later phase. That phase also merges confirmed subscribers with the user-based audience.
- CSV export of subscribers. It waits for a framework export or toolbar capability.
- Renaming
fonoteka.gotosm-fonoteka-appis a separate task. - Translating the docs into Polish.
go install git.golem15.com/golem15/summercms/cmd/summer@latestas the install command. This needs the module path to be go-gettable (a public repo plus go-import meta).- A CI pipeline that builds and publishes the binary, instead of local build and rsync.
- Making the database optional in
summer serve, for apps without data.
Reviewed Todos (not folded)
- "Nest framework packages under modules/" is already delivered by Phase 10.2.
- "Backend admin personal API tokens" is unrelated to the public site.
- "Extend fetchguard into a guarded outbound http.Client" is unrelated.
<phase_11_3_handoff>
Carried to Phase 11.3: newsletter decisions (2026-09-29, verbatim, ignore when planning 11.2)
ROADMAP.md § Phase 11.3 points here. When 11.3 is discussed, these move into 11.3-CONTEXT.md.
- Repo:
sm-newsletter-pluginis the reusable signup plugin, with Go packagenewsletter, module pathgit.golem15.com/golem15/sm-newsletter-plugin. - D-06 (moved): The site gains Polish (for example
/and/pl/, via@nuxtjs/i18nas invue-fonoteka-app). The confirmation and welcome mails are localized to the subscriber's locale through phrasebook/postcard. The 11.1 docs stay English-only.
Signup and double opt-in
- D-13: Bot protection is a honeypot field, a minimum time-to-submit check and a per-IP
surfrate-limit bucket. There is no captcha or third-party script. - D-14: A required consent checkbox ("I agree to receive SummerCMS updates") links to a privacy note. The plugin stores the consent timestamp, IP and locale with the subscriber as GDPR evidence.
- D-15: Every signup gets the same neutral "check your inbox" response, and the response never reveals list membership:
- pending: resend the confirmation, throttled
- unsubscribed: new confirmation cycle
- confirmed: no mail
- D-16: The confirm link is tokenized. On success it redirects to a localized thank-you page on the site and sends a welcome mail with the unsubscribe link, as
figs.org.pldoes. Invalid or expired tokens redirect to a localized error page. - D-17: Unsubscribe is a tokenized link in every mail. It marks the subscriber unsubscribed and redirects to a localized "unsubscribed" page.
Plugin shape
- D-18: Subscribers are standalone: the plugin has its own subscribers table and no dependency on the user plugin. Merging confirmed subscribers with a user-based audience (as the PHP
AudienceResolverdoes) belongs to the later sending phase. - D-19: The stub ships only the subscribers table, but with the fields sending will need: email, status (pending, confirmed, unsubscribed), locale, confirmation and unsubscribe tokens,
confirmed_at,unsubscribed_at, source (form or admin), consent timestamp and IP, and timestamps. The newsletter, template and recipient tables are ported from PHP in the sending phase. — Reversibility: costly — the migration shape becomes the base that the sending phase extends. - D-20: The admin backend (cabana YAML list and form) supports list, search, filters (status, locale), view, add, edit and delete. Delete is the GDPR erasure path.
- D-21: An admin-added subscriber is created as pending with source=admin, and the normal confirmation mail is sent. Nobody lands on the list without their own confirmation.
- D-22: Composing and sending newsletters, templates and campaign CLI are out of scope.
11.3 discretion (from 2026-09-29)
- How long confirmation tokens stay valid and the resend throttle interval; token format (random opaque vs signed); exact URL scheme for the API endpoints and localized result pages.
11.3 references
/media/nvme/dev/golem15/horoskopia.eu/plugins/golem15/newsletter: Golem15.Newsletter PHP (github.com/golem15com/wn-newsletter-plugin). Port source; do not modify./media/nvme/dev/golem15/figs.org.pl/plugins/figs/website: working subscribe flow (models/Subscriber.php,models/subscriber/{fields,columns}.yaml,components/subscribe/, hash confirm/resign routes inroutes.php).modules/postcard,modules/phrasebook,modules/surf,modules/lagoon,modules/cabana,modules/pactREADMEs.- 11.2 decision D-29 means
/backendis not public yet. 11.3 must decide how the subscriber admin is reached (for example an IP allowlist or basic auth in nginx).
</phase_11_3_handoff>
Phase: 11.2-ready-to-share-summercms-io-website-and-newsletter-plugin Context gathered: 2026-09-29, updated 2026-10-01