PreferredAI/PreferredAI.github.io contains both deployables and all published
editorial source:
- the root Next.js application is a static export;
apps/adminis the server-rendered Keystatic application;- posts and People records live in
content/postsandcontent/people; - editorial media lives in
public/uploadsandpublic/team/members.
The root application and apps/admin share dependency versions through the
pnpm workspace, but they have independent builds and deployments.
.github/workflows/nextjs.yml validates and exports the root application, then
deploys out/ to the Cloudflare Pages project preferredai. A push to main
that only changes apps/admin does not run this workflow. Manual runs accept an
exact site_ref for rollback.
.github/workflows/deploy-admin.yml builds only apps/admin with OpenNext and
deploys the preferredai-admin Worker. It runs when the admin application,
workspace manifests, lockfile, or its own workflow changes. Editorial-only
merges do not redeploy the Worker.
Use these protected GitHub environments:
website-production:CLOUDFLARE_ACCOUNT_IDand a Pages API token restricted to thepreferredaiproject;admin-production:CLOUDFLARE_ACCOUNT_IDand a Workers API token restricted to thepreferredai-adminWorker;editorial-publish:DEPLOY_KEY(and optional automation GitHub App ID and private key; falls back toGITHUB_TOKEN+DEPLOY_KEYwhen unset).
If an optional automation GitHub App is configured (PREFERREDAI_AUTOMATION_APP_ID
and PREFERREDAI_AUTOMATION_APP_PRIVATE_KEY), install that App only on this
repository and grant Actions read, Checks read, Contents read/write, and Pull
requests read/write. When unset, .github/workflows/publish-keystatic.yml
operates natively using GITHUB_TOKEN for pull request management and
DEPLOY_KEY (a bypass actor on main) for branch rebasing and verified
fast-forward merges. Each workflow requests only the permissions needed by its
job.
The admin Worker (https://admin.preferred.ai/keystatic) stores changes in
PreferredAI/PreferredAI.github.io on branches beginning with keystatic/.
Editors can click + New Blog Post or + Edit People Info in the bottom-right
Keystatic Workflow bar to create a fresh auto-named branch directly from the
latest main HEAD (e.g. keystatic/post-2026-10-31-a1b2 or
keystatic/people-alex-2026-10-31-c3d4), check branch freshness, sync behind
branches, and jump directly to the build or open pull request.
- Pushing a commit to a non-
mainbranch triggers oneTest website buildrun (.github/workflows/test-build.yml), which validates dependency audits, Markdown, People data, media references, the full static export, and the admin Worker without deployment secrets. Newly created empty branches (0commits ahead ofmain) exit cleanly in seconds without running a full build or opening a pull request. - Once
Test website buildsucceeds on akeystatic/*push,Publish Keystatic Changes(.github/workflows/publish-keystatic.yml) runs:- If an eligible editorial branch (
content/posts/**,public/uploads/**,content/people/**,public/team/members/**) has fallen behindmain, it automatically rebases the branch ontoorigin/mainusingDEPLOY_KEYsoTest website buildre-verifies the rebased commit (or posts a single conflict notice on the PR if manual resolution is needed).
- If an eligible editorial branch (
- Once up to date with
mainand green onTest website build, the publisher creates or updates the pull request (Keystatic (Blog): <slug>orKeystatic (People): <slug>) and applies a quiet, low-noise approval policy:- Blog-only edits (
content/posts/**,public/uploads/**): Opens the PR for history with no reviewer ping, immediately fast-forward merges the verified commit ontomainviaDEPLOY_KEY, and deletes thekeystatic/*branch. - People or mixed edits (
content/people/**,public/team/members/**): Opens the PR and requests 1 maintainer approval (@manhkhanhadvia.github/CODEOWNERS) only afterTest website buildhas passed. - Non-editorial edits: Excluded from automatic merging; require manual maintainer review.
- Blog-only edits (
- When a maintainer (
admin,maintain, orwritepermission) submits an Approve review on an openkeystatic/*PR, themerge-on-approvaljob in.github/workflows/publish-keystatic.ymlverifies passingaudit+buildchecks and editorial path eligibility, fast-forward merges ontomainviaDEPLOY_KEY(rebasing first ifmainmoved ahead cleanly), and deletes the mergedkeystatic/*branch. - Advancing
mainviaDEPLOY_KEYnatively triggers.github/workflows/nextjs.ymlto deploy the static website to Cloudflare Pages without redeploying the admin Worker. .github/workflows/scheduled-maintenance.ymlruns dependency maintenance exclusively onmainand automatically prunes abandonedkeystatic/*branches that have0commits ahead ofmain, no open pull request, and no activity for over 7 days.
Protect main with the repository ruleset (id: 20780485), requiring pull
requests, linear history, and the audit + build status checks.
- Organization & GitHub App ownership: The
PreferredAIGitHub Organization owns bothPreferredAI/PreferredAI.github.ioand thepreferredai-keystaticGitHub App (https://github.com/organizations/PreferredAI/settings/apps/preferredai-keystatic), so individual maintainer departures do not break Keystatic OAuth or branch access.hadylauwholds OrganizationOwnerand Repositoryadmin. - Day-to-day maintainer (
@manhkhanhad):- Holds Repository
maintainpermission, Cloudflare team access,.github/CODEOWNERSownership (People records, workflows,apps/admin), and bypass eligibility on themainbranch ruleset (id: 20780485). - Reviews and merges People/mixed editorial PRs and code/infrastructure PRs.
- Note: Repository
maintaincovers all routine editorial, branch, PR, and Actions operations. Repositoryadmin(viahadylauw) is only required if rotating GitHub Actions repository secrets (DEPLOY_KEY, Cloudflare tokens, or Keystatic OAuth secrets) or editing repository rulesets.
- Holds Repository
- Completing transition cleanup: Once handover from
@hieuddois finalized, a repository admin can remove@hieuddo(actor_id: 26546698) from thebypass_actorslist on ruleset20780485(Settings -> Rules -> Rulesets -> main) and downgrade or remove repository collaborator access as appropriate.
- Attach the public site domains to the Pages project
preferredai. - Deploy
apps/admin/wrangler.jsonc, which bindsadmin.preferred.aias thepreferredai-adminWorker custom domain and disables itsworkers.devhostname. - Set the Worker secrets
KEYSTATIC_GITHUB_CLIENT_ID,KEYSTATIC_GITHUB_CLIENT_SECRET, andKEYSTATIC_SECREToutside the repository. - Set the Keystatic GitHub App callback to
https://admin.preferred.ai/api/keystatic/github/oauth/callback. - Restrict the Keystatic GitHub App to this repository and verify that users without repository write access cannot save edits.
Test blog-only, People-only, mixed, renamed, deleted, malicious Markdown,
malformed JSON, missing-media, and out-of-policy pull requests. Verify that
blog-only edits create a pull request without reviewer pings and auto-merge
after Test website build succeeds, while People edits request 1 maintainer
review after Test website build succeeds and auto-merge upon approval.
For production, verify /, blog pagination, People, category pages, feeds,
sitemap, robots, 404 responses, /_next/**, uploads, and team media. The export
must remain below 20,000 files and 25 MiB per file and must not contain a Worker
bundle or Pages Functions.
After rapid consecutive merges, confirm an older run cannot overwrite a newer
production revision. Test rollback by manually running the Pages workflow with
an exact earlier site_ref.