![]() |
![]() |
|---|
Tauri + React + TypeScript で作った、ローカルで動く「かんたんなレジ・受付番号」アプリです。軽く、速く、そして安心して使えるように設計しています。
この README は「使い方・はじめ方」を中心にまとめています。設計やコーディングの詳しい指針は AGENTS.md をご覧ください。
- デスクトップ一体型: Tauri v2 でマルチプラットフォームなデスクトップアプリを提供
- ファイルベースルーティング: React Router v7 の FS Routes を採用(
src/routes直下) - とても軽い状態管理: nanostores(
persistentAtomで localStorage 永続化) - 型と検証を同時に: ArkType で「型」と「実行時バリデーション」を一元化
- 例外ではなく結果で扱う: neverthrow の
Resultで失敗を安全にハンドリング - 表現力の高い分岐: ts-pattern で網羅チェックつきの安全な分岐
- スタイルは設計から: PandaCSS(tokens / cva / sva、レシピ的スタイル)
- Mise(開発環境セットアップに使用. 以下のものが自動的に入ります.)
- Rust と Cargo(Tauri のビルドに必要)
- Tauri CLI v2
- Bun(スクリプトに
bunを使用しています) - Node.js(エディタやツールの互換用。Bun を使うので必須ではありませんが推奨)
開発用の推奨拡張:
- VS Code + Tauri 拡張 + rust-analyzer
このプロジェクトは mise を使っています。.mise.toml により、次のツールが固定バージョンでセットアップされます。
- bun 1.2.22
- rust 1.84.1
- lefthook 1.12.2(npm 由来)
一発セットアップは以下のコマンドで実行できます。
# mise が導入済みであることが前提です
mise run setup実際に行われる処理(.mise.toml より)
.vscode/settings.example.json→.vscode/settings.jsonにコピー(VS Code の推奨設定が適用されます)mise iで bun/rust/lefthook をインストールlefthook installで Git フックをセットアップ(pre-commit でbun run checkを実行)bun iで依存パッケージをインストール
補足(VS Code 設定の中身)
- Prettier は無効、ESLint の自動修正(保存時)を有効化
- ArkType ドキュメント推奨の Quick Suggestions などを設定
- 拡張機能は
.vscode/extensions.jsonで Tauri と rust-analyzer を推奨
注意:bun の「ランタイム設定」を VS Code 側で特別に入れる必要はありません。bun 自体は mise によりインストール・パス解決され、ターミナル経由で bun run ... を実行します。
- 依存関係をインストールします。
bun install- 開発サーバ(Web)を起動します。
bun run dev- デスクトップアプリ(Tauri)として起動します。
bun run tauri dev- ビルド(配布用バイナリを作成)
bun run tauri build補足:
bun run checkでスペルチェック・型チェック・Lint をまとめて実行できます(Bun 必須)。- Tauri の dev サーバは 1420/1421 番ポートを使います(
vite.config.ts)。
src/routes/ルーティング(React Router v7 FS Routes)src/components/UI コンポーネント(atomic/,overlays/など)src/lib/ドメインロジック・状態管理・ユーティリティsrc/styles/PandaCSS のグローバル・アニメ・レイヤ構成panda.config.tsPandaCSS 設定(トークンやキーフレーム拡張)
React Router v7 の FS Routes を使っています。src/routes 配下にファイルを置くと自動でルートになります。
src/routes/_index.tsxルート(/)src/routes/main._index/route.tsxのようなディレクトリでレイアウト/ページを構成- 本プロジェクトは SSR を無効化しています(
react-router.config.ts)。
このプロジェクトでは「レシピ的」スタイルを基本にしています。
- 単一要素のバリアントは
cvaを使用 - 複数スロット(タイトル/グリッド/カードなど)は
svaを使用 - デザイントークンは
panda.config.tsで定義・拡張 panda/tokensのtoken()でトークン値を安全に参照
例: 注文ステータスの表示は cva でサイズバリアントを定義し、色はセマンティックトークン(orderStatus.*)から取得しています。
// 例: src/components/OrderStatusLabel.tsx(抜粋)
const orderStatusLabelStyles = cva({ /* ...variants... */ })
const OrderStatusLabelContainer = p("div", orderStatusLabelStyles)
// 色は panda.config.ts の semanticTokens → token() で解決
const color = OrderStatusImpl(orderStatus).toColor()また、src/styles/highlight.ts では data-highlight-* 属性で点滅/ハイライトを制御するアニメをグローバルに定義しています。表示側はデータ属性を付けるだけで動きます。
- ドメイン型は ArkType で宣言(例:
Order,OrderStatus,ReceiptNumber) - 入力値の検証結果は
wrapValidation()で neverthrow のResultに変換 - 例外を投げずに UI 側で安全に分岐できます
// 例: src/lib/arktype.ts
export function wrapValidation<D>(out: D | ArkErrors): Result<D, ArkErrors> { /* ... */ }// 例: src/lib/stores/current-order.ts(要点)
const itemNumberResult = wrapValidation(ItemNumberType(parseInt(row.productCode, 10)))
if (itemNumberResult.isErr()) continuets-pattern を使って、ドメインに対する分岐を「漏れなく・安全に」記述します。
.exhaustive()を付けることでパターン漏れを型で検出- キー入力→オーバーレイ表示の切替などに活用
// 例: src/lib/order.ts(要点)
match(status)
.with("UNCONFIRMED", () => /* ... */)
.with("WAITING_COOKING", () => /* ... */)
.with("WAITING_PICKUP", () => /* ... */)
.with("PICKED_UP", () => /* ... */)
.with("REFUNDED", () => /* ... */)
.with("CANCELED", () => /* ... */)
.exhaustive()アプリ内の一部の状態(現在の注文、入力行、預かり金など)は localStorage に保存されます。nanostores の persistentAtom を使っており、ブラウザ再読込やアプリ再起動でも残ります。
-
Web でも動きますか?
はい。
bun run devでブラウザから使えます。デスクトップ機能(ウィンドウ/OS連携)は Tauri 実行時のみ有効です。 -
依存する外部サービスはありますか?
ありません。すべてローカルで完結します。
詳しい開発指針やコード例は AGENTS.md にまとめています。新しく機能を足す前に一読いただくとスムーズです。
まずは引き継ぎありがとうございます。来年度はメニューも年号も変わる前提で、最短で安全に差し替えるためのポイントをまとめました。困ったら AGENTS.md の設計方針も合わせて見てください。
ファイル: src/lib/consts.ts
- 変更内容: アプリ名の末尾にある年号を 2026 → 2027 に置き換えます。
// src/lib/consts.ts(抜粋)
export const INFO = {
name: {
ja: "シス研シンプルレジ ver. 2027", // ← 2026 から変更
en: "Sysken Simple Register ver. 2027", // ← 2026 から変更
},
config: {
localStorageVersion: 1, // 破壊的変更を入れる場合は 2,3... と上げてください
},
} as const;- 破壊的なデータ構造変更(localStorage に保存している内容が変わる等)を入れる場合は、
localStorageVersionをインクリメントすると古いデータを安全に切り離せます。
ファイル: public/data/item_groups.json
-
children: グループ(例: ポップコーン/飲料)の配列。各グループのchildrenに商品を並べます。 -
priceの上限は現在src/types/item.tsのPriceが 500 になっています。500 円を超える価格にしたい場合はPriceを見直してください。 -
商品番号(ItemNumber)は
src/lib/stores/items.tsでgroupIdx * 10 + itemIdxで自動採番しています。- 1 グループあたり 10 品目以内にすると安全です(重複回避)。
-
それ以上に増やす場合は、採番ロジック(例:
groupIdx * 100 + itemIdx)とItemNumberの上限(src/types/item.ts)を一緒に引き上げてください。
- ファイル:
public/data/discount.jsonamountのキーは「商品ID」です。商品を入れ替えた場合、対応する ID を必ず更新してください。 スキーマは ArkType で検証され、問題があると起動時にエラーになります(どの項目が不正かをメッセージで示します)。
src/types/order.tsMAX_RECEIPT_NUMBER(受付番号の最大値: デフォルト 50)OrderItemAmount(各商品の最大数量) 営業形態に合わせて調整してください。
Web で確認: bun run dev
- デスクトップで確認:
bun run tauri dev - まとめてチェック:
bun run check(スペル/型/ESLint)
- 起動時に落ちる/真っ白: メニューや割引 JSON のキー(商品ID)が合っているか、型の上限を超えていないかを確認してください(ArkType の assert が失敗すると止まります)。
- 値が更新されない: localStorage の影響かもしれません。
localStorageVersionを上げるか、ブラウザ/Tauri の localStorage をクリアしてください。
来年の運用も、なるべく「変更しやすい・壊れにくい」作りにしています。数字を変えるだけ・JSON を入れ替えるだけで、だいぶ対応できるはずです。焦らず、少しずつ確かめながら進めてください。困ったら AGENTS.md を検索して、該当の章(PandaCSS/ArkType/ts-pattern/nanostores)を見つけてみてください。応援しています。

