採用技術/ Tech Stack
使っている技術と、それぞれが担っている役割
新しく持ち込んだ技術はほとんどありません。松葉の既存の土台に、長期の保管と、数えて気づく仕組みに関わる部分だけを足しています。ここでは分類ごとに、何を使い、それが何を担っているかを並べます。最後に、記録の仕組みと検知の仕組みで共通にした部分・あえて分けた部分を整理しました。
画面Frontend
Next.jsApp Router
Box のアクティビティタブと、全社の管理画面。アラートの運用画面もここに含まれます。管理画面は既定で検索エンジンに載せない設定です。
ReactUI
タイムラインの日付グループ、カードの一覧、詳細のウィンドウ。表示の判断(どのボタンを出すか、どの空状態を出すか)は純粋な関数に切り出し、画面はそれを描くだけにしています。
TypeScriptTypes
アラート 29 種の対応表(表示名・アイコン・系統・推奨アクション)は、種別を漏らすと型が合わずコンパイルで落ちます。更新の漏れが本番まで届きません。
Tailwind CSSStyling
色・角丸・余白をトークンとして共有します。重大度や状態の色も直接の色指定ではなくトークン経由で、画面ごとに割れないようにしています。
shadcn/uiComponents
ダイアログ・入力欄・バッジ・表の土台。松葉のトークンを当てて使っています。
Radix UIPrimitives
キーボード操作と読み上げ対応を持つ土台部品。詳細のウィンドウでは、焦点の閉じ込め・Esc で閉じる・閉じたときに元のカードへ戻す、をここが担います。
TanStack QueryData
30 秒ごとの自動更新、ページを切り替えている間の前ページ保持、操作後に必要な範囲だけの取り直し。回線が切れたときは失敗ではなく待機に入るため、「最終更新: n 秒前」を常設して劣化に気づけるようにしています。
nuqsURL State
絞り込み・ページ・表示件数を URL に持たせます。「この条件の一覧を見てほしい」を URL のまま渡せます。
ZodValidation
入出力の検証。同じ定義を画面と API の両方で使います。理由の文字数(10〜256)のような規則も 1 か所で決めます。
API とデータAPI & Data
HonoHTTP
API の土台。全社の監査ログ 8 端点、アラートの運用 7 端点、配送運用 8 端点。いずれもログイン確認とシステム管理者確認の二段の保護を通します。
Node.jsRuntime
API と定期処理の実行環境。5 分ごとの検知も、月次の退避も、同じ実行ファイルから引数で振り分けて起動します。
PostgreSQLDatabase
記録も、アラートも、取り出しの台帳もここに入ります。読み書きの範囲をデータベース自身が持つため、アプリケーションに穴があっても範囲外は返りません。
SupabaseManaged Postgres
データベースの運用基盤。範囲制限の規則も拡張機能の設定も、版管理された手順として適用します。
PrismaORM
スキーマ定義とマイグレーション。月ごとの分割・条件つきの索引・範囲制限は表現できないため、その部分は手書きの SQL を末尾に足す形で運用しています。
Row Level Security行単位のアクセス制御
行ごとに「誰が読めるか・書けるか」をデータベース側で決める仕組み。記録は追加は全員/参照は管理者のみ/更新と削除は規則そのものが無い形にしてあります。
DEFINER
SECURITY DEFINERElevated Function
定義した人の権限で動く関数。Box のメンバーはこの関数だけを呼べます。閲覧者を引数に取らず接続情報から取るので、他人になりすまして呼ぶことができません。
cursor ページングKeyset Pagination
「何件目から」ではなく「この行の次から」で続きを取る方式。記録は(発生時刻, 連番)の複合キーを印にするので、読んでいる最中に行が増えても重複や取りこぼしが起きません。
長期保管と取り出しStorage & Export
partman
pg_partmanPartition Manager
月ごとの子テーブルを自動で作り、古いものを切り離す拡張機能。数ヶ月先まで先に作り、25 ヶ月を超えた月を別のスキーマへ移します。切り離すだけで、消しはしません。
pg_cronIn-Database Scheduler
データベースの中で定期処理を回す拡張機能。登録は1 本だけで、週次で子テーブルの整備が走ります。
COPY ... TO STDOUTStreaming Export
データベース自身に CSV を組み立てさせ、結果をそのまま流す命令。アプリケーションが全行をメモリに載せません。10 万行でも 100 万行でも使うメモリは変わりません。
crc32c
gzip / crc32cCompression & Checksum
圧縮と、壊れていないことの検査値。退避では行数と検査値の両方を突き合わせてから、元の月を捨てます。
Cloud StorageBuckets
1 つのバケットを 2 つの用途で使い分けます。取り出した CSV の置き場と、退避した月の置き場です。既定は Archive クラス(安く長く置く)で、CSV の置き場だけ Standard クラスを指定しています。
cycle
オブジェクトライフサイクルRetention Rules
置き場ごとの寿命の設定。取り出した CSV は7 日で自動的に消え、退避した月は無期限で残ります。消す処理をアプリケーション側に持たせません。
URL
署名付き URL(V4)Signed URL
期限つきで 1 つのファイルだけを取れる URL。取り出した CSV は 24 時間、退避した月はその場で 15 分だけ発行します。API はファイルの中身を通しません。
BOM
RFC4180 / UTF-8 BOMCSV Format
CSV の書式の標準と、表計算ソフトが文字コードを取り違えないための印。時刻は日本時間で書き出すので、開いてそのまま読めます。
検知と定期実行Detection & Batch
Run
Cloud RunServices
API と画面のアプリケーション。要求に応じて自動で増減します。記録を書くのはここで、業務の処理と同じ流れの中で書きます。
Jobs
Cloud Run JobsBatch
定期処理の実行環境。1 つの実行ファイルに処理を束ね、起動時の引数でどれを走らせるか振り分けます。5 分ごとの検知も、月次の退避も、大きい CSV の書き出しも同じ器です。
Cloud SchedulerCron
時刻で処理を起動する仕組み。検知は 5 分ごと、退避は月次です。週次の子テーブルの整備と重ならないよう、起動の時刻をずらしています。
GoDaily Reconciliation
日次で Drive とアプリの状態を突き合わせる処理と、週次の存否確認。検知したアラートは Node.js 側と同じ 1 つのテーブルへ書きます。実行体が違っても、受け取り口は 1 つです。
Monitoring
Cloud MonitoringMetrics
クラウド側の数値の観測。6 つの検知器のうち 1 つは、配信できなかったメッセージの数をここから読みます。読めなかったときは 0 件と報告せず、失敗として扱います。
Logging
Cloud LoggingLogs
ログの集約と、ログの内容に一致したときの通知。アプリのログは重大度を独自の欄に入れているため、標準の重大度で絞る条件を書くと永久に一致しません。条件は本文の側で書きます。
Pub/SubMessaging
処理のきっかけを運ぶ仕組み。大きい CSV の完成を通知の仕組みへ伝えるのに使います。配信できなかったものは専用の置き場(デッドレター)へ退避し、その数が検知の対象になります。
Resend / React EmailDelivery
メールの配送と本文の組み立て。アラートは 29 種のうち 23 種がメールで届きます(共通の文面が 2 通、種別ごとの文面が 4 通)。
テストTesting
VitestUnit & Integration
純粋な関数(表示文の組み立て・続きの印の境界・同期と非同期の分岐・状態遷移の導出)と、実際のデータベースを使う結合テスト。範囲制限の規則も専用のテストで固定しています。
PlaywrightEnd-to-End
画面を実際に操作する通しテスト。アクティビティの表示・アクセス履歴が Owner だけに見えること・絞り込み・続きの読み込みで行が重複しないこと、そしてアラート画面が権限の無い人から見えないことを確認します。
実行計画の固定Query Plan Assertion
10 万行を投入したうえで、使われる索引の集合をテストで宣言します。全件を走査する形に変わったらテストが落ちるので、行が増えてから気づく事態を避けられます。
この仕組みで特に注意して固定しているのは、「返っていないこと」を合格にしないという点です。たとえば「どんな続きの印を渡しても、閲覧の記録が 1 行増える」という規則は、印が未指定・空文字・復号できない・有効・未来の日時を詰めた細工、の 5 通りを表にして固定しています。記録が増えたことだけでなく、返ってきた中身も同時に確かめるので、「何も返さないから安全」という形の実装が通りません。