diff --git a/docs/decisions/0015-manual-html-not-pdf.md b/docs/decisions/0015-manual-html-not-pdf.md new file mode 100644 index 00000000..fa072e04 --- /dev/null +++ b/docs/decisions/0015-manual-html-not-pdf.md @@ -0,0 +1,44 @@ +# 0015: 解説マニュアル(生成した HTML)は PDF にせず、HTML のまま配信する + +- 状態:見送り +- 決めた日:2026-05-31(PM の作業メモ) +- 決めた人:45th の PM +- 決定の信頼度:記録なし + - 根拠:出典の PM の作業メモ(2026-05-31 の検討)を読んだ。決めたことと、見直す条件(印刷用に中身を固定した版が要るとき)は書かれているが、どれだけ確かだと思っていたかは書かれていない +- 出典:45th の PM の作業メモ(公開していない) + +## 背景 + +45th では、各局のマニュアル(Google ドキュメント)を、AI でスマホ向けの HTML に変換して配った(解説マニュアル)。HTML には画像を埋め込み、1ファイルで開けるようにしてある。 + +2026-05-31 に、この HTML を配るときに PDF にするかを検討した。 + +## 候補 + +| 候補 | 良い点 | 悪い点 | +| --- | --- | --- | +| 軽い変換ツール(Chromium を使わないもの)で PDF にする | 速い。PM の作業メモでは、実物の HTML 2本を変換して、4.6MB の HTML が 3.7 秒で 7.9MB の PDF になった | 目次のページ内リンクや電話番号のリンクが PDF に残らなかった(PM の作業メモ) | +| Chromium を使うツールで PDF にする | リンクは残せる | 軽さが無くなる。HTML の動く部分は、どのツールでも失われる | +| PDF にせず、HTML のまま配る | HTML の動く部分がそのまま使える | 印刷や、中身を固定した版が欲しいときには向かない | + +## 決定 + +解説マニュアルは PDF にせず、HTML のまま配る。 + +印刷用に中身を固定した版と、章へ飛ぶリンクだけが欲しい、という要望が出たときに限り、Chromium を使うツールでの PDF 化を考え直す。 + +## 理由 + +解説マニュアルの HTML には、PDF では動かない部分がある。画像を拡大表示する機能、画面の端に出る目次のボタン、章ごとの折りたたみである。PDF にすると、これらがすべて使えなくなる。 + +## 前提 + +- HTML の動く部分は、生成に使うプロンプトで指定している:`.claude/manual-prompt-card-strict.md`(画像の拡大は `openLightbox`、目次のボタンは `toggleTocOverlay`、章の折りたたみは `
`) +- 配信は `api/lib/internals/controller/manual_controller.go#manualController.ShowManual`([0006](0006-manual-serving-google-gate.md)) +- 簡易マニュアル(Google ドキュメントやスライドをそのまま使うもの)を PDF にするのは、この判断と別の話である。元が動かない文書なので、PDF にしても失うものが無い([0016](0016-simple-manual-pdf-on-drive.md)) + +## 結果 + +45th の技大祭は、解説マニュアルを HTML のまま配った。 + +## 追記 diff --git a/docs/decisions/0016-simple-manual-pdf-on-drive.md b/docs/decisions/0016-simple-manual-pdf-on-drive.md new file mode 100644 index 00000000..aaa3d41b --- /dev/null +++ b/docs/decisions/0016-simple-manual-pdf-on-drive.md @@ -0,0 +1,51 @@ +# 0016: 簡易マニュアルは PDF にして Drive に置き、アプリからそこへ移動させる + +- 状態:採用 +- 決めた日:2026-08-23(アプリへの埋め込みを検証した日。PM の作業メモ)。対象を広げたのは 2026-09-12(#248 を閉じた日) +- 決めた人:45th の PM +- 決定の信頼度:記録なし + - 根拠:#248・PR #521 には、決めたことと置き方は書かれているが、どれだけ確かだと思っていたかは書かれていない +- 出典:#248、PR #521 + +## 背景 + +45th のマニュアルのうち、AI で HTML に変換しないもの(簡易マニュアル)は、各局が作った Google ドキュメントやスライドのままだった。スマホで Google ドキュメントを直接開くと、表や図の配置が崩れて読みにくかった。 + +マニュアルには、部門長や局長の電話番号と名前が書いてあるものがあり、技大祭の関係者だけが読めるようにしたかった(PM の作業メモ)。 + +## 候補 + +| 候補 | 良い点 | 悪い点 | +| --- | --- | --- | +| アプリの中に埋め込んで表示する(#248) | アプリから出ずに読める | Google のログイン画面が、別のサイトの中への埋め込みを拒む。別のサイトの Cookie も遮られる。そのため、読める人を nutfes の Google アカウントに絞ることと両立しない(2026-08-23 に確かめた) | +| PDF にして SeeFT のサーバーに置く | 置くのが簡単 | 8/23 の時点では、SeeFT のサーバーに、読める人を絞って配る仕組みがまだ無かった(ログインで絞る仕組みが入ったのは 8/25。[0006](0006-manual-serving-google-gate.md)) | +| PDF にして技大祭の Drive のフォルダに置き、アプリからそこへ移動させる | 崩れずに読める。フォルダの共有の設定で、読める人を nutfes の Google アカウントに絞れる | アプリから Drive に移動する | + +## 決定 + +簡易マニュアルは、元のドキュメントを PDF にして、技大祭の Drive のフォルダに置く。アプリのボタンからは、その PDF に移動する。読める人は、フォルダの共有の設定で絞る。 + +2026-09-12 に、対象を広げた。マニュアルの割り当て表にあるものは、タスクに紐づくかどうかに関係なく、すべて Drive に置き、マニュアル一覧からたどれるようにする。アプリの中で PDF を表示する issue(#248)は、この日に「予定しない」として閉じた。 + +置き方は、マニュアルの割り当て表に付いた GAS で行う(PR #521)。 + +- ファイル名は、割り当て表の「マニュアル名」を使う。元のドキュメントのタイトルは、局ごとに付け方がばらばらだった +- スプレッドシートや、もともと PDF のものは、コピーせずにショートカットを置く。コピーすると、元を直しても反映されない +- 出し直すときは、同じファイル ID のまま中身だけを差し替える。ファイルが変わると URL が変わり、対応表・DB・アプリのボタンの3か所を直す必要がある +- 置き先の局のフォルダに同じ名前のファイルがすでにあれば、その行はエラーにして置かない + +## 理由 + +崩れずに読めることと、読める人を絞ることを、両方満たせたのが Drive に置く案だけだった。埋め込みはログインと両立せず、SeeFT のサーバーには、当時は読める人を絞って配る仕組みが無かった。 + +## 前提 + +- 置き方の GAS:`gas/manual-assignment/PDF配置.js#place_`、出し直しは `gas/manual-assignment/PDF配置.js#refreshPdfs`、同じ名前の確認は `gas/manual-assignment/PDF配置.js#flagExistingNames_`、ショートカットにする種類は `gas/manual-assignment/PDF配置.js#PLACE_SHORTCUT`、対象にする状態は `gas/manual-assignment/PDF配置.js#TARGET_STATUSES` +- nutfes の Google アカウントは全員 @gmail.com で、Google Workspace の共有ドライブは無い。フォルダは、技大祭で使っている Google アカウントのマイドライブを共有したものである +- 解説マニュアル(生成した HTML)は PDF にしない([0015](0015-manual-html-not-pdf.md))。簡易マニュアルは元が動かない文書なので、PDF にしても失うものが無い + +## 結果 + +45th の技大祭では、簡易マニュアルをこの形で配った。 + +## 追記 diff --git a/docs/decisions/0017-manual-ops-not-automated.md b/docs/decisions/0017-manual-ops-not-automated.md new file mode 100644 index 00000000..c82038cc --- /dev/null +++ b/docs/decisions/0017-manual-ops-not-automated.md @@ -0,0 +1,49 @@ +# 0017: マニュアル運用のスプレッドシートの操作は自動化しない + +- 状態:見送り +- 決めた日:2026-06-18(状態の監視。手順書 `docs/proposals/manual-slide-operations.md` を足したコミット 0f4c921 の日付)、2026-08-31(対応表への記入。PR #487 をマージした日) +- 決めた人:45th の PM +- 決定の信頼度:記録なし + - 根拠:`docs/proposals/manual-slide-operations.md`・`docs/proposals/manual-proposal-v4-slides/automation-design.md`・#486・PR #487 には、決めたことと理由、見直す条件(状態の管理を自動化したくなったとき)は書かれているが、どれだけ確かだと思っていたかは書かれていない +- 出典:`docs/proposals/manual-slide-operations.md`、`docs/proposals/manual-proposal-v4-slides/automation-design.md`、#486、PR #487 + +## 背景 + +解説マニュアルを作って配るまでには、生成・確認・部門長のチェック・アップロード・タスクへの紐付けと、いくつもの手作業がある。 + +2026 年 5 月に、この流れをスプレッドシートで管理する自動化を設計し、コードも書いた。スプレッドシートの行を常に監視し、状態が変わったら次の作業を進める仕組みである(`scripts/automation/` の watcher・sheets_client・drive_client)。 + +8 月には、手順を文書にして誰でも作業できるようにしたが、マニュアル1本を配るのに手作業が 10 手かかるのは変わっていなかった(#486)。 + +## 候補 + +| 候補 | 良い点 | 悪い点 | +| --- | --- | --- | +| スプレッドシートを軸に、状態の監視から対応表への記入まで自動化する | 手作業が減る | 部門長にスプレッドシートを開いてもらう必要がある。常に監視する仕組みは重い。Google の API を使うための設定(GCP のプロジェクトと認証情報)が、作業する人ごとに要る | +| 状態の管理は Slack のスレッドで行い、手作業を減らせるところだけコマンドにする | 部門長は Slack だけ見ればよい。新しく入った人も、設定なしで作業を始められる | 対応表への記入とタスクの送信は、手作業のまま残る | + +## 決定 + +マニュアル運用のスプレッドシートの操作は、自動化しない。 + +- 2026-06-18:本番は、Slack のスレッドを中心にした手作業の流れで運用する。状態の監視の自動化は、コードを残したまま保留にする(`docs/proposals/manual-slide-operations.md`) +- 2026-08-31:手作業を 10 手から 7 手に減らした(PR #487)。残る7手のうち、対応表への記入とタスクの送信の2手は自動化しない + +## 理由 + +状態の監視を保留にしたのは、部門長にスプレッドシートを開かせずに済ませたかったからである。状態の管理は SeeFT の仕事にして、部門長は Slack のスレッドだけを見れば済む形にした。常に監視する仕組みは、ほぼ1人の運用には重すぎた。 + +対応表への記入を自動化しなかったのは、Google の API を使うと、作業する人ごとに GCP のプロジェクトや認証情報の設定が要るからである。PR #487 では、「新しく入った人が最初の1本を出すまでの時間」で比べると、自動化すると逆に遅くなると判断した。 + +## 前提 + +- 保留にした自動化のコード:`scripts/automation/watcher.py`、`scripts/automation/sheets_client.py`、`scripts/automation/drive_client.py`。今の運用では使っていない +- 設計:`docs/proposals/manual-proposal-v4-slides/automation-design.md` +- 今の運用の手順:`docs/proposals/manual-slide-operations.md`、`docs/development/manual-html-operations.md` +- ほぼ1人で運用していること。担当する人が増えて、状態の管理が Slack で追いきれなくなったら、自動化を考え直す + +## 結果 + +45th は、Slack のスレッドを中心にした手作業の流れで、マニュアルを配った。 + +## 追記 diff --git a/docs/decisions/0018-test-mock-with-sqlmock.md b/docs/decisions/0018-test-mock-with-sqlmock.md new file mode 100644 index 00000000..055f6aa9 --- /dev/null +++ b/docs/decisions/0018-test-mock-with-sqlmock.md @@ -0,0 +1,42 @@ +# 0018: テストでは db.Client に go-sqlmock の偽の DB を差し込み、repository の戻り値は変えない + +- 状態:採用 +- 決めた日:2026-07-07(PR #392 をマージした日) +- 決めた人:45th の PM +- 決定の信頼度:記録なし + - 根拠:#391・PR #392・`docs/development/test-roadmap.md` には、決めたことと、案 B を選ばなかった理由は書かれているが、どれだけ確かだと思っていたかは書かれていない +- 出典:#391、PR #392、`docs/development/test-roadmap.md`(「前提: コード構造がテスト戦略を規定する」) + +## 背景 + +2026-07-06 の MT で、SeeFT 本体は保守性を上げる方向に決まり、直す前にテストを書くことになった([0003](0003-maintenance-over-features.md))。 + +api の repository は、ほとんどが `database/sql` の `*sql.Rows` や `*sql.Row` を返し、値の読み取り(Scan)は usecase の側で行う作りになっている。`*sql.Row` はテストのコードから作れない。そのため、repository のインターフェースを偽物に差し替えても、usecase のテストが書けなかった。 + +## 候補 + +| 候補 | 良い点 | 悪い点 | +| --- | --- | --- | +| A:DB への接続(`db.Client`)に、go-sqlmock の偽の `*sql.DB` を差し込む | 今のコードを直さなくてよい。repository の実装ごとテストできる | テストに SQL の文字列を書く必要がある | +| B:repository の戻り値を entity に変える | テストが書きやすくなる | 141 のメソッドに手を入れる大きな作業になる | + +## 決定 + +案 A をとる。テストでは、`db.Client` に go-sqlmock の偽の `*sql.DB` を差し込む。repository の戻り値は変えない。 + +## 理由 + +案 B は、141 のメソッドに手を入れる大きな作業で、保守に寄せる方針([0003](0003-maintenance-over-features.md))で手を付けられる大きさを超えていた。案 A なら、今のコードを変えずにテストを書き始められる。 + +## 前提 + +- 差し込む先のインターフェース:`api/lib/externals/db/db.go#Client` +- テストで使う偽物:`api/lib/internals/repository/sqlmock_helper_test.go#fakeDBClient` +- テストの進め方:`docs/development/test-roadmap.md` +- repository が `*sql.Rows` や `*sql.Row` を返す作りであること。戻り値を entity に変える作業をするなら、この ADR を見直す + +## 結果 + +2026-09-30 の時点で、`api/` のテストのファイルは 18 本ある。そのうち 9 本が go-sqlmock を使うテストで(ファイル名が `_sqlmock_test.go` のもの。repository と usecase の両方)、ほかに偽物を作る補助のファイルが1本ある。 + +## 追記 diff --git a/docs/decisions/README.md b/docs/decisions/README.md index a10a8a14..4b48d51a 100644 --- a/docs/decisions/README.md +++ b/docs/decisions/README.md @@ -114,3 +114,7 @@ python3 scripts/refcheck/refcheck.py docs/decisions/*.md | [0012](0012-slack-id-linked-by-gas.md) | Slack ID の紐付けは GAS の名簿送信で行い、API に一括のバッチは作らない | 採用 | | [0013](0013-rescue-dm-sent-immediately.md) | レスキューの対応状況の DM は、まとめずに、書き換えのたびにすぐ送る | 採用 | | [0014](0014-manual-open-in-new-tab.md) | マニュアルはアプリに埋め込まず、別タブで開く | 採用 | +| [0015](0015-manual-html-not-pdf.md) | 解説マニュアル(生成した HTML)は PDF にせず、HTML のまま配信する | 見送り | +| [0016](0016-simple-manual-pdf-on-drive.md) | 簡易マニュアルは PDF にして Drive に置き、アプリからそこへ移動させる | 採用 | +| [0017](0017-manual-ops-not-automated.md) | マニュアル運用のスプレッドシートの操作は自動化しない | 見送り | +| [0018](0018-test-mock-with-sqlmock.md) | テストでは db.Client に go-sqlmock の偽の DB を差し込み、repository の戻り値は変えない | 採用 |