Record completed internal CMS rollout

This commit is contained in:
Kevin
2026-09-04 22:25:57 -04:00
parent dc3ec3ff30
commit 5652339676
5 changed files with 234 additions and 142 deletions
+84 -50
View File
@@ -1,19 +1,21 @@
# Decap CMS Gitea pilot and promotion
Status: the preview-only pilot was accepted for promotion to the permanent
`cms` staging branch on 2026-09-04. Repository configuration now targets the
predicted stable `cms` preview origin. CORS and OAuth must be changed together
only after that first preview confirms the alias. Nothing has been merged to
`main`, and production remains unchanged.
Status: completed and operational for internal SloanOps use as of 2026-09-04.
The reviewed CMS application is deployed from `main`, Decap writes only to the
protected `cms` staging branch, and the final Journal date-control repair is
present on both branches. Production deployments from the approved merge
completed successfully.
This remains an internal capability for `sloanops.admin`, not a public feature
or a client-editing offer. No client account has been invited.
Updated: 2026-09-04
## Purpose
Use the `3031023.xyz` demonstration repository to determine whether
Decap CMS can provide a useful editing interface for all sites owned under one
root domain without allowing an editor to publish directly to production or
modify deployment code.
Record and operate the Decap CMS editing interface for both sites in the
`3031023.xyz` demonstration repository without allowing an editor to publish
directly to production or modify deployment code.
The pilot covers both the primary Happy Tails site and its journal subdomain.
That matches the SloanOps repository boundary: one private repository per root
@@ -21,8 +23,9 @@ domain, with independently built sites beneath `sites/`. A future client who
owns the root-domain site also owns the hosted subdomains represented in that
repository.
This plan does not authorize a production merge, domain change, contact-form
activation, repository invitation, or removal of a rollback resource.
The completed internal rollout does not authorize public discovery, a client
repository invitation, contact-form changes, a broader OAuth grant, or removal
of a rollback resource.
## Current evidence
@@ -41,6 +44,13 @@ activation, repository invitation, or removal of a rollback resource.
writes directly to the configured branch.
- The Gitea backend does not support Git LFS. Pilot media must remain small,
ordinary repository assets.
- The approved `sloanops.admin` account can authenticate at the production
admin route, load all collections, and write through the `cms` branch.
- Gitea rejects protected-file pushes to `cms` and direct pushes to `main`;
operator code/configuration changes therefore use pull requests as well.
- Arbitrary branch-preview hostnames are deliberately absent from the OAuth
redirect and CORS allowlists. Login from one returns `Unregistered Redirect
URI`; rendered branch previews remain usable without expanding OAuth.
References:
@@ -56,8 +66,8 @@ recorded in [Decap CMS pilot: Gitea settings](decap-cms-gitea-setup.md).
## Repository implementation
The reviewed pilot implementation is the baseline for the permanent `cms`
staging branch:
The reviewed production implementation and permanent `cms` staging branch
provide the following controls:
- `public/admin/` provides a permanently no-index admin shell and one shared
configuration for both site builds.
@@ -68,6 +78,10 @@ staging branch:
- All four Markdown content collections and every persisted frontmatter field
are modeled with the current Astro/Zod bounds. Markdown controls remain
text-first; embedded images and general file widgets are absent.
- Journal publish and optional updated dates use the supported Decap
`datetime` widget in date-only UTC mode. New posts default to the current UTC
date, and the verifier rejects the unsupported `date` widget that caused the
original create/update failures.
- A fixed image-only Markdown record controls the primary home, About,
Services, and Contact page imagery without exposing either `site.json`.
- Team and page-image fields accept optional bounded uploads. Editors can add,
@@ -94,11 +108,11 @@ staging branch:
repository cache without trusting a mutable tag or refreshing GitHub on every
job.
The pilot dependencies were verified on `cms-pilot`. The same protection rules
apply to `cms`; its exact-origin CORS and OAuth values are the remaining
operator-controlled promotion step.
The pilot dependencies were verified on `cms-pilot`, promoted to the permanent
`cms` branch, and deployed to `main`. Exact-origin CORS, PKCE OAuth, branch
protection, previews, validation, and production deployment are all applied.
## Proposed pilot architecture
## Operating architecture
```text
Decap at /admin/
@@ -126,16 +140,17 @@ is acceptable because both sites belong to the same root-domain repository and
the same owner. One Decap configuration exposes clearly labeled Primary Site
and Journal collection groups.
Predicted preview URLs for branch `cms`:
Confirmed stable preview URLs for branch `cms`:
- `https://cms-3031023-xyz-www.ksloan90.workers.dev/admin/`
- `https://cms-3031023-xyz-www.ksloan90.workers.dev/`
- `https://cms-3031023-xyz-blog.ksloan90.workers.dev/`
Confirm the aliases from the successful Gitea Actions run rather than treating
these predicted URLs as authoritative.
The production admin entry is `https://3031023.xyz/admin/`. Use the stable
`cms` admin origin or the production admin entry for interactive CMS testing;
do not use arbitrary branch aliases for OAuth login.
## Initial Decap scope
## Internal Decap scope
Allow editing and creation only within these collections:
@@ -248,34 +263,30 @@ Preview deployment remains branch-specific and may use the existing Worker
workflows. Cloudflare credentials stay scoped to the deployment step; content
validation does not need them.
Because Decap writes to a fixed `cms` branch, SloanOps creates the pull
request in Gitea. After an approved merge, synchronize the CMS branch with
`main` before the next editing cycle. Do not automate production merge.
Because Decap writes to a fixed `cms` branch, SloanOps creates the pull request
from `cms` to `main` in Gitea. Internal CMS application/configuration changes
start from the current `cms` state, enter protected `cms` through an
operator-reviewed pull request, and are then promoted with the staged content.
After an approved `main` merge, synchronize its merge commit back into `cms`
through a protected-branch pull request before the next editing cycle. Do not
automate production merge.
The accepted pilot is promoted by replacing the disposable branch with the
permanent, slash-free `cms` branch. It remains a preview/staging branch and
retains the same pull-request, validation, and approval path into `main`.
## Gitea and Decap setup
## Routine operating sequence
1. Add a non-confidential Gitea OAuth application for the exact preview
`/admin/` redirect URI or URIs. Store only the public client ID in Decap.
2. Enable Gitea API CORS for the exact approved preview origin or origins.
Allow only required methods and headers, including `Authorization` and
`Content-Type`; do not use a wildcard origin.
3. Create `cms` from the reviewed repository baseline.
4. Review the pinned Decap admin assets beneath `public/admin/`. Do not replace
the exact version and integrity value with a floating range.
5. Configure the Gitea backend for `SloanOps/3031023-xyz` and branch
`cms`.
6. Model every persisted frontmatter field with limits matching
`src/content.config.ts`. Do not let a CMS save silently remove an existing
field.
7. Apply and verify the `main` and fallback branch protections before inviting
or testing a non-operator editor.
8. Add the secret-free pull-request validation workflow.
9. Push only the review branch and confirm both no-index preview builds before
any CMS login test.
1. Edit through an approved admin origin and confirm the commit lands only on
`cms` in an allowed content or media path.
2. Confirm the affected no-index Worker version preview succeeds.
3. Run the local CMS verifier and both site build/verifier pairs before any
operator-authored CMS application or configuration PR into `cms`.
4. Review the complete staged diff and open `cms` to `main`.
5. Require the stable secret-free validation status and SloanOps approval.
6. Merge deliberately and confirm the affected production Worker jobs pass.
7. Synchronize the resulting `main` merge commit back into protected `cms`
before another editing cycle.
## Test matrix
@@ -305,13 +316,36 @@ not record OAuth tokens or Cloudflare credentials.
| DC-19 | Refresh, sign out, reauthenticate, and let a session expire | Session behavior is understandable and no unsaved-content loss is observed. |
| DC-20 | Review commit attribution and audit history | Gitea identifies the editor and the exact content/media changes. |
Do not merge DC-15 during the initial infrastructure and editing test. A later
harmless demo-content merge requires explicit approval and repeats both public
site checks after deployment.
The initial no-merge restriction applied only while the pilot was being
evaluated. Promotion is now allowed through the protected workflow above; each
release still requires explicit review and repeats both public site checks.
## Acceptance criteria
## Completion record — 2026-09-04
Accept the pilot only when:
- PR #1 launched the no-index Decap shell and Gitea-backed collections.
- PRs #2 and #3 tightened image filename validation and added bounded,
metadata-stripping build optimization.
- PRs #4 and #5 synchronized the reviewed implementation into `cms` and then
promoted it to `main`.
- Disposable Journal, page-image, and FAQ edits exposed workflow and schema
behavior; the test content was reverted and the temporary FAQ was removed.
- PR #9 consolidated the rollback history and resynchronized the branches.
- Failed Journal content runs were traced to Decap's unsupported `date` widget.
PR #10 replaced it with date-only `datetime` controls, defaulted new publish
dates, and added a verifier regression guard.
- PR #11 synchronized the final repair into protected `cms` after the direct
protected-file push was correctly rejected.
- CMS validation and both site builds passed locally. The PR #10 required
validation passed, and production blog run 342 plus primary run 343 both
completed successfully.
- The deployed Journal editor was opened at `3031023.xyz/admin/`; Publish date
displayed a populated UTC date and Updated date displayed an optional date
control. No post was saved during this final smoke test.
## Operating acceptance boundary
The internal pilot was accepted against these controls. Re-evaluate them before
any client rollout:
- both site families are understandable in one CMS;
- content edits preserve every modeled field and pass Astro validation;
@@ -329,7 +363,7 @@ account control over executable deployment files.
## Rollback and cleanup
If the pilot is rejected or paused:
If the internal CMS is paused:
1. Revert or delete disposable changes on `cms`.
2. Delete the two disposable preview aliases/versions if desired; do not delete
@@ -341,7 +375,7 @@ If the pilot is rejected or paused:
6. Remove or retain branch protections deliberately; never weaken `main` as
cleanup.
## Implementation estimate
## Historical implementation estimate
Expected hands-on implementation time: **6–9 hours**, normally one focused
working day. Budget up to two elapsed days if OAuth/CORS behavior or Gitea