From c804b529a6a9eec0b538686b361dc157a037f3d6 Mon Sep 17 00:00:00 2001 From: Romamo Date: Fri, 16 Oct 2026 12:52:43 +0300 Subject: [PATCH] Stop promising a PostgreSQL on its own, and fix the brownfield example A project with only a server and a PostgreSQL service does not validate: every database names a declared application, and an application needs a component Cloudfall deploys (#81). The Neon guide now says so and no longer suggests an app on another host can reach the database, and the site's Neon note and calls to action stop offering a PostgreSQL alone. The brownfield design's operation sample declared targets: component, which the operation schema rejects; it uses host. On phones, the site's navigation and footer links get a tap target of about 44px. Co-Authored-By: Claude Opus 5.5 --- changelog.d/81-database-claims.md | 8 ++++++++ docs/brownfield-design.md | 2 +- docs/neon-migration-guide.md | 20 ++++++++++++++------ site/public/index.html | 9 +++++---- site/public/manifesto.html | 1 + 5 files changed, 29 insertions(+), 11 deletions(-) create mode 100644 changelog.d/81-database-claims.md diff --git a/changelog.d/81-database-claims.md b/changelog.d/81-database-claims.md new file mode 100644 index 0000000..2129e93 --- /dev/null +++ b/changelog.d/81-database-claims.md @@ -0,0 +1,8 @@ +### Fixed + +- The Neon guide says each database belongs to an application Cloudfall + deploys on the same server, and no longer suggests an app on another host + can reach it; the brownfield design's operation example uses a target + scope the schema accepts (`host`); the site no longer offers a PostgreSQL + on its own, and its navigation and footer links are easier to tap on a + phone (#81) diff --git a/docs/brownfield-design.md b/docs/brownfield-design.md index 35d26e5..7565a3d 100644 --- a/docs/brownfield-design.md +++ b/docs/brownfield-design.md @@ -216,7 +216,7 @@ Every playbook or role the team already runs becomes an operation: id: deploy playbook: playbooks/deploy.yml risk: mutating -targets: component +targets: host inputs: version: string preconditions: diff --git a/docs/neon-migration-guide.md b/docs/neon-migration-guide.md index e4ee5e8..bc0ee81 100644 --- a/docs/neon-migration-guide.md +++ b/docs/neon-migration-guide.md @@ -60,13 +60,22 @@ simply absent: (a Hetzner Cloud VPS is the proven reference), or a fresh one plus an hour to get there - The Neon application's connection details and console access +- The application that uses the database, declared in the same project + so Cloudfall deploys it on the server (see Step 1) - Python 3.14 and [`uv`](https://docs.astral.sh/uv/) on the machine you run Cloudfall from ## Step 1: declare the PostgreSQL service -One `Service` resource, with the major version matching Neon's (the Neon -console shows it under application settings): +Each database belongs to an application Cloudfall deploys on the same +server: `databases[].application` names a declared `Application`, and that +application needs at least one component. Declare the application first +([getting started](getting-started.md)). A database on its own, for an app +that stays on another host, is not supported yet +([#81](https://github.com/cloudfall-dev/cloudfall/issues/81)). + +Then one `Service` resource, with the major version matching Neon's (the +Neon console shows it under application settings): ```yaml --- @@ -186,10 +195,9 @@ database will produce. ## Step 5: cut over the application -Point the application's `DATABASE_URL` at the migrated database. For a -co-located app this is the local peer-authenticated socket URL (no -password, no TLS, no pooler); for an app elsewhere, route it the same -way as any other declared service. Deploy, watch health, and keep writes +Point the application's `DATABASE_URL` at the migrated database. The app +runs on the same server, so this is the local peer-authenticated socket URL +(no password, no TLS, no pooler). Deploy, watch health, and keep writes frozen until the app is verified against the new database. ## Step 6: wind down Neon diff --git a/site/public/index.html b/site/public/index.html index 9306ab0..4a53bc9 100644 --- a/site/public/index.html +++ b/site/public/index.html @@ -92,6 +92,7 @@ .b-try { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin-top: 18px } .b-try code { font: 500 13px var(--b-mono); background: var(--b-paper); border: 1.5px dashed var(--b-ink); border-radius: 8px; padding: 7px 12px; overflow-wrap: anywhere } .b-try button { font: 700 13px var(--b-body); background: transparent; border: 0; color: var(--b-blue); cursor: pointer; padding: 4px } +@media (max-width: 560px) { .b-links a, footer .links a { display: inline-block; padding-block: 11px } .b-links { row-gap: 0 } .b-try button { padding: 12px 8px } } .b-try button:focus-visible { outline: 2px solid var(--b-blue); border-radius: 4px } .b-try small { width: 100%; color: var(--b-dim); font-size: .85rem } .b-aside code { font: 500 .85em var(--b-mono); background: var(--b-paper); padding: 1px 5px; border-radius: 4px } @@ -368,8 +369,8 @@

The record is the page you send your client

@@ -473,7 +474,7 @@

The gate lives in Cloudfall, not in the prompt

Want us to set it up with you? The pilot is free.

We're taking three outside teams this quarter. We move one app or one client fleet onto Cloudfall together with you, and you keep running it. Write to pilot@cloudfall.dev

- +
@@ -506,7 +507,7 @@

The gate lives in Cloudfall, not in the prompt

(() => { const items = [ { name: "Render", href: "https://github.com/cloudfall-dev/cloudfall/blob/main/docs/render-migration-guide.md", note: 'Import your render.yaml: apps, data and a DNS cutover that pauses until you flip it.' }, - { name: "Neon", href: "https://github.com/cloudfall-dev/cloudfall/blob/main/docs/neon-migration-guide.md#step-1-declare-the-postgresql-service", note: 'One Service file: PostgreSQL on your server, nightly backups, a daily check that the backup restores.' }, + { name: "Neon", href: "https://github.com/cloudfall-dev/cloudfall/blob/main/docs/neon-migration-guide.md#step-1-declare-the-postgresql-service", note: 'PostgreSQL next to your app on your server: nightly backups and a daily check that the backup restores.' }, ]; const btn = document.getElementById("rot-btn"), word = document.getElementById("rot-word"), note = document.getElementById("rot-note"); if (matchMedia("(prefers-reduced-motion: reduce)").matches) return; diff --git a/site/public/manifesto.html b/site/public/manifesto.html index dbcd88b..2e2a6d6 100644 --- a/site/public/manifesto.html +++ b/site/public/manifesto.html @@ -72,6 +72,7 @@ footer .wrap { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px 28px; color: var(--b-dim); font-size: .92rem } footer .links { display: flex; flex-wrap: wrap; gap: 6px 20px } footer a { color: inherit; text-decoration: none } +@media (max-width: 560px) { .b-links a, footer .links a { display: inline-block; padding-block: 11px } .b-links { row-gap: 0 } } footer a:hover { color: var(--b-ink) } footer .b-brand { color: var(--b-ink); font-size: 1.1rem } @media (max-width: 560px) { .tenet { grid-template-columns: minmax(0, 1fr) } .tenet .num { grid-row: auto } }