@ripla/godd-mcp 1.0.7-canary.9 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +457 -85
- package/dist/godd.cjs +293 -244
- package/dist/godd.js +1005 -321
- package/dist/index.js +148 -119
- package/notes/app/DESIGN.md +5 -2
- package/notes/app/e2e/fixtures.ts +39 -0
- package/notes/app/e2e/ja-typography-visual.spec.ts +185 -0
- package/notes/app/e2e/ja-typography-visual.spec.ts-snapshots/ja-typography-desktop-1280-chromium-linux.png +0 -0
- package/notes/app/e2e/ja-typography-visual.spec.ts-snapshots/ja-typography-mobile-360-chromium-linux.png +0 -0
- package/notes/app/e2e/rtl-logical-properties.spec.ts +36 -0
- package/notes/app/package-lock.json +0 -8
- package/notes/app/package.json +0 -1
- package/notes/app/playwright.config.ts +7 -0
- package/notes/app/pnpm-lock.yaml +0 -8
- package/notes/app/src/components/BranchSelectorModal.tsx +8 -8
- package/notes/app/src/components/CommentPanel.tsx +5 -5
- package/notes/app/src/components/DiffPreview.tsx +4 -4
- package/notes/app/src/components/FileContentView.tsx +1 -1
- package/notes/app/src/components/FileContextMenu.tsx +1 -1
- package/notes/app/src/components/FileInfoPanel.branch-tab.test.tsx +3 -35
- package/notes/app/src/components/IssueCommentThread.test.tsx +40 -19
- package/notes/app/src/components/IssueDetailView.test.tsx +3 -40
- package/notes/app/src/components/IssueList.tsx +3 -3
- package/notes/app/src/components/LabelSelector.tsx +1 -1
- package/notes/app/src/components/MarkdownEditor.tsx +1 -1
- package/notes/app/src/components/Skeleton.tsx +2 -2
- package/notes/app/src/components/ToastContainer.tsx +1 -1
- package/notes/app/src/components/TreeNode.tsx +6 -6
- package/notes/app/src/contexts/ToastContext.tsx +1 -1
- package/notes/app/src/hooks/useComments.ts +1 -1
- package/notes/app/src/hooks/useEditSession.ts +1 -1
- package/notes/app/src/lib/api.ts +1 -13
- package/notes/app/src/lib/csv-utils.ts +1 -1
- package/notes/app/src/lib/postLoginRedirect.ts +1 -1
- package/notes/app/src/lib/rtl-logical-properties.test.ts +59 -0
- package/notes/app/src/lib/user-colors.ts +1 -1
- package/notes/app/src/pages/MainPage.tsx +2 -2
- package/notes/app/src/pages/SettingsPage.test.tsx +40 -10
- package/notes/app/src/pages/SettingsPage.tsx +1 -1
- package/notes/app/src/pages/UserManagementPage.tsx +7 -7
- package/notes/app/src/styles/globals.css +17 -0
- package/notes/app/src/test/mockPeriodicSync.ts +68 -0
- package/notes/app/src/test/mocks.ts +1 -1
- package/package.json +7 -3
- package/templates/feedback/feedback-lambda/index.mjs +342 -0
- package/templates/feedback/frontend/FeedbackWidget.tsx +574 -0
- package/templates/feedback/frontend/api.ts +38 -0
- package/templates/feedback/frontend/composePinImage.ts +80 -0
- package/templates/feedback/frontend/config.ts +14 -0
- package/templates/feedback/frontend/types.ts +41 -0
- package/templates/feedback/terraform/Makefile +43 -0
- package/templates/feedback/terraform/backend.tf +10 -0
- package/templates/feedback/terraform/lambda.tf +95 -0
- package/templates/feedback/terraform/local.tf +12 -0
- package/templates/feedback/terraform/output.tf +9 -0
- package/templates/feedback/terraform/provider.tf +24 -0
- package/templates/feedback/terraform/variables.tf +25 -0
- package/templates/github-actions/aws/deploy-notes.yml.hbs +193 -10
- package/templates/notes-docs/001_project/README.md +0 -2
- package/templates/notes-docs/002_business_flow/README.md +19 -0
- package/templates/notes-docs/003_requirements/README.md +20 -0
- package/templates/notes-docs/003_requirements/questions.csv +1 -0
- package/templates/notes-docs/003_requirements/spec/README.md +11 -0
- package/templates/notes-docs/004_pages/README.md +22 -0
- package/templates/notes-docs/005_architecture/README.md +20 -0
- package/templates/notes-docs/006_development_workflow/README.md +67 -0
- package/templates/notes-docs/006_development_workflow/daily_flow.template.md +303 -0
- package/templates/notes-docs/006_development_workflow/git.template.md +72 -20
- package/templates/notes-docs/006_development_workflow/judgment.template.md +182 -0
- package/templates/notes-docs/006_development_workflow/workflow.template.md +167 -192
- package/templates/notes-docs/007_guides/README.md +85 -0
- package/templates/notes-docs/007_guides/bot-token-setup.md +174 -0
- package/templates/notes-docs/007_guides/getting_started.md +112 -0
- package/templates/notes-docs/007_guides/glossary.md +145 -0
- package/templates/notes-docs/007_guides/godd_notes_features.md +105 -0
- package/templates/notes-docs/007_guides/godd_notes_usage.md +28 -19
- package/templates/notes-docs/007_guides/godd_tools.md +129 -0
- package/templates/notes-docs/007_guides/godd_usage.md +88 -95
- package/templates/notes-docs/007_guides/infra/README.md +57 -0
- package/templates/notes-docs/007_guides/{setup_aws_accounts.md → infra/setup_aws_accounts.md} +3 -2
- package/templates/notes-docs/007_guides/{setup_infra.template.md → infra/setup_infra.template.md} +15 -4
- package/templates/notes-docs/007_guides/setup_godd.md +66 -23
- package/templates/notes-docs/007_guides/setup_godd_notes.md +95 -42
- package/templates/notes-docs/007_guides/setup_godd_notes.md.styles.json +2 -2
- package/templates/notes-docs/007_guides/setup_local_environment.template.md +81 -20
- package/templates/notes-docs/007_guides/troubleshooting.md +225 -0
- package/templates/notes-docs/999_ref/README.md +23 -0
- package/templates/notes-docs/GENERATED.md +1 -1
- package/templates/notes-docs/README.md +64 -34
- package/templates/terraform/aws/iam.tf.hbs +361 -4
- /package/templates/notes-docs/007_guides/{setup_aws_cost_alert.md → infra/setup_aws_cost_alert.md} +0 -0
- /package/templates/notes-docs/007_guides/{setup_aws_guard_duty.md → infra/setup_aws_guard_duty.md} +0 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// フィードバック機能の環境出し分け設定。
|
|
2
|
+
//
|
|
3
|
+
// 有効化ルール:
|
|
4
|
+
// - ローカル開発(vite dev)では常に ON(import.meta.env.DEV)。開発中に必ず試せるように。
|
|
5
|
+
// - デプロイ環境では VITE_FEEDBACK_ENABLED=true でビルドしたときだけ ON。
|
|
6
|
+
// → dev 配信用ビルドではフラグを立て、本番ビルドでは立てない、で出し分ける。
|
|
7
|
+
export const FEEDBACK_ENABLED =
|
|
8
|
+
import.meta.env.VITE_FEEDBACK_ENABLED === "true" || import.meta.env.DEV;
|
|
9
|
+
|
|
10
|
+
// 送信先エンドポイント。未指定なら同一オリジンの /api/feedback を叩く。
|
|
11
|
+
export const FEEDBACK_API_URL =
|
|
12
|
+
import.meta.env.VITE_FEEDBACK_API_URL ?? "/api/feedback";
|
|
13
|
+
|
|
14
|
+
export const FEEDBACK_TOKEN = import.meta.env.VITE_FEEDBACK_TOKEN ?? "";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// フィードバック(指摘)1件のデータ構造。フロント→バックエンドで送受信する。
|
|
2
|
+
|
|
3
|
+
/** スクリーンショット画像上でのピン位置(画像に対する相対%。0〜100) */
|
|
4
|
+
export interface FeedbackPin {
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** どの画面で撮られたかのコンテキスト */
|
|
10
|
+
export interface FeedbackPage {
|
|
11
|
+
/** 完全な URL(クエリ・ハッシュ込み) */
|
|
12
|
+
url: string;
|
|
13
|
+
/** パス + ハッシュ(ルート識別用) */
|
|
14
|
+
path: string;
|
|
15
|
+
/** document.title */
|
|
16
|
+
title: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** 環境メタ情報(再現・切り分け用) */
|
|
20
|
+
export interface FeedbackMeta {
|
|
21
|
+
viewport: { width: number; height: number };
|
|
22
|
+
userAgent: string;
|
|
23
|
+
/** 撮影時刻(ISO 8601) */
|
|
24
|
+
capturedAt: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** 送信ペイロード */
|
|
28
|
+
export interface FeedbackPayload {
|
|
29
|
+
/** クライアントが書いた指摘コメント */
|
|
30
|
+
comment: string;
|
|
31
|
+
/** 起票者名(任意・フリーテキスト) */
|
|
32
|
+
reporter?: string;
|
|
33
|
+
/** 画面名(任意・フリーテキスト) */
|
|
34
|
+
screenName?: string;
|
|
35
|
+
/** ピン合成済みスクリーンショット(PNG の data URL)。原画はペイロードサイズ削減のため送らない */
|
|
36
|
+
annotatedScreenshot: string;
|
|
37
|
+
/** 指摘位置のピン */
|
|
38
|
+
pin: FeedbackPin;
|
|
39
|
+
page: FeedbackPage;
|
|
40
|
+
meta: FeedbackMeta;
|
|
41
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Terraform 便利ターゲット(フィードバック基盤)
|
|
2
|
+
#
|
|
3
|
+
# 任意のショートカット。make が無い環境(Windows 等)では
|
|
4
|
+
# terraform init / plan / apply を直接実行すればよい。
|
|
5
|
+
#
|
|
6
|
+
# 認証プロファイルを使う場合は AWS_PROFILE を設定してから実行する。
|
|
7
|
+
# 例: make plan AWS_PROFILE=my-profile
|
|
8
|
+
|
|
9
|
+
ifdef AWS_PROFILE
|
|
10
|
+
export AWS_PROFILE
|
|
11
|
+
endif
|
|
12
|
+
|
|
13
|
+
.PHONY: default init fmt validate plan apply apply-auto-approve destroy
|
|
14
|
+
|
|
15
|
+
default:
|
|
16
|
+
@echo "make init - terraform init"
|
|
17
|
+
@echo "make fmt - terraform fmt"
|
|
18
|
+
@echo "make validate - terraform fmt(check) + validate"
|
|
19
|
+
@echo "make plan - terraform plan"
|
|
20
|
+
@echo "make apply - terraform apply"
|
|
21
|
+
@echo "make apply-auto-approve - terraform apply -auto-approve"
|
|
22
|
+
@echo "make destroy - terraform apply -destroy"
|
|
23
|
+
|
|
24
|
+
init:
|
|
25
|
+
terraform init
|
|
26
|
+
|
|
27
|
+
fmt:
|
|
28
|
+
terraform fmt
|
|
29
|
+
|
|
30
|
+
validate:
|
|
31
|
+
terraform fmt -check && terraform validate
|
|
32
|
+
|
|
33
|
+
plan: fmt
|
|
34
|
+
terraform plan
|
|
35
|
+
|
|
36
|
+
apply: fmt
|
|
37
|
+
terraform apply
|
|
38
|
+
|
|
39
|
+
apply-auto-approve: fmt
|
|
40
|
+
terraform apply -auto-approve
|
|
41
|
+
|
|
42
|
+
destroy:
|
|
43
|
+
terraform apply -destroy
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# ---------- Secrets Manager ----------
|
|
2
|
+
# godd-notes Terraform が作成済みのシークレットを参照。
|
|
3
|
+
# SystemAdministrator ロールに DescribeSecret 権限がないため data source は使わず、
|
|
4
|
+
# 名前と ARN パターンを直接指定する。
|
|
5
|
+
|
|
6
|
+
locals {
|
|
7
|
+
secret_prefix = "godd-notes/${local.env}"
|
|
8
|
+
github_app_secrets = {
|
|
9
|
+
app_id = "${local.secret_prefix}/github-app-id"
|
|
10
|
+
private_key = "${local.secret_prefix}/github-app-private-key"
|
|
11
|
+
installation_id = "${local.secret_prefix}/github-app-installation-id"
|
|
12
|
+
}
|
|
13
|
+
secrets_arn_prefix = "arn:aws:secretsmanager:${local.aws_region}:${local.account_id}:secret:${local.secret_prefix}/github-app-"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
# ---------- IAM ----------
|
|
17
|
+
|
|
18
|
+
resource "aws_iam_role" "lambda" {
|
|
19
|
+
name = "${local.function_name}-role"
|
|
20
|
+
|
|
21
|
+
assume_role_policy = jsonencode({
|
|
22
|
+
Version = "2012-10-17"
|
|
23
|
+
Statement = [{
|
|
24
|
+
Effect = "Allow"
|
|
25
|
+
Principal = { Service = "lambda.amazonaws.com" }
|
|
26
|
+
Action = "sts:AssumeRole"
|
|
27
|
+
}]
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
resource "aws_iam_role_policy_attachment" "lambda_basic" {
|
|
32
|
+
role = aws_iam_role.lambda.name
|
|
33
|
+
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
resource "aws_iam_role_policy" "lambda_secrets" {
|
|
37
|
+
name = "${local.function_name}-secrets"
|
|
38
|
+
role = aws_iam_role.lambda.id
|
|
39
|
+
|
|
40
|
+
policy = jsonencode({
|
|
41
|
+
Version = "2012-10-17"
|
|
42
|
+
Statement = [{
|
|
43
|
+
Effect = "Allow"
|
|
44
|
+
Action = "secretsmanager:GetSecretValue"
|
|
45
|
+
Resource = ["${local.secrets_arn_prefix}*"]
|
|
46
|
+
}]
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# ---------- Lambda ----------
|
|
51
|
+
|
|
52
|
+
data "archive_file" "lambda" {
|
|
53
|
+
type = "zip"
|
|
54
|
+
source_dir = local.lambda_src
|
|
55
|
+
excludes = ["node_modules", ".git"]
|
|
56
|
+
output_path = "${path.module}/.build/lambda.zip"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
resource "aws_lambda_function" "feedback" {
|
|
60
|
+
function_name = local.function_name
|
|
61
|
+
role = aws_iam_role.lambda.arn
|
|
62
|
+
handler = "index.handler"
|
|
63
|
+
runtime = "nodejs22.x"
|
|
64
|
+
timeout = 30
|
|
65
|
+
memory_size = 256
|
|
66
|
+
# 連打スパムの天井(GitHub App のレートリミットは GoDD Notes と共有のため巻き添え防止)
|
|
67
|
+
reserved_concurrent_executions = 5
|
|
68
|
+
filename = data.archive_file.lambda.output_path
|
|
69
|
+
source_code_hash = data.archive_file.lambda.output_base64sha256
|
|
70
|
+
|
|
71
|
+
environment {
|
|
72
|
+
variables = {
|
|
73
|
+
GITHUB_APP_ID_SECRET = local.github_app_secrets.app_id
|
|
74
|
+
GITHUB_APP_PRIVATE_KEY_SECRET = local.github_app_secrets.private_key
|
|
75
|
+
GITHUB_APP_INSTALLATION_ID_SECRET = local.github_app_secrets.installation_id
|
|
76
|
+
GITHUB_REPO = var.github_repo
|
|
77
|
+
GITHUB_BRANCH = "feedback-assets"
|
|
78
|
+
FEEDBACK_TOKEN = var.feedback_token
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
# ---------- Function URL ----------
|
|
84
|
+
|
|
85
|
+
resource "aws_lambda_function_url" "feedback" {
|
|
86
|
+
function_name = aws_lambda_function.feedback.function_name
|
|
87
|
+
authorization_type = "NONE"
|
|
88
|
+
|
|
89
|
+
cors {
|
|
90
|
+
allow_origins = var.allowed_origins
|
|
91
|
+
allow_methods = ["POST"]
|
|
92
|
+
allow_headers = ["content-type", "x-feedback-token"]
|
|
93
|
+
max_age = 86400
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
locals {
|
|
2
|
+
# 1 AWS アカウント = 1 プロダクト前提(GitHub App シークレットも godd-notes/<env>/* のアカウント単位)。
|
|
3
|
+
# そのためリソース名にプロダクト名は含めない。
|
|
4
|
+
project_name = "feedback"
|
|
5
|
+
env = "{{ENV}}"
|
|
6
|
+
aws_region = "{{AWS_REGION}}"
|
|
7
|
+
account_id = "{{ACCOUNT_ID}}"
|
|
8
|
+
|
|
9
|
+
function_name = "feedback-${local.env}"
|
|
10
|
+
# 標準配置: リポジトリ直下の feedback-lambda/ を terraform/feedback/<env>/ から参照する
|
|
11
|
+
lambda_src = "../../../feedback-lambda"
|
|
12
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
output "function_url" {
|
|
2
|
+
description = "Lambda Function URL(フロントの VITE_FEEDBACK_API_URL に設定する)"
|
|
3
|
+
value = aws_lambda_function_url.feedback.function_url
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
output "function_name" {
|
|
7
|
+
description = "Lambda 関数名"
|
|
8
|
+
value = aws_lambda_function.feedback.function_name
|
|
9
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
terraform {
|
|
2
|
+
required_version = ">= 1.14.3"
|
|
3
|
+
|
|
4
|
+
required_providers {
|
|
5
|
+
aws = {
|
|
6
|
+
source = "hashicorp/aws"
|
|
7
|
+
version = "~> 6.0"
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
provider "aws" {
|
|
13
|
+
region = local.aws_region
|
|
14
|
+
|
|
15
|
+
allowed_account_ids = [local.account_id]
|
|
16
|
+
|
|
17
|
+
default_tags {
|
|
18
|
+
tags = {
|
|
19
|
+
Project = local.project_name
|
|
20
|
+
Environment = local.env
|
|
21
|
+
ManagedBy = "Terraform"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
variable "github_repo" {
|
|
2
|
+
description = "Issue を作成する GitHub リポジトリ(owner/repo)"
|
|
3
|
+
type = string
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
variable "allowed_origins" {
|
|
7
|
+
description = "CORS で許可するオリジン(フロントエンドの配信 URL)。ローカル開発と dev 配信の両方を列挙する"
|
|
8
|
+
type = list(string)
|
|
9
|
+
|
|
10
|
+
validation {
|
|
11
|
+
condition = length(var.allowed_origins) > 0 && !contains(var.allowed_origins, "*")
|
|
12
|
+
error_message = "allowed_origins には具体的なオリジンを 1 つ以上指定してください(\"*\" は不可)。"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
variable "feedback_token" {
|
|
17
|
+
description = "フロントエンドからのリクエストを検証するトークン。init 時に自動生成し、gitignore された terraform.tfvars で渡す(コミット禁止)"
|
|
18
|
+
type = string
|
|
19
|
+
sensitive = true
|
|
20
|
+
|
|
21
|
+
validation {
|
|
22
|
+
condition = length(var.feedback_token) >= 32
|
|
23
|
+
error_message = "feedback_token は 32 文字以上のランダム文字列にしてください(openssl rand -base64 32 で生成)。"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -6,6 +6,11 @@ on:
|
|
|
6
6
|
paths:
|
|
7
7
|
- 'notes-api/**'
|
|
8
8
|
- 'notes-app/**'
|
|
9
|
+
- 'terraform/**'
|
|
10
|
+
pull_request:
|
|
11
|
+
branches: [main]
|
|
12
|
+
paths:
|
|
13
|
+
- 'terraform/**'
|
|
9
14
|
workflow_dispatch:
|
|
10
15
|
|
|
11
16
|
permissions:
|
|
@@ -27,6 +32,8 @@ jobs:
|
|
|
27
32
|
outputs:
|
|
28
33
|
api: $\{{ steps.filter.outputs.api }}
|
|
29
34
|
app: $\{{ steps.filter.outputs.app }}
|
|
35
|
+
terraform: $\{{ steps.filter.outputs.terraform }}
|
|
36
|
+
terraform-iam: $\{{ steps.filter.outputs.terraform-iam }}
|
|
30
37
|
steps:
|
|
31
38
|
- uses: actions/checkout@v7
|
|
32
39
|
- uses: dorny/paths-filter@v3
|
|
@@ -37,10 +44,188 @@ jobs:
|
|
|
37
44
|
- 'notes-api/**'
|
|
38
45
|
app:
|
|
39
46
|
- 'notes-app/**'
|
|
47
|
+
terraform:
|
|
48
|
+
- 'terraform/godd-notes/{{env}}/**'
|
|
49
|
+
terraform-iam:
|
|
50
|
+
- 'terraform/godd-notes/{{env}}-iam/**'
|
|
40
51
|
|
|
41
|
-
|
|
52
|
+
terraform-plan:
|
|
42
53
|
needs: changes
|
|
43
|
-
if: needs.changes.outputs.
|
|
54
|
+
if: github.event_name == 'pull_request' && needs.changes.outputs.terraform == 'true'
|
|
55
|
+
runs-on: ubuntu-latest
|
|
56
|
+
permissions:
|
|
57
|
+
id-token: write
|
|
58
|
+
contents: read
|
|
59
|
+
pull-requests: write
|
|
60
|
+
steps:
|
|
61
|
+
- uses: actions/checkout@v7
|
|
62
|
+
|
|
63
|
+
- name: Configure AWS credentials
|
|
64
|
+
uses: aws-actions/configure-aws-credentials@v6
|
|
65
|
+
with:
|
|
66
|
+
role-to-assume: arn:aws:iam::{{accountId}}:role/github-actions-{{env}}-plan
|
|
67
|
+
aws-region: {{region}}
|
|
68
|
+
|
|
69
|
+
- name: Setup Terraform
|
|
70
|
+
uses: hashicorp/setup-terraform@v3
|
|
71
|
+
with:
|
|
72
|
+
terraform_wrapper: false
|
|
73
|
+
|
|
74
|
+
- name: Terraform Plan
|
|
75
|
+
id: plan
|
|
76
|
+
working-directory: terraform/godd-notes/{{env}}
|
|
77
|
+
continue-on-error: true
|
|
78
|
+
shell: bash
|
|
79
|
+
run: |
|
|
80
|
+
set -o pipefail
|
|
81
|
+
terraform init -input=false -no-color
|
|
82
|
+
terraform plan -input=false -no-color 2>&1 | tee "$GITHUB_WORKSPACE/plan.txt"
|
|
83
|
+
|
|
84
|
+
- name: Comment PR with Plan
|
|
85
|
+
uses: actions/github-script@v7
|
|
86
|
+
with:
|
|
87
|
+
script: |
|
|
88
|
+
const fs = require('fs');
|
|
89
|
+
|
|
90
|
+
let plan = '';
|
|
91
|
+
try { plan = fs.readFileSync('plan.txt', 'utf8'); } catch { plan = 'Plan failed to execute'; }
|
|
92
|
+
|
|
93
|
+
const maxLen = 60000;
|
|
94
|
+
const truncate = (s) => s.length > maxLen ? s.substring(0, maxLen) + '\n... (truncated)' : s;
|
|
95
|
+
|
|
96
|
+
const body = `## Terraform Plan Results (\`{{env}}\`)
|
|
97
|
+
<details><summary>Show Plan</summary>
|
|
98
|
+
|
|
99
|
+
\`\`\`
|
|
100
|
+
${truncate(plan)}
|
|
101
|
+
\`\`\`
|
|
102
|
+
|
|
103
|
+
</details>`;
|
|
104
|
+
|
|
105
|
+
const comments = await github.rest.issues.listComments({
|
|
106
|
+
issue_number: context.issue.number,
|
|
107
|
+
owner: context.repo.owner,
|
|
108
|
+
repo: context.repo.repo,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const botComment = comments.data.find(c =>
|
|
112
|
+
c.user.type === 'Bot' && c.body.includes('## Terraform Plan Results')
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
if (botComment) {
|
|
116
|
+
await github.rest.issues.updateComment({
|
|
117
|
+
owner: context.repo.owner,
|
|
118
|
+
repo: context.repo.repo,
|
|
119
|
+
comment_id: botComment.id,
|
|
120
|
+
body: body,
|
|
121
|
+
});
|
|
122
|
+
} else {
|
|
123
|
+
await github.rest.issues.createComment({
|
|
124
|
+
issue_number: context.issue.number,
|
|
125
|
+
owner: context.repo.owner,
|
|
126
|
+
repo: context.repo.repo,
|
|
127
|
+
body: body,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
- name: Check Plan Status
|
|
132
|
+
if: steps.plan.outcome == 'failure'
|
|
133
|
+
run: exit 1
|
|
134
|
+
|
|
135
|
+
terraform-iam-notice:
|
|
136
|
+
needs: changes
|
|
137
|
+
if: |
|
|
138
|
+
github.event_name == 'pull_request' &&
|
|
139
|
+
needs.changes.outputs.terraform-iam == 'true' &&
|
|
140
|
+
needs.changes.outputs.terraform != 'true'
|
|
141
|
+
runs-on: ubuntu-latest
|
|
142
|
+
permissions:
|
|
143
|
+
pull-requests: write
|
|
144
|
+
steps:
|
|
145
|
+
- name: Comment IAM notice
|
|
146
|
+
uses: actions/github-script@v7
|
|
147
|
+
with:
|
|
148
|
+
script: |
|
|
149
|
+
const body = '## Terraform IAM Notice (`{{env}}-iam`)\n\n' +
|
|
150
|
+
'`{{env}}-iam` ディレクトリに変更が検出されました。' +
|
|
151
|
+
'IAM 変更は自動 plan/apply の対象外です。手動で適用してください。\n\n' +
|
|
152
|
+
'```bash\ncd terraform/godd-notes/{{env}}-iam\nterraform init\nterraform plan\nterraform apply\n```';
|
|
153
|
+
|
|
154
|
+
await github.rest.issues.createComment({
|
|
155
|
+
issue_number: context.issue.number,
|
|
156
|
+
owner: context.repo.owner,
|
|
157
|
+
repo: context.repo.repo,
|
|
158
|
+
body: body,
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
terraform-apply:
|
|
162
|
+
needs: changes
|
|
163
|
+
if: |
|
|
164
|
+
github.event_name == 'push' &&
|
|
165
|
+
needs.changes.outputs.terraform == 'true'
|
|
166
|
+
runs-on: ubuntu-latest
|
|
167
|
+
environment: {{env}}
|
|
168
|
+
concurrency:
|
|
169
|
+
group: terraform-{{env}}
|
|
170
|
+
cancel-in-progress: false
|
|
171
|
+
steps:
|
|
172
|
+
- uses: actions/checkout@v7
|
|
173
|
+
|
|
174
|
+
- name: Configure AWS credentials
|
|
175
|
+
uses: aws-actions/configure-aws-credentials@v6
|
|
176
|
+
with:
|
|
177
|
+
role-to-assume: arn:aws:iam::{{accountId}}:role/github-actions-{{env}}
|
|
178
|
+
aws-region: {{region}}
|
|
179
|
+
|
|
180
|
+
- name: Setup Terraform
|
|
181
|
+
uses: hashicorp/setup-terraform@v3
|
|
182
|
+
with:
|
|
183
|
+
terraform_wrapper: false
|
|
184
|
+
|
|
185
|
+
- name: Terraform init
|
|
186
|
+
working-directory: terraform/godd-notes/{{env}}
|
|
187
|
+
run: terraform init -input=false
|
|
188
|
+
|
|
189
|
+
- name: Verify Terraform state is present
|
|
190
|
+
working-directory: terraform/godd-notes/{{env}}
|
|
191
|
+
shell: bash
|
|
192
|
+
run: |
|
|
193
|
+
set -euo pipefail
|
|
194
|
+
state_file=$(mktemp)
|
|
195
|
+
trap 'rm -f "$state_file"' EXIT
|
|
196
|
+
|
|
197
|
+
# 初回構築(空 state からの apply)は手動セットアップ手順で行う。
|
|
198
|
+
# この workflow は既存環境の更新だけを扱い、state 欠落時は fail-closed にする。
|
|
199
|
+
# A missing/empty state is dangerous for an existing stack: Terraform
|
|
200
|
+
# would plan already-managed resources as new and may fail or replace
|
|
201
|
+
# them. Stop before apply and recover the backend with the documented
|
|
202
|
+
# `terraform init -migrate-state` procedure instead.
|
|
203
|
+
if ! terraform state pull >"$state_file"; then
|
|
204
|
+
echo "::error::Terraform state を取得できません。backend の bucket/key を確認し、移行時は terraform init -migrate-state を使用してください。"
|
|
205
|
+
exit 1
|
|
206
|
+
fi
|
|
207
|
+
if ! jq -e '
|
|
208
|
+
type == "object" and
|
|
209
|
+
(.version | type == "number") and
|
|
210
|
+
(.serial | type == "number") and
|
|
211
|
+
(.lineage | type == "string" and length > 0) and
|
|
212
|
+
(.resources | type == "array" and length > 0)
|
|
213
|
+
' "$state_file" >/dev/null; then
|
|
214
|
+
echo "::error::Terraform state が空または不正です。apply を中止しました。バックアップを確認し、terraform init -migrate-state で正しい state を再接続してください。"
|
|
215
|
+
exit 1
|
|
216
|
+
fi
|
|
217
|
+
|
|
218
|
+
- name: Terraform Apply
|
|
219
|
+
working-directory: terraform/godd-notes/{{env}}
|
|
220
|
+
run: terraform apply -input=false -auto-approve -lock-timeout=5m
|
|
221
|
+
|
|
222
|
+
deploy-api:
|
|
223
|
+
needs: [changes, terraform-apply]
|
|
224
|
+
if: |
|
|
225
|
+
always() &&
|
|
226
|
+
github.event_name != 'pull_request' &&
|
|
227
|
+
needs.changes.outputs.api == 'true' &&
|
|
228
|
+
(needs.terraform-apply.result == 'success' || needs.terraform-apply.result == 'skipped')
|
|
44
229
|
runs-on: ubuntu-latest
|
|
45
230
|
steps:
|
|
46
231
|
- uses: actions/checkout@v7
|
|
@@ -55,9 +240,6 @@ jobs:
|
|
|
55
240
|
id: ecr-login
|
|
56
241
|
uses: aws-actions/amazon-ecr-login@v2
|
|
57
242
|
|
|
58
|
-
# ECS タスクは ARM64(Graviton)。x86_64 ランナー上で arm64 イメージを
|
|
59
|
-
# クロスビルドするため buildx + QEMU を用いる(QEMU 無しだと最初の RUN で
|
|
60
|
-
# `exec /bin/sh: exec format error` になる)。
|
|
61
243
|
- name: Set up Docker Buildx
|
|
62
244
|
uses: docker/setup-buildx-action@v4
|
|
63
245
|
|
|
@@ -121,8 +303,12 @@ jobs:
|
|
|
121
303
|
--services $ECS_SERVICE
|
|
122
304
|
|
|
123
305
|
deploy-app:
|
|
124
|
-
needs: changes
|
|
125
|
-
if:
|
|
306
|
+
needs: [changes, terraform-apply]
|
|
307
|
+
if: |
|
|
308
|
+
always() &&
|
|
309
|
+
github.event_name != 'pull_request' &&
|
|
310
|
+
needs.changes.outputs.app == 'true' &&
|
|
311
|
+
(needs.terraform-apply.result == 'success' || needs.terraform-apply.result == 'skipped')
|
|
126
312
|
runs-on: ubuntu-latest
|
|
127
313
|
steps:
|
|
128
314
|
- uses: actions/checkout@v7
|
|
@@ -153,9 +339,6 @@ jobs:
|
|
|
153
339
|
working-directory: notes-app
|
|
154
340
|
run: aws s3 sync dist/ s3://$S3_BUCKET --delete
|
|
155
341
|
|
|
156
|
-
# CLOUDFRONT_DISTRIBUTION_ID secret 未登録だと空文字が --distribution-id に渡り
|
|
157
|
-
# exit 252 でジョブ全体が失敗する(#1097)。未登録時は warning を出してスキップし、
|
|
158
|
-
# S3 デプロイ自体は成功扱いにする(CDN キャッシュは TTL 失効まで旧コンテンツが残る)。
|
|
159
342
|
- name: Invalidate CloudFront
|
|
160
343
|
run: |
|
|
161
344
|
if [ -z "$CLOUDFRONT_DISTRIBUTION_ID" ]; then
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
> 本ドキュメントは `docs/001_project/README.md` の **テンプレート(プレースホルダー版)** です。
|
|
4
4
|
> `[ ]` で囲まれたプレースホルダーを自プロジェクトの内容に置き換えて利用してください。
|
|
5
|
-
> 書き起こし例として [`ripla-inc/saas-box-manage`](https://github.com/ripla-inc/saas-box-manage) の `saas-box-docs/001_project/` も併せて参照してください。
|
|
6
5
|
|
|
7
6
|
---
|
|
8
7
|
|
|
@@ -54,7 +53,6 @@ graph LR
|
|
|
54
53
|
| RDB | [MySQL / PostgreSQL 等] | [Amazon RDS / Aurora 等] |
|
|
55
54
|
| _(任意)_ LLM/AI 基盤 | [Python / FastAPI + ベクトル DB 等] | [ECS Fargate + EFS 等] |
|
|
56
55
|
|
|
57
|
-
> 技術スタックの埋め方は [`saas-box-manage` の `saas-box-docs/007_development/stacks.md`](https://github.com/ripla-inc/saas-box-manage/blob/main/saas-box-docs/007_development/stacks.md) を参照してください。
|
|
58
56
|
|
|
59
57
|
---
|
|
60
58
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# 002_business_flow — ビジネスフロー
|
|
2
|
+
|
|
3
|
+
> 本ドキュメントは `docs/002_business_flow/README.md` の **テンプレート(プレースホルダー版)** です。
|
|
4
|
+
> `[ ]` で囲まれたプレースホルダーを自プロジェクトの内容に置き換えて利用してください。
|
|
5
|
+
|
|
6
|
+
本ディレクトリは、プロダクトが対象とする **業務(ビジネス)フロー** を業務単位で整理する場所です。1 業務 = 1 ファイル(`<business_flow_name>.md`、必要に応じて同名の `.drawio`)で管理します。
|
|
7
|
+
|
|
8
|
+
## ファイル構成
|
|
9
|
+
|
|
10
|
+
| ファイル | 内容 |
|
|
11
|
+
|---|---|
|
|
12
|
+
| `<business_flow_name>.md` | 特定業務のビジネスフローの解説(登場ロール・手順・分岐・例外) |
|
|
13
|
+
| `<business_flow_name>.drawio` | 同業務のフロー図(GoDD Notes で閲覧・編集可能) |
|
|
14
|
+
|
|
15
|
+
## ビジネスフロー一覧
|
|
16
|
+
|
|
17
|
+
| # | 業務名 | ファイル | 概要 |
|
|
18
|
+
|---|---|---|---|
|
|
19
|
+
| 1 | [業務名] | [business_flow_name].md | [3〜5 行で業務の概要] |
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# 003_requirements — 機能要件
|
|
2
|
+
|
|
3
|
+
> 本ドキュメントは `docs/003_requirements/README.md` の **テンプレート(プレースホルダー版)** です。
|
|
4
|
+
> `[ ]` で囲まれたプレースホルダーを自プロジェクトの内容に置き換えて利用してください。
|
|
5
|
+
|
|
6
|
+
本ディレクトリは、**機能要件(Feature 単位の要件定義)** を整理する場所です。画面・機能の一覧は `docs/001_project/pages.csv` / `features.csv` が SSOT で、本ディレクトリはその各機能を詳細化します。
|
|
7
|
+
|
|
8
|
+
## 構成ルール
|
|
9
|
+
|
|
10
|
+
| パス | 内容 |
|
|
11
|
+
|---|---|
|
|
12
|
+
| `<Product Name>/<feature_name>.md` | 機能別の要件定義(管理画面・ユーザー向け画面などプロダクトごとにフォルダを分ける) |
|
|
13
|
+
| `spec/` | 仕様 SSOT(API 仕様・インフラ仕様・言語仕様等)。実装と常に同期させる |
|
|
14
|
+
| `questions.csv` | 未回答の質問リスト(`unanswered → answered → spec_reflected` のライフサイクルで管理) |
|
|
15
|
+
|
|
16
|
+
## requirements 一覧
|
|
17
|
+
|
|
18
|
+
| # | プロダクト | 機能 | ファイル | ステータス |
|
|
19
|
+
|---|---|---|---|---|
|
|
20
|
+
| 1 | [プロダクト名] | [機能名] | [Product Name]/[feature_name].md | [draft / fixed] |
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
id,status,question,context,answer,owner,created_at,resolved_at,spec_ref,related_job_id,category
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# spec — 仕様 SSOT
|
|
2
|
+
|
|
3
|
+
> 本ドキュメントは `docs/003_requirements/spec/README.md` の **テンプレート** です。
|
|
4
|
+
|
|
5
|
+
本ディレクトリは、プロダクトの **仕様 SSOT(Single Source of Truth)** です。API 仕様・インフラ仕様・言語仕様など、実装の根拠となる仕様書をここに置きます。
|
|
6
|
+
|
|
7
|
+
## 運用ルール
|
|
8
|
+
|
|
9
|
+
- 挙動を変更したら、**同じ PR で** 本ディレクトリの該当仕様書を更新する(仕様書の更新漏れは不具合として扱う)
|
|
10
|
+
- 仕様と実装が矛盾したときは、どちらが正か確認してから両方を揃える(推測で実装しない)
|
|
11
|
+
- 1 仕様領域 = 1 ファイルを基本とし、肥大化したら分割する
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# 004_pages — 画面設計
|
|
2
|
+
|
|
3
|
+
> 本ドキュメントは `docs/004_pages/README.md` の **テンプレート** です。
|
|
4
|
+
|
|
5
|
+
本ディレクトリは、**画面ごとの画面要件** を URL パス単位で整理する場所です。画面の URL 構造がそのままフォルダ構造になるよう、フロントエンドの `app/` ディレクトリ構成を模したフォルダを配置します。
|
|
6
|
+
|
|
7
|
+
## 構成ルール
|
|
8
|
+
|
|
9
|
+
- `app/` 配下に、画面の URL パスに対応するフォルダを作成する(例: `/admin/corporations` → `app/admin/corporations/`)
|
|
10
|
+
- 各フォルダに `requirements.md`(その画面の画面要件)を置く
|
|
11
|
+
- 画面一覧・画面 ID は `docs/001_project/pages.csv` が SSOT。本ディレクトリの各ファイルは画面 ID と対応させる
|
|
12
|
+
|
|
13
|
+
## 例
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
docs/004_pages/
|
|
17
|
+
└── app/
|
|
18
|
+
├── admin/
|
|
19
|
+
│ └── corporations/
|
|
20
|
+
│ └── requirements.md # 管理画面: 法人管理の画面要件
|
|
21
|
+
└── users/
|
|
22
|
+
```
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# 005_architecture — 設計
|
|
2
|
+
|
|
3
|
+
> 本ドキュメントは `docs/005_architecture/README.md` の **テンプレート** です。
|
|
4
|
+
|
|
5
|
+
本ディレクトリは、開発をするにあたっての **実際の設計**(インフラ・DB・API・各機能の設計)を整理する場所です。要件(`003_requirements/`)が「何を作るか」を定めるのに対し、ここは「どう作るか」を定めます。
|
|
6
|
+
|
|
7
|
+
## フォルダ構成
|
|
8
|
+
|
|
9
|
+
| フォルダ | 内容 |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `stacks/` | 技術スタック(言語・フレームワーク・ライブラリとバージョン) |
|
|
12
|
+
| `api/` | API 設計(Swagger / OpenAPI 等) |
|
|
13
|
+
| `db/` | DB 設計(ER 図・テーブル定義等) |
|
|
14
|
+
| `infra/` | インフラアーキテクチャの設計 |
|
|
15
|
+
| `features/` | 各機能の設計(機能設計書・データフロー・DB 設計) |
|
|
16
|
+
|
|
17
|
+
## 記述ルール
|
|
18
|
+
|
|
19
|
+
- 1 機能 = 1 ファイル(`features/<feature_name>.md`)で管理する
|
|
20
|
+
- 実装と設計が乖離したら、設計書側を必ず更新する(設計書は SSOT の一部)
|