@terreno/mcp 56.0.0-beta.0 → 57.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +10 -11
- package/dist/bootstrap.js.map +1 -1
- package/dist/docs/templates/bootstrap/backend/types/models/userTypes.template.md +5 -4
- package/dist/docs/templates/tools/model.template.md +4 -2
- package/dist/docs/upgrades/0.31.0.md +60 -0
- package/dist/docs/upgrades/56.0.0-beta.2.md +59 -0
- package/dist/docs/upgrades/57.0.0-beta.1.md +41 -0
- package/dist/docs/versioned/next/README.md +1 -0
- package/dist/docs/versioned/next/explanation/README.md +7 -1
- package/dist/docs/versioned/next/explanation/deployment-architecture-gcp.md +65 -0
- package/dist/docs/versioned/next/explanation/deployment-baseline.md +78 -0
- package/dist/docs/versioned/next/explanation/positioning.md +164 -0
- package/dist/docs/versioned/next/explanation/repository-settings.md +44 -0
- package/dist/docs/versioned/next/explanation/roadmap-process.md +330 -0
- package/dist/docs/versioned/next/explanation/roadmap-seed-issues.md +887 -0
- package/dist/docs/versioned/next/how-to/README.md +8 -0
- package/dist/docs/versioned/next/how-to/build-for-web.md +69 -0
- package/dist/docs/versioned/next/how-to/deploy-backend-to-cloud-run.md +115 -0
- package/dist/docs/versioned/next/how-to/deploy-to-gcp.md +20 -228
- package/dist/docs/versioned/next/how-to/deploy-web-to-gcs-cdn.md +183 -0
- package/dist/docs/versioned/next/implementationPlans/PLAN_INDEX.md +31 -0
- package/dist/docs/versioned/next/implementationPlans/README.md +56 -30
- package/dist/docs/versioned/next/implementationPlans/agentic-sdlc-plugin.md +2 -1
- package/dist/docs/versioned/next/implementationPlans/ai-dev-loop-boost.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/b2b-platform-program.md +115 -0
- package/dist/docs/versioned/next/implementationPlans/billing-stripe.md +158 -0
- package/dist/docs/versioned/next/implementationPlans/build-terreno-app-validation.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/comms-abstraction.md +323 -0
- package/dist/docs/versioned/next/implementationPlans/comms-adapter-expo-push.md +107 -0
- package/dist/docs/versioned/next/implementationPlans/comms-adapter-sendgrid.md +157 -0
- package/dist/docs/versioned/next/implementationPlans/comms-adapter-twilio-sms.md +155 -0
- package/dist/docs/versioned/next/implementationPlans/comms-adapter-twilio-verify.md +99 -0
- package/dist/docs/versioned/next/implementationPlans/comms-admin-dashboard.md +180 -0
- package/dist/docs/versioned/next/implementationPlans/deploy-to-gcp.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/deploy-to-vercel.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/deployment-foundation.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/docs-reference-coverage.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/docs-tutorials-ai-first.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/examples-demo-coverage.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/infra-mcp-research.md +188 -0
- package/dist/docs/versioned/next/implementationPlans/infra-mcp.md +269 -0
- package/dist/docs/versioned/next/implementationPlans/migrate-cicd-to-circleci-research.md +126 -0
- package/dist/docs/versioned/next/implementationPlans/migrate-cicd-to-circleci.md +269 -0
- package/dist/docs/versioned/next/implementationPlans/native-module-baseline.md +105 -0
- package/dist/docs/versioned/next/implementationPlans/orgs-and-teams.md +158 -0
- package/dist/docs/versioned/next/implementationPlans/oss-governance-baseline.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/password-reset-and-email-verification.md +147 -0
- package/dist/docs/versioned/next/implementationPlans/positioning-django-rails-universal.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/public-roadmap-github.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/upgrade-guides-and-skill.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/web-ssr-and-admin-spa.md +1 -0
- package/dist/docs/versioned/next/reference/README.md +5 -0
- package/dist/docs/versioned/next/reference/admin-spa.md +130 -0
- package/dist/docs/versioned/next/reference/ai.md +519 -0
- package/dist/docs/versioned/next/reference/comms.md +132 -0
- package/dist/docs/versioned/next/reference/environment-variables.md +229 -382
- package/dist/docs/versioned/next/reference/test.md +108 -0
- package/dist/docs/versioned/next/roadmap.md +9 -0
- package/dist/docs/versioned/next/tasks/README.md +42 -0
- package/dist/docs/versioned/next/tasks/agentic-sdlc-plugin.md +5 -5
- package/dist/docs/versioned/next/tasks/billing-stripe.md +75 -0
- package/dist/docs/versioned/next/tasks/comms-abstraction.md +90 -0
- package/dist/docs/versioned/next/tasks/comms-adapter-expo-push.md +29 -0
- package/dist/docs/versioned/next/tasks/comms-adapter-sendgrid.md +39 -0
- package/dist/docs/versioned/next/tasks/comms-adapter-twilio-sms.md +39 -0
- package/dist/docs/versioned/next/tasks/comms-adapter-twilio-verify.md +19 -0
- package/dist/docs/versioned/next/tasks/comms-admin-dashboard.md +52 -0
- package/dist/docs/versioned/next/tasks/deploy-to-gcp.md +11 -11
- package/dist/docs/versioned/next/tasks/deployment-foundation.md +12 -12
- package/dist/docs/versioned/next/tasks/docs-reference-coverage.md +4 -4
- package/dist/docs/versioned/next/tasks/infra-mcp.md +43 -0
- package/dist/docs/versioned/next/tasks/migrate-cicd-to-circleci.md +215 -0
- package/dist/docs/versioned/next/tasks/native-module-baseline.md +42 -0
- package/dist/docs/versioned/next/tasks/orgs-and-teams.md +70 -0
- package/dist/docs/versioned/next/tasks/oss-governance-baseline.md +18 -18
- package/dist/docs/versioned/next/tasks/password-reset-and-email-verification.md +60 -0
- package/dist/docs/versioned/next/tasks/positioning-django-rails-universal.md +4 -4
- package/dist/docs/versioned/next/tasks/public-roadmap-github.md +15 -15
- package/package.json +4 -3
- package/src/docs/templates/bootstrap/backend/types/models/userTypes.template.md +5 -4
- package/src/docs/templates/tools/model.template.md +4 -2
- package/src/docs/upgrades/0.31.0.md +60 -0
- package/src/docs/upgrades/56.0.0-beta.2.md +59 -0
- package/src/docs/upgrades/57.0.0-beta.1.md +41 -0
- package/src/docs/versioned/next/README.md +1 -0
- package/src/docs/versioned/next/explanation/README.md +7 -1
- package/src/docs/versioned/next/explanation/deployment-architecture-gcp.md +65 -0
- package/src/docs/versioned/next/explanation/deployment-baseline.md +78 -0
- package/src/docs/versioned/next/explanation/positioning.md +164 -0
- package/src/docs/versioned/next/explanation/repository-settings.md +44 -0
- package/src/docs/versioned/next/explanation/roadmap-process.md +330 -0
- package/src/docs/versioned/next/explanation/roadmap-seed-issues.md +887 -0
- package/src/docs/versioned/next/how-to/README.md +8 -0
- package/src/docs/versioned/next/how-to/build-for-web.md +69 -0
- package/src/docs/versioned/next/how-to/deploy-backend-to-cloud-run.md +115 -0
- package/src/docs/versioned/next/how-to/deploy-to-gcp.md +20 -228
- package/src/docs/versioned/next/how-to/deploy-web-to-gcs-cdn.md +183 -0
- package/src/docs/versioned/next/implementationPlans/PLAN_INDEX.md +31 -0
- package/src/docs/versioned/next/implementationPlans/README.md +56 -30
- package/src/docs/versioned/next/implementationPlans/agentic-sdlc-plugin.md +2 -1
- package/src/docs/versioned/next/implementationPlans/ai-dev-loop-boost.md +1 -0
- package/src/docs/versioned/next/implementationPlans/b2b-platform-program.md +115 -0
- package/src/docs/versioned/next/implementationPlans/billing-stripe.md +158 -0
- package/src/docs/versioned/next/implementationPlans/build-terreno-app-validation.md +1 -0
- package/src/docs/versioned/next/implementationPlans/comms-abstraction.md +323 -0
- package/src/docs/versioned/next/implementationPlans/comms-adapter-expo-push.md +107 -0
- package/src/docs/versioned/next/implementationPlans/comms-adapter-sendgrid.md +157 -0
- package/src/docs/versioned/next/implementationPlans/comms-adapter-twilio-sms.md +155 -0
- package/src/docs/versioned/next/implementationPlans/comms-adapter-twilio-verify.md +99 -0
- package/src/docs/versioned/next/implementationPlans/comms-admin-dashboard.md +180 -0
- package/src/docs/versioned/next/implementationPlans/deploy-to-gcp.md +1 -0
- package/src/docs/versioned/next/implementationPlans/deploy-to-vercel.md +1 -0
- package/src/docs/versioned/next/implementationPlans/deployment-foundation.md +1 -0
- package/src/docs/versioned/next/implementationPlans/docs-reference-coverage.md +1 -0
- package/src/docs/versioned/next/implementationPlans/docs-tutorials-ai-first.md +1 -0
- package/src/docs/versioned/next/implementationPlans/examples-demo-coverage.md +1 -0
- package/src/docs/versioned/next/implementationPlans/infra-mcp-research.md +188 -0
- package/src/docs/versioned/next/implementationPlans/infra-mcp.md +269 -0
- package/src/docs/versioned/next/implementationPlans/migrate-cicd-to-circleci-research.md +126 -0
- package/src/docs/versioned/next/implementationPlans/migrate-cicd-to-circleci.md +269 -0
- package/src/docs/versioned/next/implementationPlans/native-module-baseline.md +105 -0
- package/src/docs/versioned/next/implementationPlans/orgs-and-teams.md +158 -0
- package/src/docs/versioned/next/implementationPlans/oss-governance-baseline.md +1 -0
- package/src/docs/versioned/next/implementationPlans/password-reset-and-email-verification.md +147 -0
- package/src/docs/versioned/next/implementationPlans/positioning-django-rails-universal.md +1 -0
- package/src/docs/versioned/next/implementationPlans/public-roadmap-github.md +1 -0
- package/src/docs/versioned/next/implementationPlans/upgrade-guides-and-skill.md +1 -0
- package/src/docs/versioned/next/implementationPlans/web-ssr-and-admin-spa.md +1 -0
- package/src/docs/versioned/next/reference/README.md +5 -0
- package/src/docs/versioned/next/reference/admin-spa.md +130 -0
- package/src/docs/versioned/next/reference/ai.md +519 -0
- package/src/docs/versioned/next/reference/comms.md +132 -0
- package/src/docs/versioned/next/reference/environment-variables.md +229 -382
- package/src/docs/versioned/next/reference/test.md +108 -0
- package/src/docs/versioned/next/roadmap.md +9 -0
- package/src/docs/versioned/next/tasks/README.md +42 -0
- package/src/docs/versioned/next/tasks/agentic-sdlc-plugin.md +5 -5
- package/src/docs/versioned/next/tasks/billing-stripe.md +75 -0
- package/src/docs/versioned/next/tasks/comms-abstraction.md +90 -0
- package/src/docs/versioned/next/tasks/comms-adapter-expo-push.md +29 -0
- package/src/docs/versioned/next/tasks/comms-adapter-sendgrid.md +39 -0
- package/src/docs/versioned/next/tasks/comms-adapter-twilio-sms.md +39 -0
- package/src/docs/versioned/next/tasks/comms-adapter-twilio-verify.md +19 -0
- package/src/docs/versioned/next/tasks/comms-admin-dashboard.md +52 -0
- package/src/docs/versioned/next/tasks/deploy-to-gcp.md +11 -11
- package/src/docs/versioned/next/tasks/deployment-foundation.md +12 -12
- package/src/docs/versioned/next/tasks/docs-reference-coverage.md +4 -4
- package/src/docs/versioned/next/tasks/infra-mcp.md +43 -0
- package/src/docs/versioned/next/tasks/migrate-cicd-to-circleci.md +215 -0
- package/src/docs/versioned/next/tasks/native-module-baseline.md +42 -0
- package/src/docs/versioned/next/tasks/orgs-and-teams.md +70 -0
- package/src/docs/versioned/next/tasks/oss-governance-baseline.md +18 -18
- package/src/docs/versioned/next/tasks/password-reset-and-email-verification.md +60 -0
- package/src/docs/versioned/next/tasks/positioning-django-rails-universal.md +4 -4
- package/src/docs/versioned/next/tasks/public-roadmap-github.md +15 -15
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
Problem-oriented, practical steps. Use these when you know what you want to do.
|
|
4
4
|
|
|
5
|
+
## Deployment
|
|
6
|
+
|
|
7
|
+
- [Deployment baseline](../explanation/deployment-baseline.md) — seven requirements every host must satisfy
|
|
8
|
+
- [Build for web](build-for-web.md) — export static web bundle with correct API URL
|
|
9
|
+
- [Deploy to Google Cloud Platform](deploy-to-gcp.md) — index for GCP guides
|
|
10
|
+
- [Deploy backend to Cloud Run](deploy-backend-to-cloud-run.md) — container + Secret Manager + Cloud Run
|
|
11
|
+
- [Deploy web to GCS + CDN](deploy-web-to-gcs-cdn.md) — static hosting with SPA routing
|
|
12
|
+
|
|
5
13
|
## Contents
|
|
6
14
|
|
|
7
15
|
- [Create a Mongoose model](create-a-model.md) — Define models with proper conventions
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Build for web
|
|
2
|
+
|
|
3
|
+
Export your Terreno Expo app as static files for hosting on GCS, Netlify, or any CDN.
|
|
4
|
+
|
|
5
|
+
See the [deployment baseline](../explanation/deployment-baseline.md) for requirements that apply to every host.
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- Backend running and reachable from browsers (CORS configured).
|
|
10
|
+
- MongoDB replica set for realtime features (see baseline).
|
|
11
|
+
|
|
12
|
+
## 1. Set the API URL at build time
|
|
13
|
+
|
|
14
|
+
`EXPO_PUBLIC_API_URL` is **inlined into the JavaScript bundle** during export. Setting it on the hosting platform after deploy does nothing.
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
cd example-frontend
|
|
18
|
+
EXPO_PUBLIC_API_URL=https://api.example.com bun run export
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The export script in `example-frontend/package.json` is:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
bun expo export --platform web
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Alternative: `app.json` `extra.BASE_URL`
|
|
28
|
+
|
|
29
|
+
`@terreno/rtk` resolves the API base from `expo-constants` `extra.BASE_URL` and `EXPO_PUBLIC_API_URL` (see `rtk/src/constants.ts` `resolveBaseUrls`). Priority in **production** builds:
|
|
30
|
+
|
|
31
|
+
1. `EXPO_PUBLIC_API_URL` environment variable (set before export)
|
|
32
|
+
2. `extra.BASE_URL` in app config (when env var is unset)
|
|
33
|
+
3. Development fallbacks (hostUri, experience URL, localhost) — only in `__DEV__`
|
|
34
|
+
|
|
35
|
+
For production, prefer `EXPO_PUBLIC_API_URL` so CI and local builds behave the same.
|
|
36
|
+
|
|
37
|
+
## 2. Run the export
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
EXPO_PUBLIC_API_URL=https://api.example.com bun run export
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Output lands in `dist/` (Expo default for web export). Contents depend on the configured web `output` mode — today Terreno apps use the `single` SPA mode (one `index.html`).
|
|
44
|
+
|
|
45
|
+
## 3. Verify locally before uploading
|
|
46
|
+
|
|
47
|
+
Serve the `dist/` folder with any static server and confirm API calls hit your backend:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npx serve dist -p 4173
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Open `http://localhost:4173`, log in, and check the network tab — requests must go to your `EXPO_PUBLIC_API_URL`, not `localhost`.
|
|
54
|
+
|
|
55
|
+
## 4. Deploy the static files
|
|
56
|
+
|
|
57
|
+
Upload `dist/` to your host. **Client-side routing** requires the host to serve `index.html` for unknown paths (SPA fallback):
|
|
58
|
+
|
|
59
|
+
| Host | Configuration |
|
|
60
|
+
|------|---------------|
|
|
61
|
+
| GCS + CDN | `notFoundPage=index.html` on the bucket — see [Deploy web to GCS + CDN](deploy-web-to-gcs-cdn.md) |
|
|
62
|
+
| Netlify | `_redirects` or `netlify.toml` `/* /index.html 200` |
|
|
63
|
+
|
|
64
|
+
## Provider guides
|
|
65
|
+
|
|
66
|
+
- [Deploy to GCP](deploy-to-gcp.md) — GCS + Cloud CDN (static web) + Cloud Run (backend)
|
|
67
|
+
- Deployment baseline — [seven requirements](../explanation/deployment-baseline.md)
|
|
68
|
+
|
|
69
|
+
For server-rendered web (future), see [Web SSR and admin SPA](https://github.com/FlourishHealth/terreno/blob/master/docs/implementationPlans/web-ssr-and-admin-spa.md).
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Deploy backend to Cloud Run
|
|
2
|
+
|
|
3
|
+
Deploy a Terreno `@terreno/api` backend (for example `example-backend`) to Google Cloud Run with Secret Manager.
|
|
4
|
+
|
|
5
|
+
Replace placeholders: `$PROJECT_ID`, `$REGION`, `$SERVICE_NAME`, `$REPOSITORY`.
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- [gcloud CLI](https://cloud.google.com/sdk/docs/install) installed and authenticated
|
|
10
|
+
- GCP project with billing enabled
|
|
11
|
+
- MongoDB Atlas cluster (or other replica set) — [deployment baseline](../explanation/deployment-baseline.md)
|
|
12
|
+
- Docker (local build) or Cloud Build
|
|
13
|
+
|
|
14
|
+
Enable APIs:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
gcloud services enable run.googleapis.com artifactregistry.googleapis.com secretmanager.googleapis.com --project="$PROJECT_ID"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 1. Create Artifact Registry
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
gcloud artifacts repositories create "$REPOSITORY" \
|
|
24
|
+
--repository-format=docker \
|
|
25
|
+
--location="$REGION" \
|
|
26
|
+
--project="$PROJECT_ID"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 2. Build and push the image
|
|
30
|
+
|
|
31
|
+
From the **repository root** (the Dockerfile expects the monorepo context):
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
docker build -f example-backend/Dockerfile -t "$REGION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/$SERVICE_NAME:latest" .
|
|
35
|
+
docker push "$REGION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/$SERVICE_NAME:latest"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## 3. Create secrets
|
|
39
|
+
|
|
40
|
+
Create Secret Manager secrets (values added out of band):
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
for name in mongodb-uri token-secret token-issuer refresh-token-secret session-secret; do
|
|
44
|
+
gcloud secrets create "$SERVICE_NAME-$name" --project="$PROJECT_ID" --replication-policy=automatic
|
|
45
|
+
done
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Add secret values (example for MongoDB URI):
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
echo -n 'mongodb+srv://user:pass@cluster.example/terreno?retryWrites=true&w=majority' | \
|
|
52
|
+
gcloud secrets versions add "$SERVICE_NAME-mongodb-uri" --data-file=- --project="$PROJECT_ID"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Repeat for `TOKEN_SECRET`, `TOKEN_ISSUER`, `REFRESH_TOKEN_SECRET`, and `SESSION_SECRET`.
|
|
56
|
+
|
|
57
|
+
For Better Auth, also create `better-auth-secret` and set `AUTH_PROVIDER=better-auth` plus `BETTER_AUTH_URL` at deploy time. See [Configure Better Auth](configure-better-auth.md).
|
|
58
|
+
|
|
59
|
+
## 4. Runtime service account
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
gcloud iam service-accounts create "$SERVICE_NAME-runtime" --project="$PROJECT_ID"
|
|
63
|
+
|
|
64
|
+
gcloud projects add-iam-policy-binding "$PROJECT_ID" \
|
|
65
|
+
--member="serviceAccount:$SERVICE_NAME-runtime@$PROJECT_ID.iam.gserviceaccount.com" \
|
|
66
|
+
--role="roles/secretmanager.secretAccessor"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Grant object access on your uploads bucket separately if using GCS file storage.
|
|
70
|
+
|
|
71
|
+
## 5. Deploy to Cloud Run
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
gcloud run deploy "$SERVICE_NAME" \
|
|
75
|
+
--image="$REGION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/$SERVICE_NAME:latest" \
|
|
76
|
+
--region="$REGION" \
|
|
77
|
+
--project="$PROJECT_ID" \
|
|
78
|
+
--platform=managed \
|
|
79
|
+
--port=3000 \
|
|
80
|
+
--session-affinity \
|
|
81
|
+
--timeout=3600 \
|
|
82
|
+
--min-instances=1 \
|
|
83
|
+
--allow-unauthenticated \
|
|
84
|
+
--service-account="$SERVICE_NAME-runtime@$PROJECT_ID.iam.gserviceaccount.com" \
|
|
85
|
+
--set-secrets="MONGO_URI=$SERVICE_NAME-mongodb-uri:latest,TOKEN_SECRET=$SERVICE_NAME-token-secret:latest,TOKEN_ISSUER=$SERVICE_NAME-token-issuer:latest,REFRESH_TOKEN_SECRET=$SERVICE_NAME-refresh-token-secret:latest,SESSION_SECRET=$SERVICE_NAME-session-secret:latest" \
|
|
86
|
+
--set-env-vars="NODE_ENV=production"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Adjust `min-instances` to `0` for dev sandboxes (websockets will churn on cold start).
|
|
90
|
+
|
|
91
|
+
## 6. Verify
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
SERVICE_URL=$(gcloud run services describe "$SERVICE_NAME" --region="$REGION" --project="$PROJECT_ID" --format='value(status.url)')
|
|
95
|
+
curl -s "$SERVICE_URL/health" | jq .
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Expect `"healthy": true`.
|
|
99
|
+
|
|
100
|
+
## Production constraints
|
|
101
|
+
|
|
102
|
+
| Symptom | Cause | Fix |
|
|
103
|
+
|---------|-------|-----|
|
|
104
|
+
| Websockets disconnect every few requests | No session affinity on Cloud Run | Add `--session-affinity` |
|
|
105
|
+
| Socket connections drop after ~5 minutes | Default request timeout (300s) | Raise `--timeout` (for example `3600`) |
|
|
106
|
+
| Live feature flags / realtime never update; log mentions replica set | MongoDB is standalone, not a replica set | Use Atlas or `replSet` — change streams required (`feature-flags/src/featureFlagsApp.ts`) |
|
|
107
|
+
| First request after idle is slow; sockets reconnect constantly | Scaled to zero | Set `--min-instances=1` for user-facing services |
|
|
108
|
+
| Browser API calls blocked by CORS | `corsOrigin` / Better Auth `trustedOrigins` missing web origin | Add your CDN URL to backend CORS and auth config |
|
|
109
|
+
|
|
110
|
+
## Related
|
|
111
|
+
|
|
112
|
+
- [Deployment baseline](../explanation/deployment-baseline.md)
|
|
113
|
+
- [Environment variables](../reference/environment-variables.md)
|
|
114
|
+
- [Deploy web to GCS + CDN](deploy-web-to-gcs-cdn.md)
|
|
115
|
+
- [GCP architecture](../explanation/deployment-architecture-gcp.md)
|
|
@@ -1,244 +1,36 @@
|
|
|
1
1
|
# Deploy to Google Cloud Platform
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Deploy a Terreno full-stack app to GCP: Cloud Run for the backend, GCS + Cloud CDN for the static web export.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Before you start
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Read the [deployment baseline](../explanation/deployment-baseline.md) — seven requirements (replica-set MongoDB, auth secrets, build-time `EXPO_PUBLIC_API_URL`, and more) apply to every provider.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
- **gcloud CLI**: [Installed and authenticated](https://cloud.google.com/sdk/docs/install)
|
|
11
|
-
- **Permissions**: Your GCP user or service account needs:
|
|
12
|
-
- `roles/storage.admin` (create buckets, set IAM)
|
|
13
|
-
- `roles/compute.loadBalancerAdmin` (create backend buckets, URL maps)
|
|
14
|
-
- `roles/compute.networkAdmin` (create IPs, proxies, forwarding rules)
|
|
15
|
-
- **GitHub Repository Access**: Admin access to configure secrets
|
|
9
|
+
## Guides
|
|
16
10
|
|
|
17
|
-
|
|
11
|
+
| Guide | What it covers |
|
|
12
|
+
|-------|----------------|
|
|
13
|
+
| [Deploy backend to Cloud Run](deploy-backend-to-cloud-run.md) | Container image, Secret Manager, Cloud Run with session affinity |
|
|
14
|
+
| [Deploy web to GCS + CDN](deploy-web-to-gcs-cdn.md) | Static web export, bucket + CDN setup, cache invalidation |
|
|
15
|
+
| [Build for web](build-for-web.md) | Export command, `EXPO_PUBLIC_API_URL`, local verification |
|
|
18
16
|
|
|
19
|
-
|
|
17
|
+
## Architecture
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
# Clone the repository
|
|
23
|
-
git clone https://github.com/FlourishHealth/terreno.git
|
|
24
|
-
cd terreno
|
|
19
|
+
[GCP deployment architecture](../explanation/deployment-architecture-gcp.md) — topology diagram, component roles, and tradeoffs (Cloud Run vs GKE, static vs SSR).
|
|
25
20
|
|
|
26
|
-
|
|
27
|
-
./scripts/setup-gcs-hosting.sh
|
|
28
|
-
``````
|
|
21
|
+
## Scripts
|
|
29
22
|
|
|
30
|
-
|
|
23
|
+
- [`scripts/setup-gcs-hosting.sh`](https://github.com/FlourishHealth/terreno/blob/master/scripts/setup-gcs-hosting.sh) — parameterized GCS + CDN provisioning for one site
|
|
31
24
|
|
|
32
|
-
|
|
33
|
-
2. **Public Access**: Configured with `allUsers:objectViewer`
|
|
34
|
-
3. **SPA Routing**: `notFoundPage=index.html` for client-side routing
|
|
35
|
-
4. **CDN Resources**:
|
|
36
|
-
- Backend buckets (CDN-enabled)
|
|
37
|
-
- URL maps
|
|
38
|
-
- Static IP addresses
|
|
39
|
-
- HTTP proxies
|
|
40
|
-
- Forwarding rules
|
|
25
|
+
## Environment variables
|
|
41
26
|
|
|
42
|
-
|
|
27
|
+
[Environment variables reference](../reference/environment-variables.md) — full list of backend and client config.
|
|
43
28
|
|
|
44
|
-
|
|
29
|
+
## Legacy Flourish deployment
|
|
45
30
|
|
|
46
|
-
|
|
47
|
-
=== Setup Complete ===
|
|
31
|
+
Flourish-specific infrastructure (hardcoded project IDs, CI deploy workflows) lives in `infra/flourish/` and the existing `demo-deploy.yml` / `frontend-example-deploy.yml` workflows. New deployments should follow the generalized guides above with your own `$PROJECT_ID` and bucket names.
|
|
48
32
|
|
|
49
|
-
|
|
50
|
-
CDN IP: 34.120.xxx.xxx
|
|
51
|
-
URL: http://34.120.xxx.xxx/
|
|
52
|
-
(Point your DNS A record to this IP)
|
|
33
|
+
## Related
|
|
53
34
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
URL: http://34.149.xxx.xxx/
|
|
57
|
-
(Point your DNS A record to this IP)
|
|
58
|
-
``````
|
|
59
|
-
|
|
60
|
-
## Configure GitHub Secrets
|
|
61
|
-
|
|
62
|
-
Add the following secret to your GitHub repository:
|
|
63
|
-
|
|
64
|
-
### GCP_SA_KEY
|
|
65
|
-
|
|
66
|
-
1. Create a service account key:
|
|
67
|
-
``````bash
|
|
68
|
-
# Create service account
|
|
69
|
-
gcloud iam service-accounts create terreno-deploy \
|
|
70
|
-
--display-name="Terreno Deploy"
|
|
71
|
-
|
|
72
|
-
# Grant permissions
|
|
73
|
-
gcloud projects add-iam-policy-binding flourish-terreno \
|
|
74
|
-
--member="serviceAccount:terreno-deploy@flourish-terreno.iam.gserviceaccount.com" \
|
|
75
|
-
--role="roles/storage.objectAdmin"
|
|
76
|
-
|
|
77
|
-
gcloud projects add-iam-policy-binding flourish-terreno \
|
|
78
|
-
--member="serviceAccount:terreno-deploy@flourish-terreno.iam.gserviceaccount.com" \
|
|
79
|
-
--role="roles/compute.loadBalancerAdmin"
|
|
80
|
-
|
|
81
|
-
# Create JSON key
|
|
82
|
-
gcloud iam service-accounts keys create key.json \
|
|
83
|
-
--iam-account=terreno-deploy@flourish-terreno.iam.gserviceaccount.com
|
|
84
|
-
``````
|
|
85
|
-
|
|
86
|
-
2. Add the key to GitHub:
|
|
87
|
-
- Go to **Settings** → **Secrets and variables** → **Actions**
|
|
88
|
-
- Click **New repository secret**
|
|
89
|
-
- Name: `GCP_SA_KEY`
|
|
90
|
-
- Value: Paste the entire contents of `key.json`
|
|
91
|
-
- Click **Add secret**
|
|
92
|
-
|
|
93
|
-
3. Delete the local key file:
|
|
94
|
-
``````bash
|
|
95
|
-
rm key.json
|
|
96
|
-
``````
|
|
97
|
-
|
|
98
|
-
## Deploy to Production
|
|
99
|
-
|
|
100
|
-
Production deployments happen automatically when you push to the `master` branch:
|
|
101
|
-
|
|
102
|
-
``````bash
|
|
103
|
-
# Make changes to demo or example-frontend
|
|
104
|
-
git checkout master
|
|
105
|
-
git pull
|
|
106
|
-
# ... make changes ...
|
|
107
|
-
git add .
|
|
108
|
-
git commit -m "Update demo UI"
|
|
109
|
-
git push origin master
|
|
110
|
-
``````
|
|
111
|
-
|
|
112
|
-
The workflows will:
|
|
113
|
-
1. Build the app with Bun and Expo
|
|
114
|
-
2. Upload the build artifact
|
|
115
|
-
3. Sync assets to GCS with cache headers:
|
|
116
|
-
- Hashed assets: `Cache-Control: public, max-age=31536000, immutable`
|
|
117
|
-
- `index.html`: `Cache-Control: no-cache, no-store, must-revalidate`
|
|
118
|
-
4. Invalidate the CDN cache
|
|
119
|
-
|
|
120
|
-
### Triggered Workflows
|
|
121
|
-
|
|
122
|
-
| App | Workflow | Triggers on paths |
|
|
123
|
-
|-----|----------|-------------------|
|
|
124
|
-
| Demo | `demo-deploy.yml` | `demo/**`, `ui/**` |
|
|
125
|
-
| Example Frontend | `frontend-example-deploy.yml` | `example-frontend/**`, `ui/**`, `rtk/**` |
|
|
126
|
-
|
|
127
|
-
## Deploy PR Previews
|
|
128
|
-
|
|
129
|
-
Pull request previews deploy automatically when you open a PR that modifies the relevant paths:
|
|
130
|
-
|
|
131
|
-
``````bash
|
|
132
|
-
# Create a feature branch
|
|
133
|
-
git checkout -b feature/new-component
|
|
134
|
-
|
|
135
|
-
# Make changes
|
|
136
|
-
# ... edit files ...
|
|
137
|
-
|
|
138
|
-
git add .
|
|
139
|
-
git commit -m "Add new component"
|
|
140
|
-
git push origin feature/new-component
|
|
141
|
-
|
|
142
|
-
# Open a pull request on GitHub
|
|
143
|
-
``````
|
|
144
|
-
|
|
145
|
-
The workflow will:
|
|
146
|
-
1. Build the app with a preview-specific `baseUrl`
|
|
147
|
-
2. Deploy to `gs://BUCKET/_previews/pr-{number}/`
|
|
148
|
-
3. Create GitHub deployment with a preview URL
|
|
149
|
-
4. Comment on the PR with the preview link
|
|
150
|
-
|
|
151
|
-
### Preview URLs
|
|
152
|
-
|
|
153
|
-
Previews are accessible at:
|
|
154
|
-
- **Demo**: `http://{CDN_IP}/_previews/pr-{number}/` (or `https://storage.googleapis.com/flourish-terreno-terreno-demo/_previews/pr-{number}/` if CDN is not configured)
|
|
155
|
-
- **Example Frontend**: `http://{CDN_IP}/_previews/pr-{number}/` (or `https://storage.googleapis.com/flourish-terreno-terreno-frontend-example/_previews/pr-{number}/`)
|
|
156
|
-
|
|
157
|
-
### Preview Cleanup
|
|
158
|
-
|
|
159
|
-
When you close or merge a PR, the `preview-cleanup.yml` workflow automatically:
|
|
160
|
-
- Deletes preview files from both buckets
|
|
161
|
-
- Deactivates GitHub deployments
|
|
162
|
-
|
|
163
|
-
## Manual Deployment
|
|
164
|
-
|
|
165
|
-
To deploy manually without GitHub Actions:
|
|
166
|
-
|
|
167
|
-
``````bash
|
|
168
|
-
# Demo
|
|
169
|
-
cd demo
|
|
170
|
-
bun install
|
|
171
|
-
bun run compile
|
|
172
|
-
bun run export
|
|
173
|
-
gsutil -m -h "Cache-Control:public, max-age=31536000, immutable" \
|
|
174
|
-
rsync -r -d -x '.*\.html$' \
|
|
175
|
-
dist/ gs://flourish-terreno-terreno-demo/
|
|
176
|
-
gsutil -h "Cache-Control:no-cache, no-store, must-revalidate" \
|
|
177
|
-
cp dist/index.html gs://flourish-terreno-terreno-demo/index.html
|
|
178
|
-
|
|
179
|
-
# Invalidate CDN
|
|
180
|
-
gcloud compute url-maps invalidate-cdn-cache terreno-demo-url-map \
|
|
181
|
-
--path "/*" --async
|
|
182
|
-
|
|
183
|
-
# Example Frontend
|
|
184
|
-
cd example-frontend
|
|
185
|
-
bun install
|
|
186
|
-
bun run compile
|
|
187
|
-
bun run export
|
|
188
|
-
gsutil -m -h "Cache-Control:public, max-age=31536000, immutable" \
|
|
189
|
-
rsync -r -d -x '.*\.html$' \
|
|
190
|
-
dist/ gs://flourish-terreno-terreno-frontend-example/
|
|
191
|
-
gsutil -h "Cache-Control:no-cache, no-store, must-revalidate" \
|
|
192
|
-
cp dist/index.html gs://flourish-terreno-terreno-frontend-example/index.html
|
|
193
|
-
|
|
194
|
-
# Invalidate CDN
|
|
195
|
-
gcloud compute url-maps invalidate-cdn-cache terreno-frontend-example-url-map \
|
|
196
|
-
--path "/*" --async
|
|
197
|
-
``````
|
|
198
|
-
|
|
199
|
-
## Troubleshooting
|
|
200
|
-
|
|
201
|
-
### Build Fails with "Module not found"
|
|
202
|
-
|
|
203
|
-
**Problem**: Workspace dependencies not compiled.
|
|
204
|
-
|
|
205
|
-
**Solution**: Run `bun run compile` in `ui/` and `rtk/` before building the app.
|
|
206
|
-
|
|
207
|
-
### Preview URL Returns 404
|
|
208
|
-
|
|
209
|
-
**Problem**: CDN's `notFoundPage` serves root `index.html`, not the preview's.
|
|
210
|
-
|
|
211
|
-
**Solution**: The deploy workflow uploads "bare" route objects. Check that the workflow completed successfully.
|
|
212
|
-
|
|
213
|
-
### CDN Shows Stale Content
|
|
214
|
-
|
|
215
|
-
**Problem**: CDN cache not invalidated.
|
|
216
|
-
|
|
217
|
-
**Solution**: Run cache invalidation manually:
|
|
218
|
-
``````bash
|
|
219
|
-
gcloud compute url-maps invalidate-cdn-cache URLMAP_NAME --path "/*" --async
|
|
220
|
-
``````
|
|
221
|
-
|
|
222
|
-
### Permission Denied on gsutil
|
|
223
|
-
|
|
224
|
-
**Problem**: Service account lacks permissions.
|
|
225
|
-
|
|
226
|
-
**Solution**: Grant `roles/storage.objectAdmin`:
|
|
227
|
-
``````bash
|
|
228
|
-
gsutil iam ch "serviceAccount:SA_EMAIL:objectAdmin" gs://BUCKET_NAME
|
|
229
|
-
``````
|
|
230
|
-
|
|
231
|
-
### SPA Routes Return 404 on Refresh
|
|
232
|
-
|
|
233
|
-
**Problem**: Bucket not configured with `notFoundPage`.
|
|
234
|
-
|
|
235
|
-
**Solution**: Run the setup script or manually configure:
|
|
236
|
-
``````bash
|
|
237
|
-
gsutil web set -e index.html gs://BUCKET_NAME
|
|
238
|
-
``````
|
|
239
|
-
|
|
240
|
-
## Next Steps
|
|
241
|
-
|
|
242
|
-
- [GCP Hosting Architecture](../explanation/gcp-hosting-architecture.md) — Understand the design
|
|
243
|
-
- [Environment Variables Reference](../reference/environment-variables.md) — Configure runtime settings
|
|
244
|
-
- [Set up CI/CD pipelines](../how-to/README.md) — Automate testing and deployment
|
|
35
|
+
- [Environment variables](../reference/environment-variables.md)
|
|
36
|
+
- [Deployment baseline](../explanation/deployment-baseline.md)
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Deploy web to GCS + CDN
|
|
2
|
+
|
|
3
|
+
Host a static Terreno web export on Google Cloud Storage with Cloud CDN.
|
|
4
|
+
|
|
5
|
+
Replace placeholders: `$PROJECT_ID`, `$REGION`, `$WEB_BUCKET`, `$SITE_NAME`, `$DOMAIN`.
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- [gcloud CLI](https://cloud.google.com/sdk/docs/install) installed and authenticated
|
|
10
|
+
- Backend deployed and CORS configured — see [Deploy backend to Cloud Run](deploy-backend-to-cloud-run.md)
|
|
11
|
+
- [Build for web](build-for-web.md) completed with the correct `EXPO_PUBLIC_API_URL`
|
|
12
|
+
|
|
13
|
+
## 1. Build the web bundle
|
|
14
|
+
|
|
15
|
+
Set the API URL **before** export — it is inlined into the bundle:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
cd example-frontend
|
|
19
|
+
EXPO_PUBLIC_API_URL=https://api.example.com bun run export
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The export script is `bun expo export --platform web` (see `example-frontend/package.json`).
|
|
23
|
+
|
|
24
|
+
Output is in `dist/`.
|
|
25
|
+
|
|
26
|
+
## 2. Enable the Compute Engine API
|
|
27
|
+
|
|
28
|
+
Cloud CDN and its global load-balancing resources require the Compute Engine API:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
gcloud services enable compute.googleapis.com --project="$PROJECT_ID"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 3. Create the GCS bucket
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
gsutil mb -p "$PROJECT_ID" -l "$REGION" "gs://$WEB_BUCKET/"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## 4. Allow public object reads
|
|
41
|
+
|
|
42
|
+
Cloud CDN must be able to serve the bucket's objects to unauthenticated visitors:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
gsutil iam ch allUsers:objectViewer "gs://$WEB_BUCKET"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Do not grant `allUsers` a write role such as `objectAdmin`.
|
|
49
|
+
|
|
50
|
+
## 5. Configure SPA routing
|
|
51
|
+
|
|
52
|
+
Client-side routes require `index.html` for unknown paths:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
gsutil web set -e index.html "gs://$WEB_BUCKET"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Do not set `MainPageSuffix` — GCS 301 redirects break client-side routing.
|
|
59
|
+
|
|
60
|
+
## 6. Upload the build
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
gsutil -m -h "Cache-Control:public, max-age=31536000, immutable" \
|
|
64
|
+
rsync -r -d -x '.*\.html$' \
|
|
65
|
+
dist/ "gs://$WEB_BUCKET/"
|
|
66
|
+
|
|
67
|
+
gsutil -h "Cache-Control:no-cache, no-store, must-revalidate" \
|
|
68
|
+
cp dist/index.html "gs://$WEB_BUCKET/index.html"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## 7. Create HTTPS CDN resources
|
|
72
|
+
|
|
73
|
+
The load balancer serves the bucket over HTTPS only. A Google-managed certificate secures
|
|
74
|
+
the domain:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Backend bucket (CDN-enabled)
|
|
78
|
+
gcloud compute backend-buckets create "${SITE_NAME}-backend" \
|
|
79
|
+
--gcs-bucket-name="$WEB_BUCKET" \
|
|
80
|
+
--enable-cdn \
|
|
81
|
+
--no-negative-caching \
|
|
82
|
+
--project="$PROJECT_ID"
|
|
83
|
+
|
|
84
|
+
# URL map
|
|
85
|
+
gcloud compute url-maps create "${SITE_NAME}-url-map" \
|
|
86
|
+
--default-backend-bucket="${SITE_NAME}-backend" \
|
|
87
|
+
--project="$PROJECT_ID"
|
|
88
|
+
|
|
89
|
+
# Static IP
|
|
90
|
+
gcloud compute addresses create "${SITE_NAME}-ip" --global --project="$PROJECT_ID"
|
|
91
|
+
|
|
92
|
+
# Managed TLS certificate
|
|
93
|
+
gcloud compute ssl-certificates create "${SITE_NAME}-cert" \
|
|
94
|
+
--domains="$DOMAIN" \
|
|
95
|
+
--global \
|
|
96
|
+
--project="$PROJECT_ID"
|
|
97
|
+
|
|
98
|
+
# HTTPS proxy
|
|
99
|
+
gcloud compute target-https-proxies create "${SITE_NAME}-https-proxy" \
|
|
100
|
+
--url-map="${SITE_NAME}-url-map" \
|
|
101
|
+
--ssl-certificates="${SITE_NAME}-cert" \
|
|
102
|
+
--project="$PROJECT_ID"
|
|
103
|
+
|
|
104
|
+
# HTTPS forwarding rule
|
|
105
|
+
gcloud compute forwarding-rules create "${SITE_NAME}-https-forwarding-rule" \
|
|
106
|
+
--address="${SITE_NAME}-ip" \
|
|
107
|
+
--target-https-proxy="${SITE_NAME}-https-proxy" \
|
|
108
|
+
--global \
|
|
109
|
+
--ports=443 \
|
|
110
|
+
--project="$PROJECT_ID"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## 8. Redirect HTTP to HTTPS
|
|
114
|
+
|
|
115
|
+
Port 80 should redirect rather than serve the bundle. Without a listener there at all, `http://$DOMAIN` fails to connect instead of sending visitors to the secure URL.
|
|
116
|
+
|
|
117
|
+
`gcloud` exposes redirect behavior only through an imported spec, not through `url-maps create` flags:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
gcloud compute url-maps import "${SITE_NAME}-http-redirect-url-map" \
|
|
121
|
+
--global --project="$PROJECT_ID" --source=/dev/stdin <<SPEC
|
|
122
|
+
name: ${SITE_NAME}-http-redirect-url-map
|
|
123
|
+
defaultUrlRedirect:
|
|
124
|
+
httpsRedirect: true
|
|
125
|
+
redirectResponseCode: MOVED_PERMANENTLY_DEFAULT
|
|
126
|
+
SPEC
|
|
127
|
+
|
|
128
|
+
gcloud compute target-http-proxies create "${SITE_NAME}-http-proxy" \
|
|
129
|
+
--url-map="${SITE_NAME}-http-redirect-url-map" \
|
|
130
|
+
--project="$PROJECT_ID"
|
|
131
|
+
|
|
132
|
+
gcloud compute forwarding-rules create "${SITE_NAME}-forwarding-rule" \
|
|
133
|
+
--address="${SITE_NAME}-ip" \
|
|
134
|
+
--target-http-proxy="${SITE_NAME}-http-proxy" \
|
|
135
|
+
--global \
|
|
136
|
+
--ports=80 \
|
|
137
|
+
--project="$PROJECT_ID"
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Port 80 now only ever returns a 301; the bundle itself is served exclusively over TLS.
|
|
141
|
+
|
|
142
|
+
Or run the parameterized script, which provisions steps 7 and 8 in one pass:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
./scripts/setup-gcs-hosting.sh \
|
|
146
|
+
--project "$PROJECT_ID" \
|
|
147
|
+
--site-name "$SITE_NAME" \
|
|
148
|
+
--bucket "$WEB_BUCKET" \
|
|
149
|
+
--domain "$DOMAIN"
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## 9. Point DNS and wait for the certificate
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
gcloud compute addresses describe "${SITE_NAME}-ip" --global \
|
|
156
|
+
--project="$PROJECT_ID" --format='value(address)'
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Create an A record for `$DOMAIN` pointing at that IP. Managed certificates only begin provisioning once DNS resolves to the load balancer, and can take up to about an hour to become active:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
gcloud compute ssl-certificates describe "${SITE_NAME}-cert" --global \
|
|
163
|
+
--project="$PROJECT_ID" --format='value(managed.status)'
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Wait for `ACTIVE` before sending traffic. Still `PROVISIONING` after an hour usually means the A record does not resolve to the reserved IP.
|
|
167
|
+
|
|
168
|
+
## 10. Invalidate cache after deploy
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
gcloud compute url-maps invalidate-cdn-cache "${SITE_NAME}-url-map" \
|
|
172
|
+
--path "/*" --async --project="$PROJECT_ID"
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Static-only path
|
|
176
|
+
|
|
177
|
+
This guide hosts the `expo export -p web` output as static files. Server-rendered web (SSR, API routes) requires Expo SDK ≥ 55 — see [Web SSR and admin SPA](https://github.com/FlourishHealth/terreno/blob/master/docs/implementationPlans/web-ssr-and-admin-spa.md).
|
|
178
|
+
|
|
179
|
+
## Related
|
|
180
|
+
|
|
181
|
+
- [Build for web](build-for-web.md)
|
|
182
|
+
- [Deploy backend to Cloud Run](deploy-backend-to-cloud-run.md)
|
|
183
|
+
- [GCP architecture](../explanation/deployment-architecture-gcp.md)
|