1. はじめに
ソーイ株式会社の西浦です。
今回は、友人の要望を受けて個人で開発した「勤怠管理アプリ」について、技術的なアプローチや開発の進め方を記事にまとめました。
ことの発端は、友人の会社が抱えていたコストの課題です。従業員数が数名(約10名)と小規模なのですが、「既存の勤怠管理システムやSaaSを契約しようとすると、少人数の割に月額費用が高くついてしまう」と相談を受けました。
そこで、ランニングコストを極力抑える(あわよくば無料にする)ことを絶対条件に、私がオリジナルのアプリを開発することになりました。
「無料で使えて、出退勤が打刻でき、最終的に所定のフォーマットでCSV出力して提出できる」というシンプルな要件からスタートしたプロジェクトです。
小規模な環境向けということもあり、今回はアーキテクチャの選定から開発の進め方まで、様々な工夫を取り入れました。
2. 要件を満たすための環境選定とUI設計
今回の絶対条件は 「ランニングコストを無料に抑える」 ことでした。
ネイティブアプリとして開発するとストア登録料(Apple Developer Programなどのライセンス費用)といったランニングコストが発生してしまうため、今回はブラウザから手軽にアクセスできるWebアプリとして開発することにしました。
従業員数が約10名と小規模であるため、以下の技術スタックを選定しました。
| カテゴリ | 技術・ツール |
|---|---|
| フロントエンド | React + TypeScript + Vite |
| UIライブラリ | shadcn/ui + Tailwind CSS |
| バックエンド・インフラ | Firebase (Authentication, Firestore, Hosting) |
Firebaseの無料枠(Sparkプラン)を最大限活用することで、サーバー代を完全にゼロに抑えつつ、十分なパフォーマンスを発揮できる構成にしています。
またUI設計においては、それぞれの利用シーンを明確に分けて構築しました。
- 従業員画面: 各個人が自分のスマホから日常的に打刻することを想定し、レスポンシブ対応でモバイル向けに最適化しました。
- 管理画面: 勤怠データの確認やCSV出力、打刻の修正対応といった事務作業が行いやすいよう、PCでの操作を前提としたレイアウトにしています。
開発期間とデザインの工夫
今回のプロジェクトは「開発期間が約1ヶ月」と非常に短かったため、フロントエンドはReactとViteの組み合わせでサクサク開発を進めました。さらに、スピードを落とさないための工夫として、初期のUIイメージの作成には Figma AI を活用しました。
生成されたデザインをReactのコードとして直接ダウンロードし、それをベースに開発をスタートするというフローを採用しました。これにより0から画面を作る手間を省き、デザインから実装までの時間を大幅に短縮しています。
3. 「最小構成」へのこだわりと過去の失敗
実は以前、社内のプロジェクトで「最初から完璧なものを作ろう」として、機能過多になり開発が難航するという失敗を経験しました。
その反省を活かし、今回は徹底して 「最小構成(MVP:Minimum Viable Product)」 から作り始めることを意識しました。
まずは「出勤・退勤のボタンが押せて、データがFirestoreに保存される」というコア機能だけを実装しました。UIも最初は簡素なものにし、ユーザー(友人)に触ってもらいながらフィードバックを得て、本当に必要な機能だけを肉付けしていくアプローチをとりました。結果として、早い段階で価値を提供でき、手戻りも最小限に防ぐことができました。
4. 最も難しかったこと:所定のフォーマットへのCSV出力
開発を進める中で一番の壁となったのが、「打刻データを指定のExcel/CSVフォーマットに落とし込んで出力する」機能です。
単にデータベースの内容をそのまま書き出すだけなら簡単ですが、今回は提出先のシステムが要求する特定の列順序、日付のフォーマット、空白セルの処理などを厳密に守る必要がありました。
特に苦労したのが、「所定のエクセルフォーマットにおけるセル結合の再現」 と 「従業員ごとでのシート分け」 です。これらは単なるテキストの書き出しでは対応できないため、ライブラリの選定とデータ構造の変換で一番頭を悩ませました。
技術的な対応:
- Excelファイル(
.xlsx)として高度な出力を行うため、exceljsというライブラリを採用しました。これを使うことで、既存のテンプレートファイル(あらかじめ罫線やセル結合などの書式が組まれたExcelファイル)を読み込み、特定の位置にデータを流し込むことが可能になりました。 - ロジック(
generateAttendanceXlsx.ts等)を組み、Firestoreから取得した「従業員ごとの打刻データ」をループで回して、Excel内で従業員1人につき1つのシートを自動で複製・命名(サニタイズ処理付き)して分割するようにしました。 - 単なるタイムスタンプではなく、Excel上で「時間」として正しく認識・計算させるため、時刻をシリアル値(1日を1とする小数など)に変換してセルにセットする工夫も行っています。
5. Firebaseを活用した権限管理(管理者と従業員の分離)
業務アプリとして運用する上で、「管理者」と「一般の従業員」とで使える機能や見れるデータを完全に分ける必要があります。
今回のアプリでは、Firebase Authentication の認証情報と Firestore に保存したユーザー情報を組み合わせることで、強固なアクセス制御を実現しました。
-
ロール(権限)の付与:
従業員ごとの情報はFirestoreのusersコレクションで管理し、ここにrole: "admin"やrole: "user"というフィールドを持たせています。 -
Firestore セキュリティルールでのガード:
Firestoreのfirestore.rules側で、リクエストを送ってきたユーザーのUIDを使ってusersコレクションのroleを参照する関数(isAdmin())を定義しました。例: 「打刻データの読み取りは自身のデータのみ許可、ただし管理者は全従業員のデータを読み書き可能」
「打刻の修正申請のステータス変更(承認/却下)は管理者のみ可能」
これにより、フロントエンド側で画面を隠すだけでなく、バックエンド(データベース)側の強固なガードを施しています。
6. 最小構成からの機能拡張
最小構成で無事に稼働し始めた後、現場のニーズに合わせて少しずつ機能を拡張していきました。ただし、当初の「シンプルさ」を失わないよう、スコープを広げすぎないように注意しました。
追加した主な機能:
- 直行直帰や休憩対応: 友人の会社が訪問看護関係の事業を行っているため、スタッフが事業所に寄らずに直接利用者の元へ向かったり、現場から直接帰宅したりするケースが多々ありました。その業務フローに合わせて、「直行」「直帰」専用の打刻ボタンを追加しました。
- 打刻修正機能: 押し忘れなどの際、管理者や本人が後から時間を修正できる画面を追加しました。
- 位置情報(GPS)の記録: 不正打刻防止のため、打刻時のGPS連携をオプションで追加しました。
今後の展望(現在開発中):
現在は、アプリの使い勝手をさらに向上させるため、設定画面の実装やプロフィール管理機能 の追加開発を行っています。
特に、スマートフォンからの操作性をより高めるために、下部に配置する 「ボトムナビゲーションバー」 を導入し、画面間のアクセスをスムーズにしようと取り組んでいます。
現場からの「もっとこうしてほしい」という要望にスピーディに応えられるのも、自作アプリならではの楽しさだと感じています。

7. 反省点・学んだこと
スピード感を重視して開発した一方で、反省点もありました。
一番大きな学びは 「最初に開発環境(Dev環境)などをしっかり構築しておくべきだった」 ということです。
リリース直後はローカル環境と本番環境(Firebaseの本番プロジェクト)しかなく、そのまま運用をスタートしたのですが、後から機能追加やバグ修正を行う際、検証用の環境がないため非常に苦労しました。
Dev環境の用意として考えられる選択肢:
-
Firebaseプロジェクトを完全に2つに分ける(推奨)
本番用(〇〇-prod)と開発用(〇〇-dev)の2つのFirebaseプロジェクトを作成し、環境変数(.env)で接続先ドメインやAPIキーを切り替える方法。データベースも完全に分離されるため、テストデータを気にせず安全に開発できます。 -
Firebase Hostingのプレビューチャンネルを利用する
機能ごとに一時的なURLを発行してホスティングのテストを行う方法ですが、繋がるデータベースは本番のままになってしまうため、今回のケースでは不十分でした。
最小構成を意識することは重要ですが、「運用を止めずに安全に開発を続けるためのインフラ・環境整備(別プロジェクトの用意など)」 は、初期段階でケチるべきではないと痛感しました。
8. まとめ
今回の開発は、私にとって「個人で開発したアプリが実際の業務で他人に使われる」初めての経験でした。
自分が作ったアプリが友人の会社のコスト削減や業務効率化に直結し、実際のユーザーから「便利になった」とフィードバックをもらえたことは、エンジニアとして何よりも嬉しい体験でした。
技術的な面でも、「要件を見極め、適切な技術を選び、小さく作って大きく育てる」 ことの重要性を改めて実感しました。
Firebaseを活用したサーバーレス構成は、小規模プロジェクトにおいて圧倒的なコストパフォーマンスと開発スピードをもたらしてくれます。
また、過去の失敗を教訓にMVP開発を徹底したことで、ユーザーが本当にほしいものを最短距離で届ける確かな手応えを得ることができましたが、同時に開発フローの根本的なインフラ整備の重要性という新たな学びも得られました。
今後も、技術の力を使って身近な課題をスピーディに解決できるエンジニアを目指して、学習と実践を続けていきたいと思います。
おまけ:Lottieを活用したリッチなアニメーション
Webアプリでありながらネイティブアプリのような心地よい操作感(マイクロインタラクション)を出したいと考え、今回の開発では Lottie のアニメーションも取り入れてみました。
Lottieは、リッチなアニメーションを軽量なJSONデータとしてWeb上で扱えるライブラリです。
例えば、打刻が完了した際のサクセスアニメーションやローディング画面などで活用したのですが、CSSやJavaScriptで複雑なアニメーションを自作する手間を省きつつ、ユーザー体験をグッと向上させることができました。「無料で作るWebアプリだけど、ちょっとリッチな手触りが欲しい」という場合には非常におすすめのアプローチです。
お知らせ
技術ブログを週1〜2本更新中、ソーイをフォローして最新記事をチェック!



