Cross-Site Architecture and Deployment¶
This page is the starting infrastructure reference for work that spans multiple NASPO-supported websites or shared services. Use it before creating local clones, changing deployment automation, moving secrets, or modifying transactional mail.
Last verified: August 12, 2026.
Start Here for Cross-Site Work¶
Before planning or changing a cross-site project, review OSKB for:
- Repository mapping
- Frontend/backend split
- Hosting provider or server
- Branch/environment mapping
- Deployment trigger and process
- Plugin and package management
- Server filesystem paths
- Secrets boundary
- Rollback procedure
- Ownership and contact notes, where present
If a detail is missing, document it as Unknown/TODO rather than guessing. Do not create alternate local clones when the canonical working copy already exists under ~/Sites/naspo.
Canonical Local Workspace¶
Use ~/Sites/naspo as the preferred local working-copy root for NASPO website and mail infrastructure work.
| Local path | GitHub repository | Purpose |
|---|---|---|
~/Sites/naspo/naspo.org |
NASPO-ValuePoint/naspo |
naspo.org public Next.js frontend |
~/Sites/naspo/naspovaluepoint.org |
NASPO-ValuePoint/NVP |
NASPO ValuePoint WordPress site |
~/Sites/naspo/joinppa.org |
NASPO-ValuePoint/joinppa |
JoinPPA WordPress-managed themes/plugins deployment repository |
~/Sites/naspo/uppcc.org |
NASPO-ValuePoint/uppcc |
UPPCC repository placeholder; local clone currently has no project files |
~/Sites/naspo/rfxpremier.org |
NASPO-ValuePoint/rfxpremier |
RFxPremier repository |
~/Sites/naspo/naspo-secure-mail |
NASPO-ValuePoint/naspo-secure-mail |
NASPO-owned WordPress mail transport plugin |
~/Sites/naspo/naspo-mail-gateway |
NASPO-ValuePoint/naspo-mail-gateway |
Cloudflare Worker mail gateway |
~/Sites/naspo/oskb |
NASPO-ValuePoint/OSKB |
This knowledge base |
Website Architecture and Deployment Summary¶
| Property | Current verified architecture | Repository and local path | Deployment notes |
|---|---|---|---|
www.naspo.org |
Public frontend is Next.js on Vercel. Production WordPress backend is Bitnami WordPress on AWS Lightsail at cms.naspo.org. |
Frontend repo: NASPO-ValuePoint/naspo; local path: ~/Sites/naspo/naspo.org. Staging frontend repo: NASPO-ValuePoint/naspo-staging. |
Public production site is www.naspo.org. Production CMS is cms.naspo.org. Staging frontend is sandbox.naspo.org; staging CMS uses its own WordPress host and staging mail gateway identity. See NASPO.org. |
naspovaluepoint.org |
WordPress site with production, staging, and development environments. | Repo: NASPO-ValuePoint/NVP; local path: ~/Sites/naspo/naspovaluepoint.org. |
Existing OSKB deployment model: dev auto-deploys to Development, staging auto-deploys to Staging, and main is production-ready but production deploys manually from GitHub Actions. The automation branch is for the cross-environment refresh workflow, not normal app deployment. |
joinppa.org |
WordPress site with managed theme/plugin deployment through Composer and GitHub Actions. Production runs on AWS Lightsail through Cloudflare-proxied DNS. | Repo: NASPO-ValuePoint/joinppa; local path: ~/Sites/naspo/joinppa.org. |
dev and staging auto-deploy from matching branches. Production is workflow_dispatch from main only. Production DNS was corrected August 12, 2026 so joinppa-prod is the live origin. Confirm DNS/origin routing rather than inferring role from the Lightsail instance name. See JoinPPA.org. |
uppcc.org |
Bitnami WordPress on AWS Lightsail. | Repo: NASPO-ValuePoint/uppcc; local path: ~/Sites/naspo/uppcc.org. |
Local clone is initialized but currently has no commits checked out and no project files. Treat repository/deployment source of truth as Unknown/TODO until confirmed. See UPPCC.org. |
rfxpremier.org |
Unknown/TODO; preserve any special application and data integrations already documented for this site. |
Repo: NASPO-ValuePoint/rfxpremier; local path: ~/Sites/naspo/rfxpremier.org. |
Local repo is on main; remote branches include dev-deployment-setup and local-dev-configuration. No .github/workflows directory was present in the local checkout when checked. Do not assume it matches JoinPPA. |
NASPO.org Frontend and WordPress Backend Split¶
www.naspo.org has a split architecture:
Public website request
-> Next.js frontend on Vercel project naspo
-> separate WordPress backend for content/backend behavior
-> WordPress wp_mail() calls for transactional mail
The Vercel/Next.js frontend and the WordPress backend are separate operational surfaces. The frontend deployment is currently verified as:
- Platform: Vercel
- Vercel project:
naspo - Production source branch:
main - Production domain:
www.naspo.org - Frontend GitHub repository:
NASPO-ValuePoint/naspo - Canonical local frontend path:
~/Sites/naspo/naspo.org
Transactional mail belongs to the WordPress backend because WordPress remains the source of wp_mail() calls. The Vercel frontend must not receive:
- SendGrid API credentials
- NASPO Secure Mail HMAC secrets
- WordPress backend-only mail configuration
For verified production and staging backend details, see NASPO.org. Unknown/TODO: confirm the production WordPress backend repository status if any, plugin management workflow, and deployment process.
Shared NASPO Secure Mail and Mail Gateway¶
NASPO Secure Mail replaces direct WordPress SendGrid credentials with a signed gateway transport:
WordPress wp_mail()
-> NASPO Secure Mail plugin
-> site/environment HMAC signature
-> NASPO Mail Gateway Cloudflare Worker
-> SendGrid Mail Send API
The WordPress plugin is naspo-secure-mail version 0.1.0. It intercepts normal wp_mail() calls, signs the request with HMAC-SHA256, sends to the gateway endpoint, and returns failure to WordPress if configuration, payload preparation, transport, or gateway validation fails.
The gateway is the only component that should hold SendGrid credentials.
The plugin repository is NASPO-ValuePoint/naspo-secure-mail. The gateway repository is NASPO-ValuePoint/naspo-mail-gateway.
| Environment | Worker URL |
|---|---|
| Production | https://naspo-mail-gateway.naspo.workers.dev |
| Development | https://naspo-mail-gateway-dev.naspo.workers.dev |
| Staging | https://naspo-mail-gateway-staging.naspo.workers.dev |
The full mail endpoint includes /v1/mail, for example:
Secrets Boundary¶
The canonical SendGrid API key is named NASPO Secure Mail Gateway. It is a Restricted Access SendGrid API key with Mail Send permission only.
The SendGrid API key must be stored only as Cloudflare Worker secret(s). It must not be stored in:
- WordPress
- Git
wp-config.php- the WordPress database
- Vercel frontend configuration
- screenshots, logs, OSKB pages, pull request bodies, or chat messages
The gateway administrative credential is separate from the per-site HMAC secrets. The administrative credential authorizes operator actions such as creating, inspecting, updating, revoking, and rotating site identities and policies. Each site's HMAC secret authenticates signed mail requests from that individual WordPress site and environment to the gateway.
A WordPress site does not receive or use the gateway administrative credential. Do not store the administrative credential or per-site HMAC secrets in OSKB, Git, WordPress options, logs, screenshots, pull request bodies, or chat messages.
Each site/environment identity has its own HMAC secret. Do not reuse HMAC secrets between sites or environments.
Store site configuration outside Git, outside the WordPress database, and outside web-managed content. The production pattern used across migrated sites is:
WordPress should reference that file with NASPO_SECURE_MAIL_CONFIG_FILE in wp-config.php. The protected config contains the site ID, gateway URL, HMAC secret, timeout, and attachment limit. Never print or document the secret value.
Gateway Policy Model¶
The gateway stores one policy per site identity. Policy includes:
- Site ID
- Environment
- Delivery mode
- Allowed From addresses
- Recipient limits
- Rate limits
- Revocation state
- HMAC secret
- Nonce history
Policy inspection uses the gateway admin GET /v1/sites/{siteId} endpoint. It returns non-secret policy and configuration metadata for a known site identity and does not return the site's HMAC secret. The gateway currently does not provide a GET /v1/sites list-all-sites endpoint; a collection request returns 404. Inspect a known site identity directly.
Policy changes that do not rotate the HMAC secret use the gateway admin PATCH /v1/sites/{siteId} endpoint. HMAC rotation uses POST /v1/sites/{siteId}/rotate-secret. Site revocation uses POST /v1/sites/{siteId}/revoke.
The gateway enforces sender policy:
- NASPO Secure Mail
0.1.0parses an explicit WordPressFromheader when one is supplied and passes that sender in the signed gateway payload. - When WordPress supplies no explicit
Fromheader, the payload may contain no sender. - The gateway owns sender authorization and defaulting.
- If WordPress supplies no
Fromheader, the gateway uses the policy'sdefaultFromwhen configured. - If WordPress supplies a
Fromheader listed inallowedFrom, the gateway accepts it. - If WordPress supplies a
Fromheader not listed inallowedFrom, the gateway rejects the request.
The plugin does not independently rewrite every WordPress From address. User-submitted or customer email addresses should normally remain Reply-To values. Do not configure contact forms to send as the submitter's address.
Environment Safety¶
capture, redirect, and send are server-side gateway policy. A WordPress mail request cannot select, promote, or override its delivery mode.
Use the following delivery modes:
| Environment | Mode | Behavior |
|---|---|---|
| Development | capture |
Gateway validates, authenticates, and normalizes mail requests, then returns success without calling SendGrid. |
| Staging | redirect |
Gateway calls SendGrid, but rewrites all To, CC, and BCC recipients to the server-side configured redirect recipient. The WordPress request cannot choose or override the redirect target. |
| Production | send |
Gateway sends to the requested recipients only after site policy and signature checks pass. |
Changing an environment from one delivery behavior to another is an operator-controlled gateway policy action, not a WordPress or application request property.
The gateway rejects dev/staging configurations that use arbitrary external delivery. redirect and send fail safely with sendgrid_unavailable if the SendGrid secret is absent.
Proof status last verified August 12, 2026:
- JoinPPA development:
captureverified - JoinPPA staging:
redirectverified with controlled real delivery to the configured redirect recipient - JoinPPA production:
sendverified with controlled real delivery, including WordPress transactional mail and Contact Form 7 mail - NASPO ValuePoint development:
captureverified - NASPO ValuePoint staging:
redirectverified with controlled real delivery to the configured redirect recipient - NASPO ValuePoint production:
sendverified with controlled real delivery
Do not treat a proof on one site as proof that another site has matching deployment, plugin management, backend hosting, or rollback behavior. Verify each site independently before rollout.
Adding an Authorized Sender¶
Adding a legitimate sender to an existing site identity is a policy change, not a secret rotation.
- Confirm the sender address or domain is authorized for the shared SendGrid account.
- Retrieve the current non-secret site policy from the gateway admin endpoint.
- Add the address to
allowedFrom. - Update
defaultFromonly when the new address should become the default sender. - Preserve the existing HMAC secret unless rotation is intentional.
- Do not expose the admin token or HMAC secret in documentation, logs, screenshots, or shell history.
- Verify the updated non-secret policy.
- Tail the Worker while testing.
- Send a controlled WordPress
wp_mail()test. - Confirm gateway
mail_sent, SendGrid delivery, inbox receipt, and the actual application path that uses the sender.
Provisioning a Site Identity¶
For a new WordPress site or environment:
- Choose a canonical site ID, such as
site-prod,site-staging, orsite-dev. - Generate a high-entropy per-site HMAC secret.
- Register the site identity in the matching gateway environment.
- Define allowed sender identities, default sender, recipient limit, payload limit, rate limits, delivery mode, and sandbox behavior.
- Store the HMAC secret in a protected server-side config file.
- Point WordPress to that file with
NASPO_SECURE_MAIL_CONFIG_FILE. - Install NASPO Secure Mail from the canonical plugin artifact or repository workflow.
- Activate NASPO Secure Mail only after configuration is readable from WordPress.
- Send a controlled transport test.
- Test the real application path, such as password reset, Contact Form 7, or Gravity Forms.
- Deactivate the legacy mail plugin only after proof is complete.
- Record the site/environment details in OSKB.
Use the plugin and gateway repositories as the source of truth for exact command and API syntax.
Revoking a Site Identity¶
Revoke a site identity when a site and environment should no longer be able to send through the gateway, such as after suspected HMAC exposure, decommissioning, or a cutover where the old identity must be disabled.
Use the authenticated gateway administrative operation POST /v1/sites/{siteId}/revoke. Revocation is distinct from rotating the site's HMAC secret. Rotation keeps the identity usable after WordPress and the gateway share the new secret; revocation changes the identity status so the site can no longer send.
After revocation:
- Inspect the known site identity with
GET /v1/sites/{siteId}. - Confirm the non-secret policy shows
statusasrevoked. - Confirm a signed mail request for that identity is rejected with
site_revoked. - Preserve gateway request IDs, WordPress
wp_mail_failedevidence, and the operator notes needed to explain why the identity was revoked.
Revocation notes should record the action and non-secret status only. Do not print HMAC secrets, gateway administrative credentials, message bodies, or recipient lists in tickets, OSKB, logs, screenshots, or pull request bodies.
Troubleshooting Mail¶
Troubleshoot mail in layers:
- Confirm the WordPress plugin state.
- Confirm
NASPO_SECURE_MAIL_CONFIG_FILEis defined. - Confirm the protected config file is readable by WordPress.
- Confirm site ID, gateway URL, secret presence, and expected secret length without printing the secret.
- Confirm the gateway site identity exists in the correct Worker environment.
- Confirm
allowedFromanddefaultFrom. - Run a controlled
wp_mail()test. - Watch Worker tail for
SiteGuard.getConfig,SiteGuard.verifyAndReserve,POST /v1/mail, andmail_sent. - Verify SendGrid processed the message.
- Verify inbox receipt.
- Test the actual application path.
A direct wp_mail() test can succeed while a form still fails. In that case, inspect the form's From address, Reply-To handling, frontend validation, and backend endpoint before treating the gateway as failed.
Rollback Pattern¶
During the proof window, keep the previous mail plugin installed but inactive when practical.
If Secure Mail needs temporary rollback:
- Deactivate NASPO Secure Mail.
- Reactivate the previous known-good mail transport if its configuration remains valid.
- Confirm plugin states.
- Send a controlled
wp_mail()test. - Preserve gateway request IDs and WordPress
wp_mail_failedevidence for diagnosis.
Do not delete the protected Secure Mail config or gateway identity merely to perform a temporary transport rollback.
Remaining Unknowns¶
Track these until confirmed:
- NASPO.org production backend deployment process and plugin management process.
- UPPCC remote branch state, active codebase location, and deployment process.
- RFxPremier application architecture, deployment process, and special data/application integrations.
- Production owner/approver and rollback contact notes for each site where they are not already documented.