メインコンテンツまでスキップ

Trackable Links 仕様書

1. 概要​

QRコードによるリンク追跡・転送システム。設置場所ごとのアクセスログを記録し、分析に活用する。

1.1 ユースケース図​

1.2 ドメイン​

  • API: fwd.soshosai.com(QR転送・管理API)

1.2 アーキテクチャ​


2. 機能​

2.1 QR転送機能​

QRコードをスキャンすると、設定された転送先URLにリダイレクトする。

フロー:

  1. QRコードスキャン → fwd.soshosai.com?id={qrId}
  2. QRコード情報をDBから取得
  3. 場所未設定の場合 → 場所設定画面を表示
  4. アクセスログを記録
  5. 転送先URLにリダイレクト(301)

2.2 プロジェクト管理​

プロジェクト単位でQRコードを管理する。

項目説明
プロジェクトQRコードのグループ。転送先URLを持つ
QRコード個別のQRコード。場所情報を持つ
アクセスログQRスキャン時の記録

2.3 LINE Bot連携​

LIFFを使用したQRスキャナー機能を提供。

2.4 Discord 投稿からの設置場所登録(ポスター巡り)​

ポスター巡りで Discord の対象チャンネル(03-ポスター巡り とその配下のスレッド)に投稿された 「QR コードの写真」と「設置場所」を突き合わせ、QR コードの設置場所を自動で登録する。

  • 受信: gakusai-assistant-worker の cron(1 分ごと)が Discord REST で新着を取り込む。Gateway の常時接続は使わない
  • QR 読み取り: 添付画像を Discord CDN の縮小で小さくしてから Worker 内で zxing-wasm にかける
  • 突き合わせ: 「写真と場所が同じ投稿」「場所テキスト → 写真」「写真 → 場所テキスト」「写真へのリプライ」の 4 形を、同一投稿者・同一チャンネル・10 分以内・リプライ参照で結び付ける。本文の解釈(場所か雑談か)は LLM が一次判定し、失敗時はルールに落ちる
  • 登録: 本サービスの Service Binding RPC TrackableLinksRpc.setQrLocation(qrId, location, actorDiscordId) で QRCodes.location を更新する(HTTP には露出しない。JWT を持たない Bot からの唯一の書き込み経路)
  • 結果は Discord のリアクションで返す(✅ 登録 / ⚠️ 一部の QR が未登録 / ❌ 失敗。QR が見つからない写真には何も返さず、画像の取得・変換に失敗したときだけ ❌ を返す)。登録済みの写真へのリプライは上書き(訂正)として扱う

詳細は packages/api/gakusai-assistant-worker/src/poster/README.md を参照。


3. エンドポイント​

3.1 転送系(認証不要)​

MethodPath説明
GET/?id={qrId}QR転送(メイン機能)
GET/view/:qrIdQRコード情報表示
GET/linebot/scannerLIFFスキャナー画面

3.2 プロジェクト管理系(スタッフ認証必須)​

MethodPath説明
GET/projectsプロジェクト一覧
POST/projects/createプロジェクト作成
GET/projects/:idプロジェクト詳細
PUT/projects/:idプロジェクト更新
DELETE/projects/:idプロジェクト削除
GET/projects/:id/getAccessLogsアクセスログ取得

3.3 QRコード管理系(スタッフ認証必須)​

MethodPath説明
GET/projects/getQRCodeQRコード一覧
GET/projects/getQRCode/:idQRコード詳細
POST/projects/createQRCodeQRコード作成
PUT/projects/updateQRCode/:idQRコード更新
DELETE/projects/deleteQRCode/:idQRコード削除

3.4 場所設定系(スタッフ認証 + パスコード)​

MethodPath説明
POST/api/set-location場所設定
POST/api/edit-location/:qrId場所編集

3.5 Service Binding RPC(HTTP 非公開)​

EntrypointMethod呼び出し元説明
TrackableLinksRpcsetQrLocation(qrId, location, actorDiscordId)gakusai-assistant-workerQR コードの設置場所を更新する

4. データベース​

データベース名: soshosai-qr-forwarder

4.0 ER図​

4.1 Projects​

CREATE TABLE Projects (
id INTEGER PRIMARY KEY AUTOINCREMENT,
project_id TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
destination_url TEXT NOT NULL,
admin_user_id TEXT,
created_at TEXT NOT NULL
);

4.2 QRCodes​

CREATE TABLE QRCodes (
id TEXT PRIMARY KEY, -- UUID
project_id TEXT NOT NULL,
location TEXT, -- 設置場所
creator_id TEXT, -- 作成者のDiscord ID
created_at TEXT NOT NULL,
FOREIGN KEY (project_id) REFERENCES Projects(project_id)
);

4.3 AccessLogs​

CREATE TABLE AccessLogs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
project_id TEXT NOT NULL,
qr_id TEXT NOT NULL,
accessed_at TEXT NOT NULL,
user_agent TEXT,
ip_address TEXT
);

5. 認証​

5.1 スタッフ認証​

/projects 以下のエンドポイントはスタッフ認証が必須。

認証フロー:

  1. soshosai_staff_jwt Cookieから JWT を取得
  2. unified-auth-worker で JWT を検証
  3. userType === 'staff' を確認

5.2 パスコード認証​

場所設定時は追加でパスコード認証が必要。

const expectedPasscode = c.env.LOCATION_SETUP_PASSCODE;
if (passcode !== expectedPasscode) {
return c.json({ message: 'パスコードが正しくありません' }, 401);
}

6. 環境変数​

変数名説明
D1_DBD1 Database Binding
AUTH_SERVICEunified-auth-worker Binding
LOCATION_SETUP_PASSCODE場所設定用パスコード
LIFF_IDLINE LIFFアプリID
LOGGERログサービス Binding