@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.
Files changed (92) hide show
  1. package/README.md +457 -85
  2. package/dist/godd.cjs +293 -244
  3. package/dist/godd.js +1005 -321
  4. package/dist/index.js +148 -119
  5. package/notes/app/DESIGN.md +5 -2
  6. package/notes/app/e2e/fixtures.ts +39 -0
  7. package/notes/app/e2e/ja-typography-visual.spec.ts +185 -0
  8. package/notes/app/e2e/ja-typography-visual.spec.ts-snapshots/ja-typography-desktop-1280-chromium-linux.png +0 -0
  9. package/notes/app/e2e/ja-typography-visual.spec.ts-snapshots/ja-typography-mobile-360-chromium-linux.png +0 -0
  10. package/notes/app/e2e/rtl-logical-properties.spec.ts +36 -0
  11. package/notes/app/package-lock.json +0 -8
  12. package/notes/app/package.json +0 -1
  13. package/notes/app/playwright.config.ts +7 -0
  14. package/notes/app/pnpm-lock.yaml +0 -8
  15. package/notes/app/src/components/BranchSelectorModal.tsx +8 -8
  16. package/notes/app/src/components/CommentPanel.tsx +5 -5
  17. package/notes/app/src/components/DiffPreview.tsx +4 -4
  18. package/notes/app/src/components/FileContentView.tsx +1 -1
  19. package/notes/app/src/components/FileContextMenu.tsx +1 -1
  20. package/notes/app/src/components/FileInfoPanel.branch-tab.test.tsx +3 -35
  21. package/notes/app/src/components/IssueCommentThread.test.tsx +40 -19
  22. package/notes/app/src/components/IssueDetailView.test.tsx +3 -40
  23. package/notes/app/src/components/IssueList.tsx +3 -3
  24. package/notes/app/src/components/LabelSelector.tsx +1 -1
  25. package/notes/app/src/components/MarkdownEditor.tsx +1 -1
  26. package/notes/app/src/components/Skeleton.tsx +2 -2
  27. package/notes/app/src/components/ToastContainer.tsx +1 -1
  28. package/notes/app/src/components/TreeNode.tsx +6 -6
  29. package/notes/app/src/contexts/ToastContext.tsx +1 -1
  30. package/notes/app/src/hooks/useComments.ts +1 -1
  31. package/notes/app/src/hooks/useEditSession.ts +1 -1
  32. package/notes/app/src/lib/api.ts +1 -13
  33. package/notes/app/src/lib/csv-utils.ts +1 -1
  34. package/notes/app/src/lib/postLoginRedirect.ts +1 -1
  35. package/notes/app/src/lib/rtl-logical-properties.test.ts +59 -0
  36. package/notes/app/src/lib/user-colors.ts +1 -1
  37. package/notes/app/src/pages/MainPage.tsx +2 -2
  38. package/notes/app/src/pages/SettingsPage.test.tsx +40 -10
  39. package/notes/app/src/pages/SettingsPage.tsx +1 -1
  40. package/notes/app/src/pages/UserManagementPage.tsx +7 -7
  41. package/notes/app/src/styles/globals.css +17 -0
  42. package/notes/app/src/test/mockPeriodicSync.ts +68 -0
  43. package/notes/app/src/test/mocks.ts +1 -1
  44. package/package.json +7 -3
  45. package/templates/feedback/feedback-lambda/index.mjs +342 -0
  46. package/templates/feedback/frontend/FeedbackWidget.tsx +574 -0
  47. package/templates/feedback/frontend/api.ts +38 -0
  48. package/templates/feedback/frontend/composePinImage.ts +80 -0
  49. package/templates/feedback/frontend/config.ts +14 -0
  50. package/templates/feedback/frontend/types.ts +41 -0
  51. package/templates/feedback/terraform/Makefile +43 -0
  52. package/templates/feedback/terraform/backend.tf +10 -0
  53. package/templates/feedback/terraform/lambda.tf +95 -0
  54. package/templates/feedback/terraform/local.tf +12 -0
  55. package/templates/feedback/terraform/output.tf +9 -0
  56. package/templates/feedback/terraform/provider.tf +24 -0
  57. package/templates/feedback/terraform/variables.tf +25 -0
  58. package/templates/github-actions/aws/deploy-notes.yml.hbs +193 -10
  59. package/templates/notes-docs/001_project/README.md +0 -2
  60. package/templates/notes-docs/002_business_flow/README.md +19 -0
  61. package/templates/notes-docs/003_requirements/README.md +20 -0
  62. package/templates/notes-docs/003_requirements/questions.csv +1 -0
  63. package/templates/notes-docs/003_requirements/spec/README.md +11 -0
  64. package/templates/notes-docs/004_pages/README.md +22 -0
  65. package/templates/notes-docs/005_architecture/README.md +20 -0
  66. package/templates/notes-docs/006_development_workflow/README.md +67 -0
  67. package/templates/notes-docs/006_development_workflow/daily_flow.template.md +303 -0
  68. package/templates/notes-docs/006_development_workflow/git.template.md +72 -20
  69. package/templates/notes-docs/006_development_workflow/judgment.template.md +182 -0
  70. package/templates/notes-docs/006_development_workflow/workflow.template.md +167 -192
  71. package/templates/notes-docs/007_guides/README.md +85 -0
  72. package/templates/notes-docs/007_guides/bot-token-setup.md +174 -0
  73. package/templates/notes-docs/007_guides/getting_started.md +112 -0
  74. package/templates/notes-docs/007_guides/glossary.md +145 -0
  75. package/templates/notes-docs/007_guides/godd_notes_features.md +105 -0
  76. package/templates/notes-docs/007_guides/godd_notes_usage.md +28 -19
  77. package/templates/notes-docs/007_guides/godd_tools.md +129 -0
  78. package/templates/notes-docs/007_guides/godd_usage.md +88 -95
  79. package/templates/notes-docs/007_guides/infra/README.md +57 -0
  80. package/templates/notes-docs/007_guides/{setup_aws_accounts.md → infra/setup_aws_accounts.md} +3 -2
  81. package/templates/notes-docs/007_guides/{setup_infra.template.md → infra/setup_infra.template.md} +15 -4
  82. package/templates/notes-docs/007_guides/setup_godd.md +66 -23
  83. package/templates/notes-docs/007_guides/setup_godd_notes.md +95 -42
  84. package/templates/notes-docs/007_guides/setup_godd_notes.md.styles.json +2 -2
  85. package/templates/notes-docs/007_guides/setup_local_environment.template.md +81 -20
  86. package/templates/notes-docs/007_guides/troubleshooting.md +225 -0
  87. package/templates/notes-docs/999_ref/README.md +23 -0
  88. package/templates/notes-docs/GENERATED.md +1 -1
  89. package/templates/notes-docs/README.md +64 -34
  90. package/templates/terraform/aws/iam.tf.hbs +361 -4
  91. /package/templates/notes-docs/007_guides/{setup_aws_cost_alert.md → infra/setup_aws_cost_alert.md} +0 -0
  92. /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,10 @@
1
+ terraform {
2
+ backend "s3" {
3
+ # GoDD Notes インフラ導入時に作成される tfstate バケットを共用する
4
+ bucket = "godd-notes-tfstate-{{ACCOUNT_ID}}"
5
+ key = "feedback/{{ENV}}/terraform.tfstate"
6
+ region = "{{AWS_REGION}}"
7
+ encrypt = true
8
+ use_lockfile = true
9
+ }
10
+ }
@@ -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
- deploy-api:
52
+ terraform-plan:
42
53
  needs: changes
43
- if: needs.changes.outputs.api == 'true'
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: needs.changes.outputs.app == 'true'
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 の一部)