AOVIS Direct Store - VM Deployment Preparation
This repository is prepared for a traditional Linux VM deployment path.
Release discipline
Use docs/deploy-sop.md as the formal release baseline.
Default repo entrypoint:
pnpm release:prod
docs/vm-deploy.md covers VM-specific operational details.
docs/deploy-sop.md covers:
- Git as the only valid release source
- preflight checks
- scope control
- post-deploy live truth verification
- rollback rules
Do not skip the SOP just because the VM commands are familiar.
Why VM now
- The app is a standard full-stack Next.js project with auth, cart, checkout, orders, and Stripe webhook handling.
- The Cloudflare Workers/OpenNext path is archived and is not the active deployment path.
- A VM deployment path keeps the stack aligned with standard Node.js production, simpler ops, and a clear reverse-proxy setup.
Recommended runtime
- Ubuntu 22.04 or 24.04
- Node.js 20 LTS or newer
- PostgreSQL hosted externally or on the same VM if you want a single-box staging setup
- Nginx or Caddy as the TLS reverse proxy
- PM2 as the single recommended process manager
Recommended deployment model
Use the standard Next.js production flow:
npm installnpm run buildnpm run start
For VM deployment, this is the least surprising path and keeps the runtime aligned with the current codebase.
Operator SSH entrypoint
When deploying from the operator workstation, use gcloud compute ssh rather than a handwritten ssh user@host command. This keeps the deployment path aligned with the project's actual GCP setup and avoids SSH agent / manual key drift.
The local Google Compute Engine key is typically:
~/.ssh/google_compute_engine
In the current operator environment this resolves to:
/Users/guorui/.ssh/google_compute_engine
If you are already on the VM, do not use this local key path; just run the in-VM Git / build / PM2 commands below.
External AI / Automation Guidance
If an external AI tool or automation runner needs to deploy this repo, it must not guess a private key path or assume an SSH agent is already loaded.
Use this operator-owned command path instead:
gcloud compute ssh aovis-store-staging-vm --zone us-west1-c --project aovis-site-1 --command 'cd /opt/aovis/aovis-store-staging && git fetch origin && git pull origin main && npm install && npx prisma generate && npm run build && pm2 restart aovis-store-staging --update-env'
Rules for automation tools:
- Do not require a manual
ssh user@hoststep. - Do not require the tool to read or manage the operator workstation private key.
- Do not overwrite
/opt/aovis/aovis-store-staging/.env.production. - If the tool cannot invoke
gcloud compute ssh, it should stop and ask the operator to run the command rather than inventing an alternate SSH path. - If the tool is already inside the VM shell, it may use the in-VM Git / build / PM2 sequence directly.
Current deployment scripts
npm run buildnpm run startnpm run dev- Prisma commands remain available for schema and seed workflows
Environment variables
Must have for staging
NEXT_PUBLIC_APP_URLDATABASE_URLAUTH_SECRETSTRIPE_SECRET_KEYNEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY
Add after webhook setup
STRIPE_WEBHOOK_SECRET
Can stay unset for initial staging
AUTH_GOOGLE_IDAUTH_GOOGLE_SECRETAUTH_APPLE_IDAUTH_APPLE_SECRETAUTH_APPLE_TEAM_IDAUTH_APPLE_KEY_IDAUTH_EMAIL_SERVERAUTH_EMAIL_FROM
If you enable Apple sign-in on the VM, provide all four Apple variables together. AUTH_APPLE_SECRET should hold the raw .p8 private key material, with literal newlines escaped as \n when required by the deployment environment.
Apple sign-in recovery checklist
If Apple sign-in disappears after a deploy or UI change, do this in order:
- Check the VM env file:
grep '^AUTH_APPLE_' /opt/aovis/aovis-store-staging/.env.production
- Confirm the provider list:
curl -s https://aovis.app/api/auth/providers
- Restore these variables together if missing:
AUTH_URL=https://aovis.appNEXTAUTH_URL=https://aovis.appNEXT_PUBLIC_APP_URL=https://aovis.appAUTH_TRUST_HOST=trueAUTH_APPLE_ID=app.aovis.webAUTH_APPLE_TEAM_ID=9UU8NX66DJAUTH_APPLE_KEY_ID=LD35DMBTKGAUTH_APPLE_SECRET=...
- Restart PM2 with updated env:
pm2 restart aovis-store-staging --update-env
- Verify again:
/api/auth/providersmust includeapple/signinmust show Apple as enabled
Safe restore method
Use a file-editing step on the VM, not a bulk repo sync:
- read the current
.env.production - update or append the Apple block in place
- keep
AUTH_APPLE_SECRETas a single line with literal\nescapes - restart PM2 with
--update-env
Do not bulk-sync or overwrite .env.production during code deployment. Keep it as a separately managed VM secret file.
Incident summary
This repo already hit an Apple sign-in outage caused by VM environment drift:
- the live app VM lost
AUTH_APPLE_* /api/auth/providersstopped returningapple- the sign-in UI showed Apple as unavailable
That outage was caused by deployment/environment overwrite, not by the OAuth UI itself.
Suggested .env.production
Use the same variable names as local development, but put the staging values into the VM environment or a local .env.production file on the server. Do not commit secrets to git.
Process management
Use PM2 as the process manager for this repo on a single VM:
- restart on crash
- boot on server restart
- keep logs available through
pm2 logs
Suggested command:
PORT=3000 npm run start
Then place Nginx or Caddy in front of it.
PM2 handles:
- restart on crash
- boot on server restart
- log access through
pm2 logs
Git deploy key setup
The app VM is expected to pull code from the repo over Git SSH, not by storing a personal GitHub token.
Deploy key location on the VM
- Private key:
/opt/aovis/.ssh/github_deploy_key - Public key:
/opt/aovis/.ssh/github_deploy_key.pub - SSH config:
/opt/aovis/.ssh/config
This is separate from the operator workstation's Google Compute SSH key.
Recommended SSH config:
Host github.com
HostName github.com
User git
IdentityFile /opt/aovis/.ssh/github_deploy_key
IdentitiesOnly yes
Rotation procedure
- Generate a new VM-local read-only key:
ssh-keygen -t ed25519 -C "aovis-store-staging-vm-readonly" -f /opt/aovis/.ssh/github_deploy_key -N ""
- Copy the new public key from:
/opt/aovis/.ssh/github_deploy_key.pub
- Add it to the GitHub repository as a read-only deploy key
- Remove the old deploy key from GitHub
- Verify on the VM:
cd /opt/aovis/aovis-store-staginggit fetch origingit pull origin main
Do not store personal GitHub tokens with write access on the VM.
Reverse proxy
Put Nginx or Caddy in front of the Next.js process for:
- HTTPS
- domain routing
- gzip / brotli
- optional caching headers
The proxy should forward to the local app port, typically 127.0.0.1:3000.
Historical staging domain examples
These are archived references from earlier validation passes and should not be copied into live environment variables or reverse-proxy config:
store-staging.aovis.appshop-staging.aovis.appapp-staging.aovis.app
For the current live path, keep the VM and proxy aligned to https://aovis.app.
Stripe notes
- Staging can continue using Stripe test keys.
- Keep the webhook endpoint at
/api/stripe/webhook. - The staging webhook URL should look like
https://<staging-domain>/api/stripe/webhook. - The local
stripe listenwhsecis only for local debugging. - Staging and production webhook secrets must be managed separately.
Database notes
The app continues to use Prisma with PostgreSQL in the standard Node runtime.
For VM deployment:
- keep PostgreSQL reachable from the VM
- do not change the database product in this pass
- do not introduce Cloudflare-specific runtime assumptions
Current limits
- This pass does not add new business scope.
- Device binding, entitlement automation, Pangolin integration, and new product logic remain out of scope.
- Stripe live mode is a later step after staging validation.