@c0x12c/ai-toolkit 1.15.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/.claude-plugin/marketplace.json +16 -0
- package/.claude-plugin/plugin.json +12 -0
- package/README.md +439 -0
- package/VERSION +1 -0
- package/agents/design-critic.md +127 -0
- package/agents/idea-killer.md +72 -0
- package/agents/infrastructure-expert.md +49 -0
- package/agents/micronaut-backend-expert.md +45 -0
- package/agents/phase-reviewer.md +150 -0
- package/agents/research-planner.md +70 -0
- package/agents/solution-architect-cto.md +49 -0
- package/agents/sre-architect.md +49 -0
- package/agents/team-coordinator.md +111 -0
- package/bin/cli.js +780 -0
- package/claude-md/00-header.md +39 -0
- package/claude-md/01-core.md +105 -0
- package/claude-md/05-database.md +20 -0
- package/claude-md/11-backend-micronaut.md +19 -0
- package/claude-md/20-frontend-react.md +44 -0
- package/claude-md/25-ux-design.md +56 -0
- package/claude-md/30-infrastructure.md +24 -0
- package/claude-md/30-project-mgmt.md +119 -0
- package/claude-md/40-product.md +39 -0
- package/claude-md/50-ops.md +34 -0
- package/claude-md/60-research.md +27 -0
- package/claude-md/90-footer.md +21 -0
- package/commands/spartan/brainstorm.md +134 -0
- package/commands/spartan/brownfield.md +157 -0
- package/commands/spartan/build.md +435 -0
- package/commands/spartan/careful.md +94 -0
- package/commands/spartan/commit-message.md +112 -0
- package/commands/spartan/content.md +17 -0
- package/commands/spartan/context-save.md +161 -0
- package/commands/spartan/contribute.md +140 -0
- package/commands/spartan/daily.md +42 -0
- package/commands/spartan/debug.md +308 -0
- package/commands/spartan/deep-dive.md +55 -0
- package/commands/spartan/deploy.md +207 -0
- package/commands/spartan/e2e.md +264 -0
- package/commands/spartan/env-setup.md +166 -0
- package/commands/spartan/epic.md +199 -0
- package/commands/spartan/fe-review.md +181 -0
- package/commands/spartan/figma-to-code.md +260 -0
- package/commands/spartan/forensics.md +46 -0
- package/commands/spartan/freeze.md +84 -0
- package/commands/spartan/fundraise.md +53 -0
- package/commands/spartan/gate-review.md +229 -0
- package/commands/spartan/gsd-upgrade.md +376 -0
- package/commands/spartan/guard.md +42 -0
- package/commands/spartan/init-project.md +178 -0
- package/commands/spartan/init-rules.md +298 -0
- package/commands/spartan/interview.md +154 -0
- package/commands/spartan/kickoff.md +73 -0
- package/commands/spartan/kotlin-service.md +109 -0
- package/commands/spartan/lean-canvas.md +222 -0
- package/commands/spartan/lint-rules.md +122 -0
- package/commands/spartan/map-codebase.md +124 -0
- package/commands/spartan/migration.md +82 -0
- package/commands/spartan/next-app.md +317 -0
- package/commands/spartan/next-feature.md +212 -0
- package/commands/spartan/onboard.md +326 -0
- package/commands/spartan/outreach.md +16 -0
- package/commands/spartan/phase.md +142 -0
- package/commands/spartan/pitch.md +18 -0
- package/commands/spartan/plan.md +210 -0
- package/commands/spartan/pr-ready.md +202 -0
- package/commands/spartan/project.md +106 -0
- package/commands/spartan/qa.md +222 -0
- package/commands/spartan/research.md +254 -0
- package/commands/spartan/review.md +132 -0
- package/commands/spartan/scan-rules.md +173 -0
- package/commands/spartan/sessions.md +143 -0
- package/commands/spartan/spec.md +131 -0
- package/commands/spartan/startup.md +257 -0
- package/commands/spartan/team.md +570 -0
- package/commands/spartan/teardown.md +161 -0
- package/commands/spartan/testcontainer.md +97 -0
- package/commands/spartan/tf-cost.md +123 -0
- package/commands/spartan/tf-deploy.md +116 -0
- package/commands/spartan/tf-drift.md +100 -0
- package/commands/spartan/tf-import.md +107 -0
- package/commands/spartan/tf-module.md +121 -0
- package/commands/spartan/tf-plan.md +100 -0
- package/commands/spartan/tf-review.md +106 -0
- package/commands/spartan/tf-scaffold.md +109 -0
- package/commands/spartan/tf-security.md +147 -0
- package/commands/spartan/think.md +221 -0
- package/commands/spartan/unfreeze.md +13 -0
- package/commands/spartan/update.md +134 -0
- package/commands/spartan/ux.md +1233 -0
- package/commands/spartan/validate.md +193 -0
- package/commands/spartan/web-to-prd.md +706 -0
- package/commands/spartan/workstreams.md +109 -0
- package/commands/spartan/write.md +16 -0
- package/commands/spartan.md +386 -0
- package/frameworks/00-framework-comparison-guide.md +317 -0
- package/frameworks/01-lean-canvas.md +196 -0
- package/frameworks/02-design-sprint.md +304 -0
- package/frameworks/03-foundation-sprint.md +337 -0
- package/frameworks/04-business-model-canvas.md +391 -0
- package/frameworks/05-customer-development.md +426 -0
- package/frameworks/06-jobs-to-be-done.md +358 -0
- package/frameworks/07-mom-test.md +392 -0
- package/frameworks/08-value-proposition-canvas.md +488 -0
- package/frameworks/09-javelin-board.md +428 -0
- package/frameworks/10-build-measure-learn.md +467 -0
- package/frameworks/11-mvp-approaches.md +533 -0
- package/frameworks/think-before-build.md +593 -0
- package/lib/assembler.js +197 -0
- package/lib/assembler.test.js +159 -0
- package/lib/detector.js +166 -0
- package/lib/detector.test.js +221 -0
- package/lib/packs.js +16 -0
- package/lib/resolver.js +272 -0
- package/lib/resolver.test.js +298 -0
- package/lib/worktree.sh +104 -0
- package/package.json +50 -0
- package/packs/backend-micronaut.yaml +35 -0
- package/packs/backend-nodejs.yaml +15 -0
- package/packs/backend-python.yaml +15 -0
- package/packs/core.yaml +37 -0
- package/packs/database.yaml +21 -0
- package/packs/frontend-react.yaml +24 -0
- package/packs/infrastructure.yaml +40 -0
- package/packs/ops.yaml +16 -0
- package/packs/packs.compiled.json +371 -0
- package/packs/product.yaml +22 -0
- package/packs/project-mgmt.yaml +24 -0
- package/packs/research.yaml +39 -0
- package/packs/shared-backend.yaml +14 -0
- package/packs/ux-design.yaml +21 -0
- package/rules/backend-micronaut/API_DESIGN.md +313 -0
- package/rules/backend-micronaut/BATCH_PROCESSING.md +92 -0
- package/rules/backend-micronaut/CONTROLLERS.md +388 -0
- package/rules/backend-micronaut/KOTLIN.md +414 -0
- package/rules/backend-micronaut/RETROFIT_PLACEMENT.md +290 -0
- package/rules/backend-micronaut/SERVICES_AND_BEANS.md +325 -0
- package/rules/core/NAMING_CONVENTIONS.md +208 -0
- package/rules/core/SKILL_AUTHORING.md +174 -0
- package/rules/core/TIMEZONE.md +316 -0
- package/rules/database/ORM_AND_REPO.md +289 -0
- package/rules/database/SCHEMA.md +146 -0
- package/rules/database/TRANSACTIONS.md +311 -0
- package/rules/frontend-react/FRONTEND.md +344 -0
- package/rules/infrastructure/MODULES.md +260 -0
- package/rules/infrastructure/NAMING.md +196 -0
- package/rules/infrastructure/PROVIDERS.md +309 -0
- package/rules/infrastructure/SECURITY.md +310 -0
- package/rules/infrastructure/STATE_AND_BACKEND.md +237 -0
- package/rules/infrastructure/STRUCTURE.md +234 -0
- package/rules/infrastructure/VARIABLES.md +285 -0
- package/rules/shared-backend/ARCHITECTURE.md +46 -0
- package/rules/ux-design/DESIGN_PROCESS.md +176 -0
- package/skills/api-endpoint-creator/SKILL.md +455 -0
- package/skills/api-endpoint-creator/error-handling-guide.md +244 -0
- package/skills/api-endpoint-creator/examples.md +522 -0
- package/skills/api-endpoint-creator/testing-patterns.md +302 -0
- package/skills/article-writing/SKILL.md +109 -0
- package/skills/article-writing/examples.md +59 -0
- package/skills/backend-api-design/SKILL.md +84 -0
- package/skills/backend-api-design/code-patterns.md +138 -0
- package/skills/brainstorm/SKILL.md +95 -0
- package/skills/browser-qa/SKILL.md +87 -0
- package/skills/browser-qa/playwright-snippets.md +110 -0
- package/skills/ci-cd-patterns/SKILL.md +108 -0
- package/skills/ci-cd-patterns/workflows.md +149 -0
- package/skills/competitive-teardown/SKILL.md +93 -0
- package/skills/competitive-teardown/example-analysis.md +50 -0
- package/skills/content-engine/SKILL.md +131 -0
- package/skills/content-engine/examples.md +72 -0
- package/skills/database-patterns/SKILL.md +72 -0
- package/skills/database-patterns/code-templates.md +114 -0
- package/skills/database-table-creator/SKILL.md +141 -0
- package/skills/database-table-creator/examples.md +552 -0
- package/skills/database-table-creator/kotlin-templates.md +400 -0
- package/skills/database-table-creator/migration-template.sql +68 -0
- package/skills/database-table-creator/validation-checklist.md +337 -0
- package/skills/deep-research/SKILL.md +80 -0
- package/skills/design-intelligence/SKILL.md +268 -0
- package/skills/design-workflow/SKILL.md +127 -0
- package/skills/design-workflow/checklists.md +45 -0
- package/skills/idea-validation/SKILL.md +129 -0
- package/skills/idea-validation/example-report.md +50 -0
- package/skills/investor-materials/SKILL.md +122 -0
- package/skills/investor-materials/example-outline.md +70 -0
- package/skills/investor-outreach/SKILL.md +112 -0
- package/skills/investor-outreach/examples.md +76 -0
- package/skills/kotlin-best-practices/SKILL.md +58 -0
- package/skills/kotlin-best-practices/code-patterns.md +132 -0
- package/skills/market-research/SKILL.md +99 -0
- package/skills/security-checklist/SKILL.md +65 -0
- package/skills/security-checklist/audit-reference.md +95 -0
- package/skills/service-debugging/SKILL.md +116 -0
- package/skills/service-debugging/common-issues.md +65 -0
- package/skills/startup-pipeline/SKILL.md +152 -0
- package/skills/terraform-best-practices/SKILL.md +244 -0
- package/skills/terraform-module-creator/SKILL.md +284 -0
- package/skills/terraform-review/SKILL.md +222 -0
- package/skills/terraform-security-audit/SKILL.md +280 -0
- package/skills/terraform-service-scaffold/SKILL.md +574 -0
- package/skills/testing-strategies/SKILL.md +116 -0
- package/skills/testing-strategies/examples.md +103 -0
- package/skills/testing-strategies/integration-test-setup.md +71 -0
- package/skills/ui-ux-pro-max/SKILL.md +238 -0
- package/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/skills/ui-ux-pro-max/data/colors.csv +97 -0
- package/skills/ui-ux-pro-max/data/icons.csv +101 -0
- package/skills/ui-ux-pro-max/data/landing.csv +31 -0
- package/skills/ui-ux-pro-max/data/products.csv +97 -0
- package/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/skills/ui-ux-pro-max/data/styles.csv +68 -0
- package/skills/ui-ux-pro-max/data/typography.csv +58 -0
- package/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/skills/ui-ux-pro-max/python-setup.md +146 -0
- package/skills/ui-ux-pro-max/scripts/core.py +253 -0
- package/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
- package/skills/ui-ux-pro-max/scripts/search.py +114 -0
- package/skills/web-to-prd/SKILL.md +478 -0
- package/templates/build-config.yaml +44 -0
- package/templates/commands-config.yaml +55 -0
- package/templates/competitor-analysis.md +60 -0
- package/templates/content/AGENT_TEMPLATE.md +47 -0
- package/templates/content/COMMAND_TEMPLATE.md +27 -0
- package/templates/content/RULE_TEMPLATE.md +40 -0
- package/templates/content/SKILL_TEMPLATE.md +41 -0
- package/templates/design-config.md +105 -0
- package/templates/design-doc.md +207 -0
- package/templates/epic.md +100 -0
- package/templates/feature-spec.md +181 -0
- package/templates/idea-canvas.md +47 -0
- package/templates/implementation-plan.md +159 -0
- package/templates/prd-template.md +86 -0
- package/templates/preamble.md +89 -0
- package/templates/project-readme.md +35 -0
- package/templates/quality-gates.md +230 -0
- package/templates/spartan-config.yaml +164 -0
- package/templates/user-interview.md +69 -0
- package/templates/validation-checklist.md +108 -0
- package/templates/workflow-backend-micronaut.md +409 -0
- package/templates/workflow-frontend-react.md +233 -0
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: terraform-service-scaffold
|
|
3
|
+
description: Generate complete service-level Terraform infrastructure with modules, environments, and CI/CD. Use when adding Terraform to a new service or bootstrapping infrastructure from scratch.
|
|
4
|
+
allowed_tools:
|
|
5
|
+
- Read
|
|
6
|
+
- Write
|
|
7
|
+
- Edit
|
|
8
|
+
- Glob
|
|
9
|
+
- Grep
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Terraform Service Scaffold
|
|
13
|
+
|
|
14
|
+
Generates a complete service-level Terraform structure with live orchestration, reusable modules, environment configs, and CI/CD workflow.
|
|
15
|
+
|
|
16
|
+
## When to Use
|
|
17
|
+
|
|
18
|
+
- Adding Terraform to a new service repository
|
|
19
|
+
- Bootstrapping service infrastructure from scratch
|
|
20
|
+
- Setting up a new microservice with standard cloud resources
|
|
21
|
+
|
|
22
|
+
## Process
|
|
23
|
+
|
|
24
|
+
### 1. Gather Requirements
|
|
25
|
+
|
|
26
|
+
Ask the user:
|
|
27
|
+
- **Service name** (e.g., `{service}`)
|
|
28
|
+
- **Container host**: ECS or EKS
|
|
29
|
+
- **Resources needed**: RDS, Redis, S3, SQS, or combination
|
|
30
|
+
- **Environments**: which environments to scaffold (default: dev)
|
|
31
|
+
|
|
32
|
+
### 2. Read Infra Remote State
|
|
33
|
+
|
|
34
|
+
```hcl
|
|
35
|
+
# Check existing shared infrastructure outputs
|
|
36
|
+
data "terraform_remote_state" "infra" {
|
|
37
|
+
backend = "s3"
|
|
38
|
+
|
|
39
|
+
config = {
|
|
40
|
+
bucket = "{project}-terraform-state"
|
|
41
|
+
key = "infra/terraform.tfstate"
|
|
42
|
+
region = var.region
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 3. Create Live Orchestration
|
|
48
|
+
|
|
49
|
+
Location: `terraform/live/`
|
|
50
|
+
|
|
51
|
+
#### terraform.tf
|
|
52
|
+
|
|
53
|
+
```hcl
|
|
54
|
+
terraform {
|
|
55
|
+
required_version = ">= 1.5.0"
|
|
56
|
+
|
|
57
|
+
required_providers {
|
|
58
|
+
aws = {
|
|
59
|
+
source = "hashicorp/aws"
|
|
60
|
+
version = "~> 5.0"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
backend "s3" {}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
provider "aws" {
|
|
68
|
+
region = var.region
|
|
69
|
+
|
|
70
|
+
default_tags {
|
|
71
|
+
tags = {
|
|
72
|
+
Project = var.project
|
|
73
|
+
Service = var.service
|
|
74
|
+
Environment = var.env
|
|
75
|
+
ManagedBy = "terraform"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
#### variables.tf
|
|
82
|
+
|
|
83
|
+
```hcl
|
|
84
|
+
variable "project" {
|
|
85
|
+
description = "Project identifier"
|
|
86
|
+
type = string
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
variable "service" {
|
|
90
|
+
description = "Service name"
|
|
91
|
+
type = string
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
variable "env" {
|
|
95
|
+
description = "Environment (dev, staging, prod)"
|
|
96
|
+
type = string
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
variable "region" {
|
|
100
|
+
description = "AWS region"
|
|
101
|
+
type = string
|
|
102
|
+
default = "us-east-1"
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
#### locals.tf
|
|
107
|
+
|
|
108
|
+
```hcl
|
|
109
|
+
locals {
|
|
110
|
+
name_prefix = "${var.project}-${var.service}-${var.env}"
|
|
111
|
+
|
|
112
|
+
vpc_id = data.terraform_remote_state.infra.outputs.vpc_id
|
|
113
|
+
private_subnet_ids = data.terraform_remote_state.infra.outputs.private_subnet_ids
|
|
114
|
+
public_subnet_ids = data.terraform_remote_state.infra.outputs.public_subnet_ids
|
|
115
|
+
|
|
116
|
+
common_tags = {
|
|
117
|
+
Project = var.project
|
|
118
|
+
Service = var.service
|
|
119
|
+
Environment = var.env
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
#### outputs.tf
|
|
125
|
+
|
|
126
|
+
```hcl
|
|
127
|
+
output "ecr_repository_url" {
|
|
128
|
+
description = "ECR repository URL for {service}"
|
|
129
|
+
value = module.{service}.ecr_repository_url
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
output "service_endpoint" {
|
|
133
|
+
description = "Service endpoint URL"
|
|
134
|
+
value = module.{service}.service_endpoint
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### 4. Create Service Module
|
|
139
|
+
|
|
140
|
+
Location: `terraform/modules/{service}/`
|
|
141
|
+
|
|
142
|
+
One resource per file:
|
|
143
|
+
|
|
144
|
+
#### main.tf
|
|
145
|
+
|
|
146
|
+
```hcl
|
|
147
|
+
# Module entry point — locals and data sources only
|
|
148
|
+
locals {
|
|
149
|
+
name_prefix = "${var.project}-${var.service}-${var.env}"
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
#### ecr.tf
|
|
154
|
+
|
|
155
|
+
```hcl
|
|
156
|
+
module "ecr_backend" {
|
|
157
|
+
source = "git::https://github.com/{project}/terraform-modules.git//ecr?ref=v1.0.0"
|
|
158
|
+
|
|
159
|
+
name = "${local.name_prefix}-backend"
|
|
160
|
+
image_tag_mutability = "IMMUTABLE"
|
|
161
|
+
|
|
162
|
+
lifecycle_policy_rules = [
|
|
163
|
+
{
|
|
164
|
+
description = "Keep last 20 images"
|
|
165
|
+
count_number = 20
|
|
166
|
+
tag_status = "any"
|
|
167
|
+
count_type = "imageCountMoreThan"
|
|
168
|
+
}
|
|
169
|
+
]
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
module "ecr_worker" {
|
|
173
|
+
source = "git::https://github.com/{project}/terraform-modules.git//ecr?ref=v1.0.0"
|
|
174
|
+
|
|
175
|
+
name = "${local.name_prefix}-worker"
|
|
176
|
+
image_tag_mutability = "IMMUTABLE"
|
|
177
|
+
|
|
178
|
+
lifecycle_policy_rules = [
|
|
179
|
+
{
|
|
180
|
+
description = "Keep last 20 images"
|
|
181
|
+
count_number = 20
|
|
182
|
+
tag_status = "any"
|
|
183
|
+
count_type = "imageCountMoreThan"
|
|
184
|
+
}
|
|
185
|
+
]
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
#### rds.tf
|
|
190
|
+
|
|
191
|
+
```hcl
|
|
192
|
+
module "rds" {
|
|
193
|
+
source = "git::https://github.com/{project}/terraform-modules.git//rds?ref=v1.0.0"
|
|
194
|
+
|
|
195
|
+
name = "${local.name_prefix}-db"
|
|
196
|
+
engine = "postgres"
|
|
197
|
+
engine_version = "15.4"
|
|
198
|
+
instance_class = var.rds_instance_class
|
|
199
|
+
allocated_storage = var.rds_allocated_storage
|
|
200
|
+
db_name = replace(var.service, "-", "_")
|
|
201
|
+
master_username = var.db_username
|
|
202
|
+
master_password = var.db_password
|
|
203
|
+
subnet_ids = var.private_subnet_ids
|
|
204
|
+
vpc_id = var.vpc_id
|
|
205
|
+
deletion_protection = var.env == "prod" ? true : false
|
|
206
|
+
|
|
207
|
+
backup_retention_period = var.env == "prod" ? 30 : 7
|
|
208
|
+
multi_az = var.env == "prod" ? true : false
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
#### redis.tf
|
|
213
|
+
|
|
214
|
+
```hcl
|
|
215
|
+
module "redis" {
|
|
216
|
+
source = "git::https://github.com/{project}/terraform-modules.git//elasticache?ref=v1.0.0"
|
|
217
|
+
|
|
218
|
+
name = "${local.name_prefix}-cache"
|
|
219
|
+
engine = "redis"
|
|
220
|
+
node_type = var.redis_node_type
|
|
221
|
+
num_cache_nodes = 1
|
|
222
|
+
subnet_ids = var.private_subnet_ids
|
|
223
|
+
vpc_id = var.vpc_id
|
|
224
|
+
transit_encryption = true
|
|
225
|
+
at_rest_encryption = true
|
|
226
|
+
auth_token = var.redis_auth_token
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
#### s3.tf
|
|
231
|
+
|
|
232
|
+
```hcl
|
|
233
|
+
module "s3" {
|
|
234
|
+
source = "git::https://github.com/{project}/terraform-modules.git//s3?ref=v1.0.0"
|
|
235
|
+
|
|
236
|
+
bucket_name = "${local.name_prefix}-assets"
|
|
237
|
+
versioning = true
|
|
238
|
+
|
|
239
|
+
server_side_encryption = {
|
|
240
|
+
sse_algorithm = "aws:kms"
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
block_public_access = {
|
|
244
|
+
block_public_acls = true
|
|
245
|
+
block_public_policy = true
|
|
246
|
+
ignore_public_acls = true
|
|
247
|
+
restrict_public_buckets = true
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
#### sqs.tf
|
|
253
|
+
|
|
254
|
+
```hcl
|
|
255
|
+
module "sqs" {
|
|
256
|
+
source = "git::https://github.com/{project}/terraform-modules.git//sqs?ref=v1.0.0"
|
|
257
|
+
|
|
258
|
+
name = "${local.name_prefix}-queue"
|
|
259
|
+
visibility_timeout_seconds = 300
|
|
260
|
+
message_retention_seconds = 1209600
|
|
261
|
+
receive_wait_time_seconds = 20
|
|
262
|
+
|
|
263
|
+
dead_letter_queue = {
|
|
264
|
+
enabled = true
|
|
265
|
+
max_receive_count = 3
|
|
266
|
+
retention_seconds = 1209600
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
#### ecs.tf (if container host is ECS)
|
|
272
|
+
|
|
273
|
+
```hcl
|
|
274
|
+
module "ecs_service" {
|
|
275
|
+
source = "git::https://github.com/{project}/terraform-modules.git//ecs-service?ref=v1.0.0"
|
|
276
|
+
|
|
277
|
+
name = local.name_prefix
|
|
278
|
+
cluster_id = var.ecs_cluster_id
|
|
279
|
+
task_definition = module.ecs_task.arn
|
|
280
|
+
desired_count = var.desired_count
|
|
281
|
+
subnet_ids = var.private_subnet_ids
|
|
282
|
+
security_groups = [aws_security_group.service.id]
|
|
283
|
+
|
|
284
|
+
target_group_arn = aws_lb_target_group.service.arn
|
|
285
|
+
container_name = "${local.name_prefix}-backend"
|
|
286
|
+
container_port = var.container_port
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
module "ecs_task" {
|
|
290
|
+
source = "git::https://github.com/{project}/terraform-modules.git//ecs-task?ref=v1.0.0"
|
|
291
|
+
|
|
292
|
+
family = local.name_prefix
|
|
293
|
+
cpu = var.task_cpu
|
|
294
|
+
memory = var.task_memory
|
|
295
|
+
execution_role = var.ecs_execution_role_arn
|
|
296
|
+
task_role = var.ecs_task_role_arn
|
|
297
|
+
image = "${module.ecr_backend.repository_url}:${var.image_tag}"
|
|
298
|
+
container_port = var.container_port
|
|
299
|
+
environment = var.container_environment
|
|
300
|
+
secrets = var.container_secrets
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
resource "aws_lb_target_group" "service" {
|
|
304
|
+
name = local.name_prefix
|
|
305
|
+
port = var.container_port
|
|
306
|
+
protocol = "HTTP"
|
|
307
|
+
vpc_id = var.vpc_id
|
|
308
|
+
target_type = "ip"
|
|
309
|
+
|
|
310
|
+
health_check {
|
|
311
|
+
path = "/health"
|
|
312
|
+
healthy_threshold = 2
|
|
313
|
+
unhealthy_threshold = 3
|
|
314
|
+
interval = 30
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
#### eks.tf (if container host is EKS)
|
|
320
|
+
|
|
321
|
+
```hcl
|
|
322
|
+
resource "kubernetes_namespace" "service" {
|
|
323
|
+
metadata {
|
|
324
|
+
name = var.service
|
|
325
|
+
labels = {
|
|
326
|
+
project = var.project
|
|
327
|
+
env = var.env
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
resource "kubernetes_service_account" "service" {
|
|
333
|
+
metadata {
|
|
334
|
+
name = var.service
|
|
335
|
+
namespace = kubernetes_namespace.service.metadata[0].name
|
|
336
|
+
annotations = {
|
|
337
|
+
"eks.amazonaws.com/role-arn" = module.irsa.role_arn
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
module "irsa" {
|
|
343
|
+
source = "git::https://github.com/{project}/terraform-modules.git//irsa?ref=v1.0.0"
|
|
344
|
+
|
|
345
|
+
name = "${local.name_prefix}-irsa"
|
|
346
|
+
oidc_provider_arn = var.oidc_provider_arn
|
|
347
|
+
namespace = var.service
|
|
348
|
+
service_account = var.service
|
|
349
|
+
policy_arns = var.irsa_policy_arns
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
resource "kubernetes_secret" "service" {
|
|
353
|
+
metadata {
|
|
354
|
+
name = "${var.service}-secrets"
|
|
355
|
+
namespace = kubernetes_namespace.service.metadata[0].name
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
data = var.k8s_secrets
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
resource "kubernetes_config_map" "service" {
|
|
362
|
+
metadata {
|
|
363
|
+
name = "${var.service}-config"
|
|
364
|
+
namespace = kubernetes_namespace.service.metadata[0].name
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
data = var.k8s_config
|
|
368
|
+
}
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### 5. Create Environment Config
|
|
372
|
+
|
|
373
|
+
Location: `terraform/envs/dev/`
|
|
374
|
+
|
|
375
|
+
#### state.config
|
|
376
|
+
|
|
377
|
+
```hcl
|
|
378
|
+
bucket = "{project}-terraform-state"
|
|
379
|
+
key = "{service}/dev/terraform.tfstate"
|
|
380
|
+
region = "us-east-1"
|
|
381
|
+
dynamodb_table = "{project}-terraform-locks"
|
|
382
|
+
encrypt = true
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
#### terraform.tfvars
|
|
386
|
+
|
|
387
|
+
```hcl
|
|
388
|
+
project = "{project}"
|
|
389
|
+
service = "{service}"
|
|
390
|
+
env = "dev"
|
|
391
|
+
region = "us-east-1"
|
|
392
|
+
|
|
393
|
+
# RDS
|
|
394
|
+
rds_instance_class = "db.t3.micro"
|
|
395
|
+
rds_allocated_storage = 20
|
|
396
|
+
db_username = "{service}_admin"
|
|
397
|
+
|
|
398
|
+
# Redis
|
|
399
|
+
redis_node_type = "cache.t3.micro"
|
|
400
|
+
|
|
401
|
+
# Container
|
|
402
|
+
desired_count = 1
|
|
403
|
+
task_cpu = 256
|
|
404
|
+
task_memory = 512
|
|
405
|
+
container_port = 8080
|
|
406
|
+
image_tag = "latest"
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
#### secrets.tfvars
|
|
410
|
+
|
|
411
|
+
```hcl
|
|
412
|
+
# Encrypted via git-secret-protector — committed to git, decrypted at CI/CD time
|
|
413
|
+
db_password = ""
|
|
414
|
+
redis_auth_token = ""
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
#### git-secret-protector Setup
|
|
418
|
+
|
|
419
|
+
Secrets are encrypted in git using [git-secret-protector](https://github.com/nicovince/git-secret-protector), NOT `.gitignore`.
|
|
420
|
+
|
|
421
|
+
```bash
|
|
422
|
+
# 1. Install git-secret-protector
|
|
423
|
+
pip install git-secret-protector
|
|
424
|
+
|
|
425
|
+
# 2. Initialize per-environment filters
|
|
426
|
+
git-secret-protector init --filter secrets-dev
|
|
427
|
+
git-secret-protector init --filter secrets-prod
|
|
428
|
+
|
|
429
|
+
# 3. Add .gitattributes rules for auto-encrypt on commit
|
|
430
|
+
cat >> .gitattributes <<'EOF'
|
|
431
|
+
terraform/live/envs/dev/secrets.tfvars filter=secrets-dev
|
|
432
|
+
terraform/live/envs/prod/secrets.tfvars filter=secrets-prod
|
|
433
|
+
EOF
|
|
434
|
+
|
|
435
|
+
# 4. Store encryption keys securely (CI/CD secrets, NOT in repo)
|
|
436
|
+
# GitHub Actions: store as repository secret GIT_SECRET_PROTECTOR_KEY_DEV / _PROD
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
The secrets file IS committed to git (encrypted). On checkout, the smudge filter decrypts it
|
|
440
|
+
if the key is available. In CI/CD, decrypt before terraform plan/apply.
|
|
441
|
+
|
|
442
|
+
### 6. Generate CI/CD Workflow
|
|
443
|
+
|
|
444
|
+
```yaml
|
|
445
|
+
# .github/workflows/terraform.yml
|
|
446
|
+
name: Terraform
|
|
447
|
+
|
|
448
|
+
on:
|
|
449
|
+
pull_request:
|
|
450
|
+
paths: ['terraform/**']
|
|
451
|
+
push:
|
|
452
|
+
branches: [main]
|
|
453
|
+
paths: ['terraform/**']
|
|
454
|
+
|
|
455
|
+
env:
|
|
456
|
+
TF_VERSION: '1.11'
|
|
457
|
+
ENVIRONMENT: dev
|
|
458
|
+
|
|
459
|
+
jobs:
|
|
460
|
+
plan:
|
|
461
|
+
runs-on: ubuntu-latest
|
|
462
|
+
if: github.event_name == 'pull_request'
|
|
463
|
+
steps:
|
|
464
|
+
- uses: actions/checkout@v4
|
|
465
|
+
- uses: hashicorp/setup-terraform@v3
|
|
466
|
+
with:
|
|
467
|
+
terraform_version: ${{ env.TF_VERSION }}
|
|
468
|
+
- name: Decrypt secrets
|
|
469
|
+
run: |
|
|
470
|
+
pip install git-secret-protector
|
|
471
|
+
git-secret-protector reveal --filter secrets-${{ env.ENVIRONMENT }}
|
|
472
|
+
env:
|
|
473
|
+
GIT_SECRET_PROTECTOR_KEY: ${{ secrets.GIT_SECRET_PROTECTOR_KEY_DEV }}
|
|
474
|
+
- name: Init
|
|
475
|
+
run: |
|
|
476
|
+
cd terraform/live
|
|
477
|
+
terraform init -backend-config=envs/${{ env.ENVIRONMENT }}/state.config
|
|
478
|
+
- name: Plan
|
|
479
|
+
run: |
|
|
480
|
+
cd terraform/live
|
|
481
|
+
terraform plan \
|
|
482
|
+
-var-file=envs/${{ env.ENVIRONMENT }}/terraform.tfvars \
|
|
483
|
+
-var-file=envs/${{ env.ENVIRONMENT }}/secrets.tfvars \
|
|
484
|
+
-no-color
|
|
485
|
+
|
|
486
|
+
apply:
|
|
487
|
+
runs-on: ubuntu-latest
|
|
488
|
+
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
489
|
+
steps:
|
|
490
|
+
- uses: actions/checkout@v4
|
|
491
|
+
- uses: hashicorp/setup-terraform@v3
|
|
492
|
+
with:
|
|
493
|
+
terraform_version: ${{ env.TF_VERSION }}
|
|
494
|
+
- name: Decrypt secrets
|
|
495
|
+
run: |
|
|
496
|
+
pip install git-secret-protector
|
|
497
|
+
git-secret-protector reveal --filter secrets-${{ env.ENVIRONMENT }}
|
|
498
|
+
env:
|
|
499
|
+
GIT_SECRET_PROTECTOR_KEY: ${{ secrets.GIT_SECRET_PROTECTOR_KEY_DEV }}
|
|
500
|
+
- name: Init
|
|
501
|
+
run: |
|
|
502
|
+
cd terraform/live
|
|
503
|
+
terraform init -backend-config=envs/${{ env.ENVIRONMENT }}/state.config
|
|
504
|
+
- name: Apply
|
|
505
|
+
run: |
|
|
506
|
+
cd terraform/live
|
|
507
|
+
terraform apply \
|
|
508
|
+
-var-file=envs/${{ env.ENVIRONMENT }}/terraform.tfvars \
|
|
509
|
+
-var-file=envs/${{ env.ENVIRONMENT }}/secrets.tfvars \
|
|
510
|
+
-auto-approve
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
### 7. Output Checklist
|
|
514
|
+
|
|
515
|
+
After generating all files, produce this checklist:
|
|
516
|
+
|
|
517
|
+
- [ ] `terraform/live/terraform.tf` — backend + provider
|
|
518
|
+
- [ ] `terraform/live/variables.tf` — all input variables
|
|
519
|
+
- [ ] `terraform/live/locals.tf` — computed values, remote state
|
|
520
|
+
- [ ] `terraform/live/outputs.tf` — exported values
|
|
521
|
+
- [ ] `terraform/modules/{service}/` — resource-per-file
|
|
522
|
+
- [ ] `terraform/envs/dev/state.config` — backend config
|
|
523
|
+
- [ ] `terraform/envs/dev/terraform.tfvars` — environment values
|
|
524
|
+
- [ ] `terraform/envs/dev/secrets.tfvars` — sensitive values (gitignored)
|
|
525
|
+
- [ ] `.github/workflows/terraform.yml` — CI/CD pipeline
|
|
526
|
+
- [ ] `.gitignore` includes `*.tfvars` secrets, `.terraform/`, `*.tfstate*`
|
|
527
|
+
|
|
528
|
+
## Interaction Style
|
|
529
|
+
|
|
530
|
+
- Asks service name, container host, and resources before generating
|
|
531
|
+
- Generates all files in one pass — no partial output
|
|
532
|
+
- Uses registry modules with version pinning, never inline resources
|
|
533
|
+
- Keeps providers in `live/` only, never in modules
|
|
534
|
+
|
|
535
|
+
## Rules
|
|
536
|
+
|
|
537
|
+
- Use registry modules from `{project}/terraform-modules` with `?ref=vX.Y.Z`
|
|
538
|
+
- Version-pin all providers and modules
|
|
539
|
+
- Flat locals — no nested maps unless unavoidable
|
|
540
|
+
- Providers defined in `live/` only, never in modules
|
|
541
|
+
- One resource per file in modules
|
|
542
|
+
- Remote state for cross-stack references
|
|
543
|
+
- Sensitive variables marked with `sensitive = true`
|
|
544
|
+
- All resources tagged with project, service, environment, ManagedBy
|
|
545
|
+
- State stored in S3 with DynamoDB locking
|
|
546
|
+
- Secrets never committed — use `.gitignore` and `secrets.tfvars`
|
|
547
|
+
|
|
548
|
+
## Output
|
|
549
|
+
|
|
550
|
+
Produces a complete directory tree:
|
|
551
|
+
|
|
552
|
+
```
|
|
553
|
+
terraform/
|
|
554
|
+
live/
|
|
555
|
+
terraform.tf
|
|
556
|
+
variables.tf
|
|
557
|
+
locals.tf
|
|
558
|
+
outputs.tf
|
|
559
|
+
modules/{service}/
|
|
560
|
+
main.tf
|
|
561
|
+
ecr.tf
|
|
562
|
+
rds.tf
|
|
563
|
+
redis.tf
|
|
564
|
+
s3.tf
|
|
565
|
+
sqs.tf
|
|
566
|
+
ecs.tf (or eks.tf)
|
|
567
|
+
variables.tf
|
|
568
|
+
outputs.tf
|
|
569
|
+
envs/dev/
|
|
570
|
+
state.config
|
|
571
|
+
terraform.tfvars
|
|
572
|
+
secrets.tfvars
|
|
573
|
+
.github/workflows/terraform.yml
|
|
574
|
+
```
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: testing-strategies
|
|
3
|
+
description: Testing patterns for Micronaut/Kotlin backend including repository tests, integration tests, and test data builders. Use when writing tests, setting up test infrastructure, or improving coverage.
|
|
4
|
+
allowed_tools:
|
|
5
|
+
- Read
|
|
6
|
+
- Write
|
|
7
|
+
- Edit
|
|
8
|
+
- Glob
|
|
9
|
+
- Grep
|
|
10
|
+
- Bash
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Testing Strategies — Quick Reference
|
|
14
|
+
|
|
15
|
+
> See `integration-test-setup.md` for @MicronautTest configuration, Retrofit client setup, and connection pool tuning.
|
|
16
|
+
>
|
|
17
|
+
> See `examples.md` for complete code patterns including MockK, test data builders, and assertions.
|
|
18
|
+
|
|
19
|
+
## Integration Tests
|
|
20
|
+
|
|
21
|
+
Every endpoint needs an integration test. Extend `AbstractControllerTest`, use Retrofit clients from `module-client`, and clean up with `truncateAllTables()` in `@AfterEach`.
|
|
22
|
+
|
|
23
|
+
Key rules:
|
|
24
|
+
- **Always use Retrofit clients** — never raw `HttpRequest`
|
|
25
|
+
- Generate real JWT tokens via `accessToken()`
|
|
26
|
+
- Test full HTTP stack end-to-end, no mocking managers
|
|
27
|
+
|
|
28
|
+
## Test Naming
|
|
29
|
+
|
|
30
|
+
```kotlin
|
|
31
|
+
@Test
|
|
32
|
+
fun `{action} - {expected outcome}`() = runBlocking { }
|
|
33
|
+
|
|
34
|
+
// Examples:
|
|
35
|
+
fun `getEmployee - returns employee by id`() = runBlocking { }
|
|
36
|
+
fun `getEmployee - returns 404 when not found`() = runBlocking { }
|
|
37
|
+
fun `createEmployee - fails with 401 when not authenticated`() = runBlocking { }
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Required Test Coverage Per Endpoint
|
|
41
|
+
|
|
42
|
+
1. **Happy path** — basic success case
|
|
43
|
+
2. **Not found** — 404 for missing resource
|
|
44
|
+
3. **Auth failure** — 401 without token
|
|
45
|
+
4. **Soft delete** — deleted records not returned
|
|
46
|
+
|
|
47
|
+
```kotlin
|
|
48
|
+
@Test
|
|
49
|
+
fun `getById - returns 404 when not found`() = runBlocking {
|
|
50
|
+
val token = accessToken(prepareUser())
|
|
51
|
+
assertThrows<HttpException> {
|
|
52
|
+
runBlocking {
|
|
53
|
+
client.getById(authorization = token, id = UUID.randomUUID())
|
|
54
|
+
}
|
|
55
|
+
}.also {
|
|
56
|
+
assertThat(it.code()).isEqualTo(404)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Repository Tests
|
|
62
|
+
|
|
63
|
+
Extend `AbstractRepositoryTest`. Every repository needs these tests at minimum:
|
|
64
|
+
|
|
65
|
+
```kotlin
|
|
66
|
+
class DefaultEmployeeRepositoryTest : AbstractRepositoryTest() {
|
|
67
|
+
|
|
68
|
+
private val repository = DefaultEmployeeRepository(database)
|
|
69
|
+
|
|
70
|
+
@BeforeEach
|
|
71
|
+
fun cleanup() { database.primary.truncateAllTables() }
|
|
72
|
+
|
|
73
|
+
@Test
|
|
74
|
+
fun `insert - happy path`() { }
|
|
75
|
+
|
|
76
|
+
@Test
|
|
77
|
+
fun `byId - returns entity when exists`() { }
|
|
78
|
+
|
|
79
|
+
@Test
|
|
80
|
+
fun `byId - returns null when not exists`() { }
|
|
81
|
+
|
|
82
|
+
@Test
|
|
83
|
+
fun `byId - returns null when soft deleted`() { }
|
|
84
|
+
|
|
85
|
+
@Test
|
|
86
|
+
fun `deleteById - soft deletes entity`() { }
|
|
87
|
+
|
|
88
|
+
@Test
|
|
89
|
+
fun `update - updates selected fields`() { }
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## MockK Rules
|
|
94
|
+
|
|
95
|
+
- `mockk<T>()` for creating mocks
|
|
96
|
+
- `coEvery` / `coVerify` for suspend functions (not `every`/`verify`)
|
|
97
|
+
- `slot<T>()` + `capture()` to verify what arguments were passed
|
|
98
|
+
- `runTest { }` from `kotlinx.coroutines.test` — NOT `runBlocking`. `runTest` handles virtual time and catches coroutine issues.
|
|
99
|
+
- AAA pattern with comments: `// Given`, `// When`, `// Then`
|
|
100
|
+
- Use `@Nested` + `@DisplayName` to group related tests
|
|
101
|
+
|
|
102
|
+
> See `examples.md` for full MockK code examples, `@Nested` patterns, test data builders, and AssertJ assertions.
|
|
103
|
+
|
|
104
|
+
## Gotchas
|
|
105
|
+
|
|
106
|
+
**Connection pool exhaustion:** If parallel tests fail with "cannot acquire connection", bump `maxPoolSize` to 20. See `integration-test-setup.md` for the config snippet.
|
|
107
|
+
|
|
108
|
+
**MockK + coroutines:** Always use `coEvery`/`coVerify` for suspend functions. Plain `every`/`verify` won't work and gives confusing errors.
|
|
109
|
+
|
|
110
|
+
## Run Tests
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
./gradlew test # All tests
|
|
114
|
+
./gradlew test --tests "com.yourcompany.EmployeeControllerTest" # One class
|
|
115
|
+
./gradlew :app:module-repository:test # One module
|
|
116
|
+
```
|