家族の大掃除タスクを、Firebase + React の自作PWAで管理してみた
概要
年末の大掃除、口頭やLINEでの分担だと「誰が何をやったか」「どこまで終わったか」が見えづらくなりがちです。また、「去年はどこを掃除したっけ」「この掃除にどれくらいの時間がかかるか」など、毎年のことなのに忘れてしまいがちです。
そこで今回、家族で共有できる大掃除タスク管理アプリを自作しました。複数端末からのリアルタイム反映を優先し、Firebase (Firestore) + React の PWA として構築しました。
- 想定利用者: 家族4人程度
- 利用環境: iPhone(Safari, Chrome) + 開発機はWindows
- 開発期間: 2日程度
やりたかったこと
- 掃除する箇所ごとにタスクを管理
- タスクの完了をチェックできるようにしたい
- タスクごとに予定時間と実績時間を記録し、工数を可視化したい
- 全体・場所別・担当者別の進捗率を見たい
- 家族の誰でも、自分のスマホから同じデータを見られるようにしたい
技術スタック
- フロントエンド: React 19 (JavaScript, Viteでビルド)
- データベース: Cloud Firestore
- 認証: Firebase Authentication
- ホスティング: Firebase Hosting
- 開発環境: Windows + VS Code + Node.js + Firebase CLI
データ設計
Firestoreに、フラットな2つのコレクションを用意しました。場所(area)や担当者(assigneeId)でグルーピングする設計にすることで、コレクションを分けずに柔軟な集計ができるようにしています。
tasks コレクション
| フィールド | 型 | 内容 |
|---|---|---|
area |
string | 掃除する場所(キッチン、浴室など) |
title |
string | タスク名 |
assigneeId |
string | 担当者のID(membersのドキュメントID、空文字なら未割当) |
estimateMin |
number | 予定時間(分) |
actualMin |
number | 実績時間(分) |
done |
boolean | 完了フラグ |
doneAt |
number | null | 完了日時(タイムスタンプ) |
note |
string | メモ |
createdAt |
number | 作成日時(並び順に使用) |
members コレクション
| フィールド | 型 | 内容 |
|---|---|---|
name |
string | 表示名 |
color |
string | 表示用のカラーコード |
createdAt |
number | 作成日時 |
担当者はアプリ内の「家族」タブから追加・改名・削除でき、コード内に固定リストを持たない設計にしました。担当者を削除すると、担当していたタスクは自動で「未割当」に戻ります。
進捗率の考え方
進捗率は2種類を併用しています。
- 件数ベース: 完了タスク数 ÷ 全タスク数
- 時間ベース: 完了タスクの予定時間合計 ÷ 全タスクの予定時間合計
件数だけだと「重い掃除も軽い掃除も1件」として扱われてしまうため、時間ベースの指標も加えることで、体感に近い進捗が見えるようにしています。これを全体・場所別・担当者別の3軸で表示しています。
計算ロジックはシンプルな関数にまとめています。
export function calcStats(tasks) {
const total = tasks.length
const doneTasks = tasks.filter((t) => t.done)
const est = sum(tasks.map((t) => t.estimateMin || 0))
const estDone = sum(doneTasks.map((t) => t.estimateMin || 0))
return {
total,
done: doneTasks.length,
countPct: total ? Math.round((doneTasks.length / total) * 100) : 0,
est,
estDone,
timePct: est ? Math.round((estDone / est) * 100) : 0,
}
}
画面構成
タブは「タスク」「進捗」「家族」の3つです。
- タスク: 場所ごとにグルーピングされた一覧。丸をタップして完了、行をタップして編集。担当者で絞り込み可能。
- 進捗: 全体・場所別・担当者別の進捗をバーとパーセントで表示。
- 家族: メンバーの追加・改名・色変更・削除。
認証まわりで工夫した点
当初はGoogleログイン(許可したアカウントのみ)で実装していましたが、開発中の環境(Chromeのセキュリティ設定)でポップアップ認証が通らない問題があり、家族共通の合言葉(日本語の文章)によるログインに切り替えました。
仕組みとしては、Firebase Authenticationの「メール/パスワード認証」を流用し、内部的に固定のメールアドレスを1つ用意して、パスワード部分に合言葉を入力してもらう形にしています。
// 合言葉ログイン: 固定メールアドレス + 合言葉(=パスワード)
const FAMILY_EMAIL = 'family@example.com'
const login = async (phrase) => {
await signInWithEmailAndPassword(auth, FAMILY_EMAIL, phrase.trim())
}
Firestore側のセキュリティルールも、このメールアドレス1件のみ許可する形にしています。
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
function isFamily() {
return request.auth != null
&& request.auth.token.email == 'family@example.com';
}
match /tasks/{id} {
allow read, write: if isFamily();
}
match /members/{id} {
allow read, write: if isFamily();
}
}
}
合言葉方式は「誰が操作したか」を区別できません。家族内での利用など、性善説で運用できる範囲を想定しています。
今後の拡張案
- タスクに締め切り日を設定する
- 完了時に実績時間の入力を促す
-
年次サイクルへの対応
- 来年、大掃除のタスク一覧をコピーした上で、進捗率だけをリセットして使い直せるようにする
- 年ごとの記録を残して、前年の所要時間と比較する(ダッシュボードにしようかな)
まとめ
Firestoreのリアルタイム同期を使うことで、「誰かがチェックした瞬間に他の端末にも反映される」という、家族でのタスク共有に向いた体験を、無料枠の範囲で作ることができました。件数と時間の両方で進捗を見せる設計にしたことで、「終わった感」と「残りの大変さ」が両方伝わる仕上がりになったと思います。




