# MNPPI Architecture > How MNPPI builds, ships, and runs on Cloudflare Workers. This generated file contains all published reference content. ## Reference architecture overview Source: https://architecture.mnppi.org/start/overview/ Status: Current **Standard details** - Status: Current - Reviewed: September 6, 2026 - Cadence: Review each quarter This site is the public reference for how MNPPI builds on Cloudflare Workers. It covers stack defaults, merge and deploy rules, operations, and governance. The canonical source is the private `org-standards` repository. This site is the published form of those standards. If you are starting a Worker project, read this map before you pick a framework or wire CI. > **Note — Public scope** > > This site publishes reusable decisions and controls. > It does not publish secret locations, host inventories, live incidents, or private exception records. > **Tip — For agents** > > Prefer Markdown. Start at [`/llms.txt`](/llms.txt), use each page's `/index.md`, or load [`/llms-full.txt`](/llms-full.txt). > This static site does not negotiate `Accept: text/markdown` on HTML URLs. ## Sections - [Architecture](https://architecture.mnppi.org/architecture/cloudflare-flagship-stack/index.md): Profiles, stack defaults, and platform adoption. - [Delivery](https://architecture.mnppi.org/delivery/ci-cd-and-merge-controls/index.md): GitHub merges. Cloudflare builds and deploys. - [Operations](https://architecture.mnppi.org/operations/runner-security/index.md): Runner isolation, metrics with owners, recovery. - [Governance](https://architecture.mnppi.org/governance/lifecycle/index.md): Reviews, exceptions, and rule retirement. ## Default delivery path | Stage | System | Required result | | ----------------- | ------------------------- | -------------------------------------------------- | | Pull request | GitHub Actions | Repository checks pass on the designated runner. | | Merge | GitHub rulesets | Failed or missing required checks block the merge. | | Production build | Cloudflare Workers Builds | Cloudflare builds the merged default branch. | | Production deploy | Cloudflare | Cloudflare deploys only after its build passes. | Open a PR. Enable squash auto-merge. CI runs. GitHub merges when required checks pass. Workers Builds ships the commit. No default branch requires a second approver. GitHub squash auto-merge proceeds when required checks pass. ## How to use this reference 1. Follow the [adoption checklist](https://architecture.mnppi.org/start/adoption-checklist/index.md). 2. Select an [application profile](https://architecture.mnppi.org/architecture/application-profiles/index.md). 3. Apply the delivery and operations rules for that profile. If a project cannot follow a required control, use the [exception process](https://architecture.mnppi.org/governance/exceptions/index.md). --- ## Adoption checklist Source: https://architecture.mnppi.org/start/adoption-checklist/ Status: Current **Standard details** - Status: Current - Reviewed: August 17, 2026 - Cadence: Review after each platform change Use this checklist before the first production deploy of a Cloudflare app. Repeat the relevant steps when risk, data, or profile changes. 1. **Select the application profile.** Choose the smallest profile that fits the product. A static docs site does not need Queues. A payment path is high-risk even when the rest of the app is not. Record high-risk data or actions. 2. **Configure repository controls.** Enable the organization standards that apply. Require one stable check on the default branch, such as `CI / quality`. Keep required approvals at zero for a sole-owner repository. Allow auto-merge and enable squash auto-merge when a pull request opens. 3. **Configure CI.** Run format, lint, typecheck, tests, package, and policy checks as they apply. For a Worker app, include a production build and `wrangler deploy --dry-run`. Route self-hosted jobs to the designated runner group and leave them in queue. 4. **Configure the Cloudflare project.** Connect Workers Builds to the repository. Use the default branch for production. Enable preview builds for pull requests when you need them. 5. **Apply the platform baseline.** Serve HTML, JS, CSS, and fonts with Static Assets when no server code is required. Bind Worker routes only for dynamic paths such as `/api/*` or auth callbacks. Use bindings for D1, R2, KV, Queues, and other Cloudflare services. 6. **Add data and security controls.** Access D1 only through a Drizzle database package. Enforce authz in the Worker, not only at the edge. Keep secrets in Cloudflare secrets and local Keychain wiring, not in git. 7. **Set operating limits.** Define latency, error, CPU, bundle, and cost limits you will watch. Add alerts only when a named owner will respond. 8. **Test release and recovery.** Verify the production build path end to end. Test Worker rollback or roll-forward. Test D1 recovery separately. Rolling back code does not undo a migration. 9. **Record the result.** Link the profile, required controls, numeric limits, and exceptions. Set the next review date. ## Production gate A project may enter production when: - All required GitHub checks pass. - The owner can enable squash auto-merge without an approval deadlock. - Cloudflare builds the default branch without a GitHub deploy token. - Production uses bindings and protected secrets. - The owner can detect a failed release from health or error signals. - The owner can recover the app and its data. > **Caution** > > Do not copy every optional platform service into a new project. > Add a service when the product needs it. --- ## Cloudflare flagship stack Source: https://architecture.mnppi.org/architecture/cloudflare-flagship-stack/ Status: Current Default stack and operating controls for new MNPPI projects on Cloudflare Workers. **Standard details** - Status: Current - Reviewed: July 24, 2026 - Cadence: Review each quarter - Source: org-standards ## Standards summary MNPPI's default stack is Cloudflare Workers, Static Assets, and the services listed in this standard. Keep pnpm, Workers Static Assets, Astro, React, Vite, Hono, D1, Drizzle, and Cloudflare-native services unless a project profile says otherwise. This standard also defines the operating rules for shipping a production app: - GitHub merge policy - Continuous integration - Self-hosted runners - Cloudflare build and deploy - Release recovery - Route exposure - Runtime configuration - APIs - Database changes - Authentication and authorization - Background work - Observability - Resource budgets Projects that claim conformance must pass the acceptance checks for their profile. ## Reference application status `demo-crm` is the reference application for the single-Worker product profile. Treat it as the working template for a product app on one Worker: - React and Vite for the UI - Workers Static Assets for the client build - Hono for same-origin APIs - D1 through an app-owned Drizzle database package - R2, KV, and rate limiting only where the product needs them - GitHub Actions for required pre-merge checks - Workers Builds for production build and deploy Do not copy every service from the reference app into a new repo. Add a service when the product needs it. ## Scope This standard applies to new MNPPI production projects that use Cloudflare Workers. Existing projects adopt the controls through a planned migration. Do not force a framework rewrite when the current architecture is safe and supported. Each project must record its selected profile: - Static site - Static site with Worker APIs - Interactive single-page application - Multi-Worker application - Background-processing application - Stateful application - High-risk application A high-risk application handles money, regulated data, privileged administration, or destructive automation. Those projects can add stricter controls on top of this baseline. ## Policy terms The terms `must` and `must not` identify required controls. The term `should` identifies the normal choice. An approved exception can replace a `should` rule. An exception to a `must` rule requires: - One named owner. - One documented reason. - A limited scope. - A review date. - A rollback plan. - An expiration or permanent decision. ## Control ownership `MNPPI/org-standards` owns the versioned desired state. It owns: - Required workflows. - Repository ruleset definitions. - Repository properties. - Renovate policy. - Runner policy. - Cloudflare configuration records. - Governance and drift audits. - Reference applications. - Exception records. GitHub rulesets provide live merge enforcement. Cloudflare Workers Builds provides live production build and deployment. Documentation alone is not enforcement. Audits must compare desired state with live GitHub and Cloudflare settings. ## Proposed stable baseline | Layer | Organization standard | | ----------------------- | --------------------------------------------------------------------------- | | Package manager | pnpm workspaces with a pinned package manager | | Runtime | Cloudflare Workers with a current compatibility date | | Static delivery | Workers Static Assets with asset-first routing | | Static pages | Astro static output | | Interactive application | React with Vite | | Small interactions | Astro with React islands | | Cloudflare development | `@cloudflare/vite-plugin` for Vite Worker projects | | Worker tests | `@cloudflare/vitest-pool-workers` | | Client server state | TanStack Query when the application needs remote-state management | | Client routing | TanStack Router for new non-trivial single-page applications | | HTTP API | Hono with Zod validation | | Database | D1 through a database package that uses Drizzle | | Object storage | R2 | | Configuration cache | KV only for suitable eventual-consistency use | | Background work | Queues for buffered work and Workflows for durable multi-step work | | Stateful coordination | Durable Objects for serialized per-entity state | | Staff authentication | Cloudflare Access | | Public authentication | Magic links for verification or Better Auth for application sessions | | Styling | Tailwind CSS v4 with shadcn/ui and approved design tokens | | Merge authority | GitHub Actions and GitHub rulesets | | Release build | Cloudflare Workers Builds | | Production deployment | Cloudflare Workers Builds | | Observability | Workers Logs, release metadata, runtime measures, and approved trace pilots | ## GitHub merge contract ### Protected pull requests Every protected branch must require a pull request. The organization uses a sole-owner merge model. The repository owner enables squash auto-merge when the pull request opens. GitHub merges after all required checks pass. The baseline requires: - Zero approving reviews. - All required checks to pass. - The branch to be current. - All review conversations to be resolved. - No force pushes. - No protected-branch deletion. - No ruleset bypass actors. - Squash merge. - Linear history. - Auto-merge allowed on the repository. - Squash auto-merge enabled when the pull request opens. Do not require Code Owner approval. Do not add a required deployment reviewer that blocks the sole owner. Rulesets should target `~DEFAULT_BRANCH`. Protect every non-default production or promotion branch explicitly. Repositories that use merge queues must run required workflows for `pull_request` and `merge_group`. ### Stable required check Each repository must expose one stable aggregate check. The aggregate must: - Run for every protected pull request. - Use `if: always()` when it depends on other jobs. - Reject every unsuccessful mandatory dependency. - Keep one stable check name. - Avoid path-based absence. - Exclude advisory checks from its success decision. Cloudflare build results must not replace the GitHub merge check. ### Workflow security GitHub Actions must use: - Read-only permissions by default. - Job-specific write permissions. - Full commit identifiers for actions and reusable workflows. - `persist-credentials: false` for checkout. - Frozen dependency installation. - Time limits for every job. - Concurrency controls where duplicate work has a cost or side effect. Privileged workflows must not execute untrusted pull-request code. Do not use `pull_request_target` to check out and run pull-request content. Mandatory jobs must not use `continue-on-error`. Secrets must exist only in the job or step that needs them. ### Continuous integration checks Each project must select all applicable checks: - Tokenless frozen installation. - Formatting. - Lint. - Type checking. - Unit tests. - Worker runtime integration tests. - Application build validation. - Local D1 migration validation. - Static-route Worker-invocation tests. - Wrangler package dry run. - Workflow syntax and security checks. - Secret scanning. - Dependency vulnerability review. - Software bill of materials generation when useful. - Bundle and startup-time budgets. A GitHub validation build is disposable. Cloudflare creates the authoritative production build. ## Self-hosted runner contract Private trusted repositories can use MNPPI self-hosted runners. Public repositories and fork pull requests must use standard GitHub-hosted runners. Jobs must use an approved runner group and purpose label. Runner labels identify routing. They do not prove isolation. The current persistent pool is a documented migration state. The future pool should use one-job, just-in-time runners. Disposable runners must: - Use one clean environment for each job. - Run as a non-root host user. - Avoid the host Docker socket. - Avoid privileged containers. - Avoid host directory mounts. - Apply resource limits. - Remove the container and workspace after the job. - Forward diagnostic logs. - Keep production credentials off the host. Queued jobs must wait for their designated runner. Do not change labels, runners, or execution locations to bypass a queue. Do not cancel and resubmit jobs to improve queue position. Use the [public runner security standard](https://architecture.mnppi.org/operations/runner-security/) with the internal runner topology and pilot records. ## Cloudflare build and deployment contract ### Authority split GitHub Actions decides whether code can merge. Cloudflare Workers Builds builds and deploys approved commits. Merge is not deploy. Deploy is the Workers Builds run on the merged default-branch commit. GitHub Actions must not contain the normal production deployment path. GitHub Actions must not contain routine production Cloudflare credentials. Routine local production deployment is prohibited. An emergency command requires a documented break-glass procedure. ### Workers Builds configuration Production Workers Builds must use: - The actual protected production branch. - An explicit project root. - Pinned Node.js, pnpm, and Wrangler versions. - A tokenless frozen installation. - A minimal build command. - A deployment command that contains only approved release operations. - Reviewed build watch paths. - A dedicated least-privilege Cloudflare user token. Cloudflare currently requires a user token for Workers Builds. Record this as an exception to the normal account-token preference. Disable non-production branch builds by default. Disable Deploy Hooks by default. Treat a Deploy Hook address as a bearer credential. Build watch paths control cost and noise. They are not a security boundary. `org-standards` must record and audit: - Repository. - Branch. - Root directory. - Build command. - Deployment command. - Watch paths. - Runtime versions. - Token owner. - Worker name. - Environment. A retried build uses the current Cloudflare settings. The release record must identify the settings version used for the retry. ### Lightweight release record Normal flagship projects do not require artifact signing or attestation. Record these identifiers when Cloudflare provides them: - Git commit. - Cloudflare build identifier. - Worker version identifier. - Deployment time. - Health-check result. Do not add signed artifacts or exact-byte proof unless a customer, regulation, or high-risk profile requires it. ## Release and recovery contract ### Release phases Use three release phases: 1. GitHub validates the proposed change. 2. Cloudflare builds and deploys the approved commit. 3. Runtime checks verify identity and health. A post-deployment failure is a release incident. It is not a failed merge check. Each project must define: - A health check. - An error threshold. - A latency threshold. - A rollback trigger. - A forward-recovery path. - A release owner. High-risk Workers should use version upload, smoke tests, and gradual promotion. ### Data recovery A Worker rollback does not restore D1, KV, R2, Queue, or Durable Object state. If a migration already ran, rolling back code can leave the app unable to read the new schema. Use expand-and-contract database changes: 1. Add the new structure. 2. Deploy code that supports the old and new structure. 3. Migrate or backfill data. 4. Verify the new structure. 5. Remove the old structure in a later release. Do not include an automatic destructive migration in a normal deployment. Risky D1 changes require: - A reviewed migration. - Local continuous integration validation. - A Time Travel bookmark. - Old and new code compatibility. - A forward-recovery plan. ## Static delivery and route exposure Workers Static Assets must serve a matching public asset before Worker code runs. Use `assets.run_worker_first` as a path-pattern array for reviewed dynamic paths such as `/api/*`. Do not set `run_worker_first: true` for a whole site unless you have evidence it is required. Each route inventory must record: - Delivery type. - Allowed methods. - Authentication. - Authorization. - Cache policy. - Worker invocation. - Failure response. - Owner. Set `html_handling` explicitly. Set `not_found_handling` explicitly. An unknown API route must not return the single-page application shell. A missing `/api/*` path should return JSON 404, not `index.html`. Test that representative public assets do not invoke the Worker. Confirm the result with post-deployment analytics. `_headers` applies to Static Asset responses. Worker-generated responses must set their own security headers. ### Cloudflare Access Cloudflare Access protects configured hostnames and paths. It does not automatically protect every project address. Set `workers_dev` and `preview_urls` explicitly for every environment. Disable them when they are not needed. Otherwise, apply equivalent Access controls. Cloudflare Access authenticates a caller. Application code must still enforce authorization. ## Cloudflare development and testing Use `@cloudflare/vite-plugin` for Vite Worker projects. The Vite plugin runs Worker code in `workerd` during `vite dev` and `vite preview`. It does not provide the Worker test runtime by itself. Use `@cloudflare/vitest-pool-workers` for Worker integration tests. Maintain one reference application. It must prove: - Vite. - React. - Hono. - Static Assets. - Worker bindings. - Environment selection. - Local tests. - Production packaging. Vite selects a Cloudflare environment during the build. Do not assume a later Wrangler environment flag changes an already built output. ## Runtime configuration Use `wrangler.jsonc` as the committed configuration source. New Workers must use: - A current `compatibility_date`. - The `nodejs_compat` compatibility flag. - Generated binding types from `wrangler types`. - Explicit environment bindings. - Explicit environment variables. - Explicit routes and domains. - Explicit `workers_dev` and preview settings. Do not maintain a hand-written Worker `Env` interface. Run `wrangler types --check` in continuous integration. Bindings and variables do not automatically inherit between environments. Test every staging and production binding name. Store runtime secrets through Cloudflare secret controls. Do not store a secret value in `vars`. Local values must use ignored files and the MNPPI Keychain and direnv pattern. ## Frontend composition Use Astro as the static default. Use React islands for small interactive sections. Use a React single-page application for a shared client-state application. Use TanStack Query when the application needs remote-state caching, retries, or invalidation. Do not add it to a static page without a product need. Use TanStack Router for a new non-trivial single-page application. Do not replace a correct framework router without a migration reason. Allow one combined Worker deployment when it keeps routing simple. Use separate Workers when security, ownership, or scale requires isolation. ## API contract Use Hono for new HTTP APIs. Use Zod at every untrusted boundary: path params, query strings, bodies, webhooks, and queue messages. Validate: - Path parameters. - Query parameters. - Request bodies. - Relevant headers. - Webhook messages. - Queue messages. - Environment values. Set request size and content-type limits. Mutating endpoints must define: - Authentication. - Authorization. - Idempotency. - Error responses. - Timeout behavior. - Retry behavior. Use Hono typed clients inside the same repository. Publish OpenAPI for an independent client, integration, or long-lived shared contract. Use Cloudflare bindings instead of Cloudflare REST calls from Worker code. Use service binding RPC between Workers. A service binding is a trusted transport. The receiving Worker must still enforce its caller and operation policy. ## Authentication and application security Use Cloudflare Access for workforce identity. Do not use it as the complete application authorization system. Application sessions must define: - Secure and HTTP-only cookies. - SameSite behavior. - Session expiration. - Session revocation. - Cross-Site Request Forgery protection. - Account recovery. - Replay protection. Public authentication must limit enumeration and repeated attempts. Use Turnstile or another approved abuse control when abuse risk requires it. Every public application must define: - Cross-Origin Resource Sharing policy. - Content Security Policy. - Security headers. - Rate limits. - Webhook signature validation. - Webhook replay prevention. ## Database contract Feature code must use the project database package. The database package should use Drizzle for normal D1 queries. Direct D1 access outside the database package is prohibited. The database package can use a reviewed D1 platform API only when Drizzle lacks a required function. It can also use reviewed parameterized SQL. Each exception must include: - The missing Drizzle capability. - The contained implementation location. - Tests. - An owner. - A review date. Drizzle Kit should generate committed migration files. Review every generated migration. Do not change a migration after an environment applies it. Hand-authored migration SQL is allowed when a safe change requires it. Use `db.batch()` for supported atomic groups. Review indexes and query plans for critical queries. Set rows-read and rows-written budgets for high-volume paths. D1 read replication requires the Sessions API. Keep it as an organization pilot until the database package supports the required consistency model. ## Background-work contract ### Queues Cloudflare Queues provide at-least-once delivery. Every Queue consumer must: - Be idempotent. - Set retry limits. - Use a dead-letter queue in production. - Handle poison messages. - Use partial acknowledgement when suitable. - Monitor depth, age, retries, and dead-letter growth. ### Workflows Use Workflows for durable multi-step operations. Workflow steps must: - Be deterministic. - Be idempotent. - Await each step. - Remain compatible with active instances. - Keep side effects inside reviewed step boundaries. ### Durable Objects Use Durable Objects for serialized per-entity state. Do not use one global object for unrelated tenants. New Durable Objects should use SQLite storage and RPC. Alarms must be idempotent. Durable Object migrations require a separate release review. Class deletion can permanently delete state. Use `waitUntil()` only for short, best-effort post-response work. Do not use it for required business processing. ## Observability Workers Logs are required in production. Automatic Workers Traces remain a controlled pilot with sampling and a cost budget. Each project must define: - Log sampling by environment. - Trace sampling when traces are enabled. - Personal-data and secret redaction. - Release and Worker version fields. - Error alerts. - Latency alerts. - Retention or export. - A telemetry cost budget. Use structured log records. Do not write secret values, session tokens, or unnecessary personal data. ## Resource and release budgets ### Pre-deployment gates GitHub continuous integration must record: - Compressed Worker size. - Worker startup time. - Static-route invocation proof. - Binding and type validation. - Platform-limit validation. The organization warning threshold is 50 percent of the applicable bundle ceiling. The organization blocking threshold is 75 percent of that ceiling. The startup-time warning threshold is 500 milliseconds. The startup-time blocking threshold is 750 milliseconds. Projects can set stricter limits. ### Runtime gates Runtime monitoring must record: - CPU p50, p95, and p99. - Request errors and exceptions. - Latency. - Memory pressure. - Subrequest use. - Queue backlog. Each Worker must set an approved `limits.cpu_ms` value. Set the value from the route class and observed workload. The project must set numeric CPU and latency budgets before production. Do not copy one CPU value into every application. Static asset requests must not invoke Worker code unless a reviewed route requires it. If document and asset paths hit the Worker, fix routing before you raise CPU limits. ## Platform adoption policy Staying current does not mean adopting every new Cloudflare feature. Adopt stable features after the reference application validates them. Use preview or beta features only in pilots with success and rollback criteria. | Feature | Organization position | Decision | | --------------------------- | --------------------- | ---------------------------------------------------------------- | | Vite 8 | Current stable | Adopt after the reference application passes. | | Cloudflare Vite plugin | Approved | Use for Vite Worker projects. | | Workers Static Assets | Approved | Use for new sites and asset-heavy applications. | | Workers Builds | Approved with audit | Use for production build and deployment after protected merges. | | Workers Logs | Approved | Require in production. | | Automatic Workers Traces | Beta | Use through an approved sampling and cost pilot. | | Workers Vitest integration | Beta tooling | Use for Worker-runtime tests and track known limitations. | | D1 read replication | Organization pilot | Require Sessions API support and a defined consistency model. | | Smart Placement | Beta | Pilot only when latency and CPU data can show the result. | | Secrets Store | Open beta | Track it and keep Worker secrets as the baseline. | | Workflows | Approved with budget | Use for durable multi-step work with cost and recovery controls. | | Durable Objects with SQLite | Approved | Use for new per-entity state. | | TanStack Start on Workers | Supported option | Use only when the product proves a server-render requirement. | | React Server Components | Controlled option | Do not use as the static-first baseline. | ### Pilot requirements A platform pilot must: - Have one owner. - Have one reversible scope. - Define success measures. - Define rollback measures. - Measure CPU, latency, errors, cost, and operating effort. - Avoid unnecessary production data risk. - Produce a written adoption decision. ## Dependency review snapshot These versions were current in the public package registry on 2026-07-22. They are review evidence and not permanent policy pins. | Package | Reviewed version | | ------------------------- | ---------------- | | React | 19.2.8 | | Vite | 8.1.5 | | Astro | 7.1.3 | | Hono | 4.12.31 | | Drizzle ORM | 0.45.2 | | Drizzle Kit | 0.31.10 | | `@cloudflare/vite-plugin` | 1.46.0 | | Wrangler | 4.113.0 | | TanStack Query | 5.101.4 | | TanStack Router | 1.170.18 | | Tailwind CSS | 4.3.3 | | shadcn | 4.14.0 | Use Renovate and the reference application to keep approved versions current. Do not copy this version snapshot into a permanent package policy. ## Governance lifecycle Review this standard: - Every quarter. - After a material Cloudflare platform change. - After a material GitHub Actions change. - After a Node.js, pnpm, Vite, or framework major release. - After a significant security incident. Each review must record: - Review date. - Owner. - Primary sources. - Changed decisions. - Deprecated decisions. - Active exceptions. - Required migrations. ## Acceptance gates A project can claim conformance with this standard when: - One reference application passes the approved Vite test matrix. - Static routes show no Worker invocation. - Dynamic routes use explicit path patterns. - Unknown API routes return an API error, not an application shell. - Runtime database code follows the database-package boundary. - Every migration passes local validation. - `wrangler types --check` passes. - Workers Logs are enabled. - Resource budgets have numeric project values. - GitHub enforces the merge contract. - The repository owner enables squash auto-merge when the pull request opens. - The just-in-time runner canary passes and cleans itself. - Workers Builds is the only normal production build and deployment authority. - The release record links the commit, build, version, and health result. - The rollback and data-recovery runbooks pass a review. `demo-crm` is the reference application for the application stack. Each adopting project must pass its applicable gates before production use. ## Primary references ### Cloudflare - [Cloudflare Workers best practices](https://developers.cloudflare.com/workers/best-practices/workers-best-practices/) - [Workers Static Assets](https://developers.cloudflare.com/workers/static-assets/) - [Static Asset routing](https://developers.cloudflare.com/workers/static-assets/routing/worker-script/) - [Cloudflare Vite plugin](https://developers.cloudflare.com/workers/vite-plugin/) - [Workers Vitest integration](https://developers.cloudflare.com/workers/testing/vitest-integration/) - [Workers Builds](https://developers.cloudflare.com/workers/ci-cd/builds/) - [Workers Builds configuration](https://developers.cloudflare.com/workers/ci-cd/builds/configuration/) - [Workers limits](https://developers.cloudflare.com/workers/platform/limits/) - [Workers Logs](https://developers.cloudflare.com/workers/observability/logs/workers-logs/) - [Workers Traces](https://developers.cloudflare.com/workers/observability/traces/) - [Workers rollbacks](https://developers.cloudflare.com/workers/versions-and-deployments/rollbacks/) - [Gradual deployments](https://developers.cloudflare.com/workers/versions-and-deployments/gradual-deployments/) - [D1 migrations](https://developers.cloudflare.com/d1/reference/migrations/) - [D1 Time Travel](https://developers.cloudflare.com/d1/reference/time-travel/) - [D1 read replication](https://developers.cloudflare.com/d1/best-practices/read-replication/) - [Queue delivery guarantees](https://developers.cloudflare.com/queues/reference/delivery-guarantees/) - [Workflow rules](https://developers.cloudflare.com/workflows/build/rules-of-workflows/) - [Durable Object migrations](https://developers.cloudflare.com/durable-objects/reference/durable-objects-migrations/) - [Drizzle with Cloudflare D1](https://orm.drizzle.team/docs/connect-cloudflare-d1) ### GitHub - [GitHub secure use reference](https://docs.github.com/en/actions/reference/security/secure-use) - [Organization rulesets](https://docs.github.com/en/organizations/managing-organization-settings/creating-rulesets-for-repositories-in-your-organization) - [Repository custom properties](https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization) - [Merge queues](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue) - [Self-hosted runners](https://docs.github.com/en/actions/reference/runners/self-hosted-runners) - [Runner group access](https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/manage-access) - [Just-in-time runner API](https://docs.github.com/en/rest/actions/self-hosted-runners) --- ## Application profiles Source: https://architecture.mnppi.org/architecture/application-profiles/ Status: Current **Standard details** - Status: Current - Reviewed: July 24, 2026 - Cadence: Review with each new workload Each project selects one primary profile. The profile decides which services and checks you need before production. This is the choice you make when you scaffold a repo: static only, site plus a few Worker routes, full SPA, multi-Worker, background work, or higher risk. ## Profile map | Profile | Typical composition | Use when | | ------------------------ | --------------------------------------- | ----------------------------------------------------------- | | Static site | Astro and Static Assets | No dynamic server routes. | | Static site with APIs | Static Assets, Worker, and Hono | A small set of server routes supports the site. | | Interactive application | Vite or Astro, React, Worker, and APIs | The browser holds substantial client state. | | Multi-Worker application | Multiple Workers and service bindings | Workloads need separate scale or trust boundaries. | | Background processing | Worker, Queues, and Workflows as needed | Work continues outside an HTTP request. | | Stateful application | Worker and Durable Objects | A named entity needs coordinated state. | | High-risk application | A base profile with stricter controls | Money, regulated data, or destructive actions are in scope. | ## Common selections ### Documentation Use Astro with Static Assets. Add a Worker only when a feature needs server code, such as search or a form handler. ### Product application Use Astro or Vite for the UI. Use Hono for same-origin Worker APIs. Add D1 with Drizzle only when you need durable relational data. ### Background system Use Queues for buffered work such as email or webhook fan-out. Use Workflows for multi-step jobs when durable retry state matters. Keep request handlers short. Move long work off the request path. ### Coordinated state Use Durable Objects when one object must serialize access, such as a room, lease, or counter. Do not use them as a default database for ordinary CRUD. ## Selection rules - Start with Static Assets. - Add a Worker only for dynamic work. - Add one managed service for one clear need. - Split Workers only when scale, ownership, or trust requires it. - Treat high-risk status as an extra control layer on the base profile. - Revisit the profile when the data model or trust boundary changes. --- ## Platform adoption Source: https://architecture.mnppi.org/architecture/platform-adoption/ Status: Current **Standard details** - Status: Current - Reviewed: July 24, 2026 - Cadence: Review each quarter Adopt a Cloudflare feature when it reduces work or risk. Do not adopt it because it is new. For a Worker app, that means you may pilot a beta in one reference workload. You do not make every production app depend on it until it proves out. ## Adoption test A feature can become a default when: - Cloudflare supports it for the intended production use. - It removes code or operating work. - You can measure value in CPU, latency, errors, cost, or effort. - Failure and recovery are clear. - It does not weaken the data or security contract. - The reference application proves the integration. ## Adoption stages 1. **Watch.** Record the feature and the problem it might solve. Keep it out of the default stack. 2. **Pilot.** Run one reference workload, not every production app. Define success, cost, and recovery checks before the pilot starts. 3. **Adopt.** Update the standard after the pilot passes. Add migration notes only for projects that benefit. 4. **Retire.** Remove the service from the default when support or value declines. Keep recovery notes for projects that still run it. ## Current position Static Assets and Workers Builds are part of the normal delivery path. D1 read replication is still a pilot. It needs a proven consistency model before it changes the Drizzle baseline. Cloudflare Containers and the Sandbox SDK can isolate workloads. They do not replace the designated GitHub runner policy. --- ## CI/CD and merge controls Source: https://architecture.mnppi.org/delivery/ci-cd-and-merge-controls/ Status: Current **Standard details** - Status: Current - Reviewed: August 17, 2026 - Cadence: Review each quarter CI and CD have separate owners. - GitHub decides whether code can merge. - Cloudflare builds and deploys the merged commit. That split keeps production Cloudflare credentials out of GitHub Actions. ## Authority map | Decision | System of record | Rule | | ----------------------- | ------------------------- | ------------------------------------------------------------ | | Is the change valid? | GitHub Actions | The repository check suite must pass. | | Can the change merge? | GitHub rulesets | Required checks must pass on the current commit. | | Can the owner merge? | GitHub repository | Required approvals stay at zero for a sole-owner repository. | | When does GitHub merge? | GitHub auto-merge | Enable squash auto-merge when the pull request opens. | | Can production build? | Cloudflare Workers Builds | Cloudflare builds the merged default branch. | | Can production deploy? | Cloudflare | Deploy starts only after the Cloudflare build passes. | ## Pull request flow 1. **Open a pull request.** Use a short-lived branch. Keep unrelated work out of the change. Enable squash auto-merge with `gh pr merge --squash --auto`. 2. **Run repository checks.** Use the designated self-hosted runner when the workflow selects it. Leave the job in the normal queue. Do not retarget runners to skip the wait. 3. **Require one stable result.** Require an aggregate check such as `CI / quality`. That check must fail when any required subcheck fails. Rulesets depend on a stable name, not on every job name. 4. **Let GitHub merge after checks pass.** Squash auto-merge is the default. GitHub merges after required checks pass and review conversations are resolved. No second-person approval is required in the sole-owner model. 5. **Let Cloudflare deploy.** Workers Builds receives the merged commit. Cloudflare runs the production build and deploy. Watch the Cloudflare build, not a GitHub deploy job. ## Required check classes Select the checks that fit the repo technology and risk: - Format and lint - Typecheck - Unit and integration tests - Production package or app build - API contract checks when the Worker exposes routes - D1 migration checks when schema changes - Security and dependency policy checks - Accessibility checks for a browser UI - Repository policy checks from `org-standards` The required aggregate check keeps a stable name. Subchecks can change without a ruleset update. For the control-to-tool map, see [Quality controls and reference tooling](https://architecture.mnppi.org/delivery/quality-controls-and-tooling/index.md). ## Sole-owner safeguards The ruleset must not require an approval that only another person can give. The ruleset must not add the owner as a bypass actor. Required checks, conversation resolution, and allowed merge methods can stay strict. They must not block the owner from merging a valid change. > **Danger** > > Do not move production deploy credentials into GitHub to simplify Cloudflare setup. > Cloudflare owns the normal build and deploy path. --- ## Quality controls and reference tooling Source: https://architecture.mnppi.org/delivery/quality-controls-and-tooling/ Status: Current **Standard details** - Status: Current - Reviewed: July 24, 2026 - Cadence: Review each quarter - Source: MNPPI Org Quality Standard One stable merge result. Each repository runs the quality controls that fit its technology and risk. The control defines the required result. The listed software is the approved reference implementation. An equivalent tool must provide the same signal and merge behavior. When you open a PR on a Worker app, the aggregate check should fail if format, types, tests, or `cf:check` fail. Subcheck names may change. The one ruleset-required name should not. > **Note — Stable contract** > > GitHub rulesets require a stable aggregate result. > Tools and subchecks can change without changing that merge contract. ## Quality control matrix Use this matrix before the first production release. “Profile” means the control is required when the repository matches that profile. | Control | Reference tooling | Applies when | Merge effect | | ----------------------------- | -------------------------------------------------------------------------- | ---------------------------------------------------------------- | ------------ | | Quality baseline | `@mnppi/quality` for private repositories; token-free public workflow | The repository contains software or dependency manifests. | Required | | Format and lint | Prettier and ESLint; Black and Flake8 for Python | The repository contains supported source or configuration files. | Profile | | Type safety | TypeScript or mypy | The project uses a typed language profile. | Profile | | Unused code and dependencies | Knip | The repository contains Node.js or TypeScript code. | Profile | | Tests and coverage | Repository test runner; pytest and pytest-cov for Python | The project contains behavior that can regress. | Profile | | Accessibility | Playwright, axe-core, and Lighthouse | The project has a browser-facing interface. | Profile | | Workflow security | actionlint and zizmor | The repository contains GitHub Actions workflows. | Required | | Secrets and vulnerabilities | Gitleaks and OSV-Scanner | A pull request changes source, dependencies, or workflow files. | Selective | | Security evidence | Semgrep, software bill of materials, dependency review, and license policy | The project risk needs additional evidence. | Advisory | | Cloudflare package validation | Production build and Wrangler dry-run | Cloudflare will build or deploy the project. | Profile | | Dependency maintenance | Renovate | The project has managed dependencies. | Required | | Human-facing text | MNPPI plain-language check and human review | A change adds or updates documentation or interface text. | Required | | Shell quality | ShellCheck and shfmt | Shell scripts perform build, deployment, or recovery work. | Profile | ## Merge-effect levels ### Required A failure blocks the aggregate merge result. The repository cannot merge until the failure is fixed or an approved exception applies. ### Profile The control is required when the repository matches the stated technology or application profile. Do not run it as an empty or false-positive check. ### Selective Only findings at the current blocking threshold stop a merge. Other findings stay visible for review. ### Advisory The control produces evidence and does not block by default. Governance can promote it after a successful pilot. ## Reference profiles ### TypeScript and Node.js Use Prettier for format and ESLint for source rules. Run the TypeScript compiler without emit. Use Knip for unused code, files, and dependencies. Run the project test, coverage, package, and production build checks that apply. Keep all required results under the repository aggregate check. ### Python Use a frozen `uv.lock` install with the development extra. Run Black, Flake8, mypy, Bandit, pytest, and pytest-cov. Test supported Python versions when the package claims them. Keep coverage expectations in the repository. ### Browser interface Use Playwright on representative routes and interactions. Run axe-core with the MNPPI Accessibility Conformity options. Require zero automated axe violations. Run Lighthouse with an accessibility score of at least 0.95. Complete manual WCAG review before a major public release. ### Cloudflare Build the real deployable output in GitHub before merge. Run `wrangler deploy --dry-run` through the repository `cf:check` command. Validate migrations, bindings, routes, and package limits when they apply. Workers Builds still creates the authoritative production build. ## Tool selection rules - Start with required controls, then pick the smallest suitable toolset. - Pin exact software versions in reviewed lockfiles and machine-readable policy. - Pin GitHub Actions and reusable workflows to full commit SHAs. - Do not make an advisory tool mandatory without a pilot that proves value. - Record an equivalent implementation through the [exception process](https://architecture.mnppi.org/governance/exceptions/index.md). - Keep the [CI/CD authority boundary](https://architecture.mnppi.org/delivery/ci-cd-and-merge-controls/index.md) unchanged. > **Caution — Version source** > > Do not copy a dated software snapshot into permanent policy. > Renovate, lockfiles, and the reference application keep approved versions current. ## Primary software references - **Code quality:** [Prettier](https://prettier.io/docs/), [ESLint](https://eslint.org/docs/latest/), [TypeScript](https://www.typescriptlang.org/docs/), and [Knip](https://knip.dev/). - **Browser quality:** [Playwright](https://playwright.dev/docs/intro), [axe-core](https://github.com/dequelabs/axe-core), and [Lighthouse](https://developer.chrome.com/docs/lighthouse/). - **Workflow quality:** [actionlint](https://github.com/rhysd/actionlint), [zizmor](https://docs.zizmor.sh/), [ShellCheck](https://www.shellcheck.net/), and [shfmt](https://github.com/mvdan/sh). - **Security:** [Gitleaks](https://gitleaks.io/), [OSV-Scanner](https://google.github.io/osv-scanner/), and [Semgrep](https://semgrep.dev/docs/). - **Python quality:** [Black](https://black.readthedocs.io/en/stable/), [Flake8](https://flake8.pycqa.org/en/latest/), [mypy](https://mypy.readthedocs.io/en/stable/), [Bandit](https://bandit.readthedocs.io/en/latest/), and [pytest](https://docs.pytest.org/en/stable/). - **Delivery:** [Wrangler](https://developers.cloudflare.com/workers/wrangler/) and [Renovate](https://docs.renovatebot.com/). ## Acceptance gate A repository is ready when: - Every applicable required or profile control runs on pull requests. - Required findings stop the stable aggregate check. - Advisory findings stay visible and have an owner. - The lockfile and workflow pins reproduce the reviewed toolchain. - Any approved equivalent or temporary exception is recorded. --- ## Cloudflare deployment Source: https://architecture.mnppi.org/delivery/cloudflare-deployment/ Status: Current **Standard details** - Status: Current - Reviewed: July 24, 2026 - Cadence: Review after a Cloudflare build change Workers Builds owns the normal production build and deploy. GitHub Actions validates the PR. GitHub Actions must not also run the normal production deploy. When you ship a Worker change, merge is not deploy. Deploy is the Workers Builds run on the merged default-branch commit. ## Branch contract - The default branch is the production source. - Pull requests may create preview builds. - A failed Cloudflare build cannot change production. - Cloudflare records the deployed commit and build result. - GitHub owns merge checks. Cloudflare owns deploy checks. ## Build commands ### Static reference site Use `pnpm --dir site build`. Set the output directory to `site/dist`. Point Workers Static Assets at that directory. ### Worker application Run the production app build. Deploy with Wrangler through Workers Builds. Keep D1, R2, KV, and other bindings in Wrangler config. ### Database application Validate migrations in GitHub before merge. Apply production migrations on the controlled Cloudflare deploy path. Stop the deploy if a required migration fails. ## Static delivery Use Static Assets for files that do not need server code. Do not invoke a Worker for every asset request. If `/index.html` or `/assets/*` hit the Worker, you pay CPU for free. If you set `assets.run_worker_first`, list only dynamic route patterns. Confirm that documents, scripts, styles, images, and fonts bypass Worker code. ## Configuration Use bindings for D1, R2, KV, Queues, Durable Objects, and other services. Generate Wrangler binding types for TypeScript Workers. Store secret values in the Cloudflare environment. Keep only secret names and value-free wiring in the repository. ## Build parity The lockfile must support a frozen, tokenless install for public packages. Use `pnpm install --frozen-lockfile` without `--trust-lockfile`. Do not set `trustLockfile: true` in `pnpm-workspace.yaml`. Those options disable pnpm lockfile supply-chain checks. Run a repository `cf:check` in GitHub CI before merge. That command must build the deployable output and run `wrangler deploy --dry-run`. The Cloudflare build must not depend on a developer workstation. Keep Workers Builds limited to the real post-merge build and deploy. > **Note — Release evidence** > > For normal projects, the deployed commit, Cloudflare build result, and service health are enough. > Add signed artifacts only when risk or a customer requirement demands them. --- ## Release and recovery Source: https://architecture.mnppi.org/delivery/release-and-recovery/ Status: Current **Standard details** - Status: Current - Reviewed: July 24, 2026 - Cadence: Test at least twice each year A release process must answer three questions: 1. What changed? 2. Is the service healthy? 3. How does the owner recover? For a Worker app, that usually means: know the commit and Worker version, check a public route and error rate, and know whether you can roll back code without breaking D1. ## Normal release 1. **Merge a valid pull request.** Confirm all required GitHub checks pass. 2. **Watch the Cloudflare build.** Confirm Workers Builds uses the merged commit. 3. **Check the service.** Hit the public entry point and one critical path. Review errors and latency for the new version. 4. **Record the result.** Keep the commit, deploy result, and any migration result. ## Recovery decision Roll back code when the previous Worker still supports the current data. Roll forward when data or bindings make rollback unsafe. Treat a database migration as a separate recovery problem. Reverting Worker code does not reverse a D1 schema or data change. If you added a required column and the old code cannot read the new rows, roll forward. ## Required recovery information - Current and previous deploy identifiers - Last known healthy commit - Migration state - Affected bindings and routes - Rollback or roll-forward action - Health check that ends recovery ## Test schedule Test code recovery at least twice a year. Test database backup and restore when the project stores important D1 data. High-risk projects need a shorter schedule. They may also require a human release gate or staged production rollout. --- ## Self-hosted runner security Source: https://architecture.mnppi.org/operations/runner-security/ Status: Pilot **Standard details** - Status: Pilot - Reviewed: July 24, 2026 - Cadence: Review each quarter The runner host is a trust boundary. A workflow can read or change anything its job environment can reach. If a PR runs lint and tests on your hardware, treat that job as untrusted code. Keep the host small. Create one isolated environment per job. The environment registers for one job and disappears when the job ends. ## Recommended model Use a just-in-time GitHub runner inside a rootless container. Just-in-time means GitHub registers the runner for one job only. The environment should have: - No host filesystem mounts - No container engine socket - No privileged mode - No added Linux capabilities - `no-new-privileges` - CPU, memory, process, and disk limits - An isolated working directory - A short registration lifetime - Automatic cleanup after success, failure, or timeout The host keeps only the scheduler and container runtime. It must not keep project source or job credentials after cleanup. ## Isolation options ### Rootless container Default for normal repository checks. Fast and practical for a small organization. Shares the host kernel, so it is not a full hostile-code boundary. ### Micro virtual machine Gives each job a separate kernel. Use when the host can support the added complexity. ### Ephemeral virtual machine Strongest common separation. Costs more time and operations work. Use for high-risk or untrusted workloads. ### Cloud-hosted runner Removes the long-lived private host. Use when repository policy allows it. Do not switch only to avoid a queued designated runner. ## Job admission Run untrusted fork code without secrets. Do not use privileged workflow events to execute untrusted pull request code. Limit GitHub token permissions per job. Keep package and cloud credentials out of validation jobs unless the check needs them. ## Cleanup gate A job is complete only when: - GitHub removes the one-job registration - The isolated environment stops - The work directory is gone - Temporary credentials expire or are removed - No project process remains on the host > **Caution** > > Disposable containers reduce persistence risk. > They do not make a shared kernel safe for every hostile workload. --- ## Observability Source: https://architecture.mnppi.org/operations/observability/ Status: Current **Standard details** - Status: Current - Reviewed: July 24, 2026 - Cadence: Review with each production incident Collect a signal only when someone owns the response. A dashboard with no owner is noise. In production, a Worker needs enough data to answer: - Is the critical route up? - Did this release make things worse? - Are we burning CPU on static assets? ## Minimum signals | Area | Signal | Owner action | | ------------ | ------------------------------------------------- | ------------------------------------------ | | Availability | Critical route success | Investigate a sustained failure. | | Errors | Worker exception rate | Find the route, release, and cause. | | Latency | End-to-end and Worker duration | Remove slow work or a bad dependency. | | Cost | Worker CPU and service usage | Fix a route or update a budget. | | Delivery | Failed Cloudflare build or deploy | Fix the build or keep the healthy release. | | Data | Failed migration, queue backlog, or storage error | Stop dependent work and recover safely. | ## Static-first checks Static asset requests should avoid Worker execution. Track unexpected Worker requests to asset paths. If `/favicon.ico` or `/assets/*` invoke the Worker, fix routing before you raise CPU limits. Investigate a rise in Worker CPU before you increase a limit. The usual fix is tighter route scope, caching, or less work on the request path. ## Log rules Use structured fields for service, environment, route, release, and request outcome. Do not log secrets, auth tokens, or unnecessary personal data. Use a stable release identifier from the deployed commit. That identifier ties a production error to the change that introduced it. ## Alert rules An alert must state: - The condition - The threshold and time window - The affected service - The first response action - The owner Remove alerts that stay noisy and do not change an action. --- ## Standard lifecycle Source: https://architecture.mnppi.org/governance/lifecycle/ Status: Current **Standard details** - Status: Current - Reviewed: July 24, 2026 - Cadence: Review each quarter This is a living standard, not a frozen product catalog. Cloudflare, GitHub, and framework defaults change. The reference must change with them on purpose. ## Review schedule Review the standard: - Each quarter - After a material Cloudflare product change - After a security incident - After a failed recovery exercise - Before a high-risk project adopts a new platform feature - When a supported framework reaches end of support ## Review process 1. **Check current support.** Review primary Cloudflare, Astro, GitHub, and package documentation. 2. **Check live use.** Compare the standard with active repositories and Cloudflare projects. Note where production already diverges. 3. **Review evidence.** Use incidents, performance, cost, and developer work as inputs. 4. **Propose a change.** State benefit, migration impact, risk, and recovery plan. 5. **Test the change.** Use a reference project or a limited pilot, such as `demo-crm`. 6. **Publish the decision.** Update the canonical standard and this site in one pull request. ## Change classes | Class | Example | Required action | | ------------------ | ----------------------------------- | ------------------------------------------------ | | Editorial | Clearer wording or links | Review and publish through normal checks. | | Compatible control | A new validation check | Test the check and update adoption guidance. | | Stack change | A new default service or framework | Complete a reference pilot. | | Breaking control | A rule that blocks current projects | Add migration, exception, and recovery guidance. | | Retirement | Removal of a default tool | Define the supported replacement and transition. | ## Version approach The site presents one current standard. Git history is the change log. Create formal versions only when multiple supported baselines are required. Do not add version menus before that need exists. --- ## Exceptions Source: https://architecture.mnppi.org/governance/exceptions/ Status: Current **Standard details** - Status: Current - Reviewed: July 24, 2026 - Cadence: Review at each exception date Exceptions prevent silent drift. A written exception is better than a quiet deviation. If a Worker project cannot use Workers Builds yet, or must keep a long-lived runner, write that down with an owner and a review date. Do not leave it as tribal knowledge. ## Required record Each exception must include: - Affected project and control - One named owner - Technical or business reason - Limited scope - Added risk - Compensating control when needed - Rollback or transition plan - Review date - Expiration date or a permanent decision ## Decision test Approve an exception when: - The standard cannot support a required outcome - Another design has a proven advantage - The exception has a clear owner - The project can operate and recover safely - The exception does not weaken an unrelated control Do not approve an exception only to pass a failed check. Fix the change, or update the standard when the rule is wrong. ## Public and private information This site publishes the exception process. It does not publish private exception records. The internal record may include repository names, risks, dates, and recovery details. The public standard may include a general lesson after review. ## End states At the review date, choose one result: 1. Remove the exception and return to the standard. 2. Extend the exception with new evidence and a new date. 3. Make the exception permanent for the named project. 4. Update the organization standard because the exception proved a better default.