Reviewed-on: SloanOps/3031023-xyz#15
Happy Tails Astro sites and internal CMS
This repository backs the production Happy Tails sites at 3031023.xyz and
blog.3031023.xyz. Both are static Astro builds deployed as separate
Cloudflare Workers. The retained Cloudflare Pages project remains the primary
site rollback target.
The Decap CMS workflow is operational for internal SloanOps use. It is not a
public feature or a client-editing offer. The approved internal editor is
sloanops.admin; do not invite additional editors without a separate access,
support, and security review.
Repository layout
sites/www/contains primary-site Markdown and site data.sites/blog/contains the Journal Markdown and site data.public/admin/contains the shared, no-index Decap admin shell and config.public/images/uploads/is the only CMS-writable media directory.sites.jsonis the operator-controlled build manifest, not public intake.src/contains shared Astro presentation code.schemas/,scripts/, andfixtures/enforce the content and deployment contracts.
Internal CMS workflow
Use https://3031023.xyz/admin/ for normal internal editing. Decap commits
content and approved raster media directly to the protected cms staging
branch; it never writes to main.
- Make and review content changes on
cms. - Confirm the
cmsWorker version previews and content validation results. - Open a pull request from
cmstomain. - Merge only after the required CMS validation, both site builds, and SloanOps review pass.
- Relevant
mainchanges deploy the production primary and/or blog Worker. - If
maincontains file changes that are not already incms, synchronize them back through a protected-branch pull request before the next editing cycle. A merge commit whose tree already matchescmsneeds no no-op sync.
Operator-authored CMS application or configuration work also starts from the
current cms state. Use a short branch and a pull request into protected
cms, then promote the reviewed cms state to main. Direct protected-file
pushes to cms and all direct pushes to main are intentionally rejected.
Only the stable CMS and production admin origins are registered with Gitea.
Logging in from a branch-specific Worker preview alias therefore produces
Unregistered Redirect URI; this is expected. Never solve it with a wildcard
OAuth redirect or wildcard CORS origin. Use branch previews to inspect rendered
site output and an approved admin origin to test editing.
See the CMS operating record and Gitea settings for the complete boundaries.
Content and media behavior
The CMS exposes primary FAQs, services, team members, fixed primary page
images, and Journal posts. Draft content is excluded from pages and sitemaps.
Journal publish and optional updated dates use Decap's supported datetime
widget in date-only UTC mode; new posts default the publish date to the current
UTC date.
CMS image sources must be approved JPG, PNG, WebP, or AVIF files in the flat uploads directory and may be at most 25 MiB. Every build re-encodes public copies to at most 1920 pixels and 500 KiB and strips embedded metadata.
Local checks
Use Node 22.12 or newer within the Node 22 release line.
npm ci
npm run verify:cms
SITE_KEY=www npm run build:site
SITE_KEY=www npm run verify:build
SITE_KEY=blog npm run build:site
SITE_KEY=blog npm run verify:build
Each selected site builds to dist/<site-key>/. The Worker configurations use
only static assets and a custom 404 page. They contain no custom domains,
routes, account IDs, or secrets.
npm run verify:cms checks the fixed Gitea backend and cms branch, all CMS
content contracts, media boundaries, the pinned admin shell, supported
widgets, and the stable secret-free pull-request status context.
Preview deployment
Non-main pushes upload no-index Cloudflare Worker versions with readable
branch aliases; they do not move production traffic. Relevant main pushes
deploy 3031023-xyz-www and/or 3031023-xyz-blog automatically after building
and verifying the selected site. Routine workflows contain no DNS, custom
domain, route, account ID, or token configuration.
The production domain bindings, www redirect, retained Pages rollback, and
recovery steps are recorded in the primary cutover runbook
and blog production runbook.