Accessおじさんのための“PocketBaseスキーマ移行術”──VBS廃止時代の軽量移行ガイド

Accessおじさんのための“PBスキーマ移行術”──VBS廃止時代の軽量移行ガイド TECH
Accessおじさんのための“PBスキーマ移行術”──VBS廃止時代の軽量移行ガイド

来年、2026 年──
Windows 環境から VBS(VBScript)が正式に消える
そのニュースは、単なる「古い機能の削除」ではない。
長年、日本の社内業務を裏側で支えてきた “Access アプリ文化” が、
静かにひとつの節目を迎えるという意味でもある。

VBScript deprecation: Timelines and next steps | Windows IT Pro Blog
Learn about the deprecation of Visual Basic Scripting edition.

思えば、あの時代は平和だった。
Access のフォームにボタンを置き、
クエリを 3 つほど作って VBA を 20 行書けば、
見積もりだろうが、注文管理だろうが、在庫台帳だろうが、
明日から使える業務アプリが完成した。

  • Excel では手に負えない
  • 本格的な Web システムを作る予算もない
  • エンジニアもいない
  • でも現場は明日から動かなければならない

そんな“日本の現場”を、Access は長く救ってきた。

だが、その功績と引き換えに、
巨大で複雑すぎるローカル MDB、
クエリ地獄、
VBAの迷宮、
1台のPCが壊れただけで業務停止──
そんな 構造疲労が限界に達したアプリ も少なくない。

そして今日、
ブラウザは強くなり、
LAN アプリは姿を消し、
バックエンドは 1 バイナリで起動する時代になった。

Access の“次の場所”を探すなら、
それは Excel VBA の延命でも、巨大な web フレームワークでもない。
もっと 軽くて、単純で、現場が保守可能で、
しかもクラウドにも載せられる「中庸の技術」
が必要になる。

そこで名前が挙がるのが、

  • PocketBase(軽量バックエンド)
  • Svelte(素直な UI)
  • XState(業務フローと状態管理)
    という“3本柱”。

Access の便利さとスピード感を残しながら、
根本の構造疲労だけを取り除いた組み合わせだ。

ここから先は、 Access アプリを PB に移すときの具体的なスキーマ設計術 をまとめた。
特に「テーブルを増やしすぎる」「Enum を全部マスタ化する」など、
Access 時代の“悪癖”をいかにリハビリするかに焦点を当てた。

Access 文化を知っている人ほど、
この移行は驚くほどスムーズに進むはずだ。

  1. 導入
  2. 1. Accessおじさんの「なんでもマスタ病」とは何か
  3. 2. どうしてそうなったのか(Access時代の事情)
  4. 3. Web+PocketBase時代の設計原則
  5. 4. PocketBaseで「マスタ病」を矯正するルール
    1. 4-1. 3件しかないものは enum にする
    2. 4-2. 真のマスタだけコレクションにする
    3. 4-3. 「運用で調整したい値」は設定コレクションへ
  6. 5. Svelte側での考え方:UIに正規化を引きずらない
    1. 5-1. APIで“素直な形”を取って、UI用の構造はフロントで組む
    2. 5-2. 小さなenumはSvelte側でも“直書きでいい”
  7. 6. 実際に移行するときのチェックリスト
  8. 7. まとめ
  9. 8. ケース別:AccessマスタをPocketBaseへ移行するとどう変わる?
    1. 8-1. 性別マスタ(GenderMaster)の場合
      1. ■ Access側(狂気の例)
      2. ■ PocketBase側(健全な世界)
    2. 8-2. 都道府県マスタ(PrefectureMaster)
      1. ■ Access側(よくあるやつ)
      2. ■ PocketBase側(これは“真のマスタ”なので残す)
      3. ここは 正当なマスタ として残すのが正解。
    3. 8-3. 単価マスタ(PricingMaster)
      1. ■ PocketBase側:ぜんぶ「設定コレクション」に集約
  10. 9. クエリ(アクセスの保存クエリ)をどう移行するか
    1. 9-1. PBで置き換えられる部分は意外と多い
    2. 9-2. JOINが必要な一覧は“フロントJOIN”でOK
      1. 流れ
    3. 9-3. どうしても多重JOINが必要なら「ミニAPI層」を足す
  11. 10. 一刀両断の総まとめ
  12. 11. ケーススタディ:Accessアプリを PocketBase+Svelte に移すとこうなる
    1. 11-1. Access版のテーブル構造(ありがちなやつ)
    2. 11-2. PocketBase版にするとこうなる(激スッキリ)
    3. 11-3. UI(Svelte)側の画面構造も変わる
    4. 11-4. クエリ(Access時代の地獄)をどう移す?
      1. ① 単純一覧はPBの filter で代用
      2. ② “レイヤー付き一覧”は expand
      3. ③ “単価算出”はSvelte側で計算する
    5. 11-5. 実際のデータ構造比較
      1. ● Accessの注文データ(例)
      2. ● PocketBaseの注文データ(例)
    6. 11-6. Access時代より、はるかに保守しやすい理由
  13. 12. PocketBase × Svelte × XState の“理想的な役割分担”
    1. PB:データと認証を“正しく”担当する
    2. Svelte:PBを“薄く・高速に”使うUI
    3. XState:人間の“業務手順”をコード化する
    4. なぜこの3つを組み合わせると“Access超え”が成立するのか?
    5. 今回のまとめ:この3つは「役割破綻しない」奇跡の組み合わせ
  14. 13. PocketBase + Svelte + XState の開発環境を10分で整える
    1. 1. PocketBase を置く(30秒)
    2. 2. Svelte プロジェクトを作る(1分)
    3. 3. PocketBase JS SDK を追加(30秒)
    4. 4. XState を追加(30秒)
    5. 5. とりあえず “orders” コレクションを作る(1〜2分)
    6. 6. Svelte 側で “注文を保存するミニフォーム” を追加(3分)
    7. 7. リアルタイム一覧も1行で動く(追加1分)
    8. 8. これで“開発に入れる状態”が100%整う(合計10分)
    9. XState の最小サンプル
  15. 参照

導入

古い業務システムのDBを覗くと、こんなテーブルが並んでいることがある。

  • 性別マスタ
  • 曜日マスタ
  • はい・いいえマスタ
  • フラグ値マスタ(0:無効、1:有効)

初めて見たときは「気でもふれたのか?」と思うが、当時のAccess文化ではわりと普通だった。
正規化とJOINこそ正義、という時代の産物だ。

ただ、このノリをそのままPocketBase+Svelteの世界に持ち込むと、設計が一気に重くなる。
この記事では、Access時代の「なんでもマスタ病」をどう分解し、PocketBase+Svelteにきれいに移植するかを整理してみる。


1. Accessおじさんの「なんでもマスタ病」とは何か

典型的な症状はこんな感じ。

  • 値が2〜3種類しかないのに、必ず別テーブルを作る
    • 性別マスタ(男・女・不明)
    • フラグマスタ(0/1)
    • はい・いいえマスタ
  • テーブル数がやたら多いのに、実データは数レコードしか入っていない
  • クエリを開くと、INNER JOINが何重にも重なっている

彼らの頭の中にはだいたいこんなロジックがある。

  • 「正規化されていない=悪」
  • 「マスタテーブルを作る=設計がちゃんとしている」
  • 「クエリでたくさんJOINする=仕事してる感」

その結果、
業務的には単なる enum でいいものまで全部別テーブル化され、
クエリとフォームがスパゲッティ化していく。


2. どうしてそうなったのか(Access時代の事情)

多少の擁護もしておく。

Access時代に「マスタ乱造」がそれなりに合理的だった理由はある。

  • フォームのコンボボックスで「行ソースとしてマスタを指定する」と、UI実装がラクだった
  • クエリにJOINすれば、人間が意味を読み取りやすかった(レポート設計上の都合)
  • DB=Accessファイル一つ、の世界では、
    「ちょっとしたマスタ」が増えても実害が少なかった

要するに、技術的・組織的制約の中では、それが「それなりの合理的解」だった時期がある。

問題は、この感覚をそのままWebアプリの世界に持ち込むことだ。


3. Web+PocketBase時代の設計原則

PocketBase+Svelteの世界では、次のように切り分けたほうがきれいになる。

  1. 変化しない小さな選択肢は enum(列挙)で十分
    • 性別
    • ステータスが数種類だけのフラグ
    • 画面上の「はい/いいえ」
  2. 頻繁には変わらないが、業務的に意味があるものは 真のマスタ
    • 都道府県
    • 支店/部署
    • 商品種別など
  3. 運用で増える可能性があり、管理画面から編集したいものは 設定テーブル
    • 送料テーブル
    • 単価テーブル
    • 納期ランク
  4. ロジックで吸収すべきものは マスタではなくコードに書く
    • 「2枚複写までは減感不可」
    • 「4枚複写のときは特定用紙NG」

Accessおじさんの世界では、おおむね 1〜4 を全部「マスタテーブル」でやろうとした。
Web時代はここをちゃんと分けてあげるだけで、設計がかなりスッキリする。


4. PocketBaseで「マスタ病」を矯正するルール

PocketBase+SvelteでAccessアプリを移行する前提で、
次のようなマイルールを決めておくと地獄を避けられる。

4-1. 3件しかないものは enum にする

例:性別

  • Access時代
    • M_Gender テーブル
    • GenderID 1/2/3
    • フォームやクエリで毎回JOIN
  • PocketBase時代
    • gender フィールド(type: select)
    • values: "male" | "female" | "other"

ビジネス的に「ユーザーがマスタを編集する必要がない」ものは、
基本 select型フィールドの固定値 で十分。

4-2. 真のマスタだけコレクションにする

例:都道府県、支店、担当者など。

  • 他のレコードから多数参照される
  • 将来増えたり統合されたりする可能性がある
  • 管理画面から編集したい

こういうものは PocketBase のコレクションとして作り、
relationフィールドで参照する。

「性別マスタ」や「はい/いいえマスタ」はここには入れない。

4-3. 「運用で調整したい値」は設定コレクションへ

例:複写伝票の単価テーブル

  • 用紙×色数×複写枚数×部数で単価が変わる
  • あとから単価改定することがある

これは pricing_rules のようなコレクションとして分離しておく。

Accessだと「単価マスタ」「用紙マスタ」「色マスタ」「複写区分マスタ」などが乱立していたが、
PocketBaseでは

  • 本当に意味のある軸だけをテーブルにする
  • それ以外は enum or code で表現する

くらいに削ったほうが、シンプルで保守しやすい。


5. Svelte側での考え方:UIに正規化を引きずらない

Access時代は、
「正規化されたテーブル構造」=「フォーム設計」の元ネタだった。

  • サブフォームで子テーブルをそのまま出す
  • JOIN済みクエリをフォームのレコードソースにする

Web+Svelteでは、ここを一度断ち切ってしまっていい。

5-1. APIで“素直な形”を取って、UI用の構造はフロントで組む

  • PocketBaseからは
    • orders
    • layers
    • options
      を別々に取得
  • Svelte側で
    • ordersごとに layers を紐づけて配列にまとめる
    • 表示や入力に向いた形のオブジェクトを組み立てる

つまり、

DBはあくまで整った保存形式
UIにとって都合の良い形はフロント側で組む

という設計に切り替える。

Accessの感覚で「UIとDB構造を1:1に合わせる」発想をやると、
Svelteでも結局スパゲッティになる。

5-2. 小さなenumはSvelte側でも“直書きでいい”

性別・ステータスなどの小さなenumは、
PocketBaseのフィールド定義と同じ定数をSvelte側に持っていても構わない。

  • どうせ数が少ない
  • ビジネス的にもそう簡単には増えない
  • 変わるときはコード改修でよい

「マスタを編集したい」わけではなく、
「ただ値を統一しておきたい」だけなら、
enum+共通定数で十分だ。


6. 実際に移行するときのチェックリスト

AccessアプリをPocketBase+Svelteに持っていく前に、
テーブルを一覧して次のように仕分けするといい。

  1. 性別・フラグ・はい/いいえ系:
    → enum(selectフィールド)に変換
  2. 都道府県・部署・担当者など:
    → 真のマスタとしてコレクション化
  3. 単価・ランク・種別マスタ:
    → 設定テーブル(pricing_rules, settingsなど)に集約
    → 不要な分割マスタは統合
  4. クエリ(保存クエリ・View的なもの):
    • まず必要な集計/一覧機能を洗い出す
    • PocketBaseのAPI(+必要ならBun/NodeのAPI)で実現可能な形に組み直す
    • UI側では「整形済みデータ」を受け取る
  5. フォーム・サブフォーム:
    • 画面単位でSvelteコンポーネントに分割
    • 状態遷移や依存関係が複雑なものはXStateなどに逃がす

この仕分けだけでも、「マスタ病」がかなり落ちるはず。


7. まとめ

  • Access時代の「なんでもマスタ」は、当時の事情もあってそれなりに合理性があった
  • しかしそのままWeb世界に持ち込むと、設計が重くなり、保守性も落ちる
  • PocketBase+Svelteでは
    • 小さな固定値 → enum
    • 意味のある軸 → 真のマスタ
    • 運用で変わるもの → 設定テーブル
    • 条件分岐だらけのロジック → コード(できれば状態マシン)
      にきれいに分解したほうがいい

Accessおじさんの資産をそのまま移植するのではなく、
「思想だけ引き継いで、実装は現代のやり方にする」のが正解だと思う。


8. ケース別:AccessマスタをPocketBaseへ移行するとどう変わる?

Access時代の“お決まりマスタ”を例にして、
PocketBase+Svelteでどう整理されるのか、
実際のテーブル定義レベルで比較していく。


8-1. 性別マスタ(GenderMaster)の場合

■ Access側(狂気の例)

M_Gender
----------------
GenderID | Name
1        | 男
2        | 女
3        | 不明

フォームでは毎回これとJOIN。
クエリも必ず JOIN。

■ PocketBase側(健全な世界)

users
  - gender: select ["male", "female", "other"]

終了。

  • マスタテーブル → 廃止
  • JOIN → 不要
  • 管理画面 → 値は固定なので編集不要

性別のように「世界観として増えない(頻繁に更新しない)」ものは
enum(select型)で持つのが最適解。


8-2. 都道府県マスタ(PrefectureMaster)

■ Access側(よくあるやつ)

M_Prefecture
--------------
PrefID | Name
1      | 北海道
2      | 青森
…
47     | 沖縄

顧客マスタ・住所マスタとJOINしまくる。

■ PocketBase側(これは“真のマスタ”なので残す)

prefectures(コレクション)
  - name: text
  - code: number

顧客のテーブルはこう:

clients
  - name: text
  - prefecture: relation(prefectures)

ここは 正当なマスタ として残すのが正解。

  • 将来増えない
  • UIの選択肢として必要
  • 他のレコードから何十回も参照される
  • PocketBase管理画面で簡単に編集できる

Accessの正規化思想が正しく生きる場所は“ここだけ”。


8-3. 単価マスタ(PricingMaster)

印刷・卸・製造系に頻出の地獄。

Access時代は:

M_Paper
M_Color
M_CopyCount
M_UnitPrice
M_CalcRule
…

気付いたら 10マスタ20のクエリ がぶら下がる。

■ PocketBase側:ぜんぶ「設定コレクション」に集約

pricing_rules
  - paper: select ["N40", "N30", "ケント紙"]
  - color: select ["black", "fullcolor"]
  - copies: number
  - unit_price: number
  - note: text

こうすることで:

  • マスタ乱立 → 1コレクションに統合
  • Accessのクエリ → PocketBaseのfilterで代用 or フロント整形
  • 複雑な計算 → Svelte or XStateで実行

Accessのように
マスタ単位で分割しすぎる弊害を完全除去できる。


9. クエリ(アクセスの保存クエリ)をどう移行するか

Accessの世界では最重要だった「クエリ」。
SQLを書く場所でもあり、実質的なビジネスロジックの核心部分。

問題はこれをそのままPocketBaseに移せないこと。
PBにはJOINもVIEWもない。

でも焦る必要はない。


9-1. PBで置き換えられる部分は意外と多い

  • 単純なフィルター(WHERE相当)
  • ソート(ORDER BY)
  • ページング
  • 特定フィールド条件の絞り込み

PocketBaseのRESTは「filter」で結構強いことができる。

例:

?filter=(copies=2 && size='A4')

簡単なクエリなら十分代替可能。


9-2. JOINが必要な一覧は“フロントJOIN”でOK

Accessおじさんは言う:
「JOINはDBでやるべきだ!」

Web開発者は言う:
「JOINはフロントでやっていい(データ量少ないなら)」

PocketBase+Svelteでは後者の考えでいい。

流れ

  1. PBから orders をフェッチ
  2. relationを expand=client で展開
  3. layers は order_id で追加フェッチ
  4. 入力や表示に必要な形に整形して配列化

例:

[
  {
    id: "abc123",
    title: "複写伝票A",
    client: { name: "○○商事" },
    layers: [
      { paper: "N40", color: "black" },
      { paper: "N30", color: "black" }
    ]
  }
]

これでAccessの「主テーブル+子テーブル+JOIN済みクエリ」UIを
完全にSvelte側で再現できる。


9-3. どうしても多重JOINが必要なら「ミニAPI層」を足す

Bun・Deno・Nodeのどれでもいい。
軽量APIを1枚かませて、

  • PB RESTを複数叩く
  • 結果をJOIN
  • JSONで返す

これでAccess時代のVIEW相当を再現できる。

PocketBaseの得意領域:

  • 単純なCRUD
  • 認証
  • Realtime
  • コレクション管理

苦手領域:

  • 多段JOIN
  • 複雑集計
  • 業務ルールの実行

だから、

PBは“データレイク”
JOINや集計は“別レイヤー”
UIは“Svelteで組む”

という三段構成が一番しっくり来る。


10. 一刀両断の総まとめ

  • Accessおじさんの“何でもマスタ病”はWebに持ち込んではいけない
  • PocketBaseはシンプルなDB設計とenumが相性抜群
  • 複雑ロジックはSvelte(+必要ならXState)に持ち込む
  • JOINが必要ならフロントJOIN
  • さらに複雑ならBun/NodeでミニAPI層を足す
  • 結果、Access時代よりシンプルで綺麗な設計に収束する

11. ケーススタディ:Accessアプリを PocketBase+Svelte に移すとこうなる

ここでは、実在しそうで、あなたも触ったことがありそうな
“典型的Accessアプリ” を 1つモデルにする。

題材はこれ:

複写伝票の受注管理アプリ(Access97〜2003時代の遺産)

  • 画面1枚に全部詰まってる
  • サブフォームに子テーブルが大量
  • クエリが17個くらい保存されてる
  • 何でもマスタ化
  • 複写枚数×紙×色の単価ルールが複雑
  • 印刷現場のおじさんが長年使ってる

あなたの業界にガッツリ刺さるやつ。


11-1. Access版のテーブル構造(ありがちなやつ)

T_Orders
T_OrderDetails
M_Client
M_Paper
M_Color
M_CopyCount
M_Series
M_Binding
M_DeductionFlag  ←地獄
M_PrintOption
M_Status
M_User

テーブル12個。
クエリ17個。
フォーム6枚。
レポート4枚。

ザ・Access遺産。


11-2. PocketBase版にするとこうなる(激スッキリ)

PocketBaseで作ると、
テーブル(コレクション)はたった6個で終わる。

orders
order_layers
clients
pricing_rules
users
settings(任意)

ポイント:

  • “紙マスタ”“色マスタ”“複写枚数マスタ”などは 消滅
  • order_layers には複写枚数ぶんの行が入る
  • pricing_rules に単価ロジックを全部集約
  • settings には「伝票サイズ」「ミシンオプション対応表」などを入れても良い

Access版の12テーブルが
PocketBase版の6コレクションに統合される。

理由は単純:

  • enum(固定値)はテーブル不要
  • 正規化しすぎるとPB側のAPIに合わない
  • 現代Webは「フロントでJOIN」する方が早い

11-3. UI(Svelte)側の画面構造も変わる

Access版は:

  • メインフォーム
  • サブフォーム
  • その中にさらにサブフォーム
  • タブコントロールで詳細を切り替え
  • JOINクエリが裏で暴れまわる

Svelte版はもっとシンプルになる:

OrderForm.svelte
  ├ BasicFields.svelte(ヘッダ)
  ├ LayerRepeater.svelte(複写枚数のレイヤーUI)
  ├ Options.svelte(ミシン・減感など)
  └ Summary.svelte(自動見積り)

フロントがUIロジックを受け持つので、
バックエンド側に不必要な正規化がいらなくなる。


11-4. クエリ(Access時代の地獄)をどう移す?

Access時代:

  • “受注一覧(今月分)”クエリ
  • “印刷待ち一覧”クエリ
  • “納品済み一覧”クエリ
  • “請求書発行待ち一覧”クエリ
  • “伝票合計単価”クエリ
  • “レイヤー別単価算出”クエリ

これらをぜんぶSQLで定義していた。

PocketBase版はこうする:

① 単純一覧はPBの filter で代用

?filter=status='pending'

② “レイヤー付き一覧”は expand

?expand=client

(子テーブルは別フェッチ)

③ “単価算出”はSvelte側で計算する

PBにはJOINも計算機能もないので、
pricing_rules を全部取得してフロントで条件分岐する。

XStateを使えば:

  • copies が変わった
  • 標準紙→特殊紙に変えた
  • 減感ON→OFFにした
  • ミシンの有無が変わった

こういう「Access VBAじゃないと無理だった処理」が
状態遷移図として整理され、きれいに実装できる。


11-5. 実際のデータ構造比較

● Accessの注文データ(例)

Orders
  OrderID: 102
  ClientID: 3
  Title: "A社 2枚複写 注文"
  Paper1ID: 1
  Paper2ID: 2
  Color1ID: 1
  Color2ID: 1
  Copies: 2
  DeductionFlagID: 1
  BindingID: 2

PaperID、ColorID、FlagID、BindingID…
ID地獄。


● PocketBaseの注文データ(例)

orders

{
  id: "abcd1234",
  title: "A社 2枚複写 注文",
  client: "client_record_id",
  copies: 2,
  note: ""
}

order_layers

[
  {
    order: "abcd1234",
    layer_index: 1,
    paper: "N40",
    color: "black"
  },
  {
    order: "abcd1234",
    layer_index: 2,
    paper: "N30",
    color: "black"
  }
]

Accessのように「テーブルを横に広げる」感覚ではなく、
縦方向(レコード追加)で複写レイヤーを表現する。

この方が:

  • UIで制御しやすい
  • XStateで扱いやすい
  • 子テーブル管理がシンプル

とにかく 綺麗に収まる


11-6. Access時代より、はるかに保守しやすい理由

  • 画面はSvelteが受け持つ
  • 個別ロジックはXStateに追い出せる
  • PBのコレクションは最小限
  • enumで済むものはenumにする
  • Realtimeで自動反映もできる
  • デプロイがEXE1個で終わる
  • DBはSQLite(WAL)で十分すぎる性能

Access時代の「マスタ乱造」「VBAスパゲッティ」「フォーム肥大化」から解放される。

12. PocketBase × Svelte × XState の“理想的な役割分担”

PocketBase(以下 PB)、Svelte、XState──
この3つは「小規模〜中規模の社内業務アプリ」「Access脱却」「ローコード代替」の文脈で、異常なほど相性が良い。
なぜここまで綺麗にハマるのか?
その理由は、役割の“ズレ”が一切ないからだ。

PB:データと認証を“正しく”担当する

PBはバックエンドを抱え込む。

  • スキーマ定義
  • 認証
  • CRUD
  • リアルタイム更新
  • ファイルストレージ
    これを 単一バイナリで完結させてしまう。
    Accessのような“なんでもかんでも1ファイル”のノリを、
    正しい形でインターネット時代に翻訳した存在と言っていい。

DBのことを一切考えず、テーブル作る・API叩く・トークン管理する
──全部 PB に押し付けられるのが最高。

Svelte:PBを“薄く・高速に”使うUI

Svelte は“リアルフロントエンド”。
React のようにフレームワークそのものが巨大ではなく、
コンパイル後は「ただの JS」になる。
つまり、PBの API を叩く UI も軽い。

  • PB の ListView をサクッと表に
  • レコードの編集フォームをその場で作成
  • リアルタイム購読で一覧が勝手に更新

「Accessのサブフォームを web に置き換える」と考えれば完全一致。

XState:人間の“業務手順”をコード化する

Accessで一番悲惨なのはここ。
UI に業務ロジックをベタ書きするから地獄が始まる。

  • ボタン押したらMsgBox
  • 入力チェックを複数箇所でコピペ
  • フォームの開閉で状態がバグる
  • レコード移動で意図せぬイベント発火

業務アプリの8割は「状態管理(この画面は今どういう段階?)」で決まる。
そこに XState が“公式の答え” を提示する。

  • 入力中
  • 検証中
  • 保存中
  • 保存完了
  • エラー
  • 再編集

これらを 状態遷移図で表現する → そのままコードになる
人間の業務手順を、手続きではなく“状態”で定義する。
Access 時代に一番欠けていたレイヤーだ。


なぜこの3つを組み合わせると“Access超え”が成立するのか?

結論:
Accessでグチャグチャになっていた“責務”がキレイに分断されるから。

役割AccessPB + Svelte + XState
データフォームに直刺しPocketBase(API + 認証 + DB)
UIコントロール地獄Svelte(軽量・分離)
業務ロジックVBA・マクロ混在XState(状態モデル化)
配布MDBコピー問題1つのWebアプリで全員使える

Accessが“悪いんじゃない”。
現代の業務要件を満たす設計になっていないだけだ。

PB/Svelte/XState の三位一体で構成すると、
Accessの“便利さ”は維持したまま、
地獄ポイントだけ全部取り除ける。


今回のまとめ:この3つは「役割破綻しない」奇跡の組み合わせ

  • PB が データと API を一元管理する
  • Svelte が UI を軽量・高速に描画する
  • XState が 業務フローをコードで再現する

三者が互いに食い合わない。
この組み合わせは、「社内アプリ開発の理想形」にかなり近い。

13. PocketBase + Svelte + XState の開発環境を10分で整える

開発環境を10分で準備するステップ

最速で「Accessアプリの代替 Web 環境」を動かすための、
PocketBase + Svelte + XState の最小構成を 10分以内 で整える手順。

この章は「余計な説明ゼロ」「最短ルート」に徹する。


1. PocketBase を置く(30秒)

  1. https://pocketbase.io/ から最新バージョンをダウンロード
  2. ZIP を解凍して、任意のフォルダに置くだけ
  3. 実行:
./pocketbase serve

これで以下が一気に起動:

  • APIサーバー
  • SQLite
  • 認証
  • 管理UI(Admin Panel)
  • Realtime(WebSocket)

アクセス先:

http://127.0.0.1:8090/_/

この瞬間、バックエンド全完備


2. Svelte プロジェクトを作る(1分)

Node が入っている前提で(14以降推奨):

npm create vite@latest pb-app -- --template svelte
cd pb-app
npm install
npm run dev

これだけで Svelte の開発サーバーが立つ。

URL:

http://localhost:5173

UI実装の土台が完了。


3. PocketBase JS SDK を追加(30秒)

Svelte で PB を扱いやすくするために SDK を入れる:

npm install pocketbase

あとはコンポーネントで:

import PocketBase from "pocketbase";
const pb = new PocketBase("http://127.0.0.1:8090");

これで CRUD / Auth / Realtime の全部が使える。


4. XState を追加(30秒)

状態管理(Access VBAの代替核)を入れる:

npm install xstate

Svelte とは相性が良いので、後段でそのまま使える。


5. とりあえず “orders” コレクションを作る(1〜2分)

PocketBase Admin UI で:

  1. 「New collection」
  2. 名前:orders
  3. 型:Base
  4. フィールドを追加:
FieldType
titletext
copiesnumber
sizeselect(A4縦 / A4横 / B5縦)
notetext(任意)

これで Access の“注文テーブル”が完成。

権限は開発用に:

  • List / View / Create / Update / Delete → true

でいい(本番では閉じる)。


6. Svelte 側で “注文を保存するミニフォーム” を追加(3分)

src/App.svelte に貼るだけで動く最小サンプル:

<script>
  import PocketBase from "pocketbase";
  const pb = new PocketBase("http://127.0.0.1:8090");

  let title = "";
  let size = "A4縦";
  let copies = 2;

  async function submit() {
    await pb.collection("orders").create({
      title,
      size,
      copies,
    });

    alert("保存しました!");
    title = "";
    copies = 2;
  }
</script>

<form on:submit|preventDefault={submit}>
  <input bind:value={title} placeholder="案件名" />
  <select bind:value={size}>
    <option>A4縦</option>
    <option>A4横</option>
    <option>B5縦</option>
  </select>
  <input type="number" bind:value={copies} min="1" max="4" />
  <button>保存</button>
</form>

これだけで PB → DB保存 → Svelte反映 の一連が動く。
Accessならテーブル直編集・フォーム直結で済んでた部分を、
PB+Svelteでも最短で再現した状態。


7. リアルタイム一覧も1行で動く(追加1分)

PocketBaseの強みその1。
SvelteはJSがそのまま描画されるので、Realtime購読も簡単。

pb.collection("orders").subscribe("*", (e) => {
  console.log("変化あり:", e);
});

Accessの「リスト再クエリ」のために
RefreshやMe.Requeryしてた暴力を、PBが自動で解決してくれる。


8. これで“開発に入れる状態”が100%整う(合計10分)

  • PB → サーバー/DB/認証
  • Svelte → UI
  • XState → 業務ロジック
  • PB SDK → 実質的にローコード環境

あとは機能を追加していくだけで、
Accessアプリの置き換えが着々と進む。


XState の最小サンプル

本当に最小の動くマシン:

import { createMachine } from "xstate";

const orderMachine = createMachine({
  id: "order",
  initial: "editing",
  states: {
    editing: {
      on: { SUBMIT: "saving" }
    },
    saving: {
      on: { SUCCESS: "done", FAIL: "editing" }
    },
    done: {}
  }
});

Access VBAの“BeforeUpdate/AfterUpdateイベント地獄”を
状態遷移で一刀両断できる未来がここにある。

参照

PocketBase - Open Source backend in 1 file
Open Source backend in 1 file with realtime database, authentication, file storage and admin dashboard
Svelte ??? Web development for the rest of us
Web development for the rest of us
XState - JavaScript State Machines and Statecharts