anTech

News

訪問看護のシフト管理システムを自作する — データベース設計の実例(ER図・9テーブル)とCodeIgniter 4のCRUD実装【vol.2/全4回】

開発ブログ

この連載は、訪問看護向けのシフト管理システム「YORISOI」を自作した記録です(全4回)。vol.2は、シフト表を作る前に必要な「データベース設計」と「基本機能のCRUD実装(登録・一覧・編集・削除)」の話です。前回のvol.1(Excelシフト表の限界)から読むと流れがつかみやすいと思います。

こんな方向けの記事

  • シフト管理システムを自作してみたい方(データベース設計の実例を探している方)
  • ER図の書き方を、教科書ではなく実際に動いているシステムで見たい方
  • CodeIgniter 4のModel・Controller・ViewでCRUDを実装する流れを知りたいエンジニア
  • 訪問看護・訪問介護のシステムに、どんなデータ項目が必要か気になる方

データベース設計の手順 — 要件からテーブルに落とすまで

vol.1で整理した要件は、突き詰めると「誰が」「誰に」「どんなサービスを」「いつ」提供するかを管理することでした。この4つの言葉が、そのままテーブルの候補になります。

手順としては、①要件から登場人物(エンティティ)を抜き出す → ②繰り返し登場する情報をマスタとして分ける → ③関係を線でつなぐ(ER図)→ ④実装、という流れです。「スタッフ名をシフトのセルに毎回書く」のがExcelでしたが、データベースではスタッフは1回だけ登録して、シフトからはIDで参照する。これがマスタ分離(正規化)の目的で、名前の変更が1か所で済み、表記ゆれも起きなくなります。

YORISOIの初期リリースで用意したテーブルは、次の9つです。

  • organizations(組織)/ facilities(施設) — 事業所の器
  • staff(スタッフ)/ customers(利用者)/ service_types(サービス種別マスタ)— 今回の主役
  • shifts(シフト)— すべてを結びつける中心テーブル(vol.3で詳しく)
  • visit_records(訪問記録)— 実績と署名データ
  • users(ログインアカウント)/ password_reset_tokens — 認証まわり

ER図の書き方と全体像 — 訪問看護シフト管理の実例

ER図(エンティティ・リレーションシップ図)の書き方はシンプルです。①で抜き出したエンティティを四角で並べ、主キー(id)と外部キー(〜_id)を書き込み、「1対多」の線でつなぐだけ。作図ツールはdraw.ioやMermaidで十分で、下の図も実際にMermaidで描いています。YORISOIの全体像はこうなりました。

訪問看護シフト管理システムYORISOIのER図。organizationsを頂点にstaff・customers・service_typesがshiftsに結びつく9テーブル構成
初期リリース時点のER図(9テーブル)。線の先の「多」側が子テーブルです

読み方のポイントは3つだけです。

  • organizations が頂点 — スタッフも利用者もサービス種別も、すべて organization_id を持ちます。組織ごとにデータを分離しているので、将来複数の事業所で使うマルチテナント化にも耐えられます
  • shifts が中心 — 「誰が(staff_id)」「誰に(customer_id)」「何を(service_type_id)」「いつ(start_datetime〜end_datetime)」。シフト1件はこの4点セットです
  • staff と users は分離 — 人事情報(staff)とログインアカウント(users)を分けておくと、認証まわりの変更が人事データに波及しません

スタッフ管理のCRUD実装(CodeIgniter 4)

テーブル定義(staff・抜粋)

CREATE TABLE staff (
    id INT AUTO_INCREMENT PRIMARY KEY,
    organization_id INT NOT NULL,            -- 組織ID
    facility_id INT,                         -- 所属施設ID(任意)
    employee_number VARCHAR(50) UNIQUE,      -- 社員番号(S001形式で自動採番)
    last_name VARCHAR(50) NOT NULL,          -- 姓
    first_name VARCHAR(50) NOT NULL,         -- 名
    last_name_kana VARCHAR(50),              -- セイ
    first_name_kana VARCHAR(50),             -- メイ
    email VARCHAR(255) NOT NULL,             -- メールアドレス(必須)
    employment_status ENUM('active','inactive','leave') DEFAULT 'active',  -- 在職/退職/休職
    role ENUM('admin','manager','staff') DEFAULT 'staff',                  -- 権限
    qualifications TEXT,                     -- 資格(JSON形式)
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    FOREIGN KEY (organization_id) REFERENCES organizations(id),
    FOREIGN KEY (facility_id) REFERENCES facilities(id)
);

ポイントは2つ。email は NOT NULL(必須)にしていること。スタッフ登録と同時にログインアカウントを発行してメールを送るためです(後述)。そして created_at / updated_at にDB側のデフォルトを付けていないこと。日時はCodeIgniter 4のModelの $useTimestamps = true でアプリ側から書き込む方針にしています。

社員番号の自動採番(Modelのコールバック)

社員番号を手入力にすると、重複や採番ミスが必ず起きます。そこで afterInsert コールバックで、挿入直後のIDを種に「S001」形式を自動生成しています。

// app/Models/StaffModel.php
protected $afterInsert = ['generateEmployeeNumber', 'createUserAccount'];

protected function generateEmployeeNumber(array $data)
{
    // 挿入後のIDを使って社員番号を生成・更新
    if (isset($data['id'])) {
        $employeeNumber = 'S' . str_pad($data['id'], 3, '0', STR_PAD_LEFT);
        $this->update($data['id'], ['employee_number' => $employeeNumber]);
    }
    return $data;
}

コールバックが2つ並んでいるのに気づいたでしょうか。2つ目の createUserAccount が地味に効く機能で、スタッフを登録すると users テーブルにログインアカウントが自動作成され、初期パスワード設定メールまで送信されます。管理者が「スタッフ登録」と「アカウント発行」を別々にやる必要がありません。利用者側も同じ仕組みで、利用者番号を「C001」形式で自動採番しています。

一覧・登録画面の動き

一覧画面は、雇用状態(在職・休職・退職)のフィルターボタンとキーワード検索、ページネーション(30件/ページ)付き。登録フォームの動きはこちらです。

スタッフ一覧 → 新規登録 → 保存。一覧に戻ると社員番号「S006」が自動で振られています(1.25倍速・画面はサンプルデータ)

必須チェックの本丸はModel側のバリデーションです。姓・名に加えてメールアドレスが必須(アカウント発行に使うため)で、画面側のチェックをすり抜けてもinsert時にModelが弾く二段構えにしています。実は執筆中のデモ録画で、メール欄を空のまま送信して「メールアドレスは必須です。」に弾かれました。自分で作ったバリデーションに自分で引っかかる、あるあるです。笑

利用者管理 — 訪問看護らしさが出るテーブル

利用者(customers)テーブルは、スタッフよりも項目が多くなります。訪問看護ならではのフィールドがあるからです。

// app/Database/Migrations/... (customersテーブルの一部)
'care_level' => [
    'type'       => 'ENUM',
    'constraint' => ['support1', 'support2', 'care1', 'care2', 'care3', 'care4', 'care5'],
    'null'       => true,
    'comment'    => '要介護度',
],

介護保険制度の「要支援1〜要介護5」の7段階を、そのままENUM型に落とし込んでいます。制度の知識がそのままテーブル定義(スキーマ)に現れる部分です。こういうドメイン固有の設計は、汎用パッケージだと後付けになりがちです。

ほかにも、緊急連絡先(名前・続柄・電話)、保険証番号、医療メモ、そして駐車場情報(parking_info)。駐車場は地味ですが重要で、訪問先でどこに車を停めるかが分からないと、スタッフが現場で困ることになります。

YORISOIの利用者登録フォーム。要介護度や緊急連絡先など訪問看護特有の項目が並ぶ
利用者登録フォーム。要介護度・緊急連絡先・駐車場情報など、現場で必要な項目を一通り

サービス種別マスタ — カラーピッカー付きのシンプルCRUD

サービス種別(訪問看護・リハビリ・入浴介助・食事介助など)は、シフト作成時に選ぶマスタデータです。ここはテーブルもロジックもシンプルなので、あえてModelクラスを作らず、クエリビルダーで直接操作しています。数十件程度のマスタ管理にModel一式はオーバースペックという判断です(Modelを使わないぶん、日時カラムはコントローラー側で明示的にセットしています)。

面白いのは色の管理で、サービス種別ごとに表示色(HEXカラーコード)を持たせています。vol.1のカレンダー画面で予定が色分けされていたのは、このフィールドのおかげです。

// app/Views/service_type/index.php — 色選択時のプレビュー更新
document.getElementById('color').addEventListener('input', function(e) {
    const color = e.target.value;
    document.getElementById('color-text').value = color;
    document.getElementById('color-preview').style.backgroundColor = color;
});

HTML標準の input type="color" のinputイベントを拾って、HEX表示とプレビューバッジをライブ同期させるだけ。ライブラリなしの5行です。

サービス種別の追加。カラーピッカーで選んだ色がプレビューに即反映されます(1.25倍速・画面はサンプルデータ)

データベース設計で気をつけたこと

  • 番号は自動採番 — 社員番号「S001」・利用者番号「C001」は afterInsert コールバックで生成。手入力による重複・欠番をシステム側で防ぐ
  • 選択肢はENUMで縛る — 雇用状態(在職・休職・退職)や要介護度は、DBレベルで不正な値を弾く。画面のプルダウンの選択肢もこの定義から決まる
  • カナは別カラムで持つ — last_name_kana / first_name_kana があると、五十音順ソートとカナ検索が素直に書ける。利用者を「カナ順」で探す現場では必須
  • 一覧はJOINで1クエリ — 所属施設名の表示は facilities テーブルへのLEFT JOINで1クエリにまとめ、行ごとに追加クエリが走る「N+1問題」を避ける
  • 日時はアプリ側で管理 — DBのDEFAULT CURRENT_TIMESTAMPに頼らず、Modelを使うテーブルはCI4の useTimestamps に統一(Modelを使わないサービス種別だけはコントローラーで明示セット)

シフト管理システムの費用・導入のよくある質問

Q. シフト管理システムって、導入するといくらくらい?
既製のSaaSだと1ユーザーあたり月数百円〜、訪問看護・介護向けの統合パッケージだと月数万円のものが中心です。ただ「シフトだけ作れればいい」のに多機能パッケージの料金を払うのはもったいない。YORISOIのように要件を絞って自作(または小さく受託開発)すると、月額を大きく抑えられます。

Q. 汎用のシフト管理アプリではダメ?
飲食店やコンビニ向けのシフトアプリは「出勤時間の管理」が主目的で、訪問看護の「15分きざみで、誰が・どの利用者宅に・何のサービスで訪問するか」という構造が表現できないことが多いです。この連載のようにデータ設計から現場に合わせられるのが、自作・受託開発の強みです。

Q. シフト管理システムを導入するデメリットは?
既製SaaSは月額費用が固定でかかり続けることと、現場が操作に慣れるまでの定着コストです。自作・受託開発の場合は開発と保守を担う人が必要になるのがデメリットで、その代わり画面と項目を現場に完全に合わせられます。

次回予告

vol.3は、このアプリの肝であるドラッグ&ドロップのカレンダーUIを自作する話です。FullCalendarのような既存ライブラリを使わなかった理由(ライセンス費用と提供価格の関係)から、スロット単位のグリッド描画、D&D実装まで、実際のコードを交えて解説する予定です。

このシステムについて

この連載で作っている訪問看護シフト管理システムは「YORISOI」として提供しています。機能の詳細・デモのご案内はこちらから。

YORISOIの紹介ページを見る →

お仕事のご依頼について

普段は中小企業様向けのWeb制作・システム開発を中心に活動しています。「うちもこんなシステムが欲しい」「Excelでの業務管理をやめて、スマホで操作できるようにしたい」など、お気軽にご相談ください。Excelからのデータ移行もご協力いたします。

開発の相談をしてみる →

Profile

anTech / アンテク

地域の中小企業様向けにシステム開発・Web制作を行うフリーランスエンジニア。「ちょうどいい」技術で、御社のビジネスをサポートします。

埼玉県川越市拠点 — 川越市・日高市・狭山市・鶴ヶ島市を中心に埼玉県全域対応