インテグレーションAPI を使って、公共インフラ(マンホール・街灯・標識・ベンチ)の状態を報告する地図アプリを作ります。小さなバックエンドがインテグレーションAPI のトークンを保持し、CMS へのリクエストをすべて代行するため、トークンがブラウザに渡ることはありません。
点検担当者が地図を開き、インフラの資産をクリックして、問題の種別・深刻度・メモ・任意の写真を添えた状態レポートを送信します。レポートを送信すると、インテグレーションAPI を通じて CMS にアイテムが作成・公開され、続けてその資産自身の状態と最終点検日が更新されます。「レポート履歴を見る」ボタンから、これまで送信されたレポートを一覧できます。

- Node.js 20 以降
- Git
- Re:Earth CMS のワークスペース
- TypeScript の基礎知識
ステップ1 — CMS プロジェクトを準備する
Section titled “ステップ1 — CMS プロジェクトを準備する”モデルを作成する
Section titled “モデルを作成する”Re:Earth CMS の管理画面でプロジェクトを作成し、モデルを2つ追加します。
infrastructure-assets — 地図に表示する資産。
| フィールドキー | フィールド型 | 選択肢 | 必須 |
|---|---|---|---|
asset-id | テキスト | — | はい |
asset-name | テキスト | — | はい |
asset-type | 選択肢 | manhole / streetlight / traffic_sign / public_bench | はい |
location | ジオメトリエディタ | ポイント | はい |
current-condition | 選択肢 | good / fair / poor / critical / Not inspected | いいえ |
last-inspected-at | 日付 | — | いいえ |
reference-photo | アセット | — | いいえ |

current-condition は、資産を新規作成した時点では Not inspected が初期値として入ります。自分で設定する必要はありません。
inspection-reports — 点検担当者が送信するレポート。
| フィールドキー | フィールド型 | 選択肢 | 必須 |
|---|---|---|---|
asset-id | テキスト | — | はい |
asset-type | 選択肢 | manhole / streetlight / traffic_sign / public_bench | はい |
location | ジオメトリエディタ | ポイント | はい |
inspection-date | 日付 | — | はい |
condition | 選択肢 | good / fair / poor / critical | はい |
issue-category | 選択肢 | no_issue / damage / obstruction / missing_component / malfunction / cleaning_required / other | はい |
severity | 選択肢 | low / medium / high / urgent / not_applicable | はい |
notes | テキストエリア | — | いいえ |
photos | アセット(複数値の設定を許可) | — | いいえ |
report-status | 選択肢 | pending / approved / resolved | はい |

インテグレーションを作成して連携する
Section titled “インテグレーションを作成して連携する”- パーソナルアカウントで マイインテグレーション を開き、新規インテグレーションを作成します — 手順の全体は インテグレーションの作成 を参照してください
- プロジェクトのあるワークスペースで インテグレーション を開き、作成したインテグレーションを連携します
- 役割を maintainer(管理者) に設定します
インテグレーションのトークンをコピーします。パスワードと同様に扱い、コミットしたり、フロントエンドのコードに書いたりしないでください。
curl でインテグレーションAPI を試す
Section titled “curl でインテグレーションAPI を試す”アプリに触れる前に、まずリクエストを1つ直接送ってみます。ステップ3 のバックエンドのコードが組み立てているのも、これと同じ形です。<base-url>・<workspace>・<project>・<assets-model>・<token> を、それぞれ自分の値に置き換えてください。<base-url> は https://api.cms.reearth.io/api です。<workspace> と <project> は、CMS の管理画面でそのワークスペースやプロジェクトを開いているときのブラウザの URL バーに表示されています。<assets-model> は、上で infrastructure-assets を作成したときに表示された モデルキー です。<token> は、今コピーしたインテグレーションのトークンです。
curl -X POST \ '<base-url>/<workspace>/projects/<project>/models/<assets-model>/items' \ -H 'Authorization: Bearer <token>' \ -H 'Content-Type: application/json' \ -d '{ "fields": [ { "key": "asset-id", "type": "text", "value": "MH-001" }, { "key": "asset-name", "type": "text", "value": "Demo Manhole 001" }, { "key": "asset-type", "type": "select", "value": "manhole" }, { "key": "location", "type": "geometryEditor", "value": "{\"type\":\"Point\",\"coordinates\":[138.26,36.06]}" } ] }'CMS は作成したアイテムを返します。次のリクエストで使う id もここに含まれています。
{ "id": "01...", "fields": [ { "key": "asset-id", "type": "text", "value": "MH-001" }, { "key": "asset-name", "type": "text", "value": "Demo Manhole 001" }, { "key": "asset-type", "type": "select", "value": "manhole" }, { "key": "location", "type": "geometryEditor", "value": "{\"type\":\"Point\",\"coordinates\":[138.26,36.06]}" }, { "key": "current-condition", "type": "select", "value": "Not inspected" } ], "refs": ["latest"]}新規に作成したアイテムは ドラフト の状態です — refs には latest だけが入っています。アプリがステップ3 で行っているのと同じ方法で公開します。
curl -X POST \ '<base-url>/<workspace>/projects/<project>/models/<assets-model>/items/<item-id>/publish' \ -H 'Authorization: Bearer <token>'refs に public が latest と並んで入るようになります — パブリックAPI からもこのアイテムを取得できる状態です。
これで資産を1件作成できました。残りは curl を繰り返す代わりに、CMS のコンソールから直接追加します — 街灯・標識・ベンチをそれぞれ用意してください。コンテンツ でモデルを選び、新規アイテム をクリックして値を入力し、保存 します。アプリは、資産が何件か存在しない限り地図に何も表示しません。
ステップ2 — リポジトリをクローンしてバックエンドを設定する
Section titled “ステップ2 — リポジトリをクローンしてバックエンドを設定する”git clone https://github.com/eukarya-biz/infrastructure-inspection-tutorial.gitcd infrastructure-inspection-tutorial/backendnpm installcp .env.example .envWindows(コマンドプロンプト)では、cp .env.example .env の代わりに copy .env.example .env を使ってください。
.env に、ステップ1 で確認した値を入力します。
| 変数 | 値 |
|---|---|
PORT | バックエンドのポート番号(デフォルト 3000) |
CMS_BASE_URL | Re:Earth CMS の API ベース URL |
CMS_WORKSPACE_ID | ステップ1 のワークスペース ID |
CMS_PROJECT_ID | ステップ1 のプロジェクト ID |
CMS_ASSETS_MODEL | infrastructure-assets のモデルキー |
CMS_REPORTS_MODEL | inspection-reports のモデルキー |
CMS_INTEGRATION_TOKEN | ステップ1 のインテグレーショントークン |
npm run devバックエンドが http://localhost:3000 で起動します。
ステップ3 — バックエンドがインテグレーションAPI をどう使うか
Section titled “ステップ3 — バックエンドがインテグレーションAPI をどう使うか”最初の2つのステップは、ここに来るための準備でした。このアプリが CMS に書き込む処理はすべて、.env のトークンを使ってインテグレーションAPI を呼びだす、いくつかのルートハンドラーを通ります。
共通のリクエストヘルパー
Section titled “共通のリクエストヘルパー”backend/src/cms.ts は、CMS へのリクエストをすべて同じ形で組み立てます。プロジェクトのベース URL に、Authorization: Bearer <token> ヘッダーを添えるだけです。
export function cmsProjectUrl(config: CmsConfig, path: string): string { return `${config.baseUrl}/${config.workspaceId}/projects/${config.projectId}${path}`;}
export function cmsHeaders( config: CmsConfig, extra?: Record<string, string>,): Record<string, string> { return { Authorization: `Bearer ${config.token}`, Accept: "application/json", ...extra, };}レポートを作成する
Section titled “レポートを作成する”POST /api/reports(backend/src/routes/reports.ts)は fields の配列を組み立て、レポートモデルの items エンドポイントに送信します。
const fields = [ { key: "asset-id", type: "text", value: assetId }, { key: "asset-type", type: "select", value: assetType }, { key: "location", type: "geometryEditor", value: JSON.stringify(location) }, { key: "inspection-date", type: "date", value: `${inspectionDate}T00:00:00+09:00` }, { key: "condition", type: "select", value: condition }, { key: "issue-category", type: "select", value: issueCategory }, { key: "severity", type: "select", value: severity }, { key: "report-status", type: "select", value: "pending" },];
if (validPhotoIds.length > 0) { fields.push({ key: "photos", type: "asset", value: validPhotoIds });}
await fetch(cmsProjectUrl(config, `/models/${modelKey}/items`), { method: "POST", headers: cmsHeaders(config, { "Content-Type": "application/json" }), body: JSON.stringify({ fields }),});新規アイテムは ドラフト として作成されます。アプリは作成の直後、同じインテグレーションAPI のトークンを使って公開します。
await fetch(`${itemUrl}/publish`, { method: "POST", headers: cmsHeaders(config),});資産を更新する
Section titled “資産を更新する”レポートが公開されたあと、PATCH /api/assets/:itemId(backend/src/routes/assets.ts)が資産自身の current-condition と last-inspected-at を更新し、続けて再公開してパブリックAPI 側でも変更が見えるようにします。
await fetch(itemUrl, { method: "PATCH", headers: cmsHeaders(config, { "Content-Type": "application/json" }), body: JSON.stringify({ fields: [ { key: "current-condition", type: "select", value: condition }, { key: "last-inspected-at", type: "date", value: inspectedAt }, ], }),});
await fetch(`${itemUrl}/publish`, { method: "POST", headers: cmsHeaders(config),});実際のハンドラーには、これらの呼び出しのまわりに検証とエラー処理が加わっています。完全なコードは backend/src/routes/reports.ts と backend/src/routes/assets.ts を参照してください。
ステップ4 — フロントエンドを動かす
Section titled “ステップ4 — フロントエンドを動かす”cd ../frontendnpm installnpm run devhttp://localhost:5173 を開きます。フロントエンドはインテグレーションAPI を直接呼びだすことはなく、バックエンド自身のルート(/api/assets・/api/reports など)だけを呼び出します。それを Vite の開発サーバーがポート 3000 のバックエンドにプロキシします。トークンは終始バックエンド側にとどまります。
地図上の資産をクリックしてポップアップを開き、Start inspection をクリックしてレポートのフォームを開きます。


フォームに入力し、Submit report をクリックします。すると、ステップ3 のバックエンドのルートが順番に呼び出されます — 写真のアップロード、レポートの作成、公開、資産の更新の順です。成功すると、地図のステータス欄に「Report submitted and <assetId> updated」と表示されます。View report history ボタンから、これまで送信されたレポート(添付した写真を含む)を一覧できます。

ステップ5(任意) — Re:Earth Visualizer と連携する
Section titled “ステップ5(任意) — Re:Earth Visualizer と連携する”このステップは任意です。アプリ本体の上に乗せるおまけであり、これ以降の内容が前提とするものではありません。
2つの CMS モデルは、パブリックAPI を使えばバックエンドを介さずブラウザから直接読み取ることもできます。
- 各モデルの パブリックAPI 設定で 読み取り タブを開き、モデルを有効にして 変更を保存 をクリックします
- 各モデルの
.geojsonエンドポイントを確認します:https://api.cms.reearth.io/api/p/<workspace>/<project>/<model>.geojson
続いて、Re:Earth Visualizer で次の操作をします。
- 新規プロジェクトを作成します
- 各モデルについて、+新規レイヤー → リソースからレイヤーを追加 をクリックし、GeoJSON タブを選び、ソースタイプ をデフォルトの アセットから ではなく Web から に設定して、モデルの
.geojsonエンドポイントを リソースURL に貼り付け、レイヤーに追加 をクリックします - 公開 タブを開き、公開 をクリックします
公開した URL を知っている人は誰でも、Visualizer の地図上でバックエンドが書き込んでいるのと同じインフラ資産と点検レポートを見られるようになります。

トラブルシューティング
Section titled “トラブルシューティング”レポートの作成で invalid value が返る
選択肢フィールドに送った値が、モデルで定義した選択肢のいずれとも一致していません。issue-category・severity など、他の選択肢フィールドの値をステップ1 のスキーマと照らし合わせてください。
地図に資産が1件も表示されない
バックエンドの .env が正しいワークスペース・プロジェクト・モデルキーを指しているか、infrastructure-assets に1件以上アイテムが存在するかを確認してください。
Visualizer に写真が表示されない
Visualizer はパブリックAPI を読み取っており、パブリックAPI は公開済みのアイテムしか返しません。レポートがドラフトのままになっていないか、公開済みかを確認してください。
完了チェックリスト
Section titled “完了チェックリスト”- ステップ1 で作成したインフラ資産が地図に表示される
- 点検レポートを送信すると
inspection-reportsにアイテムが作成・公開される - レポート送信後、対象資産の状態と最終点検日が更新される
- レポート履歴に送信済みのレポートがすべて表示される
- (任意)Re:Earth Visualizer でも同じデータがパブリックAPI 経由で表示される