PostgreSQL + Node.js + Express を使った家計簿データ管理システムです。買い物の記録を1件ずつ登録し、月次サマリーと清算計算を行います。
- 記録の登録・編集・削除(ダイアログUI、連続登録対応)
- 定期支出(家賃・サブスクなど毎月かかるものの自動計上)
- 「何買ったっけ?」日別ビュー(カレンダー+カテゴリ別円グラフ)
- 月次サマリー表示(カテゴリ別・人別支出)
- 清算計算(一人当たり負担額と過不足分算出)
- サマリー一覧表示
- 人・カテゴリのマスター管理
- 自動/手動データベースバックアップ(NAS保存対応)
project-directory/
├── docker-compose.yml
├── Dockerfile
├── package.json
├── app.js
├── init.sql
└── README.md
mkdir household-budget-app
cd household-budget-app提供されたファイルをすべて適切な場所に配置してください。
docker compose up --build初回起動時は、以下が実行されます:
- PostgreSQLデータベースの初期化
- 必要なテーブルの作成
- Node.jsアプリケーションの起動
ブラウザで http://localhost:3000 にアクセスします。
画面右下の「+」ボタン(またはメインページの「記録を追加する」)からダイアログを開き、1件ずつ登録します。保存すると人・カテゴリ・日付は保持されたまま次の入力に移るため、レシートを続けて入力できます。1商品につき1レコードで登録し、クーポン・割引はマイナス金額の1レコードとして扱います。
選択肢に出る「人」「カテゴリ」はマスター管理(/masters)で追加・削除します。
家賃・サブスクなど毎月かかるものを /recurring に登録しておくと、household_records へ自動で計上されます。
- 計上のタイミング: 定期支出を登録した時点と、その月に記録を1件登録した時点。同じ月に二重計上されないようDB側のユニーク制約で保証しています。
- 金額未定: 電気代など毎月変わるものは金額を空欄で登録します。自動計上はされず、
/recurringの画面から毎月の金額を入れて登録します。 - 支払日: 1〜31で指定します。その月に存在しない日(2月の31日など)は月末に丸められます。
- 定期支出を編集しても、計上済みの記録は変わりません。削除しても記録は残り、紐付けだけが外れます。
- 「停止」にすると、定義は残したまま計上されなくなります。
- メインページで「サマリー一覧を表示」ボタンをクリック
- 一覧から表示したい年月を選択
- 以下の情報が表示されます:
- 生活費合計金額
- 一人当たり負担額
- 支払者別支出と清算計算
- カテゴリ別詳細(行をクリックで詳細表示)
システムは以下の計算を行います:
- 生活費合計 = 全支出の合計
- 一人当たり負担額 = 生活費合計 ÷ 参加人数
- 過不足分 = 各人の支払額 - 一人当たり負担額
- 清算指示 = 不足分がある人が余剰分がある人に支払う金額
| フィールド名 | データ型 | 説明 |
|---|---|---|
| id | SERIAL | 主キー |
| record_date | DATE | 支出日 |
| income_expense | VARCHAR(10) | 収入/支出区分 |
| payment_method | VARCHAR(50) | 支払方法 |
| category | VARCHAR(100) | カテゴリ |
| person | VARCHAR(50) | 支払者名 |
| amount | INTEGER | 金額 |
| location | VARCHAR(200) | 場所 |
| memo | VARCHAR(500) | メモ |
| year_month | VARCHAR(7) | 年月(YYYY-MM形式) |
| recurring_id | INTEGER | 定期支出から生成された場合の紐付け(recurring_expenses へのFK / 削除時はNULL) |
| created_at | TIMESTAMP | 作成日時 |
(recurring_id, year_month) に部分ユニークインデックスを張り、同じ定期支出が同じ月に二重計上されないようにしています。
| フィールド名 | データ型 | 説明 |
|---|---|---|
| id | SERIAL | 主キー |
| name | VARCHAR(200) | 名前(家賃・電気代など) |
| category | VARCHAR(100) | カテゴリ |
| person | VARCHAR(50) | 支払者名 |
| amount | INTEGER | 金額。NULLなら「金額未定」で自動計上しない |
| day_of_month | INTEGER | 支払日(1〜31。無い日は月末に丸める) |
| location | VARCHAR(200) | 場所 |
| memo | VARCHAR(500) | 買ったもの(空ならnameを使用) |
| payment_method | VARCHAR(50) | 支払方法 |
| active | BOOLEAN | falseなら計上しない(停止) |
| sort_order | INTEGER | 表示順 |
| created_at | TIMESTAMP | 作成日時 |
登録ダイアログの選択肢。記録側は名前の文字列で保持しており、FK制約は張っていません(マスターを消しても過去の記録は変わりません)。
これらのテーブルは、アプリ起動時の ensureSchema()(db.js)で自動的に作成・マイグレーションされます。
# コンテナの状態確認
docker compose ps
# ログの確認
docker compose logs web
docker compose logs db
# コンテナの再起動
docker compose restart
# 完全な再構築
docker compose down -v
docker compose up --build- PostgreSQLコンテナが起動しているか確認
- データベースの初期化が完了しているか確認
- 接続設定(ホスト名、ポート、認証情報)を確認
/recurringでその定期支出が「停止中」になっていないか確認- 金額が空欄(金額未定)の場合は自動計上されません。画面から金額を入れて登録してください
- 当月分は、その月に記録を1件登録した時点で計上されます。すぐ入れたい場合は「この月の分をまとめて登録」を使ってください
docker-compose.yml の ports セクションを変更:
web:
ports:
- "8080:3000" # ホスト側のポートを8080に変更docker-compose.yml の environment セクションで変更可能:
environment:
POSTGRES_DB: your_db_name
POSTGRES_USER: your_username
POSTGRES_PASSWORD: your_password本システムは定期的な自動バックアップと手動バックアップの両方に対応しています。バックアップファイルはNAS上のLinux APIサーバーに送信されます。
.envファイルに以下の設定を追加してください:
# NAS APIのエンドポイントURL
BACKUP_NAS_API_URL=http://192.168.1.100:5000/api/backup/upload
# NAS API認証トークン
BACKUP_NAS_API_TOKEN=your_secure_token_here
# バックアップスケジュール(cron形式)
# デフォルト: 毎週日曜日午前3時
BACKUP_SCHEDULE=0 3 * * 0cron形式: 分 時 日 月 曜日
例:
0 3 * * 0- 毎週日曜日午前3時0 2 * * *- 毎日午前2時0 3 * * 1- 毎週月曜日午前3時0 4 1 * *- 毎月1日午前4時
- ブラウザでアプリケーションにログイン
/backup/statusにアクセス- 「手動バックアップ実行」ボタンをクリック
または、直接 POST /backup/manual を呼び出すことも可能です。
- ファイル名:
household_budget_backup_YYYY-MM-DDTHH-MM-SS.sql - 形式: PostgreSQL SQLダンプファイル
- 内容: 全テーブルデータとスキーマ
バックアップファイルからデータを復元する場合:
# コンテナ内で実行
docker compose exec db psql -U budget_user -d household_budget -f /path/to/backup.sql
# またはホストから実行
cat backup.sql | docker compose exec -T db psql -U budget_user -d household_budgetpg_dumpが見つからないエラー:
Dockerfileに postgresql-client がインストールされているか確認してください。
問題が発生した場合は、以下を確認してください:
- Docker Desktop が起動している
- 必要なファイルがすべて配置されている
- ポート3000が他のアプリケーションで使用されていない