開発手順
開発環境の構築手順
必要環境
- LinuxまたはmacOS
- Docker / Docker Compose
- uv
- Node.js 22.17以上
セットアップ手順
すべてのmakeコマンドはプロジェクトルートから実行する (app/へ移動して実行すると${PWD}がずれてMakefile内のパス解決が誤動作する)。
本リポジトリをclone
.env-exampleを.envにコピーして環境変数を設定bashcp .env-example .envCOMPOSE_PROFILE・DATA_DIR・UID・GIDを環境に合わせて編集する開発環境のセットアップを実行
bashmake setup起動
bashmake deploy
workspaceと型生成
appはアプリの依存、スクリプト、#lib/*のimportsを持つ正式なpnpm workspaceパッケージである。 ルートは開発ツールとアプリのスクリプトへの転送を持つ。 SvelteKitの設定はapp/vite.config.tsに置く。 app/tsconfig.jsonはSvelteKitの生成した型を継承し、ルートのtsconfigは検証対象へ合わせて参照する。 新しいworktreeでは依存を導入し、pnpm --dir app exec svelte-kit syncで型を生成する。 ルートのpnpm run checkとpnpm run test:unitはアプリでsyncを実行してから検証する。 静的import、動的import、mock指定は拡張子を含む#lib参照を使う。
開発コマンド
| コマンド | 内容 |
|---|---|
make format | 整形 + 軽量lint + 自動修正 |
make test | 全チェック実行(コミット前の必須検証) |
make test-e2e | e2eテスト(Playwright)単独実行 |
make update | 依存更新 |
e2eテスト(make test-e2e)は開発環境(make deploy)が起動している必要がある。
依存更新後の追随作業
make updateはpnpm update --latestによりpackage.jsonの指定範囲を超えて更新する。 稼働中の開発サーバーが更新前のモジュールを保持したままだとE2Eが失敗するため、make updateは依存更新後にappを再起動し、疎通を確認してから検証する。 RUN_NODE相当のコンテナーでpnpm addなどを実行して手動で依存を入れ替えた場合も、E2Eの前にmake restart-app、make healthcheckの順に実行する。 実行後は次の3点を確認する。
TypeScriptの版
TypeScriptの版を6系に留める。 typescript-eslintがTypeScript 7を未サポートであり、 svelte-checkもTypeScript 7では6系との併存インストールと専用フラグを要求するためである。 7系へ上がった場合はpnpm add -D 'typescript@^6.0.3'で戻す。 両ツールがTypeScript 7へ対応した時点で本運用を解除する。 対応状況は次の2点で判定する。
typescript-eslint: 対応issue(https://github.com/typescript-eslint/typescript-eslint/issues/10940)がcloseされていることsvelte-check:node_modules/svelte-check/bin/ts-version-check.jsがTypeScript 7の単独構成で例外を送出しないこと
Playwrightのイメージ版
Playwrightのイメージ版を揃える。 @playwright/testが更新された場合は、compose.yamlのplaywrightサービスが指す mcr.microsoft.com/playwrightのタグを同じ版へ更新する。 イメージ同梱のブラウザバイナリはパッケージの版ごとに配置が変わるため、 一致しないとmake test-e2eがブラウザ起動時に失敗する。
pnpmの警告
pnpmの警告を確認する。 make updateは終了コード0で終わる場合も、非推奨の推移依存とpeer dependencyの不整合を警告として報告する。 終了コードだけでは、警告を伴わない更新が成立したかを判定できない。
非推奨の推移依存はpnpm why <パッケージ名>で、その依存を引き込む直接依存を特定する。 特定した直接依存について、更新、据え置き、上流の対応待ちのいずれとするかを判定して記録する。 peer dependencyの不整合はpnpm peers checkで内容を確定する。 このコマンドは不整合が残る間、終了コード1を返す。
依存更新の完了条件は、警告が0件であること、または各警告へ根拠のある処置が対応していることとする。
サプライチェーン攻撃対策
npm / PyPIレジストリへの悪意あるパッケージ公開に対し、次の方針を採用する。
- npmパッケージ:
pnpm-workspace.yamlのminimumReleaseAge: 1440で公開から1日未満のインストールを禁止する - PyPIパッケージ:
pyproject.tomlの[tool.uv]節exclude-newer = "1 day"で公開から1日未満のインストールを禁止する pnpm installは--frozen-lockfileを明示してロックファイル乖離時の再resolveを禁止する- GitHub Actionsの
uses:はコミットSHAとバージョンコメントで固定する(.github/workflows/配下全ファイル)
依存更新はmake updateを使う。
推移的依存(直接インストールしていない依存の依存)の脆弱性は、上記の自動更新対策だけでは解消されない場合がある。 脆弱性はDependabotアラートと.github/workflows/audit.yamlの定期監査で検知し、 pnpm-workspace.yamlのoverridesで安全なバージョンへ引き上げて対処する。
GitHubリポジトリ設定のDependabot security updates(自動修正PRの作成)は無効にしている。 Dependabotのアップデーターが本リポジトリのpnpmロックファイル環境では推移的依存を 安全なバージョンへ引き上げられず、自動修正の試行が繰り返しsecurity_update_not_possibleで 失敗していたためである。
ドキュメントサイト運用
make docs静的サイトをビルドし、内部リンクも確認する。 Dockerを使わずにビルドする場合はpnpm --dir docs buildを実行する。 プレビューにはmake docs-devを使い、http://localhost:5173/GLATasks/を開く。
Docker構成
サービス構成・環境変数はcompose.yaml / .envを参照。 プロファイルはproduction、staging、developmentから選ぶ。 stagingはproductionのサービス構成を共有し、COMPOSE_PROFILEの名前を保持する。 DBの接続資格情報はComposeとMakeの設定を使い、各テストとスクリプトで再定義しない。 本文の容量上限とnginxの一時バッファ設定を同じ運用設定で管理する。
DBマイグレーション運用
自動適用
make deploy(docker compose up)の起動時にマイグレーションが自動適用される。 稼働中のappを止めずに即座にマイグレーションを反映したい場合はmake migrateを実行する。 Composeのmigrate、migrate-devとMakeは同じマイグレーションスクリプトを使う。 そのスクリプトは本番イメージへも含める。
中核5テーブルの外部キーと削除順はDB設計方針に従う。 既存環境を統一するマイグレーションは、親が存在しない子の行を深い順に削除してから制約を追加する。 同じ移行で利用者設定の旧キーをcamelCaseへ変換し、新旧のキーが共存する場合は新キーの値を保持する。
マイグレーションファイルの追加
新規スキーマ変更は必ずpnpm run db:generate経由で生成する。 drizzle/migrations/meta/_journal.jsonのwhen値(UNIXミリ秒)は直前エントリより大きくなければならない。 別ブランチで生成したmigrationのmergeで順序が逆転する場合は、新しい側のwhenを再生成してからcommitする。
既存行の値の読み替え・初期値の設定が必要な場合は、生成されたマイグレーションファイルへ値変換のSQLを書き足す。 pnpm run db:generateはスキーマ定義の差分からDDLのみを生成し、既存行の値をどう埋めるかを表現できないためである。 先例として0003_sort_order_and_status.sql(既存カラムの廃止に伴う値の読み替え)・0004_add_timer_expired.sql(新設カラムへの初期値の設定)が手書きの変換SQLを含む。
履歴整合のリカバリー
DBが半端な状態になった場合はmake sqlから__drizzle_migrationsテーブルと実DB状態を整合させる。 整合手順を実行する前に必ずmake backupを取得する。
典型例として、make start時にmigrate-devがexit 1で失敗し ALTER TABLE ... ADD ... Duplicate column nameが出る場合がある。 drizzle-kit pushでスキーマを先行適用すると実スキーマは最新だが __drizzle_migrationsに先行適用したマイグレーションが記録されず、再適用で重複エラーになる。 実スキーマに先行適用したマイグレーションの変更が反映済みであることを確認したうえで、 __drizzle_migrationsへ記録行を1行挿入して整合させる。 hashには先行適用したマイグレーションSQLファイル全文のsha256を、created_atには drizzle/migrations/meta/_journal.jsonにある同じマイグレーションのエントリのwhen値を設定する。
CI/CD
masterへのpushおよびPR時にci.yamlが自動実行される(.github/workflows/ci.yaml参照)。 masterへのpushでdocs/配下に変更があればdocs.yamlワークフローが自動実行され、 GitHub Pagesへデプロイされる。 release.yamlはリリースを作成し、deploy.yamlを起動してアプリをデプロイする。 integration jobはproduction環境でMakeのDB・E2E検証を呼び出す。 依存の脆弱性監査はaudit.yamlが毎日06:00 UTC(JST 15:00)に定期実行し、 検出結果をGitHub Code Scanningへアップロードする(.github/workflows/audit.yaml参照)。
バックアップとリストア
バックアップ
make backupバックアップ先: ${DATA_DIR}/backups/YYYYMMDD_HHMMSS/。 DBダンプと、存在する.encrypt_key・.secret_key・.mcp_clients.jsonを同じ世代へ保存する。 MCP登録ファイルが無い場合も成功する。存在するファイルの保存に失敗した場合は、未完成の世代を残さずエラー終了する。 何も指定しなければ直近5世代を保持する(BACKUP_KEEPで変更可能)。 DBコンテナが停止中の場合はエラー終了する。初回デプロイなどDBがない状態ではSKIP_DB_DUMP=1でスキップできるが、その世代にはSQLが入らない。
リストア
復旧先のリポジトリルートで、.envとweb/sslを用意する。これらはバックアップに含まれない。 .envのDATA_DIRを復旧先の絶対パスへ設定し、次の例のDATA_DIRにも同じ値を指定する。 COMPOSE_PROFILESには.envのCOMPOSE_PROFILEと同じ値を指定する。 SQLのある完成世代を選ぶ。以下の操作は復旧先のglatasksデータベースを入れ替えるため、現在のデータを残す場合は先に別の場所へ退避する。
export DATA_DIR=/復旧先のデータディレクトリ
export COMPOSE_PROFILES=production
BACKUP="$DATA_DIR/backups/YYYYMMDD_HHMMSS"
test -s "$BACKUP/glatasks.sql"
docker compose stop app
docker compose up -d db
docker compose exec -T db mariadb -uroot -pglatasks -e 'DROP DATABASE IF EXISTS glatasks; CREATE DATABASE glatasks CHARACTER SET utf8mb4'
docker compose exec -T db mariadb -uglatasks -pglatasks glatasks < "$BACKUP/glatasks.sql"
mkdir -p "$DATA_DIR"
for name in .encrypt_key .secret_key .mcp_clients.json; do
if test -f "$BACKUP/$name"; then
cp -p "$BACKUP/$name" "$DATA_DIR/$name"
else
rm -f "$DATA_DIR/$name"
fi
done
docker compose up -d app
make healthcheck鍵とMCP登録情報はDBコンテナではなくアプリのDATA_DIRから読み込まれるため、ファイルを戻してからアプリを起動する。 復旧後にブラウザーでタスクと添付ファイルを開いて内容を確認し、登録済みのMCPクライアントを再接続して登録情報を確認する。 MCP未使用の世代では.mcp_clients.jsonがなく、復旧先に以前の登録ファイルを残さない。
リリース手順
事前にghコマンドをインストールしてgh auth loginでログインしておく。次のいずれかを実行。
gh workflow run release.yaml --field="bump=PATCH"
gh workflow run release.yaml --field="bump=MINOR"
gh workflow run release.yaml --field="bump=MAJOR"