From 48a132ddffbc04125da2aaa723cb565ef0d1dbef Mon Sep 17 00:00:00 2001 From: Jye Cusch Date: Tue, 14 Oct 2025 13:59:41 +1100 Subject: [PATCH 1/3] docs: fix page ToCs, using headings instead of steps --- docs/guides/add-suga.mdx | 632 +++++++++++------------ docs/guides/build-platform.mdx | 529 +++++++++---------- docs/guides/database-migration.mdx | 120 +++-- docs/guides/local-database-setup.mdx | 228 ++++---- docs/guides/terraform-backend-config.mdx | 177 ++++--- 5 files changed, 829 insertions(+), 857 deletions(-) diff --git a/docs/guides/add-suga.mdx b/docs/guides/add-suga.mdx index 8ca8c26a..bf30cfa7 100644 --- a/docs/guides/add-suga.mdx +++ b/docs/guides/add-suga.mdx @@ -11,378 +11,372 @@ Suga helps you migrate existing applications to a cloud-agnostic architecture. W If you're starting fresh, see the [Getting Started Guide](/quickstart). - - - Navigate to your existing project directory and initialize Suga: - ```bash title="Login to Suga" icon="user" - suga login - ``` - - ```bash title="Initialize Project" icon="sparkles" - suga init - ``` +## Initialize Suga Project - When prompted, provide: - - **Project name:** `my-app` (or your preferred name) - - **Description:** Brief description of your application +Navigate to your existing project directory and initialize Suga: - This creates a `suga.yaml` configuration file in your project root. +```bash title="Login to Suga" icon="user" +suga login +``` - +```bash title="Initialize Project" icon="sparkles" +suga init +``` - - Open the Suga visual editor to design your infrastructure: +When prompted, provide: +- **Project name:** `my-app` (or your preferred name) +- **Description:** Brief description of your application - ```bash title="Open Suga Editor" icon="pencil" - suga edit - ``` +This creates a `suga.yaml` configuration file in your project root. - Build your infrastructure visually: - 1. Drag an **entrypoint** onto the canvas and name it `ingress` - 2. Add a **service** named `app` and connect the entrypoint to it - 3. Add a **bucket** named `files` and connect the service to it - 4. Configure bucket permissions to include `read`, `write`, and `delete` - 5. Configure the service with a command to run locally (e.g., `go run main.go` or `npm run dev`) +## Configure Infrastructure - ![Infrastructure Design](/images/migrate.png) +Open the Suga visual editor to design your infrastructure: - This generates your `suga.yaml` configuration: +```bash title="Open Suga Editor" icon="pencil" +suga edit +``` - ```yaml title="suga.yaml" icon="file-code" - target: suga/aws@1 - name: my-app - description: Your application description - services: +Build your infrastructure visually: +1. Drag an **entrypoint** onto the canvas and name it `ingress` +2. Add a **service** named `app` and connect the entrypoint to it +3. Add a **bucket** named `files` and connect the service to it +4. Configure bucket permissions to include `read`, `write`, and `delete` +5. Configure the service with a command to run locally (e.g., `go run main.go` or `npm run dev`) + +![Infrastructure Design](/images/migrate.png) + +This generates your `suga.yaml` configuration: + +```yaml title="suga.yaml" icon="file-code" +target: suga/aws@1 +name: my-app +description: Your application description +services: + app: + container: + docker: + dockerfile: Dockerfile + context: . + dev: + script: go run main.go +buckets: + files: + access: app: - container: - docker: - dockerfile: Dockerfile - context: . - dev: - script: go run main.go - buckets: - files: - access: - app: - - all - entrypoints: - ingress: - routes: - /: - name: app - ``` + - all +entrypoints: + ingress: + routes: + /: + name: app +``` - - The visual editor automatically maintains valid YAML syntax and ensures proper resource relationships. - + + The visual editor automatically maintains valid YAML syntax and ensures proper resource relationships. + - +## Add Container support - - Create a Dockerfile for production deployment: +Create a Dockerfile for production deployment: - ```dockerfile title="Dockerfile" icon="docker" - FROM golang:1.24-alpine as builder +```dockerfile title="Dockerfile" icon="docker" +FROM golang:1.24-alpine as builder - WORKDIR /app - COPY . . - RUN CGO_ENABLED=0 GOOS=linux go build -o main main.go +WORKDIR /app +COPY . . +RUN CGO_ENABLED=0 GOOS=linux go build -o main main.go - FROM alpine:latest - RUN apk --no-cache add ca-certificates - COPY --from=builder /app/main . - ENTRYPOINT ["/main"] - ``` +FROM alpine:latest +RUN apk --no-cache add ca-certificates +COPY --from=builder /app/main . +ENTRYPOINT ["/main"] +``` - - If you already have a Dockerfile, ensure it's referenced correctly in your `suga.yaml` configuration. - + + If you already have a Dockerfile, ensure it's referenced correctly in your `suga.yaml` configuration. + - +## Generate SDK and Migrate code - - Generate the Suga SDK for your project: +Generate the Suga SDK for your project: - ```bash title="Generate Go SDK" icon="hammer" - suga generate --go --go-out ./suga --go-package-name suga - ``` +```bash title="Generate Go SDK" icon="hammer" +suga generate --go --go-out ./suga --go-package-name suga +``` - ```bash title="Update Dependencies" icon="box" - go mod tidy - ``` +```bash title="Update Dependencies" icon="box" +go mod tidy +``` - - **Key migration steps:** - - Replace cloud SDK imports with `import "example/suga"` - - Initialize Suga client with `app, err := suga.NewClient()` - - Update API calls (e.g., S3 PutObject → `app.Files.Write()`) - - Simplify error handling (no need for AWS/GCP-specific error types) - - Test each endpoint after changes - - - Now migrate your application code. Here's a complete example showing the transformation: - - - - ```go title="main.go" icon="aws" - package main - - import ( - "context" - "fmt" - "log" - "net/http" - "os" - "strings" - - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/config" - "github.com/aws/aws-sdk-go-v2/service/s3" - ) - - func main() { - // Load AWS configuration - cfg, err := config.LoadDefaultConfig(context.TODO()) - if err != nil { - log.Fatalf("Failed to load AWS config: %v", err) - } + + **Key migration steps:** + - Replace cloud SDK imports with `import "example/suga"` + - Initialize Suga client with `app, err := suga.NewClient()` + - Update API calls (e.g., S3 PutObject → `app.Files.Write()`) + - Simplify error handling (no need for AWS/GCP-specific error types) + - Test each endpoint after changes + + +Now migrate your application code. Here's a complete example showing the transformation: + + + + ```go title="main.go" icon="aws" + package main + + import ( + "context" + "fmt" + "log" + "net/http" + "os" + "strings" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/s3" + ) + + func main() { + // Load AWS configuration + cfg, err := config.LoadDefaultConfig(context.TODO()) + if err != nil { + log.Fatalf("Failed to load AWS config: %v", err) + } - // Create S3 client - s3Client := s3.NewFromConfig(cfg) - bucketName := os.Getenv("S3_BUCKET_NAME") - - router := http.NewServeMux() - router.HandleFunc("GET /hello/{name}", func(w http.ResponseWriter, r *http.Request) { - name := r.PathValue("name") - - // AWS S3 PutObject - _, err := s3Client.PutObject(context.TODO(), &s3.PutObjectInput{ - Bucket: aws.String(bucketName), - Key: aws.String("example.txt"), - Body: strings.NewReader("Hello, " + name + "!"), - }) - if err != nil { - log.Printf("Failed to upload to S3: %v", err) - http.Error(w, "Error uploading to S3", http.StatusInternalServerError) - return - } - - fmt.Fprintf(w, "Hello, %s!", name) - }) + // Create S3 client + s3Client := s3.NewFromConfig(cfg) + bucketName := os.Getenv("S3_BUCKET_NAME") - port := os.Getenv("PORT") - if port == "" { - port = "8080" - } + router := http.NewServeMux() + router.HandleFunc("GET /hello/{name}", func(w http.ResponseWriter, r *http.Request) { + name := r.PathValue("name") - log.Printf("Server starting on port %s\n", port) - log.Fatal(http.ListenAndServe(":"+port, router)) - } - ``` - - - ```diff title="main.go" icon="file-plus-minus" -package main - - import ( -+ "example/suga" -- "context" - "fmt" - "log" - "net/http" - "os" -- "strings" -- "github.com/aws/aws-sdk-go-v2/aws" -- "github.com/aws/aws-sdk-go-v2/config" -- "github.com/aws/aws-sdk-go-v2/service/s3" - ) - - func main() { -- // Load AWS configuration -- cfg, err := config.LoadDefaultConfig(context.TODO()) -- if err != nil { -- log.Fatalf("Failed to load AWS config: %v", err) -- } - -- // Create S3 client -- s3Client := s3.NewFromConfig(cfg) -- bucketName := os.Getenv("S3_BUCKET_NAME") - -+ // Initialize Suga client -+ app, err := suga.NewClient() -+ if err != nil { -+ log.Fatalf("Failed to create suga client: %v", err) -+ } - - - router := http.NewServeMux() - router.HandleFunc("GET /hello/{name}", func(w http.ResponseWriter, r *http.Request) { - name := r.PathValue("name") - -- // AWS S3 PutObject -- _, err := s3Client.PutObject(context.TODO(), &s3.PutObjectInput{ -- Bucket: aws.String(bucketName), -- Key: aws.String("example.txt"), -- Body: strings.NewReader("Hello, " + name + "!"), -- }) -- if err != nil { -- log.Printf("Failed to upload to S3: %v", err) -- http.Error(w, "Error uploading to S3", http.StatusInternalServerError) -- return -- } -+ // Simplified file write using Suga -+ if err := app.Files.Write("example.txt", []byte("Hello, "+name+"!")); err != nil { -+ log.Printf("Failed to write file: %v", err) -+ http.Error(w, "Error writing file", http.StatusInternalServerError) -+ return -+ } - - fmt.Fprintf(w, "Hello, %s!", name) + // AWS S3 PutObject + _, err := s3Client.PutObject(context.TODO(), &s3.PutObjectInput{ + Bucket: aws.String(bucketName), + Key: aws.String("example.txt"), + Body: strings.NewReader("Hello, " + name + "!"), }) - - port := os.Getenv("PORT") - if port == "" { - port = "8080" - } - - log.Printf("Server starting on port %s\n", port) - log.Fatal(http.ListenAndServe(":"+port, router)) - } -``` - - - ```go title="main.go" icon="rocket" - package main - - import ( - "example/suga" - "fmt" - "log" - "net/http" - "os" - ) - - func main() { - // Initialize Suga client - app, err := suga.NewClient() if err != nil { - log.Fatalf("Failed to create suga client: %v", err) + log.Printf("Failed to upload to S3: %v", err) + http.Error(w, "Error uploading to S3", http.StatusInternalServerError) + return } - router := http.NewServeMux() - router.HandleFunc("GET /hello/{name}", func(w http.ResponseWriter, r *http.Request) { - name := r.PathValue("name") - - // Simplified file write using Suga - if err := app.Files.Write("example.txt", []byte("Hello, "+name+"!")); err != nil { - log.Printf("Failed to write file: %v", err) - http.Error(w, "Error writing file", http.StatusInternalServerError) - return - } + fmt.Fprintf(w, "Hello, %s!", name) + }) - fmt.Fprintf(w, "Hello, %s!", name) - }) - - port := os.Getenv("PORT") - if port == "" { - port = "8080" - } - - log.Printf("Server starting on port %s\n", port) - log.Fatal(http.ListenAndServe(":"+port, router)) + port := os.Getenv("PORT") + if port == "" { + port = "8080" } - ``` - - - - Remove all cloud provider SDK dependencies after migration to avoid conflicts and reduce bundle size. - + log.Printf("Server starting on port %s\n", port) + log.Fatal(http.ListenAndServe(":"+port, router)) + } + ``` + + + ```diff title="main.go" icon="file-plus-minus" + package main + + import ( ++ "example/suga" +- "context" + "fmt" + "log" + "net/http" + "os" +- "strings" +- "github.com/aws/aws-sdk-go-v2/aws" +- "github.com/aws/aws-sdk-go-v2/config" +- "github.com/aws/aws-sdk-go-v2/service/s3" + ) + + func main() { +- // Load AWS configuration +- cfg, err := config.LoadDefaultConfig(context.TODO()) +- if err != nil { +- log.Fatalf("Failed to load AWS config: %v", err) +- } + +- // Create S3 client +- s3Client := s3.NewFromConfig(cfg) +- bucketName := os.Getenv("S3_BUCKET_NAME") + ++ // Initialize Suga client ++ app, err := suga.NewClient() ++ if err != nil { ++ log.Fatalf("Failed to create suga client: %v", err) ++ } + + + router := http.NewServeMux() + router.HandleFunc("GET /hello/{name}", func(w http.ResponseWriter, r *http.Request) { + name := r.PathValue("name") + +- // AWS S3 PutObject +- _, err := s3Client.PutObject(context.TODO(), &s3.PutObjectInput{ +- Bucket: aws.String(bucketName), +- Key: aws.String("example.txt"), +- Body: strings.NewReader("Hello, " + name + "!"), +- }) +- if err != nil { +- log.Printf("Failed to upload to S3: %v", err) +- http.Error(w, "Error uploading to S3", http.StatusInternalServerError) +- return +- } ++ // Simplified file write using Suga ++ if err := app.Files.Write("example.txt", []byte("Hello, "+name+"!")); err != nil { ++ log.Printf("Failed to write file: %v", err) ++ http.Error(w, "Error writing file", http.StatusInternalServerError) ++ return ++ } + + fmt.Fprintf(w, "Hello, %s!", name) + }) + + port := os.Getenv("PORT") + if port == "" { + port = "8080" + } + + log.Printf("Server starting on port %s\n", port) + log.Fatal(http.ListenAndServe(":"+port, router)) + } + ``` + + + ```go title="main.go" icon="rocket" + package main + + import ( + "example/suga" + "fmt" + "log" + "net/http" + "os" + ) + + func main() { + // Initialize Suga client + app, err := suga.NewClient() + if err != nil { + log.Fatalf("Failed to create suga client: %v", err) + } + + router := http.NewServeMux() + router.HandleFunc("GET /hello/{name}", func(w http.ResponseWriter, r *http.Request) { + name := r.PathValue("name") + + // Simplified file write using Suga + if err := app.Files.Write("example.txt", []byte("Hello, "+name+"!")); err != nil { + log.Printf("Failed to write file: %v", err) + http.Error(w, "Error writing file", http.StatusInternalServerError) + return + } + + fmt.Fprintf(w, "Hello, %s!", name) + }) + + port := os.Getenv("PORT") + if port == "" { + port = "8080" + } + + log.Printf("Server starting on port %s\n", port) + log.Fatal(http.ListenAndServe(":"+port, router)) + } + ``` + + + + + Remove all cloud provider SDK dependencies after migration to avoid conflicts and reduce bundle size. + + +## Test Locally + +Start the Suga development environment: + +```bash title="Start Development Server" icon="play" +suga dev +``` - +Test your migrated application: - - Start the Suga development environment: +```bash title="Test Endpoint" icon="circle-check" +curl http://localhost:3000/hello/world +``` - ```bash title="Start Development Server" icon="play" - suga dev - ``` +Expected response: - Test your migrated application: +``` +Hello, world! +``` - ```bash title="Test Endpoint" icon="circle-check" - curl http://localhost:3000/hello/world - ``` + + Suga dev provides local emulation of cloud services. Files are stored locally during development and in real cloud storage when deployed. + - Expected response: - ``` - Hello, world! - ``` +## Deploy to Cloud - - Suga dev provides local emulation of cloud services. Files are stored locally during development and in real cloud storage when deployed. - +Build your application and generate Terraform: - +```bash title="Build Application" icon="hammer" +suga build +``` - - Build your application and generate Terraform: +Select your cloud provider and region when prompted. You'll see: - ```bash title="Build Application" icon="hammer" - suga build - ``` +```bash +✓ Terraform generated successfully + output written to ./.suga/stacks/my-app-aws-12345 - Select your cloud provider and region when prompted. You'll see: +Next steps: +1. Run cd ./.suga/stacks/my-app-aws-12345 to move to the stack directory +2. Initialize the stack terraform init -upgrade +3. Optionally, preview with terraform plan +4. Deploy with terraform apply +``` - ```bash - ✓ Terraform generated successfully - output written to ./.suga/stacks/my-app-aws-12345 +Configure cloud provider credentials: - Next steps: - 1. Run cd ./.suga/stacks/my-app-aws-12345 to move to the stack directory - 2. Initialize the stack terraform init -upgrade - 3. Optionally, preview with terraform plan - 4. Deploy with terraform apply + + + ```bash title="Configure AWS" icon="aws" + aws configure ``` - - Configure cloud provider credentials: - - - - ```bash title="Configure AWS" icon="aws" - aws configure - ``` - - - ```bash title="Configure GCP" icon="google" - gcloud auth application-default login - ``` - - - - Deploy with Terraform: - - ```bash title="Navigate to Stack" icon="folder" - cd .suga/stacks/my-app-aws-* + + + ```bash title="Configure GCP" icon="google" + gcloud auth application-default login ``` + + - ```bash title="Initialize Terraform" icon="download" - terraform init -upgrade - ``` +Deploy with Terraform: - ```bash title="Preview Changes" icon="eye" - terraform plan - ``` +```bash title="Navigate to Stack" icon="folder" +cd .suga/stacks/my-app-aws-* +``` - ```bash title="Deploy Infrastructure" icon="rocket" - terraform apply - ``` +```bash title="Initialize Terraform" icon="download" +terraform init -upgrade +``` - Type `yes` when prompted. After deployment completes, your application endpoints will be displayed in the output. +```bash title="Preview Changes" icon="eye" +terraform plan +``` + +```bash title="Deploy Infrastructure" icon="rocket" +terraform apply +``` - - +Type `yes` when prompted. After deployment completes, your application endpoints will be displayed in the output. Your application is now cloud-agnostic. Deploy to AWS or GCP without code diff --git a/docs/guides/build-platform.mdx b/docs/guides/build-platform.mdx index 061a60e0..4b93a51b 100644 --- a/docs/guides/build-platform.mdx +++ b/docs/guides/build-platform.mdx @@ -15,388 +15,371 @@ Platforms can start simple and evolve as your needs grow. This guide walks throu ## Phase 1: Build Serverless Platform - - - This architecture shows a CloudFront distribution routing requests to a Lambda function, which accesses an S3 bucket and a Neon database. +### Understanding the Architecture - ![Serverless Functions Architecture](/images/build-platform/aws-lambda-arch.png) +This architecture shows a CloudFront distribution routing requests to a Lambda function, which accesses an S3 bucket and a Neon database. - The platform will need the following resource blueprints to deploy this architecture: - - **Entrypoint** - CloudFront CDN for routing requests - - **Service** - Lambda functions with IAM role for running code and accessing resources - - **Bucket** - S3 for file storage - - **Database** - Neon PostgreSQL - +![Serverless Functions Architecture](/images/build-platform/aws-lambda-arch.png) - - Sign in to the Suga platform editor at [https://app.addsuga.com](https://app.addsuga.com), select your team, then click **"Create New Platform"**. +The platform will need the following resource blueprints to deploy this architecture: +- **Entrypoint** - CloudFront CDN for routing requests +- **Service** - Lambda functions with IAM role for running code and accessing resources +- **Bucket** - S3 for file storage +- **Database** - Neon PostgreSQL - ![Suga Platform Dashboard](/images/build-platform/create-platform.png) +### Create New Platform - Fill out the platform details and click **"Create Platform"**: +Sign in to the Suga platform editor at [https://app.addsuga.com](https://app.addsuga.com), select your team, then click **"Create New Platform"**. - ![Create New Platform Dialog](/images/build-platform/platform-details.png) +![Suga Platform Dashboard](/images/build-platform/create-platform.png) - - Platforms are owned by teams and shared with team members. Public platforms are visible to all Suga users, while private platforms are only visible to your team. - +Fill out the platform details and click **"Create Platform"**: - The platform editor has two sections: +![Create New Platform Dialog](/images/build-platform/platform-details.png) - - **[Foundations](/platforms#variables)** - Common infrastructure shared by other resources (VPCs, load balancers) and common variables for platform configuration - - **[Resource Blueprints](/platforms#resource-blueprints)** - Templates that define how to provision application specific resources, such as services, databases, buckets, and entrypoints + + Platforms are owned by teams and shared with team members. Public platforms are visible to all Suga users, while private platforms are only visible to your team. + - ![Edit Platform Dialog](/images/build-platform/edit-platform.png) +The platform editor has two sections: +- **[Foundations](/platforms#variables)** - Common infrastructure shared by other resources (VPCs, load balancers) and common variables for platform configuration +- **[Resource Blueprints](/platforms#resource-blueprints)** - Templates that define how to provision application specific resources, such as services, databases, buckets, and entrypoints - +![Edit Platform Dialog](/images/build-platform/edit-platform.png) - - This blueprint maps an application's entrypoints to a CloudFront distribution that routes HTTP traffic to services. Without this, applications would have no way to receive external HTTP requests. +### Configure Entrypoint Blueprints - Expand **Entrypoint Blueprints** in Resource Blueprints. +This blueprint maps an application's entrypoints to a CloudFront distribution that routes HTTP traffic to services. Without this, applications would have no way to receive external HTTP requests. - - Browse available plugins by clicking any blueprint category. Request custom plugins from the Suga team. - +Expand **Entrypoint Blueprints** in Resource Blueprints. - Add the `cloudfront` plugin and apply the following configuration: - ```yaml - name: default + + Browse available plugins by clicking any blueprint category. Request custom plugins from the Suga team. + - # Properties - default_cache_policy_id: - ``` +Add the `cloudfront` plugin and apply the following configuration: +```yaml +name: default - - Leave blank for default, or use an existing policy ID from AWS console for consistency. - +# Properties +default_cache_policy_id: +``` - + + Leave blank for default, or use an existing policy ID from AWS console for consistency. + - - This blueprint maps an application's services to Lambda functions for serverless execution. This is the compute layer where application code runs. +### Configure Service Blueprints - Expand **Service Blueprints** in Resource Blueprints. +This blueprint maps an application's services to Lambda functions for serverless execution. This is the compute layer where application code runs. - Add the `lambda` plugin and apply the following configuration: - ```yaml - name: lambda - ``` +Expand **Service Blueprints** in Resource Blueprints. - Add the `iam-role` plugin as the identity to enable automatic IAM permission generation for accessing buckets and databases: +Add the `lambda` plugin and apply the following configuration: +```yaml +name: lambda +``` - ![Add IAM-Role](/images/build-platform/add-iam-role.png) +Add the `iam-role` plugin as the identity to enable automatic IAM permission generation for accessing buckets and databases: +![Add IAM-Role](/images/build-platform/add-iam-role.png) - +### Configure Bucket Blueprints - - This blueprint maps an application's buckets to S3 for object storage with automatic IAM permissions. Applications use buckets to store and retrieve files like images, documents, or user uploads. +This blueprint maps an application's buckets to S3 for object storage with automatic IAM permissions. Applications use buckets to store and retrieve files like images, documents, or user uploads. - Expand **Bucket Blueprints** in Resource Blueprints. +Expand **Bucket Blueprints** in Resource Blueprints. - Add the `s3-bucket` plugin and apply the following configuration: - ```yaml - name: default - ``` +Add the `s3-bucket` plugin and apply the following configuration: +```yaml +name: default +``` - +### Configure Database Blueprints - - This blueprint maps an application's databases to Neon PostgreSQL with automatic credential injection into services. Applications use databases to persist and query structured data. +This blueprint maps an application's databases to Neon PostgreSQL with automatic credential injection into services. Applications use databases to persist and query structured data. - Expand **Database Blueprints** in Resource Blueprints. +Expand **Database Blueprints** in Resource Blueprints. - Add platform variable in **Foundations** to specify which Neon project to create databases in: - ```yaml - neon_project_id: - type: string - description: "" - default: - nullable: false - ``` +Add platform variable in **Foundations** to specify which Neon project to create databases in: +```yaml +neon_project_id: + type: string + description: "" + default: + nullable: false +``` - Add the `database` plugin and apply the following configuration: - ```yaml - name: default +Add the `database` plugin and apply the following configuration: +```yaml +name: default - # Variables - neon_branch_id: - type: string - description: The ID of the Neon branch to use if using an existing branch - default: null - nullable: true +# Variables +neon_branch_id: + type: string + description: The ID of the Neon branch to use if using an existing branch + default: null + nullable: true - # Properties - project_id: ${var.neon_project_id} - branch_id: ${self.neon_branch_id} - ``` +# Properties +project_id: ${var.neon_project_id} +branch_id: ${self.neon_branch_id} +``` - - Suga uses three types of references in platform configurations: - - `${var.name}` - References platform variables from Foundations - - `${self.name}` - References resource-specific variables defined in the same resource blueprint - - `${infra.name.output}` - References outputs from infrastructure components (you'll see this in Phase 2) - + + Suga uses three types of references in platform configurations: + - `${var.name}` - References platform variables from Foundations + - `${self.name}` - References resource-specific variables defined in the same resource blueprint + - `${infra.name.output}` - References outputs from infrastructure components (you'll see this in Phase 2) + - - Applications can optionally set `neon_branch_id` for isolated Neon branches (e.g., one per PR). - + + Applications can optionally set `neon_branch_id` for isolated Neon branches (e.g., one per PR). + - +### Save Your Platform - - Click "Commit Revision" in the platform editor, add a descriptive commit message (e.g., "Initial serverless platform with Lambda, S3, and Neon"), and commit. +Click "Commit Revision" in the platform editor, add a descriptive commit message (e.g., "Initial serverless platform with Lambda, S3, and Neon"), and commit. - - Each commit creates a new platform revision. Applications reference specific revisions, so you can safely update platforms without breaking existing apps. New applications always use the latest revision. - - + + Each commit creates a new platform revision. Applications reference specific revisions, so you can safely update platforms without breaking existing apps. New applications always use the latest revision. + - - Create an [application](/projects) from the project editor and design your application architecture using the platform you just created. +### Test with an Application - - Not familiar with building applications with Suga? Start with the [Quickstart guide](/quickstart). - +Create an [application](/projects) from the project editor and design your application architecture using the platform you just created. + + + Not familiar with building applications with Suga? Start with the [Quickstart guide](/quickstart). + - The diagram below shows an example application using this platform. Once you've created your application, use the build icon to [build your Terraform](/cli/build). +The diagram below shows an example application using this platform. Once you've created your application, use the build icon to [build your Terraform](/cli/build). - ![Test Platform](/images/build-platform/test-platform.png) +![Test Platform](/images/build-platform/test-platform.png) - - Suga generates Terraform for CloudFront→Lambda routing, IAM policies for declared resources, and database credential injection. - - - + + Suga generates Terraform for CloudFront→Lambda routing, IAM policies for declared resources, and database credential injection. + ## Phase 2: Add Stateful Services - - - This architecture shows CloudFront routing to an Application Load Balancer, which distributes traffic to Fargate containers in a VPC. The containers access the same S3 bucket and Neon database. +### Understanding the Architecture + +This architecture shows CloudFront routing to an Application Load Balancer, which distributes traffic to Fargate containers in a VPC. The containers access the same S3 bucket and Neon database. - ![Stateful Services Architecture](/images/build-platform/aws-fargate-arch.png) +![Stateful Services Architecture](/images/build-platform/aws-fargate-arch.png) - To extend the platform with stateful services, the platform will need the following infrastructure and blueprints: +To extend the platform with stateful services, the platform will need the following infrastructure and blueprints: - **Shared Infrastructure (Foundations)**: - - **VPC** - Private network for Fargate containers - - **Security Group Rules** - Firewall rules for container traffic - - **Load Balancer** - Internal ALB for routing to Fargate containers +**Shared Infrastructure (Foundations)**: +- **VPC** - Private network for Fargate containers +- **Security Group Rules** - Firewall rules for container traffic +- **Load Balancer** - Internal ALB for routing to Fargate containers - **Service Blueprint (Resource Blueprints)**: - - **Service** - Fargate containers with IAM role as an alternative to Lambda +**Service Blueprint (Resource Blueprints)**: +- **Service** - Fargate containers with IAM role as an alternative to Lambda - - Applications can declare multiple services—some using `lambda`, others using `fargate`, along with as many buckets and databases as needed. - - + + Applications can declare multiple services—some using `lambda`, others using `fargate`, along with as many buckets and databases as needed. + - - This shared infrastructure configures the VPC network foundation with isolated subnets, NAT gateways, and routing for stateful containers. Unlike serverless Lambda functions, Fargate containers require a private network to run securely. +### Configure VPC Infrastructure - In the **Foundations** section, expand **Infrastructure**. +This shared infrastructure configures the VPC network foundation with isolated subnets, NAT gateways, and routing for stateful containers. Unlike serverless Lambda functions, Fargate containers require a private network to run securely. - Add the `vpc` plugin and apply the following configuration: - ```yaml - name: aws_vpc +In the **Foundations** section, expand **Infrastructure**. - # Variables - single_nat_gateway: - type: bool - description: "" - default: true - nullable: false +Add the `vpc` plugin and apply the following configuration: +```yaml +name: aws_vpc - # Properties - enable_nat_gateway: true - single_nat_gateway: ${self.single_nat_gateway} - ``` +# Variables +single_nat_gateway: + type: bool + description: "" + default: true + nullable: false - - `single_nat_gateway = true` reduces costs but removes redundancy. Use multiple for production HA. - +# Properties +enable_nat_gateway: true +single_nat_gateway: ${self.single_nat_gateway} +``` - + + `single_nat_gateway = true` reduces costs but removes redundancy. Use multiple for production HA. + - - These platform variables configure the network ports for container communication. The `container_port` defines where containers listen for traffic, while `lb_listener_port` defines where the load balancer accepts incoming requests. +### Configure Platform Variables - Add platform variables in **Foundations**: +These platform variables configure the network ports for container communication. The `container_port` defines where containers listen for traffic, while `lb_listener_port` defines where the load balancer accepts incoming requests. - ```yaml - container_port: - type: number - description: "" - default: 8080 - nullable: false +Add platform variables in **Foundations**: - lb_listener_port: - type: number - description: "" - default: 80 - nullable: false - ``` +```yaml +container_port: + type: number + description: "" + default: 8080 + nullable: false - +lb_listener_port: + type: number + description: "" + default: 80 + nullable: false +``` - - This shared infrastructure configures firewall rules for container network traffic: outbound internet access, health check access, and CDN-only ingress. These rules ensure containers can communicate with external services while blocking unauthorized access. +### Configure Security Group Rules - In the **Foundations** section, expand **Infrastructure**. +This shared infrastructure configures firewall rules for container network traffic: outbound internet access, health check access, and CDN-only ingress. These rules ensure containers can communicate with external services while blocking unauthorized access. - **Outbound Internet Access** +In the **Foundations** section, expand **Infrastructure**. - Add the `security-group-rule` plugin and apply the following configuration: - ```yaml - name: aws_sg_http_egress +**Outbound Internet Access** - # Dependencies - ${infra.aws_vpc} +Add the `security-group-rule` plugin and apply the following configuration: +```yaml +name: aws_sg_http_egress - # Properties - type: egress - protocol: -1 - cidr_blocks: ["0.0.0.0/0"] - security_group_ids: ["${infra.aws_vpc.default_security_group_id}"] - ``` +# Dependencies +${infra.aws_vpc} - - Dependencies ensure infrastructure is created in the correct order, creating the VPC before this security group rule. - +# Properties +type: egress +protocol: -1 +cidr_blocks: ["0.0.0.0/0"] +security_group_ids: ["${infra.aws_vpc.default_security_group_id}"] +``` - - `cidr_blocks: ["0.0.0.0/0"]` allows outbound traffic to any IP address on the internet. - + + Dependencies ensure infrastructure is created in the correct order, creating the VPC before this security group rule. + - **Health Check Access** + + `cidr_blocks: ["0.0.0.0/0"]` allows outbound traffic to any IP address on the internet. + - Add another `security-group-rule` plugin and apply the following configuration: - ```yaml - name: aws_sg_health_check_ingress +**Health Check Access** - # Dependencies - ${infra.aws_vpc} +Add another `security-group-rule` plugin and apply the following configuration: +```yaml +name: aws_sg_health_check_ingress - # Properties - type: ingress - protocol: tcp - self: true - from_port: ${var.container_port} - to_port: ${var.container_port} - security_group_ids: ["${infra.aws_vpc.default_security_group_id}"] - ``` +# Dependencies +${infra.aws_vpc} - - `self: true` allows same-security-group communication for load balancer health checks. - +# Properties +type: ingress +protocol: tcp +self: true +from_port: ${var.container_port} +to_port: ${var.container_port} +security_group_ids: ["${infra.aws_vpc.default_security_group_id}"] +``` - **CloudFront Access** + + `self: true` allows same-security-group communication for load balancer health checks. + - Add another `security-group-rule` plugin and apply the following configuration: - ```yaml - name: aws_sg_allow_cloudfront +**CloudFront Access** - # Dependencies - ${infra.aws_vpc} +Add another `security-group-rule` plugin and apply the following configuration: +```yaml +name: aws_sg_allow_cloudfront - # Properties - type: ingress - protocol: tcp - from_port: ${var.lb_listener_port} - to_port: ${var.lb_listener_port} - prefix_list_names: ["com.amazonaws.global.cloudfront.origin-facing"] - security_group_ids: ["${infra.aws_vpc.default_security_group_id}"] - ``` +# Dependencies +${infra.aws_vpc} - - `prefix_list_names` restricts access to CloudFront and prevents direct internet access with DDoS protection. - +# Properties +type: ingress +protocol: tcp +from_port: ${var.lb_listener_port} +to_port: ${var.lb_listener_port} +prefix_list_names: ["com.amazonaws.global.cloudfront.origin-facing"] +security_group_ids: ["${infra.aws_vpc.default_security_group_id}"] +``` - + + `prefix_list_names` restricts access to CloudFront and prevents direct internet access with DDoS protection. + - - This shared infrastructure configures an internal Application Load Balancer to route traffic and perform health checks for containers. The load balancer distributes incoming requests across container instances and removes unhealthy containers from rotation. +### Configure Load Balancer - In the **Foundations** section, expand **Infrastructure**. +This shared infrastructure configures an internal Application Load Balancer to route traffic and perform health checks for containers. The load balancer distributes incoming requests across container instances and removes unhealthy containers from rotation. - Add the `loadbalancer` plugin and apply the following configuration: +In the **Foundations** section, expand **Infrastructure**. - ```yaml - name: aws_lb +Add the `loadbalancer` plugin and apply the following configuration: - # Dependencies - ${infra.aws_vpc} - ${infra.aws_sg_http_egress} - ${infra.aws_sg_health_check_ingress} - ${infra.aws_sg_allow_cloudfront} +```yaml +name: aws_lb - # Properties - internal: true - subnets: ${infra.aws_vpc.private_subnets} - security_groups: ["${infra.aws_vpc.default_security_group_id}"] - ``` +# Dependencies +${infra.aws_vpc} +${infra.aws_sg_http_egress} +${infra.aws_sg_health_check_ingress} +${infra.aws_sg_allow_cloudfront} - - Properties like `subnets` and `security_groups` use `${infra.aws_vpc.*}` to access outputs from the VPC infrastructure component. This wires the load balancer to the correct network configuration. - +# Properties +internal: true +subnets: ${infra.aws_vpc.private_subnets} +security_groups: ["${infra.aws_vpc.default_security_group_id}"] +``` - + + Properties like `subnets` and `security_groups` use `${infra.aws_vpc.*}` to access outputs from the VPC infrastructure component. This wires the load balancer to the correct network configuration. + - - This blueprint maps application services to Fargate containers for stateful workloads, providing an alternative to the Lambda blueprint from Phase 1. Stateful containers support long-running processes, persistent connections, and custom runtimes that aren't suitable for serverless functions. +### Configure Service Blueprints - Expand **Service Blueprints** in Resource Blueprints. +This blueprint maps application services to Fargate containers for stateful workloads, providing an alternative to the Lambda blueprint from Phase 1. Stateful containers support long-running processes, persistent connections, and custom runtimes that aren't suitable for serverless functions. - Add the `fargate` plugin and apply the following configuration: - ```yaml - name: fargate +Expand **Service Blueprints** in Resource Blueprints. - # Dependencies - ${infra.aws_lb} - ${infra.aws_vpc} - ``` +Add the `fargate` plugin and apply the following configuration: +```yaml +name: fargate - - The plugin name becomes the subtype dropdown option in the application editor. Use descriptive names when adding multiple service plugins. - +# Dependencies +${infra.aws_lb} +${infra.aws_vpc} +``` - Add the `iam-role` plugin as the identity to enable automatic IAM permission generation for accessing buckets and databases: + + The plugin name becomes the subtype dropdown option in the application editor. Use descriptive names when adding multiple service plugins. + - ![Add IAM-Role](/images/build-platform/add-iam-role.png) +Add the `iam-role` plugin as the identity to enable automatic IAM permission generation for accessing buckets and databases: - Configure the Fargate properties: - ```yaml - # Properties - vpc_id: ${infra.aws_vpc.vpc_id} - subnets: ${infra.aws_vpc.private_subnets} - security_groups: ["${infra.aws_vpc.default_security_group_id}"] - alb_arn: ${infra.aws_lb.arn} - alb_security_group: ${infra.aws_vpc.default_security_group_id} - container_port: ${var.container_port} - ``` +![Add IAM-Role](/images/build-platform/add-iam-role.png) - - These properties wire Fargate containers into the VPC network and register them with the load balancer for traffic routing and health checks. - +Configure the Fargate properties: +```yaml +# Properties +vpc_id: ${infra.aws_vpc.vpc_id} +subnets: ${infra.aws_vpc.private_subnets} +security_groups: ["${infra.aws_vpc.default_security_group_id}"] +alb_arn: ${infra.aws_lb.arn} +alb_security_group: ${infra.aws_vpc.default_security_group_id} +container_port: ${var.container_port} +``` - + + These properties wire Fargate containers into the VPC network and register them with the load balancer for traffic routing and health checks. + - - Your platform now supports both architectures! +### Test Complete Platform - Applications select blueprints using the subtype dropdown (`fargate` or `lambda`). +Your platform now supports both architectures! - ![Test Platform](/images/build-platform/test-platform-subtype.png) +Applications select blueprints using the subtype dropdown (`fargate` or `lambda`). - This enables different services within the same application to use different architectures based on their requirements. +![Test Platform](/images/build-platform/test-platform-subtype.png) - ![Test Platform Multiple Services](/images/build-platform/test-multiple-services.png) +This enables different services within the same application to use different architectures based on their requirements. - - +![Test Platform Multiple Services](/images/build-platform/test-multiple-services.png) ## Troubleshooting diff --git a/docs/guides/database-migration.mdx b/docs/guides/database-migration.mdx index 48815845..4c64c853 100644 --- a/docs/guides/database-migration.mdx +++ b/docs/guides/database-migration.mdx @@ -32,67 +32,65 @@ The recommended approach follows a four-phase deployment pattern: ### Implementation Steps - - - First, apply only the database module using Terraform's `-target` flag: - - ```bash - # Initialize Terraform - terraform init - - # Plan database module deployment - terraform plan -target=module.database -out=tfplan-database - - # Apply database module - terraform apply tfplan-database - ``` - - - - After the database module is deployed, extract the connection details from Terraform state: - - ```bash - # Extract database connection components - terraform output -json database_connection_string - - # Or extract from state directly - terraform state show module.database - ``` - - For Neon databases specifically, you'll typically need: - - Role name and password - - Endpoint host - - Database name - - SSL mode (usually `require`) - - - - With the connection string available, run your migrations: - - ```bash - # Example using golang-migrate - migrate -database "$DATABASE_URL" -path ./migrations up - - # Example using a custom migration tool - ./run-migrations.sh --database-url "$DATABASE_URL" - - # Example using Node.js migration tool - npm run migrate:up - ``` - - - - After migrations succeed, deploy the complete application stack: - - ```bash - # Plan full deployment - terraform plan -out=tfplan-app - - # Apply all modules - terraform apply tfplan-app - ``` - - +#### Deploy Database Module + +First, apply only the database module using Terraform's `-target` flag: + +```bash +# Initialize Terraform +terraform init + +# Plan database module deployment +terraform plan -target=module.database -out=tfplan-database + +# Apply database module +terraform apply tfplan-database +``` + +#### Extract Database Connection String + +After the database module is deployed, extract the connection details from Terraform state: + +```bash +# Extract database connection components +terraform output -json database_connection_string + +# Or extract from state directly +terraform state show module.database +``` + +For Neon databases specifically, you'll typically need: +- Role name and password +- Endpoint host +- Database name +- SSL mode (usually `require`) + +#### Run Migrations + +With the connection string available, run your migrations: + +```bash +# Example using golang-migrate +migrate -database "$DATABASE_URL" -path ./migrations up + +# Example using a custom migration tool +./run-migrations.sh --database-url "$DATABASE_URL" + +# Example using Node.js migration tool +npm run migrate:up +``` + +#### Deploy Application + +After migrations succeed, deploy the complete application stack: + +```bash +# Plan full deployment +terraform plan -out=tfplan-app + +# Apply all modules +terraform apply tfplan-app +``` ### Best Practices diff --git a/docs/guides/local-database-setup.mdx b/docs/guides/local-database-setup.mdx index b1041126..f11f53e5 100644 --- a/docs/guides/local-database-setup.mdx +++ b/docs/guides/local-database-setup.mdx @@ -9,136 +9,134 @@ Suga doesn't currently auto-provision databases for local development. This guid **Prerequisites:** This guide assumes you have an existing Suga project with a service that needs database access. If you need to create a project, see the [Getting Started Guide](/quickstart). - - - Create these files in your project root: - - ```yaml title="docker-compose.yml" icon="docker" - services: - postgres: - image: postgres:15 - environment: - POSTGRES_USER: ${POSTGRES_USER:-admin} - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-secure_password} - POSTGRES_DB: ${POSTGRES_DB:-myapp} - ports: - - '5433:5432' - volumes: - - postgres_data:/var/lib/postgresql/data - command: postgres -c ssl=off - +## Setup PostgreSQL with Docker + +Create these files in your project root: + +```yaml title="docker-compose.yml" icon="docker" +services: + postgres: + image: postgres:15 + environment: + POSTGRES_USER: ${POSTGRES_USER:-admin} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-secure_password} + POSTGRES_DB: ${POSTGRES_DB:-myapp} + ports: + - '5433:5432' volumes: - postgres_data: - ``` + - postgres_data:/var/lib/postgresql/data + command: postgres -c ssl=off + +volumes: + postgres_data: +``` + +```bash title=".env" icon="shield-check" +POSTGRES_USER=admin +POSTGRES_PASSWORD=secure_password +POSTGRES_DB=myapp +DATABASE_URL=postgresql://admin:secure_password@localhost:5433/myapp?sslmode=disable +``` - ```bash title=".env" icon="shield-check" - POSTGRES_USER=admin - POSTGRES_PASSWORD=secure_password - POSTGRES_DB=myapp - DATABASE_URL=postgresql://admin:secure_password@localhost:5433/myapp?sslmode=disable - ``` + + Change the default password before using in any shared environment. + - - Change the default password before using in any shared environment. - +Start your database: - Start your database: +```bash title="Start Database" icon="play" +docker compose up -d +``` - ```bash title="Start Database" icon="play" - docker compose up -d - ``` +Verify it's running: - Verify it's running: +```bash title="Verify Database" icon="circle-check" +docker compose ps +``` - ```bash title="Verify Database" icon="circle-check" - docker compose ps - ``` +You should see the postgres service in "Up" status. - You should see the postgres service in "Up" status. - +## Configure Database in Suga - - Open the Suga dashboard: +Open the Suga dashboard: - ```bash title="Open Suga Editor" icon="pencil-ruler" - suga edit - ``` +```bash title="Open Suga Editor" icon="pencil-ruler" +suga edit +``` - Drag a database resource onto your project canvas and connect it to your service. Set the environment key to `DATABASE_URL`. +Drag a database resource onto your project canvas and connect it to your service. Set the environment key to `DATABASE_URL`. - ![Database Configuration](/images/database.png) +![Database Configuration](/images/database.png) - This automatically updates your `suga.yaml`: +This automatically updates your `suga.yaml`: - ```yaml title="suga.yaml" icon="file-code" - name: my-app - services: +```yaml title="suga.yaml" icon="file-code" +name: my-app +services: + api: + # Your service configuration here +databases: + mydb: + access: api: - # Your service configuration here - databases: - mydb: - access: - api: - - query - env_var_key: DATABASE_URL - ``` - - - For local development, you manually set `DATABASE_URL` to point to your Docker database. When deployed, Suga automatically configures this same environment variable with your production database URL. - - - - - You can set up your database schema however you prefer - using SQL files, ORM migrations, or database management tools. Below is one simple approach using a SQL file. - - Create an `init.sql` file in your project root: - - ```sql title="init.sql" icon="database" - DROP TABLE IF EXISTS users; - - CREATE TABLE users ( - id SERIAL PRIMARY KEY, - email VARCHAR(255) UNIQUE NOT NULL, - created_at TIMESTAMP DEFAULT NOW() - ); - - INSERT INTO users (email) VALUES - ('admin@example.com'), - ('user@example.com'); - ``` - - Apply your schema: - - ```bash title="Reset Database with Schema" icon="refresh-cw" - docker compose down -v - docker compose up -d - sleep 2 - docker compose exec -T postgres psql -U admin -d myapp < init.sql - ``` - - - For production, use a proper migration tool like golang-migrate, Flyway, or your ORM's migration system. - - - - - Your application can now access the database using the `DATABASE_URL` environment variable that Suga provides. The connection string will be automatically injected when you run `suga dev`. - - First, verify you can connect to the database directly: - - ```bash title="Test Direct Connection" icon="database" - docker compose exec postgres psql -U admin -d myapp -c "SELECT * FROM users;" - ``` - - You should see your test data. Now start your application: - - ```bash title="Start Your Application" icon="rocket" - suga dev - ``` - - Your application now has access to the `DATABASE_URL` environment variable and can connect to PostgreSQL. Create a simple endpoint or function in your application to test the database connection and verify everything works end-to-end. - - + - query + env_var_key: DATABASE_URL +``` + + + For local development, you manually set `DATABASE_URL` to point to your Docker database. When deployed, Suga automatically configures this same environment variable with your production database URL. + + +## Initialize Database Schema + +You can set up your database schema however you prefer - using SQL files, ORM migrations, or database management tools. Below is one simple approach using a SQL file. + +Create an `init.sql` file in your project root: + +```sql title="init.sql" icon="database" +DROP TABLE IF EXISTS users; + +CREATE TABLE users ( + id SERIAL PRIMARY KEY, + email VARCHAR(255) UNIQUE NOT NULL, + created_at TIMESTAMP DEFAULT NOW() +); + +INSERT INTO users (email) VALUES + ('admin@example.com'), + ('user@example.com'); +``` + +Apply your schema: + +```bash title="Reset Database with Schema" icon="refresh-cw" +docker compose down -v +docker compose up -d +sleep 2 +docker compose exec -T postgres psql -U admin -d myapp < init.sql +``` + + + For production, use a proper migration tool like golang-migrate, Flyway, or your ORM's migration system. + + +## Test Your Database Connection + +Your application can now access the database using the `DATABASE_URL` environment variable that Suga provides. The connection string will be automatically injected when you run `suga dev`. + +First, verify you can connect to the database directly: + +```bash title="Test Direct Connection" icon="database" +docker compose exec postgres psql -U admin -d myapp -c "SELECT * FROM users;" +``` + +You should see your test data. Now start your application: + +```bash title="Start Your Application" icon="rocket" +suga dev +``` + +Your application now has access to the `DATABASE_URL` environment variable and can connect to PostgreSQL. Create a simple endpoint or function in your application to test the database connection and verify everything works end-to-end. **Database won't start:** diff --git a/docs/guides/terraform-backend-config.mdx b/docs/guides/terraform-backend-config.mdx index 794527b5..fe8c45cf 100644 --- a/docs/guides/terraform-backend-config.mdx +++ b/docs/guides/terraform-backend-config.mdx @@ -38,96 +38,95 @@ The synthesized output can be found in the `terraform` directory. After running `suga build`, add a backend configuration file to the synthesized output: - - - ```bash title="Generate Terraform Stack" icon="hammer" - suga build - ``` - - - - Create `backend.tf` in the synthesized stack directory: - - ```bash title="Create Backend File" icon="file-plus" - touch terraform/stacks//backend.tf - ``` - - - - Choose your backend provider and add the appropriate configuration: - - - ```hcl title="backend.tf - AWS S3" icon="aws" - terraform { - backend "s3" { - bucket = "my-terraform-state-bucket" - key = "suga/terraform.tfstate" - region = "us-east-1" - encrypt = true - dynamodb_table = "terraform-locks" - } - } - ``` - - - Ensure your S3 bucket has versioning enabled and consider enabling MFA delete for production environments. - - - - - ```hcl title="backend.tf - Google Cloud" icon="cloud" - terraform { - backend "gcs" { - bucket = "my-terraform-state-bucket" - prefix = "suga/terraform/state" - } - } - ``` - - - Enable object versioning on your GCS bucket to maintain state history. - - - - - ```hcl title="backend.tf - Azure Storage" icon="cloud" - terraform { - backend "azurerm" { - resource_group_name = "terraform-state-rg" - storage_account_name = "terraformstatestorage" - container_name = "terraform-state" - key = "suga.terraform.tfstate" - } - } - ``` - - - - ```hcl title="backend.tf - Terraform Cloud" icon="cloud" - terraform { - backend "remote" { - organization = "my-org" - workspaces { - name = "suga-production" - } - } +### Generate the Stack + +```bash title="Generate Terraform Stack" icon="hammer" +suga build +``` + +### Create Backend Configuration + +Create `backend.tf` in the synthesized stack directory: + +```bash title="Create Backend File" icon="file-plus" +touch terraform/stacks//backend.tf +``` + +### Add Backend Configuration + +Choose your backend provider and add the appropriate configuration: + + + + ```hcl title="backend.tf - AWS S3" icon="aws" + terraform { + backend "s3" { + bucket = "my-terraform-state-bucket" + key = "suga/terraform.tfstate" + region = "us-east-1" + encrypt = true + dynamodb_table = "terraform-locks" + } + } + ``` + + + Ensure your S3 bucket has versioning enabled and consider enabling MFA delete for production environments. + + + + + ```hcl title="backend.tf - Google Cloud" icon="cloud" + terraform { + backend "gcs" { + bucket = "my-terraform-state-bucket" + prefix = "suga/terraform/state" + } + } + ``` + + + Enable object versioning on your GCS bucket to maintain state history. + + + + + ```hcl title="backend.tf - Azure Storage" icon="cloud" + terraform { + backend "azurerm" { + resource_group_name = "terraform-state-rg" + storage_account_name = "terraformstatestorage" + container_name = "terraform-state" + key = "suga.terraform.tfstate" + } + } + ``` + + + + ```hcl title="backend.tf - Terraform Cloud" icon="cloud" + terraform { + backend "remote" { + organization = "my-org" + workspaces { + name = "suga-production" } - ``` - - - - - - ```bash title="Initialize Terraform" icon="terminal" - cd terraform/stacks/ - terraform init - ``` - - ```bash title="Deploy Infrastructure" icon="rocket" - terraform apply - ``` - - + } + } + ``` + + + +### Initialize and Deploy + +```bash title="Initialize Terraform" icon="terminal" +cd terraform/stacks/ +terraform init +``` + +```bash title="Deploy Infrastructure" icon="rocket" +terraform apply +``` Only the cdktf files are managed by Suga. You can safely add custom `.tf` files to the stack directory to extend the configuration. From f4e35dcf46db3eb0c7d4e4c89502cf652b3e10fd Mon Sep 17 00:00:00 2001 From: Jye Cusch Date: Tue, 14 Oct 2025 14:20:58 +1100 Subject: [PATCH 2/3] doc: spelling fixes --- docs/.vale/styles/config/vocabularies/Suga/accept.txt | 10 ++++++++++ docs/guides/terraform-backend-config.mdx | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/.vale/styles/config/vocabularies/Suga/accept.txt b/docs/.vale/styles/config/vocabularies/Suga/accept.txt index e4b362bf..fa7920cb 100644 --- a/docs/.vale/styles/config/vocabularies/Suga/accept.txt +++ b/docs/.vale/styles/config/vocabularies/Suga/accept.txt @@ -22,6 +22,16 @@ serverless subnets runtimes rollout +VPCs +fmt +gcloud +dynamodb_table +gcs +azurerm +resource_group_name +storage_account_name +container_name +tfstatestorage # Defaults from mintlify Mintlify diff --git a/docs/guides/terraform-backend-config.mdx b/docs/guides/terraform-backend-config.mdx index fe8c45cf..43a834cd 100644 --- a/docs/guides/terraform-backend-config.mdx +++ b/docs/guides/terraform-backend-config.mdx @@ -95,7 +95,7 @@ Choose your backend provider and add the appropriate configuration: terraform { backend "azurerm" { resource_group_name = "terraform-state-rg" - storage_account_name = "terraformstatestorage" + storage_account_name = "tfstatestorage" container_name = "terraform-state" key = "suga.terraform.tfstate" } From eb225f372a1641686da6a097dfa1f93990cc6eb0 Mon Sep 17 00:00:00 2001 From: Jye Cusch Date: Tue, 14 Oct 2025 15:09:45 +1100 Subject: [PATCH 3/3] docs: fix stack path Co-authored-by: David Moore <4121492+davemooreuws@users.noreply.github.com> --- docs/guides/add-suga.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/guides/add-suga.mdx b/docs/guides/add-suga.mdx index bf30cfa7..961512aa 100644 --- a/docs/guides/add-suga.mdx +++ b/docs/guides/add-suga.mdx @@ -334,10 +334,10 @@ Select your cloud provider and region when prompted. You'll see: ```bash ✓ Terraform generated successfully - output written to ./.suga/stacks/my-app-aws-12345 + output written to ./terraform/stacks/my-app Next steps: -1. Run cd ./.suga/stacks/my-app-aws-12345 to move to the stack directory +1. Run cd ./terraform/stacks/my-app to move to the stack directory 2. Initialize the stack terraform init -upgrade 3. Optionally, preview with terraform plan 4. Deploy with terraform apply @@ -361,7 +361,7 @@ Configure cloud provider credentials: Deploy with Terraform: ```bash title="Navigate to Stack" icon="folder" -cd .suga/stacks/my-app-aws-* +cd terraform/stacks/my-app ``` ```bash title="Initialize Terraform" icon="download"