@ripla/godd-mcp 0.1.2-beta-20260312091403

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.
Files changed (180) hide show
  1. package/README.md +412 -0
  2. package/dist/godd.cjs +465 -0
  3. package/dist/godd.js +34845 -0
  4. package/dist/index.js +224 -0
  5. package/notes-api/.env.example +29 -0
  6. package/notes-api/README.md +65 -0
  7. package/notes-api/alembic/README +1 -0
  8. package/notes-api/alembic/env.py +62 -0
  9. package/notes-api/alembic/script.py.mako +28 -0
  10. package/notes-api/alembic/versions/001_initial_notes_tables.py +71 -0
  11. package/notes-api/alembic.ini +149 -0
  12. package/notes-api/app/__init__.py +1 -0
  13. package/notes-api/app/config.py +90 -0
  14. package/notes-api/app/database.py +31 -0
  15. package/notes-api/app/main.py +55 -0
  16. package/notes-api/app/models/__init__.py +17 -0
  17. package/notes-api/app/models/audit.py +38 -0
  18. package/notes-api/app/models/base.py +38 -0
  19. package/notes-api/app/models/session.py +32 -0
  20. package/notes-api/app/models/setting.py +16 -0
  21. package/notes-api/app/models/user.py +38 -0
  22. package/notes-api/app/routers/__init__.py +1 -0
  23. package/notes-api/app/routers/auth.py +205 -0
  24. package/notes-api/app/routers/files.py +76 -0
  25. package/notes-api/app/routers/pr.py +92 -0
  26. package/notes-api/app/routers/settings.py +44 -0
  27. package/notes-api/app/routers/tree.py +22 -0
  28. package/notes-api/app/routers/users.py +145 -0
  29. package/notes-api/app/schemas/__init__.py +1 -0
  30. package/notes-api/app/schemas/auth.py +45 -0
  31. package/notes-api/app/schemas/user.py +41 -0
  32. package/notes-api/app/security.py +94 -0
  33. package/notes-api/app/services/__init__.py +1 -0
  34. package/notes-api/app/services/audit.py +25 -0
  35. package/notes-api/app/services/business_date.py +38 -0
  36. package/notes-api/app/services/github.py +140 -0
  37. package/notes-api/app/services/github_pr.py +120 -0
  38. package/notes-api/app/services/pr_chain.py +225 -0
  39. package/notes-api/app/startup.py +66 -0
  40. package/notes-api/docker/Dockerfile +14 -0
  41. package/notes-api/docker/Dockerfile.test +14 -0
  42. package/notes-api/pyproject.toml +53 -0
  43. package/notes-api/tests/conftest.py +21 -0
  44. package/notes-api/tests/test_business_date.py +32 -0
  45. package/notes-api/tests/test_health.py +11 -0
  46. package/notes-api/uv.lock +1012 -0
  47. package/notes-app/README.md +30 -0
  48. package/notes-app/docker/Dockerfile.prod +12 -0
  49. package/notes-app/docker/Dockerfile.test +12 -0
  50. package/notes-app/eslint.config.js +23 -0
  51. package/notes-app/index.html +12 -0
  52. package/notes-app/nginx.conf +23 -0
  53. package/notes-app/package.json +37 -0
  54. package/notes-app/pnpm-lock.yaml +3124 -0
  55. package/notes-app/src/App.tsx +13 -0
  56. package/notes-app/src/main.tsx +13 -0
  57. package/notes-app/src/pages/LoginPage.test.tsx +15 -0
  58. package/notes-app/src/pages/LoginPage.tsx +10 -0
  59. package/notes-app/src/pages/MainPage.tsx +14 -0
  60. package/notes-app/src/styles/globals.css +1 -0
  61. package/notes-app/src/vite-env.d.ts +1 -0
  62. package/notes-app/tsconfig.json +24 -0
  63. package/notes-app/tsconfig.node.json +10 -0
  64. package/notes-app/vite.config.js +21 -0
  65. package/notes-app/vite.config.ts +22 -0
  66. package/notes-app/vitest.config.ts +16 -0
  67. package/package.json +58 -0
  68. package/stacks/django-vue.yaml +33 -0
  69. package/stacks/fastapi-react.yaml +160 -0
  70. package/stacks/flutter-firebase.yaml +58 -0
  71. package/stacks/nextjs-prisma.yaml +33 -0
  72. package/stacks/schema.json +144 -0
  73. package/templates/agents/architect.hbs +183 -0
  74. package/templates/agents/auto-documenter.hbs +36 -0
  75. package/templates/agents/backend-developer.hbs +175 -0
  76. package/templates/agents/code-reviewer.hbs +29 -0
  77. package/templates/agents/database-developer.hbs +52 -0
  78. package/templates/agents/debug-specialist.hbs +39 -0
  79. package/templates/agents/environment-setup.hbs +41 -0
  80. package/templates/agents/frontend-developer.hbs +45 -0
  81. package/templates/agents/integration-qa.hbs +26 -0
  82. package/templates/agents/performance-qa.hbs +24 -0
  83. package/templates/agents/pr-writer.hbs +53 -0
  84. package/templates/agents/quality-lead.hbs +26 -0
  85. package/templates/agents/requirements-analyst.hbs +26 -0
  86. package/templates/agents/security-analyst.hbs +21 -0
  87. package/templates/agents/security-reviewer.hbs +20 -0
  88. package/templates/agents/ssot-updater.hbs +45 -0
  89. package/templates/agents/technical-writer.hbs +28 -0
  90. package/templates/agents/unit-test-engineer.hbs +19 -0
  91. package/templates/agents/user-clone.hbs +43 -0
  92. package/templates/github-actions/aws/deploy-notes.yml.hbs +118 -0
  93. package/templates/github-actions/azure/deploy-notes.yml.hbs +78 -0
  94. package/templates/github-actions/gcp/deploy-notes.yml.hbs +76 -0
  95. package/templates/github-actions/vercel-railway/deploy-notes.yml.hbs +49 -0
  96. package/templates/mindsets/agent-stdio.hbs +51 -0
  97. package/templates/mindsets/dart.hbs +39 -0
  98. package/templates/mindsets/ddd-clean-architecture.hbs +52 -0
  99. package/templates/mindsets/electron.hbs +41 -0
  100. package/templates/mindsets/fastapi.hbs +40 -0
  101. package/templates/mindsets/flutter.hbs +56 -0
  102. package/templates/mindsets/kotlin.hbs +46 -0
  103. package/templates/mindsets/postgresql.hbs +39 -0
  104. package/templates/mindsets/python.hbs +39 -0
  105. package/templates/mindsets/react.hbs +51 -0
  106. package/templates/mindsets/swift.hbs +46 -0
  107. package/templates/mindsets/terraform.hbs +53 -0
  108. package/templates/mindsets/typescript.hbs +34 -0
  109. package/templates/mindsets/vite.hbs +37 -0
  110. package/templates/notes-compose.yml +79 -0
  111. package/templates/partials/cogito-geo.hbs +84 -0
  112. package/templates/partials/cogito-godd.hbs +22 -0
  113. package/templates/partials/cogito-grammar.hbs +105 -0
  114. package/templates/partials/cogito-particle.hbs +76 -0
  115. package/templates/partials/cogito-root-ai.hbs +79 -0
  116. package/templates/partials/cogito-root-arch.hbs +75 -0
  117. package/templates/partials/cogito-root-core.hbs +75 -0
  118. package/templates/partials/cogito-root-daily.hbs +58 -0
  119. package/templates/partials/cogito-root-dev.hbs +71 -0
  120. package/templates/partials/cogito-root-devops.hbs +71 -0
  121. package/templates/partials/cogito-root-framework.hbs +80 -0
  122. package/templates/partials/cogito-root-lang.hbs +74 -0
  123. package/templates/partials/godd-core.hbs +50 -0
  124. package/templates/partials/project-context.hbs +52 -0
  125. package/templates/partials/ssot-header.hbs +40 -0
  126. package/templates/partials/ssot-rules.hbs +30 -0
  127. package/templates/prompts/adr.hbs +39 -0
  128. package/templates/prompts/agent-dev-workflow.hbs +34 -0
  129. package/templates/prompts/analyze-report.hbs +36 -0
  130. package/templates/prompts/auto-documentation.hbs +37 -0
  131. package/templates/prompts/check.hbs +52 -0
  132. package/templates/prompts/commit.hbs +96 -0
  133. package/templates/prompts/dev.hbs +127 -0
  134. package/templates/prompts/docs-init.hbs +95 -0
  135. package/templates/prompts/docs-update.hbs +51 -0
  136. package/templates/prompts/git-workflow.hbs +125 -0
  137. package/templates/prompts/impact-analysis.hbs +43 -0
  138. package/templates/prompts/install.hbs +40 -0
  139. package/templates/prompts/new-branch.hbs +61 -0
  140. package/templates/prompts/notes-deploy.hbs +72 -0
  141. package/templates/prompts/pr-analyze.hbs +44 -0
  142. package/templates/prompts/pr-create.hbs +125 -0
  143. package/templates/prompts/push-execute.hbs +83 -0
  144. package/templates/prompts/push.hbs +24 -0
  145. package/templates/prompts/release-notes.hbs +38 -0
  146. package/templates/prompts/requirements-to-business-flow.hbs +29 -0
  147. package/templates/prompts/requirements-to-tickets.hbs +26 -0
  148. package/templates/prompts/review.hbs +126 -0
  149. package/templates/prompts/setup.hbs +247 -0
  150. package/templates/prompts/spec.hbs +35 -0
  151. package/templates/prompts/specification-to-tickets.hbs +24 -0
  152. package/templates/prompts/submit.hbs +143 -0
  153. package/templates/prompts/sync.hbs +63 -0
  154. package/templates/prompts/test-plan.hbs +56 -0
  155. package/templates/terraform/aws/alb.tf.hbs +58 -0
  156. package/templates/terraform/aws/backend.tf.hbs +10 -0
  157. package/templates/terraform/aws/cloudfront.tf.hbs +96 -0
  158. package/templates/terraform/aws/ecr.tf.hbs +30 -0
  159. package/templates/terraform/aws/ecs.tf.hbs +136 -0
  160. package/templates/terraform/aws/iam.tf.hbs +88 -0
  161. package/templates/terraform/aws/local.tf.hbs +34 -0
  162. package/templates/terraform/aws/output.tf.hbs +49 -0
  163. package/templates/terraform/aws/provider.tf.hbs +26 -0
  164. package/templates/terraform/aws/rds.tf.hbs +38 -0
  165. package/templates/terraform/aws/s3.tf.hbs +34 -0
  166. package/templates/terraform/aws/secrets.tf.hbs +38 -0
  167. package/templates/terraform/aws/security_groups.tf.hbs +72 -0
  168. package/templates/terraform/aws/vpc.tf.hbs +63 -0
  169. package/templates/terraform/azure/backend.tf.hbs +8 -0
  170. package/templates/terraform/azure/iam.tf.hbs +36 -0
  171. package/templates/terraform/azure/main.tf.hbs +199 -0
  172. package/templates/terraform/azure/output.tf.hbs +19 -0
  173. package/templates/terraform/azure/provider.tf.hbs +19 -0
  174. package/templates/terraform/gcp/backend.tf.hbs +6 -0
  175. package/templates/terraform/gcp/iam.tf.hbs +47 -0
  176. package/templates/terraform/gcp/main.tf.hbs +171 -0
  177. package/templates/terraform/gcp/output.tf.hbs +15 -0
  178. package/templates/terraform/gcp/provider.tf.hbs +19 -0
  179. package/templates/terraform/vercel-railway/main.tf.hbs +64 -0
  180. package/templates/terraform/vercel-railway/output.tf.hbs +11 -0
@@ -0,0 +1,96 @@
1
+ resource "aws_cloudfront_origin_access_control" "notes_app" {
2
+ name = "${local.project}-oac"
3
+ origin_access_control_origin_type = "s3"
4
+ signing_behavior = "always"
5
+ signing_protocol = "sigv4"
6
+ }
7
+
8
+ resource "random_password" "origin_verify" {
9
+ length = 64
10
+ special = false
11
+ }
12
+
13
+ resource "aws_cloudfront_distribution" "notes" {
14
+ enabled = true
15
+ default_root_object = "index.html"
16
+ price_class = "PriceClass_200"
17
+ tags = local.tags
18
+
19
+ # S3 Origin (SPA)
20
+ origin {
21
+ domain_name = aws_s3_bucket.notes_app.bucket_regional_domain_name
22
+ origin_id = "s3-origin"
23
+ origin_access_control_id = aws_cloudfront_origin_access_control.notes_app.id
24
+ }
25
+
26
+ # ALB Origin (API)
27
+ origin {
28
+ domain_name = aws_lb.api.dns_name
29
+ origin_id = "api-origin"
30
+
31
+ custom_origin_config {
32
+ http_port = 80
33
+ https_port = 443
34
+ origin_protocol_policy = "http-only"
35
+ origin_ssl_protocols = ["TLSv1.2"]
36
+ }
37
+
38
+ custom_header {
39
+ name = "X-Origin-Verify"
40
+ value = random_password.origin_verify.result
41
+ }
42
+ }
43
+
44
+ # Default behavior → S3
45
+ default_cache_behavior {
46
+ allowed_methods = ["GET", "HEAD"]
47
+ cached_methods = ["GET", "HEAD"]
48
+ target_origin_id = "s3-origin"
49
+ viewer_protocol_policy = "redirect-to-https"
50
+
51
+ forwarded_values {
52
+ query_string = false
53
+ cookies { forward = "none" }
54
+ }
55
+ }
56
+
57
+ # /api/* → ALB
58
+ ordered_cache_behavior {
59
+ path_pattern = "/api/*"
60
+ allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
61
+ cached_methods = ["GET", "HEAD"]
62
+ target_origin_id = "api-origin"
63
+ viewer_protocol_policy = "redirect-to-https"
64
+
65
+ forwarded_values {
66
+ query_string = true
67
+ headers = ["Authorization", "Origin", "Accept"]
68
+ cookies { forward = "all" }
69
+ }
70
+
71
+ min_ttl = 0
72
+ default_ttl = 0
73
+ max_ttl = 0
74
+ }
75
+
76
+ # SPA fallback
77
+ custom_error_response {
78
+ error_code = 403
79
+ response_code = 200
80
+ response_page_path = "/index.html"
81
+ }
82
+
83
+ custom_error_response {
84
+ error_code = 404
85
+ response_code = 200
86
+ response_page_path = "/index.html"
87
+ }
88
+
89
+ restrictions {
90
+ geo_restriction { restriction_type = "none" }
91
+ }
92
+
93
+ viewer_certificate {
94
+ cloudfront_default_certificate = true
95
+ }
96
+ }
@@ -0,0 +1,30 @@
1
+ resource "aws_ecr_repository" "notes_api" {
2
+ name = "godd-notes-api"
3
+ image_tag_mutability = "MUTABLE"
4
+ force_delete = local.env == "dev"
5
+ tags = local.tags
6
+
7
+ image_scanning_configuration {
8
+ scan_on_push = true
9
+ }
10
+ }
11
+
12
+ resource "aws_ecr_lifecycle_policy" "notes_api" {
13
+ repository = aws_ecr_repository.notes_api.name
14
+
15
+ policy = jsonencode({
16
+ rules = [
17
+ {
18
+ rulePriority = 1
19
+ description = "Delete untagged images after 1 day"
20
+ selection = {
21
+ tagStatus = "untagged"
22
+ countType = "sinceImagePushed"
23
+ countUnit = "days"
24
+ countNumber = 1
25
+ }
26
+ action = { type = "expire" }
27
+ }
28
+ ]
29
+ })
30
+ }
@@ -0,0 +1,136 @@
1
+ resource "aws_ecs_cluster" "main" {
2
+ name = local.project
3
+ tags = local.tags
4
+ }
5
+
6
+ resource "aws_cloudwatch_log_group" "ecs" {
7
+ name = "/ecs/godd-notes-api"
8
+ retention_in_days = 30
9
+ tags = local.tags
10
+ }
11
+
12
+ resource "aws_iam_role" "ecs_task_execution" {
13
+ name = "${local.project}-ecs-task-execution"
14
+ tags = local.tags
15
+
16
+ assume_role_policy = jsonencode({
17
+ Version = "2012-10-17"
18
+ Statement = [{
19
+ Action = "sts:AssumeRole"
20
+ Effect = "Allow"
21
+ Principal = { Service = "ecs-tasks.amazonaws.com" }
22
+ }]
23
+ })
24
+ }
25
+
26
+ resource "aws_iam_role_policy_attachment" "ecs_task_execution" {
27
+ role = aws_iam_role.ecs_task_execution.name
28
+ policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
29
+ }
30
+
31
+ resource "aws_iam_role_policy" "ecs_secrets" {
32
+ name = "${local.project}-ecs-secrets"
33
+ role = aws_iam_role.ecs_task_execution.id
34
+
35
+ policy = jsonencode({
36
+ Version = "2012-10-17"
37
+ Statement = [{
38
+ Effect = "Allow"
39
+ Action = ["secretsmanager:GetSecretValue"]
40
+ Resource = "arn:aws:secretsmanager:${local.region}:${local.account_id}:secret:godd-notes/${local.env}/*"
41
+ }]
42
+ })
43
+ }
44
+
45
+ resource "aws_iam_role" "ecs_task" {
46
+ name = "${local.project}-ecs-task"
47
+ tags = local.tags
48
+
49
+ assume_role_policy = jsonencode({
50
+ Version = "2012-10-17"
51
+ Statement = [{
52
+ Action = "sts:AssumeRole"
53
+ Effect = "Allow"
54
+ Principal = { Service = "ecs-tasks.amazonaws.com" }
55
+ }]
56
+ })
57
+ }
58
+
59
+ resource "aws_ecs_task_definition" "api" {
60
+ family = "godd-notes-api"
61
+ requires_compatibilities = ["FARGATE"]
62
+ network_mode = "awsvpc"
63
+ cpu = local.ecs_cpu
64
+ memory = local.ecs_memory
65
+ execution_role_arn = aws_iam_role.ecs_task_execution.arn
66
+ task_role_arn = aws_iam_role.ecs_task.arn
67
+ tags = local.tags
68
+
69
+ runtime_platform {
70
+ operating_system_family = "LINUX"
71
+ cpu_architecture = "ARM64"
72
+ }
73
+
74
+ container_definitions = jsonencode([{
75
+ name = "notes-api"
76
+ image = "${aws_ecr_repository.notes_api.repository_url}:latest"
77
+ essential = true
78
+ command = ["sh", "-c", "alembic upgrade head && uvicorn app.main:app --host 0.0.0.0 --port ${local.container_port}"]
79
+
80
+ portMappings = [{
81
+ containerPort = local.container_port
82
+ protocol = "tcp"
83
+ }]
84
+
85
+ environment = [
86
+ { name = "DB_PORT", value = "5432" },
87
+ { name = "DB_NAME", value = local.rds_db_name },
88
+ { name = "API_HOST", value = "0.0.0.0" },
89
+ { name = "API_PORT", value = tostring(local.container_port) },
90
+ { name = "ALLOWED_ORIGINS", value = "https://${aws_cloudfront_distribution.notes.domain_name}" },
91
+ ]
92
+
93
+ secrets = [
94
+ { name = "DB_HOST", valueFrom = aws_secretsmanager_secret.rds_credentials.arn },
95
+ { name = "DB_USER", valueFrom = aws_secretsmanager_secret.rds_credentials.arn },
96
+ { name = "DB_PASSWORD", valueFrom = aws_secretsmanager_secret.rds_credentials.arn },
97
+ { name = "JWT_SECRET", valueFrom = aws_secretsmanager_secret.jwt_secret.arn },
98
+ { name = "GITHUB_TOKEN", valueFrom = aws_secretsmanager_secret.github_token.arn },
99
+ { name = "NOTES_ADMIN_USERNAME", valueFrom = aws_secretsmanager_secret.admin_credentials.arn },
100
+ { name = "NOTES_ADMIN_PASSWORD", valueFrom = aws_secretsmanager_secret.admin_credentials.arn },
101
+ ]
102
+
103
+ logConfiguration = {
104
+ logDriver = "awslogs"
105
+ options = {
106
+ "awslogs-group" = aws_cloudwatch_log_group.ecs.name
107
+ "awslogs-region" = local.region
108
+ "awslogs-stream-prefix" = "ecs"
109
+ }
110
+ }
111
+ }])
112
+ }
113
+
114
+ resource "aws_ecs_service" "api" {
115
+ name = "notes-api"
116
+ cluster = aws_ecs_cluster.main.id
117
+ task_definition = aws_ecs_task_definition.api.arn
118
+ desired_count = 1
119
+ launch_type = "FARGATE"
120
+ platform_version = "1.4.0"
121
+ tags = local.tags
122
+
123
+ enable_execute_command = true
124
+
125
+ network_configuration {
126
+ subnets = [aws_subnet.public_1a.id]
127
+ security_groups = [aws_security_group.ecs.id]
128
+ assign_public_ip = true
129
+ }
130
+
131
+ load_balancer {
132
+ target_group_arn = aws_lb_target_group.api.arn
133
+ container_name = "notes-api"
134
+ container_port = local.container_port
135
+ }
136
+ }
@@ -0,0 +1,88 @@
1
+ data "aws_iam_openid_connect_provider" "github" {
2
+ url = "https://token.actions.githubusercontent.com"
3
+ }
4
+
5
+ resource "aws_iam_role" "github_actions" {
6
+ name = "github-actions-${local.env}"
7
+ tags = local.tags
8
+
9
+ assume_role_policy = jsonencode({
10
+ Version = "2012-10-17"
11
+ Statement = [{
12
+ Effect = "Allow"
13
+ Principal = {
14
+ Federated = data.aws_iam_openid_connect_provider.github.arn
15
+ }
16
+ Action = "sts:AssumeRoleWithWebIdentity"
17
+ Condition = {
18
+ StringLike = {
19
+ "token.actions.githubusercontent.com:sub" = "repo:${local.github_owner}/${local.github_repo}:*"
20
+ }
21
+ StringEquals = {
22
+ "token.actions.githubusercontent.com:aud" = "sts.amazonaws.com"
23
+ }
24
+ }
25
+ }]
26
+ })
27
+ }
28
+
29
+ resource "aws_iam_role_policy" "github_actions" {
30
+ name = "${local.project}-github-actions"
31
+ role = aws_iam_role.github_actions.id
32
+
33
+ policy = jsonencode({
34
+ Version = "2012-10-17"
35
+ Statement = [
36
+ {
37
+ Sid = "ECR"
38
+ Effect = "Allow"
39
+ Action = [
40
+ "ecr:GetAuthorizationToken",
41
+ "ecr:BatchCheckLayerAvailability",
42
+ "ecr:GetDownloadUrlForLayer",
43
+ "ecr:BatchGetImage",
44
+ "ecr:PutImage",
45
+ "ecr:InitiateLayerUpload",
46
+ "ecr:UploadLayerPart",
47
+ "ecr:CompleteLayerUpload",
48
+ ]
49
+ Resource = "*"
50
+ },
51
+ {
52
+ Sid = "ECS"
53
+ Effect = "Allow"
54
+ Action = [
55
+ "ecs:UpdateService",
56
+ "ecs:DescribeServices",
57
+ "ecs:DescribeTaskDefinition",
58
+ "ecs:RegisterTaskDefinition",
59
+ "iam:PassRole",
60
+ ]
61
+ Resource = "*"
62
+ },
63
+ {
64
+ Sid = "S3"
65
+ Effect = "Allow"
66
+ Action = [
67
+ "s3:PutObject",
68
+ "s3:GetObject",
69
+ "s3:DeleteObject",
70
+ "s3:ListBucket",
71
+ ]
72
+ Resource = [
73
+ "arn:aws:s3:::${local.project}-${local.account_id}",
74
+ "arn:aws:s3:::${local.project}-${local.account_id}/*",
75
+ ]
76
+ },
77
+ {
78
+ Sid = "CloudFront"
79
+ Effect = "Allow"
80
+ Action = [
81
+ "cloudfront:CreateInvalidation",
82
+ "cloudfront:GetDistribution",
83
+ ]
84
+ Resource = "*"
85
+ },
86
+ ]
87
+ })
88
+ }
@@ -0,0 +1,34 @@
1
+ locals {
2
+ project = "godd-ripla-notes"
3
+ env = "{{env}}"
4
+ account_id = "{{accountId}}"
5
+ region = "{{region}}"
6
+
7
+ # VPC
8
+ vpc_cidr = "{{vpcCidr}}"
9
+ public_subnet_1a = cidrsubnet(local.vpc_cidr, 8, 1)
10
+ public_subnet_1c = cidrsubnet(local.vpc_cidr, 8, 2)
11
+ private_subnet_1a = cidrsubnet(local.vpc_cidr, 8, 10)
12
+ private_subnet_1c = cidrsubnet(local.vpc_cidr, 8, 11)
13
+
14
+ # ECS
15
+ ecs_cpu = {{ecsCpu}}
16
+ ecs_memory = {{ecsMemory}}
17
+
18
+ # RDS
19
+ rds_instance_class = "{{rdsInstanceClass}}"
20
+ rds_engine_version = "16"
21
+ rds_db_name = "notes"
22
+
23
+ # Container
24
+ container_port = 3100
25
+
26
+ # GitHub
27
+ github_owner = "{{githubOwner}}"
28
+ github_repo = "{{githubRepo}}"
29
+
30
+ tags = {
31
+ Project = local.project
32
+ Environment = local.env
33
+ }
34
+ }
@@ -0,0 +1,49 @@
1
+ output "cloudfront_domain" {
2
+ description = "CloudFront distribution domain name"
3
+ value = aws_cloudfront_distribution.notes.domain_name
4
+ }
5
+
6
+ output "cloudfront_distribution_id" {
7
+ description = "CloudFront distribution ID"
8
+ value = aws_cloudfront_distribution.notes.id
9
+ }
10
+
11
+ output "alb_dns_name" {
12
+ description = "ALB DNS name"
13
+ value = aws_lb.api.dns_name
14
+ }
15
+
16
+ output "ecr_repository_url" {
17
+ description = "ECR repository URL for notes-api"
18
+ value = aws_ecr_repository.notes_api.repository_url
19
+ }
20
+
21
+ output "ecs_cluster_name" {
22
+ description = "ECS cluster name"
23
+ value = aws_ecs_cluster.main.name
24
+ }
25
+
26
+ output "ecs_service_name" {
27
+ description = "ECS service name"
28
+ value = aws_ecs_service.api.name
29
+ }
30
+
31
+ output "rds_endpoint" {
32
+ description = "RDS endpoint"
33
+ value = aws_db_instance.main.endpoint
34
+ }
35
+
36
+ output "s3_bucket_name" {
37
+ description = "S3 bucket name for notes-app"
38
+ value = aws_s3_bucket.notes_app.id
39
+ }
40
+
41
+ output "notes_app_url" {
42
+ description = "Notes App URL"
43
+ value = "https://${aws_cloudfront_distribution.notes.domain_name}"
44
+ }
45
+
46
+ output "notes_api_url" {
47
+ description = "Notes API URL"
48
+ value = "https://${aws_cloudfront_distribution.notes.domain_name}/api"
49
+ }
@@ -0,0 +1,26 @@
1
+ terraform {
2
+ required_version = ">= 1.5"
3
+
4
+ required_providers {
5
+ aws = {
6
+ source = "hashicorp/aws"
7
+ version = "~> 5.0"
8
+ }
9
+ random = {
10
+ source = "hashicorp/random"
11
+ version = "~> 3.0"
12
+ }
13
+ }
14
+ }
15
+
16
+ provider "aws" {
17
+ region = "{{region}}"
18
+
19
+ default_tags {
20
+ tags = {
21
+ Project = "godd-ripla-notes"
22
+ Environment = "{{env}}"
23
+ ManagedBy = "terraform"
24
+ }
25
+ }
26
+ }
@@ -0,0 +1,38 @@
1
+ resource "aws_db_subnet_group" "main" {
2
+ name = "${local.project}-db-subnet"
3
+ subnet_ids = [aws_subnet.private_1a.id, aws_subnet.private_1c.id]
4
+ tags = local.tags
5
+ }
6
+
7
+ resource "aws_db_instance" "main" {
8
+ identifier = "${local.project}-db"
9
+ engine = "postgres"
10
+ engine_version = local.rds_engine_version
11
+ instance_class = local.rds_instance_class
12
+
13
+ allocated_storage = 20
14
+ max_allocated_storage = 30
15
+ storage_type = "gp3"
16
+ storage_encrypted = true
17
+
18
+ db_name = local.rds_db_name
19
+ username = "app_user"
20
+ password = random_password.rds_password.result
21
+
22
+ db_subnet_group_name = aws_db_subnet_group.main.name
23
+ vpc_security_group_ids = [aws_security_group.rds.id]
24
+
25
+ multi_az = false
26
+ publicly_accessible = false
27
+
28
+ backup_retention_period = 7
29
+ skip_final_snapshot = local.env == "dev"
30
+ deletion_protection = local.env != "dev"
31
+
32
+ tags = local.tags
33
+ }
34
+
35
+ resource "random_password" "rds_password" {
36
+ length = 32
37
+ special = false
38
+ }
@@ -0,0 +1,34 @@
1
+ resource "aws_s3_bucket" "notes_app" {
2
+ bucket = "${local.project}-${local.account_id}"
3
+ force_destroy = local.env == "dev"
4
+ tags = local.tags
5
+ }
6
+
7
+ resource "aws_s3_bucket_public_access_block" "notes_app" {
8
+ bucket = aws_s3_bucket.notes_app.id
9
+ block_public_acls = true
10
+ block_public_policy = true
11
+ ignore_public_acls = true
12
+ restrict_public_buckets = true
13
+ }
14
+
15
+ resource "aws_s3_bucket_policy" "notes_app" {
16
+ bucket = aws_s3_bucket.notes_app.id
17
+ policy = jsonencode({
18
+ Version = "2012-10-17"
19
+ Statement = [
20
+ {
21
+ Sid = "AllowCloudFrontOAC"
22
+ Effect = "Allow"
23
+ Principal = { Service = "cloudfront.amazonaws.com" }
24
+ Action = "s3:GetObject"
25
+ Resource = "${aws_s3_bucket.notes_app.arn}/*"
26
+ Condition = {
27
+ StringEquals = {
28
+ "AWS:SourceArn" = aws_cloudfront_distribution.notes.arn
29
+ }
30
+ }
31
+ }
32
+ ]
33
+ })
34
+ }
@@ -0,0 +1,38 @@
1
+ resource "aws_secretsmanager_secret" "rds_credentials" {
2
+ name = "godd-notes/${local.env}/rds-credentials"
3
+ tags = local.tags
4
+ }
5
+
6
+ resource "aws_secretsmanager_secret_version" "rds_credentials" {
7
+ secret_id = aws_secretsmanager_secret.rds_credentials.id
8
+ secret_string = jsonencode({
9
+ host = aws_db_instance.main.address
10
+ username = aws_db_instance.main.username
11
+ password = random_password.rds_password.result
12
+ })
13
+ }
14
+
15
+ resource "aws_secretsmanager_secret" "jwt_secret" {
16
+ name = "godd-notes/${local.env}/jwt-secret"
17
+ tags = local.tags
18
+ }
19
+
20
+ resource "aws_secretsmanager_secret" "github_token" {
21
+ name = "godd-notes/${local.env}/github-token"
22
+ tags = local.tags
23
+ }
24
+
25
+ resource "aws_secretsmanager_secret" "admin_credentials" {
26
+ name = "godd-notes/${local.env}/admin-credentials"
27
+ tags = local.tags
28
+ }
29
+
30
+ resource "aws_secretsmanager_secret" "origin_verify" {
31
+ name = "godd-notes/${local.env}/origin-verify"
32
+ tags = local.tags
33
+ }
34
+
35
+ resource "aws_secretsmanager_secret_version" "origin_verify" {
36
+ secret_id = aws_secretsmanager_secret.origin_verify.id
37
+ secret_string = random_password.origin_verify.result
38
+ }
@@ -0,0 +1,72 @@
1
+ data "aws_ec2_managed_prefix_list" "cloudfront" {
2
+ name = "com.amazonaws.global.cloudfront.origin-facing"
3
+ }
4
+
5
+ resource "aws_security_group" "alb" {
6
+ name_prefix = "${local.project}-alb-"
7
+ vpc_id = aws_vpc.main.id
8
+ tags = merge(local.tags, { Name = "${local.project}-alb-sg" })
9
+
10
+ lifecycle { create_before_destroy = true }
11
+ }
12
+
13
+ resource "aws_security_group_rule" "alb_from_cloudfront" {
14
+ type = "ingress"
15
+ from_port = 80
16
+ to_port = 80
17
+ protocol = "tcp"
18
+ prefix_list_ids = [data.aws_ec2_managed_prefix_list.cloudfront.id]
19
+ security_group_id = aws_security_group.alb.id
20
+ }
21
+
22
+ resource "aws_security_group_rule" "alb_to_ecs" {
23
+ type = "egress"
24
+ from_port = local.container_port
25
+ to_port = local.container_port
26
+ protocol = "tcp"
27
+ source_security_group_id = aws_security_group.ecs.id
28
+ security_group_id = aws_security_group.alb.id
29
+ }
30
+
31
+ resource "aws_security_group" "ecs" {
32
+ name_prefix = "${local.project}-ecs-"
33
+ vpc_id = aws_vpc.main.id
34
+ tags = merge(local.tags, { Name = "${local.project}-ecs-sg" })
35
+
36
+ lifecycle { create_before_destroy = true }
37
+ }
38
+
39
+ resource "aws_security_group_rule" "ecs_from_alb" {
40
+ type = "ingress"
41
+ from_port = local.container_port
42
+ to_port = local.container_port
43
+ protocol = "tcp"
44
+ source_security_group_id = aws_security_group.alb.id
45
+ security_group_id = aws_security_group.ecs.id
46
+ }
47
+
48
+ resource "aws_security_group_rule" "ecs_to_internet" {
49
+ type = "egress"
50
+ from_port = 443
51
+ to_port = 443
52
+ protocol = "tcp"
53
+ cidr_blocks = ["0.0.0.0/0"]
54
+ security_group_id = aws_security_group.ecs.id
55
+ }
56
+
57
+ resource "aws_security_group" "rds" {
58
+ name_prefix = "${local.project}-rds-"
59
+ vpc_id = aws_vpc.main.id
60
+ tags = merge(local.tags, { Name = "${local.project}-rds-sg" })
61
+
62
+ lifecycle { create_before_destroy = true }
63
+ }
64
+
65
+ resource "aws_security_group_rule" "rds_from_ecs" {
66
+ type = "ingress"
67
+ from_port = 5432
68
+ to_port = 5432
69
+ protocol = "tcp"
70
+ source_security_group_id = aws_security_group.ecs.id
71
+ security_group_id = aws_security_group.rds.id
72
+ }