@@ -168,7 +168,7 @@ GitHub Actions(`.github/workflows/docker-publish.yml`)がビルド時に`<JST日
168168
169169### スポット種別ごとのON/OFF設定(EAV: ` spot_type_settings ` )
170170
171- `reviews_enabled`/`wikipedia_enabled`/`public_visible`/`rank_enabled`は`spot_types`に列を持たず、EAV形式の`spot_type_settings`テーブル(`spot_type_id, key, value` — boolean設定は`'true'`/`'false'`の文字列。同じテーブルに`series_styles`・`region_scope`・`wikipedia_lang`・`categories`のような文字列値のキーも同居する)に保存する。新しい設定を増やす際にDBマイグレーションが要らないようにするための設計で、キー・既定値・表示名は`lib/types.ts`の`SPOT_TYPE_SETTING_DEFAULTS`/`SPOT_TYPE_SETTING_LABELS`に登録するだけでよい(行が存在しないキーは設定ごとの既定値扱い、`getSpotTypeSetting`参照)。`public_visible`と`rank_enabled`は既定`false`(前者は種別追加当初は非公開・admin/spot_admin限定、後者はランクを使わない)で、他2つは既定`true`。`app/api/spot-types/[id]/route.ts`のPATCHは`{ settings: { key: boolean, ... } }`を受け取り`spot_type_settings`へupsertする汎用エンドポイントで、設定を増やしてもAPI自体の変更は不要。`SpotType`型の`settings`フィールド(`key→value`の文字列マップ)は`lib/spot-types-query.ts`の`SPOT_TYPE_SELECT`(`spot_type_settings`をjsonbに集約するSELECT共通部品)を使うクエリでのみ埋まる点に注意(`select * from spot_types`だけでは`settings`は付与されない)。
171+ `reviews_enabled`/`wikipedia_enabled`/`public_visible`/`rank_enabled`は`spot_types`に列を持たず、EAV形式の`spot_type_settings`テーブル(`spot_type_id, key, value` — boolean設定は`'true'`/`'false'`の文字列。同じテーブルに`series_styles`・`region_scope`・`wikipedia_lang`・`categories`のような文字列値のキーも同居する)に保存する。新しい設定を増やす際にDBマイグレーションが要らないようにするための設計で、キー・既定値・表示名は`lib/types.ts`の`SPOT_TYPE_SETTING_DEFAULTS`/`SPOT_TYPE_SETTING_LABELS`に登録するだけでよい(行が存在しないキーは設定ごとの既定値扱い、`getSpotTypeSetting`参照)。既定`false`は`public_visible`(種別追加当初は非公開・admin/spot_admin限定)と`ai_discovery_enabled`(**押すとAIの枠を使う**ので、全部の種別のメニューに最初から並んでいてほしいものではない)の2つで、他は既定`true`。**`rank_enabled`は既定で開ける** —— 種別を足すたびに開けさせるより、要らない種別で閉じるほうが手数が少ない。**開けても既存のデータは動かない**(ランクの付いていないスポットは`rankStyleOf(null)`がどちらでも同じ`NO_RANK_STYLE`を返すので、ピンの見た目が変わらない)。`app/api/spot-types/[id]/route.ts`のPATCHは`{ settings: { key: boolean, ... } }`を受け取り`spot_type_settings`へupsertする汎用エンドポイントで、設定を増やしてもAPI自体の変更は不要。`SpotType`型の`settings`フィールド(`key→value`の文字列マップ)は`lib/spot-types-query.ts`の`SPOT_TYPE_SELECT`(`spot_type_settings`をjsonbに集約するSELECT共通部品)を使うクエリでのみ埋まる点に注意(`select * from spot_types`だけでは`settings`は付与されない)。
172172
173173### 見た目の軸: ランク・シリーズ・カテゴリ
174174
@@ -208,7 +208,7 @@ GitHub Actions(`.github/workflows/docker-publish.yml`)がビルド時に`<JST日
208208 旧: 26 / 22 / 18 / 15 / 12 → 現: ** 30 / 26 / 23 / 20 / 18** 。Eの12pxは地図上で
209209 点にしか見えず、ピンの中のアイコンも潰れていた。段の差は詰めて全体を上げてある
210210- ** ランクなしはBと同じ大きさで白** 。小さくすると「まだ決めていない」ものが埋もれる
211- - ** 種別ごとに使うかを選ぶ** (` rank_enabled ` 。** 既定は使わない ** )。使わない種別では
211+ - ** 種別ごとに使うかを選ぶ** (` rank_enabled ` 。** 既定で使う ** )。使わない種別では
212212 ランクは常になし扱いで、大きさはランクなし相当に固定される
213213- ** 色はシリーズが勝つ。** シリーズに` color ` の指定があればそれを使い、無いときだけ
214214 ランクの色になる —— ** ランクと色を別の軸に使いたい種別がある** ため
@@ -983,9 +983,17 @@ travel-log-data(MIT側)へ持ち込まないよう、還元するときは出ど
983983AIが動かないことが、あの口を外へ開けておける理由。** 画面は止まっている間その旨を出す**
984984(これが読めないと「依頼したのに何も集まらない」で止まる)。
985985
986- ** 間隔は30日** (` COLLECT_INTERVAL_MINUTES ` )。あちらは間隔が必須(最小5分)で
987- 「手動のみ」が無いので、レポートのように欲しくなったときだけ起こす使い方に合わせるには、
988- 長く置いて予定のほうを事実上使わない形にするしかない。
986+ ** 間隔は3時間** (` COLLECT_INTERVAL_MINUTES ` )。** 1回あたりを長く・広く取り、周回で
987+ 精度を上げる** 使い方に合わせてある —— 1回で薄く10件ずつ拾っても全国は埋まらないし、
988+ 間隔を詰めても知識サーバーは同時に1本しか走らせない(混んでいれば断られるだけ)。
989+ 1回でどこまで広く扱うかはプロンプト側の仕事で、足りなければ画面の「いま集める」で
990+ 予定を待たずに起こせる。
991+
992+ ** どこを回り終えたかは知識サーバーが持つ** (あちらの` covered ` )。` {cursor} ` が
993+ 「次はどこ」の1本なのに対し、あれは一覧 —— これが無いと「2周目で埋める」も
994+ 「この円は収集済みか」も判定できない。既定のプロンプト(` defaultCollectPrompt ` )は
995+ ` {cursor} ` と` {covered} ` を両方使い、** 件数を決めず** 「その地域にあるだけ挙げる」
996+ 「全部回り終えたら、いちばん古く回った地域へ戻って前回より細かく」と書いてある。
989997
990998#### 取り出し(` ./candidates ` )
991999
@@ -1017,10 +1025,52 @@ AIが動かないことが、あの口を外へ開けておける理由。**画
10171025「位置を直す」を押せば選べるようになる。** ` addDiscoveryRows ` でも同じ歯止めを掛ける**
10181026(画面だけだと、経路を1つ足したときに赤道上へスポットが立つ)。
10191027
1028+ #### 円の中が収集済みか(` coverage ` )
1029+
1030+ 地図の長押しメニューの「この周辺の集めた情報」は、** その円の中が収集済みかも一緒に返す**
1031+ (` ?lat=&lng=&radius= ` )。** 集まっているぶんは出したうえで、足りない範囲を言う** ——
1032+ 「0件」と「まだ集めていない」は別のことで、後者なら集めさせれば済む。
1033+
1034+ ** 中心だけでは足りない。** 円が市区町村の境界を跨いでいると隣を見落とすので、
1035+ ** 中心と円周8方位** を突く(` areaProbePoints ` )。円の中を隙間なく確かめることはできない
1036+ (地図辞典は地物の点しか持たず、市区町村の形は持っていない)ので、代表点で見る。
1037+ 8方位なのは市区町村が円より大きいのが普通だからで、増やしても同じ地域を何度も引くだけ。
1038+
1039+ ** 1点の所在は辞典を2つとも引く** (` areaAt ` )。市区町村は** Overtureの` locality ` **
1040+ (OSMは持たない)、都道府県は** OSMの` area ` ** —— Overtureの` area ` はJISのコードで
1041+ 日本ではほぼ空。実測でも、片方だけだと同じ円の中で「東京都新宿区」と「新宿区」が
1042+ 混ざり、` Tokyo ` のような英字の広い地名まで地域として数えられた。** いちばん多いものを採る**
1043+ (先頭1件だと、境界のすぐ内側にある隣の市区町村の地物を掴む)。
1044+
1045+ ** 突き合わせは書き方の揺れを吸う** (` isCovered ` )。回り終えた印はAIが書くので
1046+ 「東京都新宿区」とも「新宿区」とも来る。市区町村が入っていることを必須にし、
1047+ 都道府県は** 別の県を名乗っているときだけ** 弾く(同名の市が別の県にあるため)。
1048+ 実測: 印が` ["東京都新宿区","中野区","大阪府渋谷区"] ` のとき、新宿区と中野区は収集済み、
1049+ 東京都渋谷区は未収集と出る。
1050+
1051+ ** まだのところは「いま集める」で先に回らせる** (` POST .../run?area= ` )。専用の口は
1052+ 知識サーバーに無いが、「次はどこ」のカーソルは元から書き換えられるので、
1053+ ** 書き換えてから起こす** だけで足りる。書き換えるのは1回ぶんで、AIが` next_cursor ` を
1054+ 返せば順番は元の流れへ戻る。** 1つずつしか頼めない** (あちらは同時に1本しか走らせない)
1055+ ので、足りない地域のうち先頭を渡す。
1056+
1057+ ** 円を指定すると候補もその中だけ** 返す。座標の引けなかった候補は所在地で見る ——
1058+ 新しい店は地図辞典に載っていないのが普通で、そこを落とすとこの機能で拾いたいものが
1059+ ちょうど落ちる。
1060+
10201061#### 画面
10211062
10221063** 取り出しと選択は周辺を探すのパネルを流用する** (地図の長押しメニューの
1023- 「集めた候補を見る」→ ` openCollected ` )。出てくるのは同じ` DiscoveryResult ` なので、
1064+ 「この周辺の集めた情報」→ ` openCollected ` )。円の半径は** 周辺を探すより広い2km**
1065+ (` COLLECT_CIRCLE_RADIUS ` )—— あちらは「いま歩いて行ける範囲」を見るが、
1066+ こちらが答えるのは「この辺りは収集済みか」で、収集の単位は市区町村。300mで聞くと
1067+ 同じ市区町村の中を何度も聞き直すことになる。
1068+
1069+ ** 管理画面には「いま収集中か」を出す** (` GET /v1/ingest/status ` )。知識サーバーは
1070+ 同時に1本しか受けないので、走っている間に頼んでも断られる —— 押してから断られるのと、
1071+ 押せないことが見えているのとでは別物。回り終えた件数と直近に回った地域も並べる
1072+ (積む順が回った順なので、末尾が直近)。
1073+ 出てくるのは同じ` DiscoveryResult ` なので、
10241074地図の印・行ごとのシリーズ・登録済みの印・まとめて追加がそのまま使える ——
10251075出どころが違うだけのものに別の画面を作る理由が無い。** 出どころは3つ目** として
10261076` DiscoverySource ` に` collect ` を足し、地図の印もバッジも専用の色(teal)にする。
@@ -1029,7 +1079,7 @@ AIが動かないことが、あの口を外へ開けておける理由。**画
10291079
10301080### 公開スポットの全削除・スポット種別の削除
10311081
1032- 管理画面の`/[type]/admin`にはadmin専用の「公開スポットの全削除」(`app/api/spots/purge/route.ts`)と「スポット種別の削除」(`DELETE /api/spot-types/[id]`、同ファイルのPATCHと同居)がある。前者は`spot_types`の行自体は消さず、対象種別の公開(published)スポットのみを全件削除する(承認待ち・却下・非公開のスポットは残す。CSVで作り直す対象=CSVインポートが取り込む公開スポットに限定するため)。削除される公開スポットに紐づく`visits`/`visit_plans`/`reviews`(FKの`on delete cascade`)・写真ファイルと、対象種別のルート(`spot_routes`。status問わず丸ごと)も一括で消す。後者はstatus問わず対象種別の全スポットを削除(紐づくデータ・写真ファイルの扱いは前者と同じ)した上で`spot_types`の行自体も削除する(「別のスポット種別の管理」一覧には現在表示中の種別も含めて全種別を出すが、現在表示中の種別だけはリンク化・削除ボタンをUI側で出さないことで自分が今開いている種別を誤って消せないようにしている)。後者は`public_visible`がtrue(一般公開中)の種別、または対象種別が`app_settings.active_spot_type_id`(ルート`/`リダイレクトのフォールバック既定)の場合はAPIレベルで拒否する(既定の種別は常にpublic_visible=trueであるため後者は実質前者に含まれるが、防御的に両方チェックしている)。どちらもCSVでデータを作り直す前提の機能で、spot_adminには許可していない(ユーザー管理と同様、他ユーザーのデータを巻き込むため)。ルート`/`アクセス時に開く既定の種別(最後に開いていた種別のCookieが無い・開けないときのフォールバック)の変更は、この一括削除等の管理系操作とは別の独立したセレクトボックス(`app_settings.active_spot_type_id`を更新)として`/[type]/admin`に置いている。
1082+ 管理画面の`/[type]/admin`にはadmin専用の「公開スポットの全削除」(`app/api/spots/purge/route.ts`)と「スポット種別の削除」(`DELETE /api/spot-types/[id]`、同ファイルのPATCHと同居)がある。前者は`spot_types`の行自体は消さず、対象種別の公開(published)スポットのみを全件削除する(承認待ち・却下・非公開のスポットは残す。CSVで作り直す対象=CSVインポートが取り込む公開スポットに限定するため)。削除される公開スポットに紐づく`visits`/`visit_plans`/`reviews`(FKの`on delete cascade`)・写真ファイルと、対象種別のルート(`spot_routes`。status問わず丸ごと)も一括で消す。後者はstatus問わず対象種別の全スポットを削除(紐づくデータ・写真ファイルの扱いは前者と同じ)した上で`spot_types`の行自体も削除する(「別のスポット種別の管理」一覧には現在表示中の種別も含めて全種別を出す。現在表示中の種別だけはリンク化しない(いま開いている画面へのリンクになるため)が、**削除はできる** —— 作っては試す種別ほど「いまここ」で消したくなるため。**削除したら別の種別の管理画面へ移す**(`AdminView`の`handleDeleteType`。URLの`[type]`が消えた状態に留まると以降の読み込みが全部404になる。残りが1つも無ければ`/`へ送る)。確認ダイアログには「いま開いている種別です」の一文を足す。削除ボタンを出さないのは**公開中(`public_visible`)の種別**だけで、これはAPIも断るため押せても意味が無い)。後者は`public_visible`がtrue(一般公開中)の種別、または対象種別が`app_settings.active_spot_type_id`(ルート`/`リダイレクトのフォールバック既定)の場合はAPIレベルで拒否する(既定の種別は常にpublic_visible=trueであるため後者は実質前者に含まれるが、防御的に両方チェックしている)。どちらもCSVでデータを作り直す前提の機能で、spot_adminには許可していない(ユーザー管理と同様、他ユーザーのデータを巻き込むため)。ルート`/`アクセス時に開く既定の種別(最後に開いていた種別のCookieが無い・開けないときのフォールバック)の変更は、この一括削除等の管理系操作とは別の独立したセレクトボックス(`app_settings.active_spot_type_id`を更新)として`/[type]/admin`に置いている。
10331083
10341084### スポットの新規登録フロー
10351085
0 commit comments