deploy-stack 0.13.0 → 0.14.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/README.md CHANGED
@@ -30,7 +30,7 @@ You retain complete ownership of your infrastructure code without relying on bla
30
30
  **🚀 Zero-Config Deployments**
31
31
  * **Framework Agnostic:** Tailored container presets for Next.js, Express.js, FastAPI, Go, Django, Rails, Nuxt 3, and Static Sites (React, Vue, SvelteKit, Astro).
32
32
  * **Smart Discovery:** Automatically detects build output directories and generates highly optimized, multi-stage Dockerfiles.
33
- * **PaaS Migration Engine:** Natively parses Heroku `Procfile` configurations to automatically translate web and background worker processes (like Celery or Sidekiq) into multi-container AWS Fargate architectures.
33
+ * **PaaS Migration Engine:** Natively parses Heroku `Procfile` configurations and `vercel.json` files to automatically translate proprietary edge routing (redirects/rewrites) and background workers into standard AWS Fargate and Application Load Balancer architectures.
34
34
  * **Database Scaffolding:** Automatically provisions fully isolated, zero-trust AWS RDS PostgreSQL databases for backend monoliths.
35
35
 
36
36
  **🛡️ DevSecOps & Security**
@@ -51,6 +51,15 @@ You retain complete ownership of your infrastructure code without relying on bla
51
51
 
52
52
  ---
53
53
 
54
+ ## 📚 Documentation & Guides
55
+ Transitioning from PaaS to AWS involves a few architectural shifts. We've written concise guides to help you understand how `deploy-stack` handles the heavy lifting:
56
+ * [Migrating from Heroku to AWS (Procfile Support)](./docs/migrations/heroku-procfile-to-aws.md)
57
+ * [Managing Secrets & Environment Variables](./docs/guides/secrets-management.md)
58
+ * [Zero-Trust Database Connections](./docs/guides/database-connections.md)
59
+ * [Migrating Next.js from Vercel](./docs/migrations/nextjs-vercel-to-aws.md)
60
+
61
+ ---
62
+
54
63
  ## 🚀 Quick Start
55
64
 
56
65
  Run the CLI directly in your project root:
@@ -158,7 +167,7 @@ npx deploy-stack --no-telemetry
158
167
 
159
168
  ### Phase 6: Migration & Trust Engine (Current)
160
169
  - [x] **Dry-Run Visualization:** Interactive pre-flight terminal UI with ASCII topology maps and precise, dynamic AWS cost estimation.
161
- - [ ] **PaaS Importers:** Auto-parse `vercel.json` or Heroku `Procfile` configurations to map build commands and environment variables automatically.
170
+ - [x] **PaaS Importers:** Auto-parse `vercel.json` and Heroku `Procfile` configurations to map routing rules, web commands, and background workers automatically.
162
171
  - [ ] **Docker Compose to ECS Translator:** Automatically converting a familiar local `docker-compose.yml` into production ECS task definitions.
163
172
  - [ ] **AI Agent Rulesets:** Publishing `.cursorrules` and Copilot instructions that teach AI assistants exactly how to utilize the CLI on the user's behalf.
164
173
 
@@ -0,0 +1,27 @@
1
+ # Managed Database Connections
2
+
3
+ When you run `npx deploy-stack` for a backend framework (Node, Django, Rails, Go, etc.), the CLI prompts you to automatically provision a managed AWS RDS PostgreSQL database.
4
+
5
+ ## Zero-Trust Architecture
6
+
7
+ If you select "Yes", `deploy-stack` builds a true zero-trust network topology:
8
+ 1. The PostgreSQL instance is deployed into heavily restricted **Isolated Subnets**.
9
+ 2. It is given a strict Security Group that *only* allows inbound traffic from your specific ECS Fargate containers on port `5432`.
10
+ 3. The database is completely inaccessible from the public internet.
11
+
12
+ ## Auto-Injected Environment Variables
13
+
14
+ You do not need to configure database connection strings manually. The generated Terraform automatically creates a secure, random master password in AWS Secrets Manager and injects the following environment variables directly into your running containers:
15
+
16
+ * `DB_HOST` (The internal AWS DNS endpoint)
17
+ * `DB_PORT` (5432)
18
+ * `DB_NAME` (Your auto-generated database name)
19
+ * `DB_USER` (Injected securely at runtime)
20
+ * `DB_PASSWORD` (Injected securely at runtime)
21
+
22
+ To connect your application, simply configure your ORM (Prisma, Django, TypeORM, Active Record) to read from these standard environment variables.
23
+
24
+ ## Running Database Migrations
25
+
26
+ Because the database is in an isolated subnet, you cannot run schema migrations directly from your local laptop.
27
+ The best practice is to configure your CI/CD pipeline or your Docker container's startup script to run your migrations (e.g., `npx prisma deploy` or `python manage.py migrate`) before starting the main web process.
@@ -0,0 +1,24 @@
1
+ # Secrets Management in deploy-stack
2
+
3
+ Managing `.env` files across a team and syncing them to the cloud is a notorious pain point. `deploy-stack` solves this by natively integrating with **AWS Secrets Manager**, ensuring zero plaintext secrets ever touch your GitHub repository or CI/CD pipelines.
4
+
5
+ ## Pushing Secrets to AWS
6
+
7
+ Instead of manually clicking through the AWS Console, use the built-in secrets command:
8
+
9
+ ```bash
10
+ npx deploy-stack secrets push .env.production
11
+ ```
12
+
13
+ ### What happens under the hood?
14
+ 1. The CLI reads your local `.env.production` file.
15
+ 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`).
16
+ 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**.
17
+
18
+ ## How Secrets Reach Your App
19
+
20
+ When you commit `terraform/secret_keys.json` and push to GitHub, your CI/CD pipeline runs Terraform.
21
+
22
+ Terraform reads the JSON array of key names and dynamically maps them to your ECS Task Definition. When your AWS Fargate container boots up, it automatically injects those secrets directly into your application's environment as standard environment variables (e.g., `process.env.STRIPE_SECRET` or `os.getenv("API_KEY")`).
23
+
24
+ *Note: Because Terraform maps the secrets at runtime, updating a secret value in AWS and running an empty GitHub deployment will instantly cycle your containers with the new keys!*
@@ -0,0 +1,47 @@
1
+ # Migrating Astro from Vercel to AWS Fargate
2
+
3
+ If you are seeing a warning from `deploy-stack` about your Astro adapter, it means your project is currently configured to build specifically for Vercel's proprietary serverless network.
4
+
5
+ To deploy Astro as a containerized application on standard AWS infrastructure, you simply need to switch to Astro's official Node.js adapter.
6
+
7
+ ## How to Fix
8
+
9
+ ### 1. Install the Node adapter
10
+ Run the following command in your terminal to swap out the Vercel adapter for the Node adapter:
11
+
12
+ \`\`\`bash
13
+ npm install @astrojs/node
14
+ npm uninstall @astrojs/vercel
15
+ \`\`\`
16
+
17
+ ### 2. Update `astro.config.mjs`
18
+ Open your Astro configuration file and replace the Vercel import with the Node import.
19
+
20
+ **Before (Vercel Lock-in):**
21
+ \`\`\`javascript
22
+ import { defineConfig } from 'astro/config';
23
+ import vercel from '@astrojs/vercel/serverless';
24
+
25
+ export default defineConfig({
26
+ output: 'server',
27
+ adapter: vercel(),
28
+ });
29
+ \`\`\`
30
+
31
+ **After (AWS Ready):**
32
+ \`\`\`javascript
33
+ import { defineConfig } from 'astro/config';
34
+ import node from '@astrojs/node';
35
+
36
+ export default defineConfig({
37
+ output: 'server',
38
+ adapter: node({
39
+ mode: 'standalone'
40
+ }),
41
+ });
42
+ \`\`\`
43
+
44
+ ### 3. Deploy
45
+ That's it! Your Astro app is now decoupled from Vercel.
46
+
47
+ Run `npx deploy-stack apply` and the CLI will automatically package this standalone Node server into a hardened Docker container and deploy it to your AWS cluster.
@@ -0,0 +1,32 @@
1
+ # Migrating from Heroku to AWS (Procfile Support)
2
+
3
+ When migrating from Heroku or Render, you likely rely on a `Procfile` to define your application's architecture (e.g., a web server and a background worker like Celery or Sidekiq).
4
+
5
+ `deploy-stack` natively understands Heroku `Procfile` syntax and automatically translates it into a production-grade, multi-container AWS architecture.
6
+
7
+ ## How it Works
8
+
9
+ When you run `npx deploy-stack`, the CLI scans your root directory for a `Procfile`.
10
+
11
+ ### The `web` Process
12
+ If the CLI detects a `web:` declaration:
13
+ 1. It overrides the default Docker `CMD`.
14
+ 2. It provisions an AWS ECS Fargate service for this process.
15
+ 3. It automatically wires this specific container to your public-facing Application Load Balancer (ALB) so it can receive internet traffic.
16
+
17
+ ### The `worker` Process
18
+ If the CLI detects a `worker:` declaration:
19
+ 1. It generates a completely separate ECS Fargate task definition (`worker.tf`).
20
+ 2. It spins up the worker in a **fully isolated private subnet**.
21
+ 3. It intentionally strips all public ingress, ensuring your background workers are secure and can only communicate with your database or message brokers internally.
22
+
23
+ ## Example
24
+
25
+ **Your `Procfile`:**
26
+ ```text
27
+ web: gunicorn myapp.wsgi
28
+ worker: celery -A myapp worker -l info
29
+ ```
30
+
31
+ **The Result:**
32
+ Running `deploy-stack` will automatically generate the Terraform required to spin up both containers simultaneously from the exact same Docker image, scaling them independently based on your needs.
@@ -0,0 +1,43 @@
1
+ # Migrating Next.js from Vercel to AWS Fargate
2
+
3
+ If you are seeing a warning from `deploy-stack` about `output: 'standalone'`, your Next.js configuration is missing a crucial setting required for containerized environments.
4
+
5
+ By default, Next.js requires your entire `node_modules` folder to run the production server. This creates massive, bloated Docker containers that boot slowly and cost more to host. The `standalone` output mode tells Next.js to trace your code and bundle *only* the specific files and dependencies actually used in production, creating an ultra-lean deployment artifact.
6
+
7
+ ## How to Fix
8
+
9
+ ### 1. Update `next.config.js` (or `.mjs` / `.cjs`)
10
+ Open your Next.js configuration file in the root of your project and add `output: 'standalone'` to the configuration object.
11
+
12
+ **Before (Vercel Default):**
13
+ ```javascript
14
+ /** @type {import('next').NextConfig} */
15
+ const nextConfig = {
16
+ reactStrictMode: true,
17
+ // Other existing config...
18
+ };
19
+
20
+ export default nextConfig;
21
+ ```
22
+
23
+ **After (AWS Ready):**
24
+ ```javascript
25
+ /** @type {import('next').NextConfig} */
26
+ const nextConfig = {
27
+ reactStrictMode: true,
28
+ output: 'standalone', // <-- Add this line
29
+ // Other existing config...
30
+ };
31
+
32
+ export default nextConfig;
33
+ ```
34
+
35
+ ### 2. (Optional) Define a Health Check Route
36
+ AWS Application Load Balancers require a route to ping to ensure your app is healthy. If you don't already have one, create a simple API route in your app (e.g., `app/api/health/route.ts` for App Router, or `pages/api/health.ts` for Pages Router) that returns a `200 OK` status.
37
+
38
+ When running `deploy-stack`, choose **Advanced Configuration** and set your ALB Health Check Path to this route (e.g., `/api/health`).
39
+
40
+ ### 3. Deploy
41
+ Your Next.js app is now perfectly optimized for AWS ECS Fargate!
42
+
43
+ Run `npx deploy-stack apply`. The CLI's generated `Dockerfile` will automatically target your new `.next/standalone` directory and deploy the optimized build to the cloud.
@@ -0,0 +1,55 @@
1
+ # Migrating SvelteKit from Vercel to AWS Fargate
2
+
3
+ If you are seeing a warning from `deploy-stack` about your SvelteKit adapter, your project is currently using `@sveltejs/adapter-auto` (which often defaults to Vercel) or the explicit `@sveltejs/adapter-vercel`.
4
+
5
+ These adapters are designed specifically for proprietary serverless edge networks. To run your SvelteKit app in a scalable, standard Docker container on AWS Fargate, you need to switch to Svelte's official Node adapter.
6
+
7
+ ## How to Fix
8
+
9
+ ### 1. Install the Node Adapter
10
+ Run the following command in your terminal to install the Node adapter and remove the Vercel/Auto adapter:
11
+
12
+ ```bash
13
+ npm install -D @sveltejs/adapter-node
14
+ npm uninstall @sveltejs/adapter-auto @sveltejs/adapter-vercel
15
+ ```
16
+
17
+ ### 2. Update `svelte.config.js`
18
+ Open your `svelte.config.js` file and change the adapter import at the top of the file.
19
+
20
+ **Before (Locked into Vercel/Auto):**
21
+ ```javascript
22
+ import adapter from '@sveltejs/adapter-auto'; // or '@sveltejs/adapter-vercel'
23
+ import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
24
+
25
+ /** @type {import('@sveltejs/kit').Config} */
26
+ const config = {
27
+ preprocess: vitePreprocess(),
28
+ kit: {
29
+ adapter: adapter()
30
+ }
31
+ };
32
+
33
+ export default config;
34
+ ```
35
+
36
+ **After (AWS Ready):**
37
+ ```javascript
38
+ import adapter from '@sveltejs/adapter-node';
39
+ import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
40
+
41
+ /** @type {import('@sveltejs/kit').Config} */
42
+ const config = {
43
+ preprocess: vitePreprocess(),
44
+ kit: {
45
+ adapter: adapter()
46
+ }
47
+ };
48
+
49
+ export default config;
50
+ ```
51
+
52
+ ### 3. Deploy
53
+ Your SvelteKit app is now decoupled!
54
+
55
+ Run `npx deploy-stack apply`. The CLI will automatically detect the standard Node build output, package it into a hardened Docker container, and deploy it to your AWS cluster.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deploy-stack",
3
- "version": "0.13.0",
3
+ "version": "0.14.1",
4
4
  "description": "Provision production-ready AWS infrastructure and CI/CD pipelines in seconds.",
5
5
  "engines": {
6
6
  "node": ">=18.0.0"
@@ -0,0 +1,20 @@
1
+ # 📚 The Documentation & Contextual UX Update
2
+
3
+ This patch release focuses entirely on Developer Experience (DX), ensuring that users migrating from PaaS platforms have clear, actionable documentation for AWS-native concepts right when they need them.
4
+
5
+ ### 📖 What's New
6
+ * **PaaS Escape Hatch Guides:** Added step-by-step guides for decoupling frontend frameworks from Vercel's proprietary edge network:
7
+ * **Next.js:** Enforcing `output: 'standalone'` for standard Docker deployments.
8
+ * **SvelteKit:** Swapping `@sveltejs/adapter-auto` or the Vercel adapter for the official Node adapter.
9
+ * **Astro:** Replacing `@astrojs/vercel` with `@astrojs/node`.
10
+ * **Comprehensive AWS Migration Guides:** Added dedicated documentation for our core backend engines:
11
+ * **Heroku Migration:** Detailed breakdown of how `Procfile` `web` and `worker` processes map to AWS Fargate and private subnets.
12
+ * **Secrets Management:** A deep dive into how `deploy-stack` leverages AWS Secrets Manager to inject environment variables at runtime.
13
+ * **Database Scaffolding:** Explains our zero-trust PostgreSQL architecture and auto-injected connection strings.
14
+
15
+ ### 🛠️ CLI UX Enhancements
16
+ * **Context-Aware Documentation Links:** The CLI now dynamically injects links to the relevant documentation at the exact moment a user might need it.
17
+ * If a Vercel-locked Next.js, SvelteKit, or Astro config is detected, the CLI links directly to the respective migration fix.
18
+ * If a `Procfile` is detected, the `deploy-stack` outro links to the Heroku guide.
19
+ * If a database is provisioned, the outro links to the database connection guide.
20
+ * Running `deploy-stack secrets push` now outputs a direct link explaining how those secrets reach the Fargate containers.
@@ -5,6 +5,7 @@ import { intro, outro, spinner, log, cancel } from '@clack/prompts';
5
5
  import color from 'picocolors';
6
6
  import { renderDryRunPreview, parseTerraformConfig } from '../utils/visualizer.js';
7
7
  import { detectFramework } from '../utils/detector.js';
8
+ import { trackEvent, flushTelemetry } from '../core/telemetry.js';
8
9
 
9
10
  // Helper to run a command while piping the latest stdout line into a @clack spinner
10
11
  function runTerraformCommand(args, cwd, spin, loadingPrefix) {
@@ -125,6 +126,14 @@ export async function applyStack(options = {}) {
125
126
 
126
127
  outro(`${finalMessage}\n\n ${color.yellow('Push code to deploy your app and clear the 503 error:')}\n ${color.cyan('git add . && git commit -m "ci: infra" && git push origin main')}`);
127
128
 
129
+ const actualProjectName = path.basename(process.cwd());
130
+ trackEvent('infrastructure_applied', {
131
+ projectName: actualProjectName,
132
+ framework: detectedConfig.framework,
133
+ success: true
134
+ });
135
+ await flushTelemetry();
136
+
128
137
  process.exit(0);
129
138
 
130
139
  } catch (error) {
@@ -146,6 +155,15 @@ export async function applyStack(options = {}) {
146
155
  log.message(`${color.bold('To debug manually, navigate to your terraform folder:')}`);
147
156
  log.message(color.cyan('cd terraform && terraform apply'));
148
157
  }
158
+
159
+ const actualProjectName = path.basename(process.cwd());
160
+ trackEvent('infrastructure_applied', {
161
+ projectName: actualProjectName,
162
+ success: false,
163
+ error_code: error.code || 'UNKNOWN'
164
+ });
165
+ await flushTelemetry();
166
+
149
167
  process.exit(1);
150
168
  }
151
169
  }
@@ -87,6 +87,15 @@ export async function destroyStack() {
87
87
  } catch (error) {
88
88
  s.stop(color.red('❌ Terraform destroy failed.'));
89
89
  console.error(color.red(error.message));
90
+
91
+ const actualProjectName = path.basename(process.cwd());
92
+ trackEvent('infrastructure_destroyed', {
93
+ projectName: actualProjectName,
94
+ success: false,
95
+ error_code: error.code || 'UNKNOWN'
96
+ });
97
+ await flushTelemetry();
98
+
90
99
  process.exit(1);
91
100
  }
92
101
 
@@ -111,9 +120,11 @@ export async function destroyStack() {
111
120
  }
112
121
  }
113
122
 
114
- trackEvent('project_destroyed', {
123
+ const actualProjectName = path.basename(process.cwd());
124
+ trackEvent('infrastructure_destroyed', {
125
+ projectName: actualProjectName,
115
126
  region,
116
- bucket: bucketName,
127
+ retained_state_bucket: !(deleteS3Bucket && typeof deleteS3Bucket !== 'symbol'),
117
128
  success: true
118
129
  });
119
130
  await flushTelemetry();
@@ -1,6 +1,7 @@
1
1
  import { intro, outro, spinner } from '@clack/prompts';
2
2
  import color from 'picocolors';
3
3
  import { checkDependency } from '../utils/system.js';
4
+ import { trackEvent, flushTelemetry } from '../core/telemetry.js';
4
5
 
5
6
  export async function runDoctor() {
6
7
  intro(color.bgCyan(color.black(' deploy-stack ☁️ ')));
@@ -36,4 +37,9 @@ export async function runDoctor() {
36
37
  } else {
37
38
  outro(color.yellow('Please install the missing dependencies before running the provisioning tool.'));
38
39
  }
40
+
41
+ trackEvent('doctor_run', {
42
+ success: hasTerraform && hasAws && hasDocker && hasGit
43
+ });
44
+ await flushTelemetry();
39
45
  }
@@ -2,6 +2,7 @@ import fs from 'fs';
2
2
  import path from 'path';
3
3
  import { intro, outro, confirm, spinner, cancel } from '@clack/prompts';
4
4
  import color from 'picocolors';
5
+ import { trackEvent, flushTelemetry } from '../core/telemetry.js';
5
6
 
6
7
  export async function ejectStack() {
7
8
  intro(color.bgRed(color.white(' deploy-stack eject ⏏️ ')));
@@ -68,6 +69,12 @@ export async function ejectStack() {
68
69
 
69
70
  s.stop('Ejection complete.');
70
71
 
72
+ const actualProjectName = path.basename(process.cwd());
73
+ trackEvent('project_ejected', {
74
+ projectName: actualProjectName
75
+ });
76
+ await flushTelemetry();
77
+
71
78
  outro(`
72
79
  ${color.green('✅ Successfully ejected from deploy-stack!')}
73
80