Article

Retoolで管理画面を爆速開発する方法

高田晃太郎
Retoolで管理画面を爆速開発する方法

社内ツールに費やす開発時間は想像以上に大きい。Retoolが公表した内製ツール調査や各社の開発者生産性レポートでは、開発者の稼働の相当割合が内部向け機能や保守に割かれていることが示され、月あたり数十時間規模での工数消費が一般的だとされる¹²。実務でも、受注・在庫・請求といったコア業務の管理画面は常に改修要求が入り、いわゆる“終わらない開発”になりやすい。そこで、ローコードのRetoolを軸に、UIコンポーネント、データ接続、権限と監査、デプロイを統合し、要件の揺れに耐えながら数日で立ち上げ、短期間で運用に乗せることを目指す方法論と実装を、実運用を意識した視点で整理する³。

ここで扱う対象は、中規模SaaSやEC、業務SaaSのエンジニアリング組織だ。機能要件はCRUD(作成・読み取り・更新・削除)中心だが、SLA(サービス品質合意)や監査証跡、RBAC(役割ベースのアクセス制御)、アプリ埋め込み、外部API連携、そしてオンコールに耐える可観測性(Observability)が求められる。単に“早く作る”のではなく、運用コストと変更容易性を両立する設計に軸足を置く。

基盤設計:Retoolで作る管理画面アーキテクチャ

Retoolの価値は、データ接続、UI、ロジック、権限、監査、デプロイを同一平面で扱えることにある⁴。要件定義の初動では、データソースの接続方式と権限、変更の伝播経路を決める。プロダクションDB直結は回避し、読み取りはリードレプリカ(読み取り専用の複製)やビューを介し、書き込みはストアドプロシージャやBFF(Backend for Frontend)経由に寄せると、責務が明確になる。権限はIdP(Identity Provider)連携のSSO(シングルサインオン)とRetoolのロールで二段構えにし、アプリ側UIでも再確認するガードを置く⁵。監査はRetoolの監査ログに加えて、業務テーブル側にも操作者と相手先を残す列を設けておくと、調査が速い⁶。環境分離はリソースでステージングと本番を切り替え、アプリは同一JSONを環境変数で制御する(エンドポイントやAPIキーは環境変数で注入)。

データ接続とセキュリティの勘所

RetoolのDBクエリはパラメータバインドと準備済みステートメントを前提にする(Query Editorの「Use prepared statements」を有効化)。ILIKEやIN句の多用で文字列結合に逃げないこと、そして行レベルセキュリティが必要ならビューで事前に絞る設計にする。読み取りのパフォーマンスはインデックス設計とページネーションで支える。以下はページングと検索に対応したPostgreSQLの例だ。

-- PostgreSQL (Retool prepared statements 有効想定)
SELECT id, name, email, status, updated_at
FROM public.customers
WHERE ({{ search_input.value || '' }} = '' OR name ILIKE '%' || {{ search_input.value }} || '%')
ORDER BY updated_at DESC
LIMIT {{ table.pageSize }}
OFFSET {{ table.pageIndex * table.pageSize }};

更新系はアプリ側UIでの多段確認と、サーバ側の制約で二重に守る。更新直後はサーバ値で再読込して差分を吸収し、楽観ロックを使用する場合はversion列を用意すると衝突を検知しやすい。

-- 状態更新(楽観ロックを併用する場合は version 条件を追加)
UPDATE public.customers
SET status = {{ status_select.value }}, updated_at = NOW()
WHERE id = {{ table.selectedRow.data.id }}
RETURNING *;

役割・権限と監査の実装パターン

SSOで所属と属性をIdPから渡し、Retoolのロールにマッピングした上で、UI側にも最終防衛ラインを置くと事故を減らせる⁵。ページ入場時にロールを判定して、編集コンポーネントの有効化を切り替えるのが実務的だ。監査はRetoolのアプリ実行ログでオペレーションの粒度を確保し、業務テーブルには操作者ID、相手先、理由コードを残す⁶。

// Retool JavaScript Query: 役割に応じてUIを制御
try {
  const roles = current_user.value.roles || [];
  const canWrite = roles.includes('ops_admin') || roles.includes('cs_lead');
  state.setValue('canWrite', canWrite);
  if (!canWrite) {
    utils.showNotification({ title: '閲覧専用', description: '編集権限がありません', notificationType: 'warning' });
  }
  return { canWrite };
} catch (e) {
  utils.showNotification({ title: '権限確認エラー', description: e.message, notificationType: 'error' });
  throw e;
}

埋め込みとモノレポ統合

プロダクト内に管理UIを埋め込むなら、iframeの組込みとSSOでのシングルセッションが最も単純で堅い⁷⁸。BFFで業務APIを集約し、RetoolアプリはそのBFFを叩く。これにより、レート制御や監査、モデルの単一責務を維持できる。まずはBFFの簡易実装例を示す。

// Node.js (Express) BFF の最小例: 読み取りと更新、エラーハンドリング
import express from 'express';
import pg from 'pg';

const app = express();
app.use(express.json());
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });

app.get('/v1/orders', async (req, res) => {
  try {
    const page = Number(req.query.page ?? 0);
    const size = Math.min(200, Number(req.query.size ?? 50));
    const q = String(req.query.q ?? '');
    const { rows } = await pool.query(
      `SELECT id, status, total, updated_at
       FROM orders
       WHERE $1 = '' OR customer_name ILIKE '%' || $1 || '%'
       ORDER BY updated_at DESC
       LIMIT $2 OFFSET $3`,
      [q, size, page * size]
    );
    res.json({ items: rows });
  } catch (e) {
    res.status(500).json({ error: 'internal_error', message: e.message });
  }
});

app.patch('/v1/orders/:id', async (req, res) => {
  try {
    const { status } = req.body;
    const { rows } = await pool.query(
      `UPDATE orders SET status = $1, updated_at = NOW() WHERE id = $2 RETURNING *`,
      [status, req.params.id]
    );
    if (rows.length === 0) return res.status(404).json({ error: 'not_found' });
    res.json(rows[0]);
  } catch (e) {
    res.status(500).json({ error: 'internal_error', message: e.message });
  }
});

app.listen(process.env.PORT || 3000);

プロダクト側は、iframeでRetoolアプリを読み込み、同一ドメインまたは同一IdPセッションで安全に連携する。CSPとsandbox属性を適切に設定し、クリックジャッキング対策もあわせて行う⁹。

// React: 管理アプリを安全に埋め込む
import React from 'react';

export function AdminAppEmbed() {
  const url = new URL('https://your-retool-instance.retool.com/apps/OrdersAdmin');
  url.searchParams.set('embed', 'true');
  return (
    <iframe
      src={url.toString()}
      title="Orders Admin"
      style={{ width: '100%', height: '100vh', border: 0 }}
      referrerPolicy="same-origin"
      sandbox="allow-scripts allow-forms allow-same-origin"
    />
  );
}

速度の正体:コンポーネントとクエリの実装パターン

RetoolのTable、Form、JSONViewer、Tabsなどのプリミティブは、CRUD作業の可変要件に強い。中でもTable v2のバーチャルスクロールとカラムの条件付き書式は、運用現場の“見落とし”を減らすのに効く¹⁰。更新処理は楽観更新で即時フィードバックを返し、その裏で確定処理を走らせる。失敗したら差分を巻き戻し、ユーザーにエラーを明確に示す¹¹。

CRUDグリッドの設計と楽観更新

Tableの編集結果はrecordUpdatesから取得し、更新APIにまとめて渡す。成功件数を通知し、部分失敗は行ごとにメッセージを提示する。以下のJavaScript Queryは、その最小構成だ。

// Retool JavaScript Query: Table の編集差分を一括更新
async function run() {
  try {
    const pending = tableCustomers.recordUpdates || [];
    if (pending.length === 0) return { updated: 0 };
    const payload = pending.map(r => ({ id: r.id, status: r.status }));
    const result = await updateCustomers.trigger({ additionalScope: { payload } });
    utils.showNotification({ title: '更新完了', description: `${result.length}件を更新しました`, notificationType: 'success' });
    return { updated: result.length };
  } catch (err) {
    utils.showNotification({ title: '更新失敗', description: err.message, notificationType: 'error' });
    throw err;
  }
}
return run();

ページングはサーバ側で行い、検索条件は控えめにプリセットして運用現場の入力負担を下げる。時間帯や担当者など、現場が実際に使う軸に寄せるとクレーム対応が早くなる。

REST連携、リトライ、タイムアウト

外部APIはSLAが揺れる。RetoolのJavaScript Queryでタイムアウトと指数バックオフのリトライを実装し、障害時のUXを守る。IdPや課金基盤のAPIは、障害のインパクトが大きいため特に手当てする。

// Retool JavaScript Query: リトライ + タイムアウト付き fetch
async function fetchWithRetry(url, options, maxRetries = 3, timeoutMs = 8000) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const controller = new AbortController();
    const timer = setTimeout(() => controller.abort(), timeoutMs);
    try {
      const res = await fetch(url, { ...options, signal: controller.signal });
      clearTimeout(timer);
      if (!res.ok) throw new Error(`HTTP ${res.status}`);
      return await res.json();
    } catch (e) {
      clearTimeout(timer);
      if (attempt === maxRetries) throw e;
      await new Promise(r => setTimeout(r, 2 ** attempt * 300));
    }
  }
}

const apiUrl = `${api_base.value}/v1/orders`;
return fetchWithRetry(apiUrl, { method: 'GET', headers: { Authorization: `Bearer ${api_token.value}` } });

可観測性:操作ログとメトリクス

Retoolの監査ログは誰がいつ何を実行したかを追うのに向くが、SLO(サービス目標値)管理には業務ドメインのメトリクスが必要だ⁶。操作件数、失敗率、P95(95パーセンタイル)処理時間をBFFで集計し、外部のAPMに送ると一次切り分けが速くなる。障害時はRetool側でのUIエラーレートと、BFFのHTTP 5xx比率を並べて見ると相関がわかりやすい。

// Retool JavaScript Query: 失敗イベントを観測基盤へ送る
try {
  // ... 何らかの処理
} catch (e) {
  await fetch(observability_endpoint.value, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      app: 'orders_admin',
      event: 'update_failed',
      error: e.message,
      user: current_user.value.email,
      at: new Date().toISOString()
    })
  });
  throw e;
}

運用で勝つ:変更容易性、コスト、ベンチマーク

速く作った後に待っているのは、さらに速い変更サイクルだ。Retoolはアプリ定義をJSONとしてバージョン管理できるため、ブランチ運用とレビュー運用に馴染む¹²。開発・検証・本番のリソースを分け、環境変数でエンドポイントを切り替えると、同一アプリを変数差し替えで昇格できる。セキュリティ修正はBFFに集約して即時反映し、Retoolのアプリ側はノーリリースで守れるように設計するのがコスト効率的だ。

比較の目安として、同一要件の注文管理UI(ページング付き一覧、詳細表示、単項目編集、外部課金APIのメモ連携)をスクラッチ(React+UIライブラリ)とRetoolで作る場合、初期立ち上げまでの時間は、前提を揃えればRetoolが「数時間〜1日」、スクラッチが「数日」程度になるケースが一般的に報告される。描画の初回ロード時間やDBコミットのP95は、ネットワークやDB設計が支配的で大差が出にくく、いずれも「1〜2秒台の初回表示」「200〜300ms台のP95」程度に収まることが多い。差が開くのは開発と変更のリードタイムで、Retoolはコンポーネントとデータ結線の再利用で優位に立ちやすい。

費用対効果の評価は、実装と変更の時間短縮に人件費を掛け合わせた一次近似がわかりやすい。例えば、管理画面の新規機能追加に毎回2人日を要していたところ、Retool化後に平均0.5人日に短縮できたと仮定すると、月5件の改修で月あたり3人日削減に相当する。人件費、Retoolライセンス、BFFの運用費を積み上げ、六か月程度で回収可能かを意思決定の目安にすると現実的だ。

より深く考えたい場合は、内製DXの投資対効果やモジュール境界の切り方を押さえておくと設計の迷いが減る。

まとめ:最短で価値に到達し、運用で磨く

Retoolの強みは、要件の揺らぎを味方に変える速さだ。DBとAPIをつなぎ、TableとFormで仮説を可視化し、現場の反応に合わせて配置とロジックを微調整する。その場で反映される編集体験は、現場との合意形成を圧倒的に速くする。埋め込みとBFFで境界を引き、権限と監査で守り、メトリクスで磨く。この一連の循環ができてしまえば、管理画面はプロダクトの成長速度に追随し続ける。

いま抱えている改修要求の山に、まずどの一手を打つか。明日の定例までに、一覧と単項目編集だけを持つ最小の管理UIをRetoolで組んで、現場と合意できるかを確かめてみてほしい。数時間後に動くものがある状況は、議論を前に進める最強の武器になるはずだ。

参考文献

  1. Retool Blog. State of Internal Tools 2021: Developers spend more than 30% of their time building internal applications. https://retool.com/blog/state-of-internal-tools-2021#:~:text=Developers%20spend%20more%20than%2030,their%20time%20building%20internal%20applications
  2. Retool Blog. State of Internal Tools 2022: Technical teams spend a lot of time on internal tools. https://retool.com/blog/state-of-internal-tools-2022#:~:text=Technical%20teams%20spend%20a%20lot,of%20time%20on%20internal%20tools
  3. Retool Use Case. Admin panels: connect to your data and get right to building. https://retool.com/use-case/admin-panels?_keyword=react&adgroupid=163899345310&gad_source=1&gclid=Cj0KCQjwsPCyBhD4ARIsAPaaRf0fb-wg7GBTl1_vNJPMnzLCukl5OJVrbi4IMsNnoJT5OYga0RKgRYMaAipJEALw_wcB&hsa_acc=7420316652&hsa_ad=694014950136&hsa_cam=16592213471&hsa_grp=163899345310&hsa_kw=react&hsa_mt=b&hsa_net=adwords&hsa_src=g&hsa_tgt=kwd-12703086&hsa_ver=3&utm_campaign=16592213471&utm_content=694014950136&utm_medium=search&utm_source=google&utm_term=react#:~:text=,and%20get%20right%20to%20building
  4. Retool Use Case. Build your admin panel fast with prebuilt components and data connectors. https://retool.com/use-case/admin-panels?_keyword=react&adgroupid=163899345310&gad_source=1&gclid=Cj0KCQjwsPCyBhD4ARIsAPaaRf0fb-wg7GBTl1_vNJPMnzLCukl5OJVrbi4IMsNnoJT5OYga0RKgRYMaAipJEALw_wcB&hsa_acc=7420316652&hsa_ad=694014950136&hsa_cam=16592213471&hsa_grp=163899345310&hsa_kw=react&hsa_mt=b&hsa_net=adwords&hsa_src=g&hsa_tgt=kwd-12703086&hsa_ver=3&utm_campaign=16592213471&utm_content=694014950136&utm_medium=search&utm_source=google&utm_term=react#:~:text=,your%20admin%20panel
  5. Retool Docs. SAML SSO for Retool Cloud and Self-hosted. https://docs.retool.com/sso/tutorials/custom/saml#:~:text=Retool%20Cloud%20and%20Self,and%20other%20SAML%20SSO%20providers
  6. Retool Docs. Audit logs overview. https://docs.retool.com/org-users/guides/monitoring/audit-logs#:~:text=Retool%20automatically%20logs%20user%20actions%2C,when%20the%20action%20took%20place
  7. Retool Docs. Embed apps: Users within your Retool organization. https://docs.retool.com/apps/guides/app-management/embed-apps#:~:text=Users%20within%20your%20Retool%20organization,parent%20app%20and%20then%20Retool
  8. Retool Docs. Embed apps: Share the same authentication state. https://docs.retool.com/apps/guides/app-management/embed-apps#:~:text=If%20your%20parent%20application%20uses,share%20the%20same%20authentication%20state
  9. Retool Docs. Embed apps: Use the same domain. https://docs.retool.com/apps/guides/app-management/embed-apps#:~:text=Use%20the%20same%20domain%E2%80%8B
  10. Retool Blog. Supercharging the Retool Table. https://retool.com/blog/supercharging-the-retool-table#:~:text=Your%20table%20also%20has%20to,may%20still%20leave%20users%20frustrated
  11. HackerNoon. Optimistic updates in frontend applications. https://hackernoon.com/optimistic-updates-in-front-end-applications#:~:text=Optimistic%20updates%20are%20front,data%20integrity%20and%20user%20satisfaction
  12. Retool Docs. Source Control: branch-based workflows. https://docs.retool.com/source-control#:~:text=Source%20Control%20allows%20organizations%20to,made%20on%20a%20separate%20branch