grada-run 0.0.2 → 0.32.0
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/.github/workflows/deploy-docs.yml +37 -0
- package/.github/workflows/iac-validation.yml +303 -0
- package/.github/workflows/publish.yml +68 -0
- package/.github/workflows/sync-bedrock-models.yml +57 -0
- package/.github/workflows/test.yml +43 -0
- package/.muserules +31 -0
- package/LICENSE +21 -0
- package/README.md +193 -3
- package/apps/docs/.astro/collections/docs.schema.json +644 -0
- package/apps/docs/.astro/content-assets.mjs +4 -0
- package/apps/docs/.astro/content-modules.mjs +4 -0
- package/apps/docs/.astro/content.d.ts +179 -0
- package/apps/docs/.astro/data-store.json +1 -0
- package/apps/docs/.astro/dev.json +14 -0
- package/apps/docs/.astro/settings.json +5 -0
- package/apps/docs/.astro/types.d.ts +2 -0
- package/apps/docs/astro.config.mjs +97 -0
- package/apps/docs/package.json +17 -0
- package/apps/docs/src/content/docs/adrs/0001-s3-native-state-locking.md +37 -0
- package/apps/docs/src/content/docs/adrs/0002-eject-mechanism-pure-iac.md +39 -0
- package/apps/docs/src/content/docs/adrs/0003-sync-ai-context-strategy.md +48 -0
- package/apps/docs/src/content/docs/adrs/0004-iac-driven-diagnostic-context.md +37 -0
- package/apps/docs/src/content/docs/adrs/0005-ecs-fargate-alb-runtime-target.md +38 -0
- package/apps/docs/src/content/docs/adrs/0006-github-oidc-no-stored-keys.md +37 -0
- package/apps/docs/src/content/docs/adrs/0007-framework-detection-with-fallback.md +37 -0
- package/apps/docs/src/content/docs/adrs/0008-secrets-names-in-git-values-in-aws.md +37 -0
- package/apps/docs/src/content/docs/adrs/0009-regenerate-with-backup-on-rerun.md +37 -0
- package/apps/docs/src/content/docs/adrs/0010-advisory-only-security-scans.md +37 -0
- package/apps/docs/src/content/docs/cli/add.md +84 -0
- package/apps/docs/src/content/docs/cli/apply.md +32 -0
- package/apps/docs/src/content/docs/cli/db.md +200 -0
- package/apps/docs/src/content/docs/cli/destroy.md +31 -0
- package/apps/docs/src/content/docs/cli/diagnose.md +37 -0
- package/apps/docs/src/content/docs/cli/doctor.md +28 -0
- package/apps/docs/src/content/docs/cli/domain.md +57 -0
- package/apps/docs/src/content/docs/cli/drift.md +40 -0
- package/apps/docs/src/content/docs/cli/eject.md +29 -0
- package/apps/docs/src/content/docs/cli/exec.md +49 -0
- package/apps/docs/src/content/docs/cli/gc.md +37 -0
- package/apps/docs/src/content/docs/cli/init.md +72 -0
- package/apps/docs/src/content/docs/cli/logs.md +39 -0
- package/apps/docs/src/content/docs/cli/rollback.md +51 -0
- package/apps/docs/src/content/docs/cli/secrets.md +73 -0
- package/apps/docs/src/content/docs/cli/sleep.md +53 -0
- package/apps/docs/src/content/docs/cli/status.md +34 -0
- package/apps/docs/src/content/docs/cli/sync-ai.md +27 -0
- package/apps/docs/src/content/docs/guides/architecture.md +87 -0
- package/apps/docs/src/content/docs/guides/aws-credentials.md +72 -0
- package/apps/docs/src/content/docs/guides/background-workers.md +45 -0
- package/apps/docs/src/content/docs/guides/cicd-pipeline.md +64 -0
- package/apps/docs/src/content/docs/guides/database-connections.md +64 -0
- package/apps/docs/src/content/docs/guides/docker-compose.md +37 -0
- package/apps/docs/src/content/docs/guides/dockerfiles.md +46 -0
- package/apps/docs/src/content/docs/guides/ephemeral-pr-previews.md +39 -0
- package/apps/docs/src/content/docs/guides/examples.md +50 -0
- package/apps/docs/src/content/docs/guides/frameworks.md +88 -0
- package/apps/docs/src/content/docs/guides/headless.md +75 -0
- package/apps/docs/src/content/docs/guides/quickstart.md +52 -0
- package/apps/docs/src/content/docs/guides/rerun-init.md +43 -0
- package/apps/docs/src/content/docs/guides/secrets-management.md +83 -0
- package/apps/docs/src/content/docs/guides/understanding-your-bill.md +63 -0
- package/apps/docs/src/content/docs/index.mdx +103 -0
- package/apps/docs/src/content/docs/migrations/astro-vercel-to-aws.md +55 -0
- package/apps/docs/src/content/docs/migrations/heroku-procfile-to-aws.md +41 -0
- package/apps/docs/src/content/docs/migrations/nextjs-vercel-to-aws.md +51 -0
- package/apps/docs/src/content/docs/migrations/sveltekit-vercel-to-aws.md +63 -0
- package/apps/docs/src/content/docs/roadmap.md +97 -0
- package/apps/docs/src/content/docs/testing-strategy.md +32 -0
- package/apps/docs/src/content.config.ts +7 -0
- package/apps/docs/src/custom.css +14 -0
- package/apps/docs/tsconfig.json +6 -0
- package/bin/cli.js +140 -0
- package/package.json +105 -7
- package/scripts/sync-bedrock-models.js +22 -0
- package/scripts/test-iac.js +261 -0
- package/specs/add-redis-sqs-bedrock.md +128 -0
- package/specs/add-storage-dynamodb.md +106 -0
- package/specs/bedrock-model-catalog.md +131 -0
- package/specs/ci-pipeline.md +17 -0
- package/specs/cost-transparency.md +115 -0
- package/specs/custom-domains-and-ses.md +153 -0
- package/specs/database-suite-expansion.md +151 -0
- package/specs/db-connect.md +69 -0
- package/specs/db-lifecycle-migrations.md +159 -0
- package/specs/dependency-aware-init.md +176 -0
- package/specs/deploy-stack-to-grada-run-rebrand.md +45 -0
- package/specs/deployment-safety.md +170 -0
- package/specs/diagnose.md +16 -0
- package/specs/docs-hub.md +16 -0
- package/specs/dx-polish.md +46 -0
- package/specs/exec.md +25 -0
- package/specs/finops-cron-drift.md +161 -0
- package/specs/gc.md +26 -0
- package/specs/integration-suite.md +16 -0
- package/specs/logs.md +32 -0
- package/specs/rollback-live-polling.md +40 -0
- package/specs/secrets-pull-audit.md +51 -0
- package/specs/serverless-lambda-target.md +133 -0
- package/specs/status.md +31 -0
- package/specs/telemetry-and-spawn-hardening.md +69 -0
- package/specs/telemetry-hardening.md +35 -0
- package/src/commands/add.js +1111 -0
- package/src/commands/apply.js +214 -0
- package/src/commands/db/backup.js +229 -0
- package/src/commands/db/connect.js +304 -0
- package/src/commands/db/enable-vector.js +344 -0
- package/src/commands/db/import.js +604 -0
- package/src/commands/db/migrate.js +477 -0
- package/src/commands/db/restore.js +361 -0
- package/src/commands/db.js +87 -0
- package/src/commands/destroy.js +217 -0
- package/src/commands/diagnose.js +460 -0
- package/src/commands/doctor.js +109 -0
- package/src/commands/domain.js +685 -0
- package/src/commands/drift.js +243 -0
- package/src/commands/eject.js +127 -0
- package/src/commands/exec.js +222 -0
- package/src/commands/gc.js +250 -0
- package/src/commands/init.js +649 -0
- package/src/commands/logs.js +256 -0
- package/src/commands/rollback.js +323 -0
- package/src/commands/secrets.js +485 -0
- package/src/commands/sleep.js +347 -0
- package/src/commands/status.js +309 -0
- package/src/commands/sync-ai.js +115 -0
- package/src/commands/wake.js +337 -0
- package/src/core/parser.js +126 -0
- package/src/core/telemetry.js +244 -0
- package/src/data/bedrock-models.json +896 -0
- package/src/utils/addons.js +126 -0
- package/src/utils/ai-rules.js +59 -0
- package/src/utils/args.js +91 -0
- package/src/utils/aws.js +178 -0
- package/src/utils/backup.js +69 -0
- package/src/utils/bedrock-catalog.js +511 -0
- package/src/utils/capabilities.js +500 -0
- package/src/utils/command.js +65 -0
- package/src/utils/db-tunnel.js +164 -0
- package/src/utils/detector.js +298 -0
- package/src/utils/dockerCompose.js +65 -0
- package/src/utils/domains.js +73 -0
- package/src/utils/ecs-runner.js +289 -0
- package/src/utils/ecs.js +92 -0
- package/src/utils/frameworks.js +55 -0
- package/src/utils/generator.js +527 -0
- package/src/utils/hcl.js +426 -0
- package/src/utils/lambda-ecr.js +185 -0
- package/src/utils/prompts.js +278 -0
- package/src/utils/rds.js +131 -0
- package/src/utils/resolvers.js +174 -0
- package/src/utils/sleep-state.js +140 -0
- package/src/utils/sleep-targets.js +139 -0
- package/src/utils/system.js +42 -0
- package/src/utils/terraform.js +70 -0
- package/src/utils/visualizer.js +381 -0
- package/src/utils/warnings.js +49 -0
- package/templates/README.md +150 -0
- package/templates/docker/django.Dockerfile +40 -0
- package/templates/docker/go.Dockerfile +23 -0
- package/templates/docker/nestjs.Dockerfile +33 -0
- package/templates/docker/nextjs.Dockerfile +55 -0
- package/templates/docker/node.Dockerfile +24 -0
- package/templates/docker/nuxt.Dockerfile +47 -0
- package/templates/docker/python.Dockerfile +38 -0
- package/templates/docker/rails.Dockerfile +59 -0
- package/templates/docker/static.Dockerfile +32 -0
- package/templates/docker/svelte.Dockerfile +52 -0
- package/templates/github/deploy-lambda.yml +120 -0
- package/templates/github/deploy.yml +138 -0
- package/templates/github/drift.yml +112 -0
- package/templates/github/preview-lambda.yml +86 -0
- package/templates/github/preview.yml +69 -0
- package/templates/github/teardown.yml +43 -0
- package/templates/terraform/addons/bedrock.tf +34 -0
- package/templates/terraform/addons/cron-lambda.tf +78 -0
- package/templates/terraform/addons/cron.tf +101 -0
- package/templates/terraform/addons/dynamodb.tf +73 -0
- package/templates/terraform/addons/redis.tf +64 -0
- package/templates/terraform/addons/s3.tf +143 -0
- package/templates/terraform/addons/ses.tf +73 -0
- package/templates/terraform/addons/sqs.tf +67 -0
- package/templates/terraform/backend.tf +22 -0
- package/templates/terraform/cloudfront-lambda.tf +80 -0
- package/templates/terraform/cloudfront.tf +80 -0
- package/templates/terraform/database-aurora-postgresql.tf +92 -0
- package/templates/terraform/database-mysql.tf +72 -0
- package/templates/terraform/database.tf +71 -0
- package/templates/terraform/main-lambda.tf +229 -0
- package/templates/terraform/main.tf +296 -0
- package/templates/terraform/network.tf +95 -0
- package/templates/terraform/oidc.tf +64 -0
- package/templates/terraform/secrets.tf +31 -0
- package/templates/terraform/worker.tf +69 -0
- package/tests/__snapshots__/generator.test.js.snap +9633 -0
- package/tests/add.test.js +2037 -0
- package/tests/ai.test.js +94 -0
- package/tests/apply.test.js +488 -0
- package/tests/args.test.js +86 -0
- package/tests/aws.test.js +244 -0
- package/tests/capabilities.test.js +307 -0
- package/tests/cli.test.js +29 -0
- package/tests/command.test.js +100 -0
- package/tests/commands-import.test.js +74 -0
- package/tests/db.test.js +2704 -0
- package/tests/destroy.test.js +391 -0
- package/tests/detector.test.js +79 -0
- package/tests/diagnose.test.js +779 -0
- package/tests/doctor.test.js +202 -0
- package/tests/domain.test.js +899 -0
- package/tests/drift.test.js +243 -0
- package/tests/ecs.test.js +130 -0
- package/tests/eject.test.js +65 -0
- package/tests/exec.test.js +380 -0
- package/tests/gc.test.js +496 -0
- package/tests/generator.test.js +794 -0
- package/tests/headless.test.js +562 -0
- package/tests/lambda-ecr.test.js +185 -0
- package/tests/logs.test.js +447 -0
- package/tests/parser.test.js +160 -0
- package/tests/rds.test.js +244 -0
- package/tests/resolvers.test.js +282 -0
- package/tests/rollback.test.js +692 -0
- package/tests/secrets.test.js +752 -0
- package/tests/sleep-wake.test.js +1016 -0
- package/tests/status.test.js +370 -0
- package/tests/system.test.js +70 -0
- package/tests/telemetry.test.js +520 -0
- package/tests/terraform.test.js +84 -0
- package/tests/visualizer.test.js +496 -0
- package/vitest.config.js +9 -0
- package/index.js +0 -2
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Docker Compose Support
|
|
3
|
+
description: How grada maps docker-compose.yml services to ECS — web-service selection, ports, env vars, and sidecars.
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 5
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
If your repo contains a Compose file (`docker-compose.yml`, `docker-compose.yaml`, `compose.yml`, or `compose.yaml`), setup parses it (`src/utils/dockerCompose.js`) and translates its services into the ECS task definition. Your Compose file keeps working locally, and these are the exact mapping rules that decide what runs in AWS.
|
|
9
|
+
|
|
10
|
+
## File discovery
|
|
11
|
+
|
|
12
|
+
Only the repo root is checked, trying `docker-compose.yml`, `docker-compose.yaml`, `compose.yml`, then `compose.yaml` in order — the first file found wins. A file with no `services` key — or one that fails YAML parsing — is treated as absent (a warning is printed, setup continues), so a stray or malformed file never blocks generation.
|
|
13
|
+
|
|
14
|
+
## Which service is "web"
|
|
15
|
+
|
|
16
|
+
The service used as the ECS web service is the **first service with an exposed port**; if none exposes a port, the first service listed wins. Every other service becomes an ECS **sidecar** in the same task definition. Structure your file accordingly: the publicly reachable app must be the port-exposing service.
|
|
17
|
+
|
|
18
|
+
## Port mapping
|
|
19
|
+
|
|
20
|
+
The container port is taken from the **last segment of the first port entry** — `"8080:80"` and `"127.0.0.1:8001:8001"` both resolve to the right-hand value (`80` and `8001`). Only the first entry is read, and any non-numeric characters are stripped. This port overrides the configured container port during setup, and the ALB health check targets it.
|
|
21
|
+
|
|
22
|
+
## Environment and command injection
|
|
23
|
+
|
|
24
|
+
- **Environment** supports both Compose styles: `environment:` as a mapping is used as-is; as a list (`- KEY=value`) each entry is split on the first `=`.
|
|
25
|
+
- The web service's variables are injected directly into the ECS task definition, and its `command` overrides the container start command — but only when no `Procfile` `web:` process already set one (`Procfile` wins; see [Dockerfiles](/grada/guides/dockerfiles/)).
|
|
26
|
+
- Sidecars get the same treatment: their environment is injected, their `command` is preserved, a missing `image` defaults to `alpine:latest`, and each sidecar logs to the shared CloudWatch log group under an `ecs-<service>` stream prefix.
|
|
27
|
+
|
|
28
|
+
## What this means in practice
|
|
29
|
+
|
|
30
|
+
- Sidecars (Redis, Memcached, background helpers) run **in the same task** as the web container and share its lifecycle — this is co-location, not separate services.
|
|
31
|
+
- Compose `build:` contexts are not used in AWS; the image is built from the generated `Dockerfile` by the [CI/CD pipeline](/grada/guides/cicd-pipeline/).
|
|
32
|
+
- Runtime secrets still belong in AWS Secrets Manager, not in Compose `environment:`. See [Secrets Management](/grada/guides/secrets-management/).
|
|
33
|
+
|
|
34
|
+
## See also
|
|
35
|
+
|
|
36
|
+
- [Supported Frameworks](/grada/guides/frameworks/) for detection and defaults.
|
|
37
|
+
- [Dockerfiles & the container contract](/grada/guides/dockerfiles/) for runtime requirements.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Dockerfiles & the Container Contract
|
|
3
|
+
description: What your app must do at runtime (port, bind address, health check) and the per-framework prerequisites.
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 4
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Setup generates a framework-specific Alpine multi-stage `Dockerfile` engineered for zero Critical/High CVEs. Your app only needs to honor a small runtime contract — plus a few per-framework prerequisites printed as warnings (`src/utils/warnings.js`) at the end of setup.
|
|
9
|
+
|
|
10
|
+
## The container contract
|
|
11
|
+
|
|
12
|
+
Every generated image assumes three things. Violating any of them is the most common cause of failing ALB health checks after an otherwise successful `apply`:
|
|
13
|
+
|
|
14
|
+
1. **Listen on `$PORT`.** The container must serve traffic on the port baked in as `{{PORT}}` (default per framework — see [Supported Frameworks](/grada/guides/frameworks/)).
|
|
15
|
+
2. **Bind `0.0.0.0`, not `localhost`.** Localhost-bound apps are unreachable inside ECS networking and Docker.
|
|
16
|
+
3. **Answer the health check with `200 OK`.** The ALB polls your health-check path (default `/`) and accepts any `2xx–3xx` status; anything outside that range marks the task unhealthy and the pipeline's new deployment never stabilizes.
|
|
17
|
+
|
|
18
|
+
## Per-framework prerequisites
|
|
19
|
+
|
|
20
|
+
| Framework | What setup warns you about |
|
|
21
|
+
| --------- | -------------------------- |
|
|
22
|
+
| NestJS | Bind `0.0.0.0` in `src/main.ts`: `await app.listen(process.env.PORT ?? 3000, '0.0.0.0')` |
|
|
23
|
+
| Next.js | Set `output: 'standalone'` in your Next config and create a health-check route (copy-paste code is in the generated README's "Critical Application Prerequisites") |
|
|
24
|
+
| Node.js / Express | A `start` script in `package.json` (e.g. `"start": "node index.js"`) and `0.0.0.0` binding |
|
|
25
|
+
| Python (FastAPI) | Web framework in `requirements.txt`, `0.0.0.0` binding, and a health-check route returning `200 OK` |
|
|
26
|
+
| Rails | Your default `Dockerfile` is backed up to `Dockerfile.bak` and replaced with the Alpine build; if you use SQLite locally but provisioned RDS, add the `pg` gem |
|
|
27
|
+
| Static sites | Output folder defaults to `/app/dist` — if your framework emits `build/` or `out/`, update the `COPY` command; ensure a `build` script exists (e.g. `vite build`) |
|
|
28
|
+
|
|
29
|
+
Warnings are skipped with `--preconfigured` and for `static` projects whose build directory was auto-detected.
|
|
30
|
+
|
|
31
|
+
## What command runs your app
|
|
32
|
+
|
|
33
|
+
The container's start command is resolved in this order:
|
|
34
|
+
|
|
35
|
+
1. `Procfile` `web:` command, if a `Procfile` exists (a `worker:` process additionally generates `worker.tf`, i.e. a second ECS service that doubles Fargate cost).
|
|
36
|
+
2. Otherwise the `command` of the `docker-compose.yml` web service, if one exists.
|
|
37
|
+
3. Otherwise the default `CMD` in the generated `Dockerfile`.
|
|
38
|
+
|
|
39
|
+
## Keeping images lean
|
|
40
|
+
|
|
41
|
+
Setup writes a `.dockerignore` excluding `.git/`, `terraform/`, state files, and `.env`, and appends Terraform entries to an existing `.gitignore`. Never commit `.env` — runtime secrets come from AWS Secrets Manager (see [Secrets Management](/grada/guides/secrets-management/)).
|
|
42
|
+
|
|
43
|
+
## See also
|
|
44
|
+
|
|
45
|
+
- [CI/CD Pipeline & First Deploy](/grada/guides/cicd-pipeline/) for how the image is built and rolled out.
|
|
46
|
+
- [diagnose](/grada/cli/diagnose/) for reading ECS failure output when the contract is broken.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Ephemeral PR Previews"
|
|
3
|
+
description: "Spin up isolated temporary AWS environments for every pull request."
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 8
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
When enabled, `grada` automatically configures your GitHub Actions pipeline to spin up isolated, temporary AWS environments every time a developer opens a Pull Request.
|
|
9
|
+
|
|
10
|
+
A bot will comment on the PR with a live URL (e.g., `http://pr-123-your-app...`), allowing your team to test features, UI changes, and API updates before merging to `main`. When the PR is closed or merged, the environment is automatically destroyed.
|
|
11
|
+
|
|
12
|
+
### 🏗️ How it Works
|
|
13
|
+
|
|
14
|
+
Under the hood, `grada` utilizes **Terraform Workspaces**.
|
|
15
|
+
|
|
16
|
+
When a PR is opened, Terraform creates a new workspace (e.g., `pr-12`). It provisions a completely isolated Application Load Balancer and ECS Fargate Task using the exact same infrastructure definitions as your production environment, ensuring 100% parity. On `--target lambda` projects the same workspace model provisions an isolated function and API Gateway per PR instead, deploys the PR-tagged image to it, and comments the preview API Gateway URL — same open-and-teardown lifecycle, no ALB per PR.
|
|
17
|
+
|
|
18
|
+
To save time and simplify architecture, PR environments **share** your production AWS Secrets Manager vault and ECR Image Repository.
|
|
19
|
+
|
|
20
|
+
### ⚖️ The Rule of Thumb: Should I enable this?
|
|
21
|
+
|
|
22
|
+
**✅ Enable PR Previews if:**
|
|
23
|
+
* You are working on a team of 2+ developers and require visual QA or UX sign-off before merging code.
|
|
24
|
+
* You are building a frontend application or full-stack monolith where seeing the live UI is critical.
|
|
25
|
+
|
|
26
|
+
**❌ Do NOT enable PR Previews if:**
|
|
27
|
+
* You are a solo developer (you can just test locally).
|
|
28
|
+
* You have a massive volume of PRs (e.g., automated Dependabot updates). Spinning up an AWS Load Balancer takes ~3 minutes, which will slow down rapid automated merges.
|
|
29
|
+
|
|
30
|
+
### 💰 AWS Cost Implications
|
|
31
|
+
|
|
32
|
+
Because PR previews provision a real Application Load Balancer (ALB) and ECS Fargate compute tasks, **they are not free.**
|
|
33
|
+
|
|
34
|
+
* **Compute:** You are charged standard AWS Fargate rates per minute while the PR environment is running.
|
|
35
|
+
* **Load Balancing:** AWS charges ~$16/month per active Load Balancer. If a PR is open for 2 days, you pay the prorated ALB cost for those 48 hours (~$1.00).
|
|
36
|
+
* **Addons:** Because [`grada add`](/grada/cli/add/) resources use `${local.app_name}`, each open PR preview workspace provisions its own isolated S3 bucket and/or DynamoDB table — accruing usage-based storage, request, and PITR charges until the PR closes and the workspace is destroyed. If you use `db:redis`, each open PR also runs its own isolated Valkey node at ~$9.49/mo (~$0.013/hr) until the PR closes, while `queue:sqs`, `ai:bedrock`, and `cron` add no fixed per-PR cost (each open PR runs its own copy of the schedule, billed only for Fargate seconds per invocation). Secrets Manager secrets are shared via `data` source at no extra per-PR secret cost. SES (`email:ses`) is the exception: the domain identity, DKIM, MAIL FROM, and DNS records are account-wide singletons scoped to the production workspace, so previews neither duplicate them nor delete them on teardown — preview containers simply inherit sending permission through their own task role.
|
|
37
|
+
* **Custom domains:** [`domain add`](/grada/cli/domain/) resources (ACM certificate, validation, and alias records) are likewise scoped to the production workspace. PR previews serve over their own isolated `*.cloudfront.net` URL and never claim your production alias, so closing a PR cannot disturb production DNS or TLS.
|
|
38
|
+
|
|
39
|
+
To keep costs low, ensure your team closes or merges Pull Requests promptly so the `teardown.yml` workflow can destroy the resources and stop the billing clock!
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Reference Implementations & Examples
|
|
3
|
+
description: Example repositories demonstrating how grada handles frameworks and architectural patterns, plus ecosystem plugins and starters.
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 3
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
These repositories demonstrate how `grada` handles various frameworks and architectural patterns. Each example includes the auto-generated Terraform, GitHub Actions, and container configurations.
|
|
9
|
+
|
|
10
|
+
## Featured migrations
|
|
11
|
+
|
|
12
|
+
* **[Heroku to AWS Migration (Django)](https://github.com/anton-codes-iac/deploy-stack-heroku-django-example):** A classic Heroku-style monolith migrated via the Procfile Importer, demonstrating a multi-container Web and Celery Worker architecture deployed from a single codebase.
|
|
13
|
+
* **[Vercel to AWS Migration (Next.js)](https://github.com/anton-codes-iac/deploy-stack-vercel-nextjs-example):** Demonstrates automatic translation of Vercel edge routing (`vercel.json`) to native AWS Application Load Balancer rules.
|
|
14
|
+
* **[Docker Compose to AWS Migration](https://github.com/anton-codes-iac/deploy-stack-docker-compose-example):** Demonstrates automatic translation of local `docker-compose.yml` sidecars (like Redis) into a multi-container AWS ECS Task Definition communicating over `localhost`.
|
|
15
|
+
|
|
16
|
+
## DevSecOps & security architectures
|
|
17
|
+
|
|
18
|
+
* **[Zero-Secret AWS Secrets Manager Injection](https://github.com/anton-codes-iac/deploy-stack-secrets-example):** A production-grade Node.js architecture demonstrating zero-plaintext secret injection. It pushes local `.env` variables directly to AWS and maps them into ECS memory at runtime, exposing a live endpoint querying GitHub's API.
|
|
19
|
+
|
|
20
|
+
## Frontend & fullstack frameworks
|
|
21
|
+
|
|
22
|
+
* **[Next.js Fullstack App](https://github.com/anton-codes-iac/deploy-stack-nextjs-example):** A complete Next.js deployment showcasing the generated Terraform, CloudFront setup, and automated OIDC workflow.
|
|
23
|
+
* **[Vite / React SPA](https://github.com/anton-codes-iac/deploy-stack-vite-example):** Demonstrates SPA routing and `dist/` auto-detection.
|
|
24
|
+
* **[Create React App](https://github.com/anton-codes-iac/deploy-stack-cra-example):** Validates backward compatibility with legacy Webpack pipelines and `build/` auto-detection.
|
|
25
|
+
* **[Astro Static Site](https://github.com/anton-codes-iac/deploy-stack-astro-example):** Demonstrates modern static site generation (SSG).
|
|
26
|
+
* **[SvelteKit Application](https://github.com/anton-codes-iac/deploy-stack-svelte-example):** Demonstrates static adapter integration and custom output folder detection.
|
|
27
|
+
* **[Nuxt 3 (SSR)](https://github.com/anton-codes-iac/deploy-stack-nuxt-example):** Demonstrates a fully server-side rendered Nuxt application using Nitro's optimized Node output.
|
|
28
|
+
|
|
29
|
+
## Backend APIs & monoliths
|
|
30
|
+
|
|
31
|
+
* **[Express.js API](https://github.com/anton-codes-iac/deploy-stack-express-example):** A standard Node.js backend setup.
|
|
32
|
+
* **[NestJS API](https://github.com/anton-codes-iac/deploy-stack-nest-example):** A robust NestJS architecture utilizing AST code-patching and highly optimized multi-stage TypeScript builds.
|
|
33
|
+
* **[Python FastAPI](https://github.com/anton-codes-iac/deploy-stack-fastapi-example):** A Python API demonstrating unprivileged port mapping.
|
|
34
|
+
* **[Ruby on Rails](https://github.com/anton-codes-iac/deploy-stack-rails-example):** A production Rails 7+ setup featuring an auto-provisioned PostgreSQL database and secure `RAILS_MASTER_KEY` string-literal injection into the initial Secrets Manager placeholder.
|
|
35
|
+
* **[Django / Python](https://github.com/anton-codes-iac/deploy-stack-django-example):** A secure Gunicorn/WSGI implementation with PostgreSQL and unprivileged container adapters.
|
|
36
|
+
* **[Go / Fiber](https://github.com/anton-codes-iac/deploy-stack-go-example):** A distroless, compiled Go binary deployment demonstrating ultra-low memory footprints and instant boot times.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Ecosystem plugins & starters
|
|
41
|
+
|
|
42
|
+
In addition to standalone reference repositories, `grada` provides native integrations that hook directly into framework build pipelines and community template engines:
|
|
43
|
+
|
|
44
|
+
* **[astro-grada](https://www.npmjs.com/package/astro-grada):** Push-button deployment plugin for Astro sites.
|
|
45
|
+
* **[nuxt-grada](https://www.npmjs.com/package/nuxt-grada):** Nitro-optimized deployment integration for Nuxt 3 applications.
|
|
46
|
+
* **[vite-plugin-grada](https://www.npmjs.com/package/vite-plugin-grada):** Zero-config Vite build plugin for single-page applications.
|
|
47
|
+
* **[svelte-adapter-grada](https://www.npmjs.com/package/svelte-adapter-grada):** Native SvelteKit adapter producing optimized Fargate container builds.
|
|
48
|
+
* **[nest-grada](https://www.npmjs.com/package/nest-grada):** Native Angular DevKit schematic for NestJS, installable via `nest add`.
|
|
49
|
+
* **[cookiecutter-django-grada](https://github.com/anton-codes-iac/cookiecutter-django-grada):** Community Django starter listed on Django Packages.
|
|
50
|
+
* **[cookiecutter-fastapi-grada](https://github.com/anton-codes-iac/cookiecutter-fastapi-grada):** Instant scaffolding for modern, async FastAPI deployments.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Supported Frameworks & Detection
|
|
3
|
+
description: Which frameworks grada detects, the signals it looks for, the valid --framework ids, and per-framework requirements.
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 2
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
`grada` is designed to be as "zero-config" as possible. During setup, it inspects your repo (`src/utils/detector.js`) and preselects a framework preset. However, because different frameworks have unique internal architectures (especially around network binding and build outputs), a few frameworks require minor application-level tweaks to run securely in a Dockerized AWS Fargate environment.
|
|
9
|
+
|
|
10
|
+
## The 3-tier support philosophy
|
|
11
|
+
|
|
12
|
+
We handle framework requirements using a 3-tier strategy so you are never left guessing why a deployment failed:
|
|
13
|
+
|
|
14
|
+
1. **Zero-touch plugins (Tier 1):** If you use one of our ecosystem plugins (e.g., `nest add nest-grada` or `cookiecutter-django-grada`), your code is automatically patched and configured. Zero manual intervention required.
|
|
15
|
+
2. **Intelligent CLI pre-flight (Tier 2):** If you run the standalone `grada` CLI against a raw repository, the CLI statically analyzes your code. If it detects a missing production requirement (like a localhost binding), it will flag it inline in your terminal with the exact copy-paste fix.
|
|
16
|
+
3. **In-repo docs (Tier 3):** The generated `DEPLOYMENT.md` file always contains a framework-specific checklist before you push to CI/CD.
|
|
17
|
+
|
|
18
|
+
## Detection precedence
|
|
19
|
+
|
|
20
|
+
Checks run top-down; the first match wins.
|
|
21
|
+
|
|
22
|
+
| # | Signal | Preset (`id` / name) |
|
|
23
|
+
| - | ------ | -------------------- |
|
|
24
|
+
| 1 | `package.json` depends on `@nestjs/core` | `nestjs` / NestJS |
|
|
25
|
+
| 2 | `package.json` depends on `next` | `nextjs` / Next.js |
|
|
26
|
+
| 3 | `package.json` depends on `nuxt` | `nuxt` / Nuxt 3 (SSR) |
|
|
27
|
+
| 4 | `package.json` depends on `express` | `node` / Node.js / Express |
|
|
28
|
+
| 5 | `package.json` depends on `@sveltejs/kit` | `svelte` / SvelteKit SSR |
|
|
29
|
+
| 6 | `package.json` depends on `react-scripts`, `gatsby`, `astro`, `vite`, `@vue/cli-service`, or `@angular/cli` | `static` / (that generator) |
|
|
30
|
+
| 7 | `requirements.txt` contains `fastapi` | `python` / Python FastAPI |
|
|
31
|
+
| 8 | `requirements.txt` contains `django`, or `manage.py` exists | `django` / Django |
|
|
32
|
+
| 9 | `Gemfile` contains a `rails` gem | `rails` / Ruby on Rails |
|
|
33
|
+
| 10 | `go.mod` exists | `go` / Go |
|
|
34
|
+
| 11 | No match | No preset — you pick from the interactive list |
|
|
35
|
+
|
|
36
|
+
Notes from the actual code:
|
|
37
|
+
|
|
38
|
+
- Both `dependencies` and `devDependencies` are searched, so a framework listed only under dev dependencies still matches.
|
|
39
|
+
- A malformed `package.json` or `vercel.json` is silently ignored (no match), never fatal.
|
|
40
|
+
- An empty `vercel.json` (no `redirects`, `headers`, or `rewrites`) is treated as absent.
|
|
41
|
+
|
|
42
|
+
## Valid `--framework` ids
|
|
43
|
+
|
|
44
|
+
The interactive picker and the headless `--framework` flag accept: `node`, `nestjs`, `nextjs`, `nuxt`, `svelte`, `python`, `django`, `rails`, `go`, `static`. In headless mode with no `--framework`, detection applies and anything unmatched falls back to `static`.
|
|
45
|
+
|
|
46
|
+
## Per-framework defaults
|
|
47
|
+
|
|
48
|
+
- **Static build directory** (`buildDir`): SvelteKit `build`, Gatsby `public`, everything else (`astro`, `vite`, Vue, Angular) `dist`. This selects the folder the generated `Dockerfile` serves.
|
|
49
|
+
- **Default container port**: `8080` for `static` and `go`, `8000` for `python` and `django`, `3000` for everything else (headless uses `8080` only when `--framework=static`, else `3000`).
|
|
50
|
+
- **Database prompt**: offered only for backend presets (`node`, `nestjs`, `nextjs`, `nuxt`, `svelte`, `python`, `django`, `rails`, `go`).
|
|
51
|
+
|
|
52
|
+
## Framework requirements cheat sheet
|
|
53
|
+
|
|
54
|
+
| Framework | What `grada` automates | Application code requirement | Zero-click starter / plugin |
|
|
55
|
+
|---|---|---|---|
|
|
56
|
+
| **Next.js** | Multi-stage Dockerfile, CloudFront edge routing, `vercel.json` parsing | `output: 'standalone'` must be set in `next.config.js` | Built-in CLI detection |
|
|
57
|
+
| **NestJS** | Multi-stage TypeScript build (`dist/`), unprivileged Node runtime | `await app.listen(port, '0.0.0.0')` in `src/main.ts` | `nest-grada` (`nest add`) |
|
|
58
|
+
| **FastAPI** | Alpine Python container, Uvicorn CLI args, unprivileged port mapping | None (0.0.0.0 set via Docker CMD) | `cookiecutter-fastapi-grada` |
|
|
59
|
+
| **Django** | Gunicorn WSGI adapter, Celery worker topologies, RDS bindings | None (0.0.0.0 set via Docker CMD) | `cookiecutter-django-grada` |
|
|
60
|
+
| **Ruby on Rails** | Puma adapter, `RAILS_MASTER_KEY` injection into Secrets Manager placeholder, Kamal Dockerfile replaced with 0-CVE Alpine build | None (0.0.0.0 set via Docker CMD) | `rails-template-grada` |
|
|
61
|
+
| **Nuxt 3** | Nitro-optimized Node output | None (`NITRO_HOST=0.0.0.0` injected automatically) | `nuxt-grada` |
|
|
62
|
+
| **SvelteKit** | Node adapter conversion | None (`HOST=0.0.0.0` injected automatically) | `svelte-adapter-grada` |
|
|
63
|
+
| **Static Sites** *(Vite, Astro, React)* | Output folder detection (`dist/`, `build/`), Nginx routing | None | `vite-plugin-grada` |
|
|
64
|
+
|
|
65
|
+
## Post-detection checks
|
|
66
|
+
|
|
67
|
+
After detection, setup validates framework-specific requirements and warns before generating:
|
|
68
|
+
|
|
69
|
+
- **NestJS**: `src/main.ts` (or `main.js`) must bind `0.0.0.0`, e.g. `await app.listen(process.env.PORT ?? 3000, '0.0.0.0')`.
|
|
70
|
+
- **Next.js**: config must set `output: 'standalone'` (`.js/.mjs/.cjs/.ts` checked).
|
|
71
|
+
- **SvelteKit**: adapter must not be `@sveltejs/adapter-vercel` or `adapter-auto`.
|
|
72
|
+
- **Astro**: adapter must not be `@astrojs/vercel`.
|
|
73
|
+
|
|
74
|
+
Alongside detection, setup also auto-detects `Procfile` (web/worker commands), `vercel.json` edge rules (translated to ALB listener rules), and `docker-compose.yml` services (port override plus sidecars).
|
|
75
|
+
|
|
76
|
+
## The golden rule: 0.0.0.0 vs localhost
|
|
77
|
+
|
|
78
|
+
The most common reason a newly deployed container fails its ALB health check is network binding.
|
|
79
|
+
|
|
80
|
+
In local development, frameworks bind to `localhost` (or `127.0.0.1`) for security. However, inside a Docker container on AWS ECS, binding to `localhost` means the web server only listens to internal container traffic. The AWS Application Load Balancer (ALB) trying to route traffic from the outside world will hit a closed port, resulting in a `502 Bad Gateway` or `503 Service Temporarily Unavailable`.
|
|
81
|
+
|
|
82
|
+
**Always ensure your application explicitly binds to `0.0.0.0`.**
|
|
83
|
+
|
|
84
|
+
## See also
|
|
85
|
+
|
|
86
|
+
- [Dockerfiles & the container contract](/grada/guides/dockerfiles/) for what your app must do at runtime.
|
|
87
|
+
- [Headless Mode](/grada/guides/headless/) for automating framework selection.
|
|
88
|
+
- [Examples](/grada/guides/examples/) for reference repositories and ecosystem plugins per framework.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Headless Mode & Automation Guide"
|
|
3
|
+
description: "Run grada without prompts for CI/CD pipelines, scripts, and framework plugins."
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 11
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
The `grada` CLI is designed to be fully automatable for CI/CD pipelines, custom scripts, Cookiecutters, and framework plugins (like `vite-plugin-grada`).
|
|
9
|
+
|
|
10
|
+
By passing the `--headless` flag, you bypass all interactive terminal prompts. This is a tested contract (`tests/headless.test.js`): with `--headless --preconfigured`, the CLI guarantees no interactive prompt ever fires, so external schematics and CI pipelines can invoke it without hanging.
|
|
11
|
+
|
|
12
|
+
## Required Flags
|
|
13
|
+
To use headless mode, simply include the `--headless` flag.
|
|
14
|
+
|
|
15
|
+
If `grada` cannot auto-detect your framework, you should also provide the `--framework` flag to ensure the correct infrastructure is generated.
|
|
16
|
+
|
|
17
|
+
* **Valid `--framework` options:** `node`, `nestjs`, `nextjs`, `nuxt`, `svelte`, `python`, `django`, `rails`, `go`, `static`
|
|
18
|
+
|
|
19
|
+
## Optional Configuration Flags
|
|
20
|
+
|
|
21
|
+
You can append any of these flags to customize the generated architecture. These map exactly to the options available in the interactive setup:
|
|
22
|
+
|
|
23
|
+
| Flag | Description | Default |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| `--region=<region>` | The AWS region to deploy to (e.g., `us-east-1`, `eu-west-1`). | `us-east-2` |
|
|
26
|
+
| `--size=<size>` | The Fargate compute size (`micro` or `small`). | `micro` |
|
|
27
|
+
| `--port=<number>` | The internal port your container exposes. | Framework dependent (`3000`, `8080`, `8000`) |
|
|
28
|
+
| `--healthCheckPath=<path>`| The ALB health check endpoint path. | `/` |
|
|
29
|
+
| `--desiredCount=<number>` | Number of container replicas to run (`1` or `2`). | `1` |
|
|
30
|
+
| `--branch=<name>` | The primary Git deployment branch for CI/CD. | `main` |
|
|
31
|
+
| `--dir=<path>` | The directory to generate files into (use `.` for current).| `.` |
|
|
32
|
+
| `--target=<target>` | Compute architecture: `ecs` (default, `fargate` synonym) or `lambda` (scale-to-zero serverless). | `ecs` |
|
|
33
|
+
| `--needsDatabase` | Provisions a managed AWS database alongside Fargate (engine via `--db-engine`). | `false` |
|
|
34
|
+
| `--db-engine=<engine>` | Database engine: `postgres` (default), `mysql` (MySQL 8.0), or `aurora-postgresql` (Serverless v2 scale-to-zero). | `postgres` |
|
|
35
|
+
| `--enablePrPreviews` | Generates workflows for Ephemeral PR Previews. | `false` |
|
|
36
|
+
| `--no-telemetry` | Disables anonymous usage analytics (or set `DO_NOT_TRACK=1` for all runs). | `false` |
|
|
37
|
+
| `--preconfigured` | Suppresses framework warnings for pre-validated configs from external schematics/integrations (e.g., `nest add`). | `false` |
|
|
38
|
+
| `--with=<capabilities>` | Comma-separated (or repeatable) addon capabilities to scaffold during init (`storage:s3`, `db:dynamodb`, `db:redis`, `queue:sqs`, `ai:bedrock`, `email:ses`, `cron`). | none |
|
|
39
|
+
| `--model=<id>` | Bedrock model override when `ai:bedrock` is included. | Catalog recommended model |
|
|
40
|
+
| `--domain=<domain>` | Domain for the SES identity when `email:ses` is included (required in headless mode). | none |
|
|
41
|
+
| `--zone-id=<id>` | Route 53 hosted zone ID for automatic SES DNS records. | none |
|
|
42
|
+
| `--from-email=<email>` | Default SES sender address. | `noreply@<domain>` |
|
|
43
|
+
| `--setup-ci-migrate` | Wire the pre-deploy database migration gate into the generated workflow when a database and migration command are detected. | `false` |
|
|
44
|
+
| `--setup-ci-drift` | Scaffold `.github/workflows/drift.yml`: a daily 06:00 UTC `terraform plan` check that opens (or updates) a GitHub Issue labeled `iac-drift` on drift and closes it when resolved. | `false` |
|
|
45
|
+
|
|
46
|
+
*(Note: Boolean flags like `--needsDatabase` and `--enablePrPreviews` can be passed alone or as `--flag=true`).*
|
|
47
|
+
|
|
48
|
+
## Example Usage
|
|
49
|
+
|
|
50
|
+
**Standard Static Site Automation (e.g., Vite/React):**
|
|
51
|
+
```bash
|
|
52
|
+
npx grada-run --headless --framework=static --region=eu-west-1 --size=micro
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Next.js High-Availability CI/CD Generation:**
|
|
56
|
+
```bash
|
|
57
|
+
npx grada-run --headless --framework=nextjs --size=small --desiredCount=2
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Django Setup with Managed RDS Database:**
|
|
61
|
+
```bash
|
|
62
|
+
npx grada-run --headless --framework=django --needsDatabase
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Full-Stack Automation with Addons and Migration Gate:**
|
|
66
|
+
```bash
|
|
67
|
+
npx grada-run --headless --framework=nestjs --needsDatabase \
|
|
68
|
+
--with db:redis,ai:bedrock,email:ses --domain example.com --setup-ci-migrate
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## See also
|
|
72
|
+
|
|
73
|
+
- [`npx grada-run`](/grada/cli/init/) for the full flag table.
|
|
74
|
+
- [Supported Frameworks](/grada/guides/frameworks/) for valid `--framework` ids.
|
|
75
|
+
- [CI/CD Pipeline & First Deploy](/grada/guides/cicd-pipeline/) for what runs after generation.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Quickstart (5 minutes)
|
|
3
|
+
description: Go from empty repo to live AWS deployment in five minutes with grada.
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 0
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Deploy your first app to AWS in about five minutes. This is the fastest path; follow the links for details at each step.
|
|
9
|
+
|
|
10
|
+
## Prerequisites
|
|
11
|
+
|
|
12
|
+
- Node.js 18+, an AWS account, and AWS credentials in your terminal (`aws sso login` or `aws configure`).
|
|
13
|
+
- A git repository with your app. Stuck on auth? See [Troubleshooting AWS Credentials](/grada/guides/aws-credentials/).
|
|
14
|
+
|
|
15
|
+
## Step 1 — Scaffold
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx grada-run
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The wizard auto-detects your framework, `Procfile`, `vercel.json`, and Compose files, then writes Terraform, a `Dockerfile`, and `.github/workflows/deploy.yml`. Not sure your stack is supported? Check [Supported Frameworks](/grada/guides/frameworks/).
|
|
22
|
+
|
|
23
|
+
## Step 2 — Provision
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx grada-run apply
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
This creates the ALB, ECS cluster, and service. Your URL returns `503` until the first image is pushed — that is expected.
|
|
30
|
+
|
|
31
|
+
## Step 3 — Ship
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
git add .
|
|
35
|
+
git commit -m "ci: infra"
|
|
36
|
+
git push
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Pushing to your deploy branch triggers the pipeline: Terraform sync, Docker build, image scan, ECS rollout. How it works is explained in [CI/CD Pipeline & First Deploy](/grada/guides/cicd-pipeline/).
|
|
40
|
+
|
|
41
|
+
## Step 4 — Verify
|
|
42
|
+
|
|
43
|
+
- Open the ALB URL from the `apply` output.
|
|
44
|
+
- Still seeing `503` or `502` after the workflow finishes? Run `npx grada-run diagnose` — usually the container failed its health check. See [Dockerfiles & the Container Contract](/grada/guides/dockerfiles/).
|
|
45
|
+
- Need env vars? Continue with [Secrets Management](/grada/guides/secrets-management/).
|
|
46
|
+
|
|
47
|
+
## Next steps
|
|
48
|
+
|
|
49
|
+
- [Supported Frameworks](/grada/guides/frameworks/) — framework requirements and detection rules.
|
|
50
|
+
- [Reference Implementations & Examples](/grada/guides/examples/) — working repos per framework.
|
|
51
|
+
- [Headless Mode & Automation](/grada/guides/headless/) — non-interactive `npx grada-run --headless` for CI.
|
|
52
|
+
- Migrating? Start with [Vercel (Next.js)](/grada/migrations/nextjs-vercel-to-aws/), [Vercel (Astro)](/grada/migrations/astro-vercel-to-aws/), [Vercel (SvelteKit)](/grada/migrations/sveltekit-vercel-to-aws/), or [Heroku (Procfile)](/grada/migrations/heroku-procfile-to-aws/).
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Re-running Init Safely
|
|
3
|
+
description: What happens when setup finds existing files — backups, regeneration, and how to recover.
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 10
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Re-running `npx grada-run` to change region, size, or framework is safe and predictable: setup never merges with your existing generated files. It backs them up, regenerates from scratch, and tells you exactly what moved.
|
|
9
|
+
|
|
10
|
+
## The conflict prompt
|
|
11
|
+
|
|
12
|
+
When setup finds any of `terraform/`, `Dockerfile`, or `.github/workflows/deploy.yml` in the target directory (`src/utils/backup.js`), it lists the conflicts and offers two choices:
|
|
13
|
+
|
|
14
|
+
- **Backup & Regenerate** — each conflicting path is renamed with a timestamp suffix (e.g. `terraform.bak.1726771200000`), then fresh files are generated.
|
|
15
|
+
- **Cancel** — exits immediately with no changes.
|
|
16
|
+
|
|
17
|
+
In `--headless` mode there is no prompt: existing files are backed up automatically. Either way, nothing is ever merged or partially overwritten.
|
|
18
|
+
|
|
19
|
+
## Backups stay local
|
|
20
|
+
|
|
21
|
+
After backing up, setup appends a `# grada backups` block (`*.bak.*`) to `.gitignore` (creating the file if needed), so backup clutter never reaches GitHub. To recover a previous configuration, compare with `diff -r terraform.bak.<timestamp> terraform/` and copy back what you need — then delete the `.bak.*` directory when you are satisfied. (`npx grada-run eject` removes all `*.bak.*` files as part of decoupling.)
|
|
22
|
+
|
|
23
|
+
## What regeneration touches
|
|
24
|
+
|
|
25
|
+
`src/utils/generator.js` writes a fixed file set and handles pre-existing files explicitly:
|
|
26
|
+
|
|
27
|
+
- `terraform/*.tf`, `Dockerfile`, `.github/workflows/deploy.yml`, plus `preview.yml`/`teardown.yml` only when PR previews are enabled.
|
|
28
|
+
- `terraform/secret_keys.json` is preserved when it already exists (only created as `[]` on first setup) — your pushed key map survives re-runs with no need to re-push.
|
|
29
|
+
- If your repo already has a `README.md`, it is kept and gets a short Deployment pointer appended; the generated guide goes to `DEPLOYMENT.md` instead.
|
|
30
|
+
- Existing `.gitignore` / `.dockerignore` files are preserved with only the grada entries appended (Terraform state paths, `.env`); missing ones are created with framework-appropriate presets.
|
|
31
|
+
- **Rails only:** if `ci.yml` or `dependabot.yml` exist, setup asks whether to disable them by renaming to `.bak` (default CI usually crashes without a database service); in headless mode they are disabled automatically.
|
|
32
|
+
|
|
33
|
+
## Suggested workflow
|
|
34
|
+
|
|
35
|
+
1. Commit your work before re-running, so `git status` shows exactly what regeneration changed.
|
|
36
|
+
2. Re-run, review the diff (`git diff`, plus `diff -r` against the `.bak` copies for untracked files like `terraform/` internals).
|
|
37
|
+
3. Run `npx grada-run apply` to converge AWS with the new configuration.
|
|
38
|
+
4. Delete the `.bak.<timestamp>` copies once the new infrastructure is verified.
|
|
39
|
+
|
|
40
|
+
## See also
|
|
41
|
+
|
|
42
|
+
- [apply](/grada/cli/apply/) for converging AWS after regeneration.
|
|
43
|
+
- [eject](/grada/cli/eject/) for what happens to backups on decoupling.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Secrets Management in grada"
|
|
3
|
+
description: "Sync .env files to AWS Secrets Manager without committing plaintext secrets."
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 7
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Managing `.env` files across a team and syncing them to the cloud is a notorious pain point. `grada` solves this by natively integrating with **AWS Secrets Manager**, ensuring zero plaintext secrets ever touch your GitHub repository or CI/CD pipelines. Secrets Manager bills $0.40 per secret per month (one for your app secrets, plus one for the database master password when applicable) — itemized in the `apply` cost preview.
|
|
9
|
+
|
|
10
|
+
## The Secrets Lifecycle
|
|
11
|
+
|
|
12
|
+
To maintain zero-secret Git repositories and safe infrastructure provisioning, secrets follow a strict 4-step lifecycle:
|
|
13
|
+
|
|
14
|
+
```text
|
|
15
|
+
1. Scaffold ───▶ 2. Provision Vault ───▶ 3. Push Secrets ───▶ 4. Deploy to App
|
|
16
|
+
(grada) (grada apply) (secrets push .env) (git push)
|
|
17
|
+
Generates Terraform Creates empty vault Uploads encrypted keys ECS container boots
|
|
18
|
+
& secret_keys.json in AWS Secrets Mgr & updates secret_keys with injected env
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
### Step 1: Provision the Vault (Day 1)
|
|
24
|
+
Your Secrets Manager vault is declared in `terraform/secrets.tf`. Provision the base infrastructure first:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npx grada-run apply
|
|
28
|
+
```
|
|
29
|
+
*This creates an empty, secure secret vault named `<project-name>-secrets` in your AWS account.*
|
|
30
|
+
|
|
31
|
+
### Step 2: Push Secrets to AWS
|
|
32
|
+
Once the vault exists, push your local `.env` values directly to AWS:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npx grada-run secrets push .env
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**What happens under the hood?**
|
|
39
|
+
1. The CLI reads your local `.env` file.
|
|
40
|
+
2. It encrypts the key-value pairs and pushes them securely into AWS Secrets Manager under your project's namespace (e.g., `my-project-secrets`).
|
|
41
|
+
3. It generates a local `terraform/secret_keys.json` file containing *only the names* of your keys (e.g., `["API_KEY", "STRIPE_SECRET"]`), **not the values**. Re-running setup never wipes this file.
|
|
42
|
+
|
|
43
|
+
> 💡 **Tip:** The `secrets push` command takes the file path as the first argument. If you need to use other flags, ensure they are appended at the end of the command:
|
|
44
|
+
> `npx grada-run secrets push .env --any-other-flags`
|
|
45
|
+
|
|
46
|
+
> 🌱 **No `.env` yet?** `secrets push` offers to create an empty one for you interactively. In CI / `--headless` mode it exits 1 instead of prompting, so generate the file before pushing.
|
|
47
|
+
|
|
48
|
+
### Step 3: Map Secrets into the Container
|
|
49
|
+
Commit the updated `terraform/secret_keys.json` and push to GitHub:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
git add terraform/secret_keys.json
|
|
53
|
+
git commit -m "chore: map new secrets to ECS"
|
|
54
|
+
git push origin main
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Terraform reads `secret_keys.json` during the GitHub Actions deployment and maps each key directly into your ECS Task Definition. When your Fargate container boots up, AWS injects the secret values into `process.env` (Node) or `os.environ` (Python) in memory. On `--target lambda` projects the vault stays shared for runtime reads (`APP_SECRETS_ARN`) and fresh invocations pick up new values automatically — no restart step exists.
|
|
58
|
+
|
|
59
|
+
> ⚠️ **Commit this file.** `secret_keys.json` holds key *names* only — never values — so it is safe for version control, and deployment depends on it.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
### Day-2: Pull, Audit, and Rotate (no redeploy)
|
|
64
|
+
|
|
65
|
+
Secrets don't stand still — teammates join, keys rotate, local `.env` files get lost. Two commands close the loop:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
npx grada-run secrets pull # merge remote values into local .env
|
|
69
|
+
npx grada-run secrets audit # diff local .env vs AWS, change nothing
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`pull` appends missing remote keys after your existing entries, keeps local-only variables, and asks before overwriting conflicting values (automatic in `--headless` mode). `audit` prints a colored drift report: `+` missing locally, `~` mismatched values, `-` never pushed to AWS.
|
|
73
|
+
|
|
74
|
+
**Which flow do I need?**
|
|
75
|
+
|
|
76
|
+
| Situation | Command |
|
|
77
|
+
|---|---|
|
|
78
|
+
| New variable name added/removed | `secrets push`, then commit `secret_keys.json` + `git push` (task definition must be rebuilt) |
|
|
79
|
+
| Only a value changed (same keys) | `secrets push`, then accept the rolling ECS restart prompt — live in seconds, no redeploy |
|
|
80
|
+
| New machine / lost `.env` | `secrets pull` |
|
|
81
|
+
| "Why doesn't my app see the new value?" | `secrets audit` first, then push or restart accordingly |
|
|
82
|
+
|
|
83
|
+
See the [secrets CLI reference](/grada/cli/secrets/) for flags, merge rules, and prerequisites.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Understanding Your AWS Bill
|
|
3
|
+
description: What each part of your grada infrastructure costs, what the CLI estimates cover, and how to keep spend low.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Every grada command that touches infrastructure tells you what it costs *before* you pay it: `apply` shows a pre-flight estimate, `add` prints the cost impact of each addon, and your `README.md` keeps a refreshed monthly baseline. This guide explains what those numbers include, what they leave out, and where the cost levers are.
|
|
7
|
+
|
|
8
|
+
All reference rates below are for `us-east-2` (the stack default) and assume a 730-hour month. Other regions typically land within ~5–15% of these figures.
|
|
9
|
+
|
|
10
|
+
## The Fixed Monthly Baseline
|
|
11
|
+
|
|
12
|
+
These resources bill by the hour (or month) whether your app serves one request or one million. A minimal stack (256 CPU / 512 MB Fargate micro, no database) runs **~$31.68/mo**:
|
|
13
|
+
|
|
14
|
+
| Resource | Math | Monthly |
|
|
15
|
+
| -------- | ---- | ------- |
|
|
16
|
+
| Fargate task (0.25 vCPU + 0.5 GB) | (0.25 × $0.04048 + 0.5 × $0.004445) × 730 hrs | ~$9.01 |
|
|
17
|
+
| Application Load Balancer (base + ~1 LCU) | ($0.0225 + $0.008) × 730 hrs | ~$22.27 |
|
|
18
|
+
| Secrets Manager (1 app secret) | 1 × $0.40 | $0.40 |
|
|
19
|
+
|
|
20
|
+
Optional fixed add-ons to the baseline:
|
|
21
|
+
|
|
22
|
+
| Addition | Monthly |
|
|
23
|
+
| -------- | ------- |
|
|
24
|
+
| Background worker service (second identical Fargate task) | doubles Fargate to ~$18.02 — but scales to $0 when its SQS queue is empty |
|
|
25
|
+
| RDS Postgres (`db.t4g.micro` + 20 GB gp3 + managed secret) | ~$13.98 + $0.40 secret |
|
|
26
|
+
| Valkey caching (`add db:redis`, `cache.t4g.micro`) | ~$9.49 |
|
|
27
|
+
|
|
28
|
+
So a typical full stack (web + database + Valkey) lands around **~$55.55/mo**, and the CLI's estimate always reflects your actual `terraform/` directory — container size, worker, database, secrets, and fixed-cost addons included.
|
|
29
|
+
|
|
30
|
+
On the Lambda target (`--target lambda`) there is no Fargate or ALB baseline at all: compute and the API Gateway HTTP API bill purely on use, so a no-database project idles at **~$0.40/mo** (one Secrets Manager secret) and an Aurora-backed one at **~$0.80/mo**. The pre-flight estimate shows this as `Fixed Baseline: ~$0.80/mo (RDS: $0.00, Secrets: $0.80 + API GW & Lambda usage)` — the trailing caveat is the reminder that requests, not hours, are the real bill.
|
|
31
|
+
|
|
32
|
+
## What the Estimate Leaves Out (Usage Billing)
|
|
33
|
+
|
|
34
|
+
Anything that scales with traffic is billed on use and intentionally excluded from the fixed number:
|
|
35
|
+
|
|
36
|
+
- **Addons:** `storage:s3` (storage, requests, CloudFront egress), `db:dynamodb` (requests, storage, backups), `queue:sqs` (requests past the 1M free tier), `ai:bedrock` (per-token inference), `email:ses` ($0.10 per 1,000 emails sent), `cron` (Fargate seconds per scheduled run). Each `add` run prints its own billing drivers.
|
|
37
|
+
- **Data transfer:** outbound traffic and CloudFront egress beyond free tiers.
|
|
38
|
+
- **Logs & images:** CloudWatch Logs ingestion (14-day retention is configured) and ECR image storage (~$0.10/GB-mo) — usually cents, plus `gc` cleans up orphans.
|
|
39
|
+
- **Traffic spikes:** ALB capacity units above the ~1 LCU baseline, and RDS backup storage past the free allowance.
|
|
40
|
+
- **Serverless compute (Lambda target):** API Gateway HTTP API requests ($1.00 per million) plus Lambda request charges and GB-second compute time. Sporadic traffic costs pennies; sustained high-concurrency traffic can overtake the ~$31/mo Fargate baseline — see the [Fargate vs Lambda tradeoffs](/grada/guides/architecture/#fargate-vs-lambda-tradeoffs).
|
|
41
|
+
|
|
42
|
+
Rule of thumb: the fixed baseline is your floor; side projects with modest traffic typically land within a few dollars above it.
|
|
43
|
+
|
|
44
|
+
### Which target costs less for my workload?
|
|
45
|
+
|
|
46
|
+
- **Side project / internal tool** (dozens to hundreds of requests a day): Lambda, by a mile — pennies a month against ~$31+ of idle ECS baseline.
|
|
47
|
+
- **Steady product API** (sustained traffic around the clock): Fargate — the flat baseline undercuts per-request billing once concurrency stops dropping to zero.
|
|
48
|
+
- **Spiky or unpredictable traffic** (launches, webhooks, batch-driven): Lambda absorbs bursts with no capacity planning; just mind the database-connection note in [Fargate vs Lambda tradeoffs](/grada/guides/architecture/#fargate-vs-lambda-tradeoffs).
|
|
49
|
+
|
|
50
|
+
## Cost Savers Built Into the Stack
|
|
51
|
+
|
|
52
|
+
- **No NAT gateway.** Tasks run in public subnets behind the ALB security group instead of behind a ~$33/mo NAT — the single biggest saving versus a conventional VPC layout.
|
|
53
|
+
- **Micro defaults, scale up deliberately.** Fargate micro, single-AZ `db.t4g.micro`, and single-node Valkey keep the floor low; grow container size or add read replicas only when metrics say so.
|
|
54
|
+
- **Workers scale to zero.** The SQS-driven worker parks at 0 tasks (and $0 compute) when the queue drains — you pay for background capacity only while jobs exist.
|
|
55
|
+
- **Sleep idle environments.** `sleep [env]` scales ECS services to 0 and stops RDS, printing the exact hourly/monthly compute savings (e.g. ~$20.69/mo for a micro web service plus Postgres: ~$9.01 Fargate + ~$11.68 RDS compute paused); `wake [env]` restores everything. Storage (~$2.30/mo), the ALB (~$22.27/mo), Valkey (~$9.49/mo, no pause API), and secrets keep billing while asleep, and AWS auto-restarts stopped databases after 7 days — the CLI shows the exact restart timestamp.
|
|
56
|
+
- **PR previews self-destruct.** Each open pull request runs a full copy of the stack (~$31+/mo each while open, mostly the extra ALB), so previews are destroyed automatically when the PR closes. Close stale PRs and run `gc` to catch leftovers.
|
|
57
|
+
- **Serverless-first addons.** DynamoDB on-demand, SQS, SES, Bedrock, and scheduled cron jobs cost nothing at rest — prefer them over always-on resources when the workload fits.
|
|
58
|
+
|
|
59
|
+
## Keeping Estimates Accurate
|
|
60
|
+
|
|
61
|
+
- The `README.md` estimate refreshes automatically on every `add` and `apply` — if you hand-edit `terraform/`, re-run `apply` (or `--dry-run`) to re-sync it.
|
|
62
|
+
- Estimates follow your real config: bigger `--size` at `init`, extra secrets, and new addons all flow into the number on the next run.
|
|
63
|
+
- For hard budget enforcement, pair the CLI estimates with an AWS Budgets billing alarm in the console — the CLI tells you the expected spend, AWS tells you the actuals.
|