Appearance
KIZAMI 要件定義書
- 版: Draft 4(2026-08-21)
- 名称: KIZAMI(刻み — 1分単位で時を刻む。npm
kizami未使用確認済み)
1. 目的とポジショニング
日本の労働法制(労働基準法)に準拠した出退勤打刻型の勤怠管理システムを、セルフホスト可能なOSSとして開発・公開する。開発者自身の技術学習(TypeScriptスタックの深化)を主目的としつつ、最終的には一般企業が社内利用できる品質を目指す。
自作の動機は既存セルフホストOSS(Kimai、solidtime、TimeTagger等)への不満・不足。既存製品は工数トラッキング寄りで、日本の勤怠慣行 — 1分単位把握、法定内/法定外・深夜・法定休日の時間区分、フレックスの清算期間集計、有給の基準日付与と年5日取得義務 — をカバーするものが存在しない。ここが本プロダクトの存在理由であり差別化軸。
打刻による客観的な労働時間の記録は、労働安全衛生法66条の8の3が事業者に課す労働時間状況の客観的把握義務にも資する(同義務を単独で充足させることを謳うものではなく、対象者の範囲や把握方法の細目は導入企業が別途確認する必要がある)。
2. ドメインスコープ
- 決定: 本システムは出退勤打刻型(勤怠)。タスク別工数トラッキングはスコープ外。
- 決定: 集計の出口は時間区分の算出まで。法定内・法定時間外・深夜・法定休日・月60時間超の「時間数」を区分別に確定させる。割増率を掛けた金額計算は給与システム側の責任。
対応する労働時間制(最終ゴール)
- フレックスタイム制 — v0.1で最初に実装(開発者自身でドッグフーディング可能な唯一の制度)
- 固定時間制 — v0.5で実装(前倒し。当初はv1.0予定)
- シフト制/1ヶ月単位の変形労働時間制 — v0.7で実装(design/shift-work.md)
- 裁量労働・みなしは当面スコープ外
訂正(2026-08-23): 固定時間制を当初「清算期間=1日の退化ケース」として表現する想定にしていたが、これは誤り。固定時間制は1日8時間と1週40時間の両方で判定し、しかも日次で時間外にした分を週の集計から除いて二重計上を防ぐ必要がある。この週次の判定は「清算期間=1日」では表現できない。また、所定を超えるが1日8時間以内の法定内残業(割増不要・賃金は発生)という区分がフレックスには存在しない。制度ごとに独立した集計として実装する(WorkSystem の判別可能ユニオン)。詳細は docs/design/work-systems.md。
v0.1のフレックス仕様
決定: 清算期間1ヶ月・コアタイムなし(スーパーフレックス)。月の総枠(法定: 週平均40h×暦日数/7)との差分で時間外を判定。コアタイム・3ヶ月清算はロードマップ。
制度変更の遡及防止
決定: 労働時間制・日界・法定休日・休憩ルールなど計算に影響する制度・設定の変更は**適用開始日付きの版(effective-dated)**として扱い、過去期間の計算に遡って影響しない。過去日は常に「その日に有効だった設定」で計算され、締め済み期間はスナップショットで二重に保護される。
休日・カレンダー
決定: 法定休日は選択式で柔軟に指定できる。既定は日曜、テナント設定で曜日変更・暦日個別指定に対応。週1日(または4週4日)の法定休日判定と所定休日の区別を持ち、法定休日労働は独立した時間区分として集計。シフト制導入時には従業員別指定へ拡張。
3. 打刻
記録の原則
- 1分単位固定。生データは常に1分単位で保持し、丸めは実装しない(労働者不利の丸めは違法判断があるため)。月次集計の端数処理のみ将来のオプション候補
- 日界(1日の起算時刻)はテナント設定(既定0時)。日跨ぎ勤務を正しく日別配賦する
- 休憩は打刻(休憩入/戻)と自動控除ルール(6h超45分・8h超1h)の併用選択式
- 打刻忘れ検知(退勤なし・休憩なし)と本人/上長へのリマインド
- 打刻には証跡メタデータ(IPアドレス・UA・打刻手段)を添付。GPS座標の取得は既定OFF — テナント設定でopt-in。有効化時は従業員に取得中であることを明示する。保持期間の既定は勤怠記録本体と同一とし、テナント(会社)単位で短縮設定できる
打刻手段(最終ゴール、フェーズ分割は §11)
- Web画面のボタン(PWA含む) — v0.1
- スマホPWA+位置情報(直行直帰対応) — v0.4
- Slack/チャットコマンド — v0.4
- 公開打刻API(ICカード等の外部クライアントは外置き) — v0.4
- MCPサーバー — AIアシスタントからの打刻・勤怠照会・申請(公開APIの上に薄く実装。操作は呼び出しユーザーの権限で評価し、通常操作と同様に監査ログへ記録) — v0.4
4. 承認・権限・監査
決定: 打刻の事後修正は本人直接編集不可。修正申請→承認者のapproveで反映し、全変更を不可変監査ログに記録する。承認フローは単段(多段承認はロードマップ)。
組織モデルは部署ツリー+役職ベース。承認者の判定は部署ツリーと権限スコープで解決する。
権限モデル: 権限プリセット方式
決定: 固定ロール(admin/manager/member)ではなく、権限プリセット方式を採用。会社の管理者相当のユーザーが、権限のON/OFFとスコープをチェックボックスUIで組み合わせてプリセットを作成し、各ユーザーに割り当てる — AWS IAMロールの発想。ただしUIは非エンジニアが迷わず使える平易さを必須要件とする。
- 粒度はハイブリッド: 内部モデルはリソース×操作(CRUD相当)で網羅的に定義し、UIでは業務タスク単位の項目(「打刻修正を承認できる」「締めを解除できる」等、20〜30個目安)に束ねて表示。業務タスク→内部権限の対応表はコードで一元管理。カタログの具体項目はv0.1設計時に確定(§12)
- スコープ: 各権限に「本人のみ/自部署/自部署+配下部署/テナント全体」を設定。権限ごとに意味のあるスコープのみ選択肢に出す
- 複数プリセット割当・合算方式: 1ユーザーに複数プリセット割当可、実効権限はその合算(union)。兼務をプリセットの組合せで表現。帰結として、ユーザー詳細に実効権限ビュー(この人が結局何をできるか・どのプリセット由来か)を必須で備える
- denyなし・加算のみで開始: 権限は与えたものの合集合とし、拒否ルールは持たない。ただし評価器はdeny追加を妨げない構造にしておき、deny対応はロードマップ
- 操作は閲覧を含意: 操作権限をONにすると必要な閲覧権限が自動的に付随。UI上も「この権限には○○の閲覧が含まれます」と明示し、「承認できるのに見えない」矛盾設定を作れなくする
- 固定原則(設定で変更不可): 本人の打刻・申請・自分の記録閲覧のセルフサービス権限は全員が常に保持。最後の「権限管理」保持者は削除・降格不可。自分自身の権限昇格につながる操作は不可。プリセットの編集・割当変更はすべて監査ログ対象
- 標準プリセット同梱: 出荷時に「管理者」「マネージャー」「メンバー」相当を同梱。v0.1は同梱プリセットのみで運用、カスタムプリセット編集UIはv0.2(権限エンジン自体はv0.1から permission ベース)
- 締め後の遡及修正は専用権限「締めの解除」保持者に限定(§6)
- 危険度の高い権限(締めの解除・監査ログ閲覧・権限管理など)は、編集UI上で影響範囲の説明を添えて表示(§10のコンテキストヘルプと連動)
5. 有給休暇管理(v1スコープ)
- 付与方式: **法定(入社日基準)+基準日方式(全社一斉)**の両対応
- 比例付与(パート向け)対応(2026-08-24 実装、労基法39条3項・労基法施行規則24条の3): メンバーごとに「有給付与の区分」(通常/週4日/週3日/週2日/週1日)を持ち、区分に応じた日数表で法定付与・付与の予告を計算する。区分は管理者が就業規則・雇用契約に基づいて明示的に選ぶ(週所定労働時間・日数からの自動判定はしない)。設計・判断点は design/leave-proportional-grant.md
- 残日数管理(時効2年・繰越)、年5日取得義務の追跡とアラート
- 休暇申請→承認フロー(§4の仕組みを共用)
- 集計との連動: 有給日は欠勤控除せず所定労働扱いでフレックス枠に算入
36協定アラート(早期導入)
決定: 36協定の上限監視は早いフェーズで導入。v0.2で基本アラート(時間外の月45h — 実績および月内ペースからの超過見込み)、v0.3で完全版(年360h、特別条項時の月100h未満・複数月平均80h・年720h・月45h超は年6回まで)。通知は§7のチャネルに乗せる。
6. 締めと出口
- 月次締め(確定・ロック)
- 締め後の遡及修正: 専用権限「締めの解除」を持つユーザーのみが再オープン可能。再オープン→修正→再締めの全操作を監査ログに記録し、締め状態の履歴(誰がいつ解除したか)も保持
- 汎用CSV/APIエクスポートで区分別時間数を出力(v0.3)
- freee/マネーフォワード連携(各社のインポート形式・API)はロードマップ
7. テナント・認証・通知
- マルチテナント対応。全データモデルに最初から
tenant_idを設計(v0.1の運用自体は単一テナント) - 認証は自前認証(email+パスワード、将来パスキー)とOIDC(Google Workspace / Entra ID等)の両対応。自前はv0.1、OIDCはv1.0
- 登録は招待式のみ(2026-08-23 決定)。自由登録(セルフサインアップ)は提供しない — 従業員は会社に属してはじめて意味を持ち、誰を登録するかは管理側の決定事項のため。管理者がメンバーを作成(この時点で users 行ができ「招待中」)→ 招待トークン発行(32バイトランダム・ハッシュ保存・7日期限・再発行/取り消し可)→ 従業員がリンクからパスワードを設定して受諾(auth_credentials はこの時点で作成、受諾前はログイン不可能)。リンクの配布は SMTP 設定済みならメール、未設定でもリンクコピーで手渡しできる(SMTP を導入の前提条件にしない)
- 同一メールアドレスの複数テナント登録は許容(ユニーク制約は tenant_id+email。顧問社労士等)。ログインでパスワード一致が複数テナントにまたがる場合はテナント選択を挟む(
multiple_tenants)。招待はテナント固有の users 行に紐づくため受諾時の曖昧さは生じない - 通知チャネル: メール(SMTP)・Slack/Discord Webhook・Web Push/アプリ内の3系統(フェーズ分割は§11)。用途は打刻忘れリマインド・承認依頼・年5日/36協定アラート等
通知設定の2層構造(2026-08-22 決定・修正)
チャネルの接続情報(会社が決める)と受け取りの希望(従業員本人が決める)を分ける。 当初の実装はテナント設定しか持たず、全員分の通知が1つの共有 Webhook に集約されて 他人の勤怠情報が見える状態だった。通知の宛先は個人情報であり、混ぜてはいけない。
| 層 | 誰が決める | 内容 |
|---|---|---|
| チャネルの接続情報 | 会社 | SMTP サーバー、テナント共有の Webhook URL |
| 個人の受け取り設定 | 従業員本人 | 通知の種類ごとにアプリ内 / メールの ON/OFF、個人 Webhook、通知先メールアドレス |
通知の宛先の原則:
- 本人宛の通知(打刻忘れ・有給失効間近・年5日期限・自分の申請の承認結果・ 自分の勤務とシフトとの乖離)は本人の個人チャネルにのみ送る。 テナント共有 Webhook には送らない
- 管理者向けの通知(承認依頼、誰かが36協定の上限に近づいた等)は、権限を持つ人に送る。 テナント共有 Webhook はこちらの用途
種類ごとの制御: 「打刻忘れはメールで欲しいが36協定アラートはアプリ内でよい」のような 希望を反映できるよう、通知の種類 × チャネルで ON/OFF できる。既定値は製品側が決め、 従業員が変更できる。
8. 非機能・OSS体裁・技術スタック
- ライセンス: AGPL-3.0
- i18n: UIは日・英・韓・中(簡体)の4言語(2026-08-23 拡張。当初は日/英2言語設計)。翻訳漏れは型で防ぐ(全ロケール辞書が日本語辞書と同一キー構造であることをコンパイル時に強制)。労働法ロジックは日本専用と割り切り、法令用語の英訳は労基法の公式英訳に準拠。制度ガイド(ヘルプ文言)は日本語から段階的に翻訳(未翻訳は日本語フォールバック)
- タイムゾーン: Asia/Tokyo前提だがUTC保存・表示変換の原則は守る
| レイヤ | 選定 | 備考 |
|---|---|---|
| 言語 | TypeScript | Node 26+ |
| API | Hono | Node上で運用(Workers両対応、下記) |
| フロント | Waku (React) | RSCベース |
| ビルド/テスト | Vite / Vitest | WakuはVite基盤。ツールチェーンをViteエコシステムに統一 |
| ドキュメント | VitePress | OSSドキュメントサイト(日/英) |
| ORM | Drizzle | SQLite/PostgreSQL両ダイアレクトを抽象 |
| DB | SQLiteベース+PostgreSQL選択式 | 既定はSQLite。Cloudflare D1にも対応(動作保証、§9)。大規模はPostgreSQL |
| キュー/キャッシュ | Valkey + BullMQ | リマインドスケジューラ・ジョブキュー用(確定) |
| 配布 | Docker Compose+Helm chart | 1社1インスタンスでもマルチテナントでも可 |
| リファレンス環境 | 既存k3sクラスタ | 開発者自身のドッグフーディング環境 |
決定: Cloudflare Workers + D1 での動作を保証する(v1.0要件)。コアロジック(集計エンジン・ドメイン層)はランタイム非依存に保ち、Node/workerd両方をCIで検証(§9)。Valkey+BullMQはNode環境前提のため、キュー/スケジューラ層は差し替え可能な抽象とする: Node環境=Valkey+BullMQ、Workers環境=Cloudflare Queues+Cron Triggers。両実装をv1.0までに揃える。
9. テスト戦略
Workers動作保証(§8)と SQLite/PostgreSQL/D1 の3ダイアレクト対応をテストマトリクスで担保する。原則は**「集計エンジンを純関数・ランタイム非依存・DB非依存に保つ」**こと。
法令ゴールデンケース
- 集計エンジンの正しさは宣言的フィクスチャ(YAML)で担保。「入力: 打刻列+テナント設定」→「期待: 区分別時間数」のペアを網羅的に用意
- 必須ケース群: フレックス月枠の過不足、日界跨ぎ(深夜勤務の日別配賦)、深夜帯(22-5時)、休憩の打刻/自動控除、法定休日判定(曜日設定・暦日指定)、有給日の枠算入、36協定の各閾値、月境界・うるう年
- 法改正時はフィクスチャの追加・更新で対応し、ケース自体をVitePressドキュメントの根拠資料として相互参照
レイヤ別方針
| レイヤ | 手法 | 実行環境 |
|---|---|---|
| 集計エンジン(unit) | Vitest+ゴールデンケース。不変条件(区分合計=総実労働 等)は fast-check の property-based で補強 | Node と workerd(@cloudflare/vitest-pool-workers)の両方で同一スイート |
| リポジトリ層(integration) | Drizzle経由の実DBテスト。同一スイートを3ダイアレクトで実行 | SQLite(libSQL) / PostgreSQL(Testcontainers) / D1(Miniflare) |
| API(integration) | hono/testing でリクエストレベル検証。権限マトリクス(permission×scope)網羅と監査ログ不可変性テストを含む | Node と workerd の両方 |
| E2E | Playwright。主要業務フロー(打刻→集計→修正申請→承認→締め→CSV) | SQLite構成のフルスタック |
CIマトリクス
- 毎PR: unit(Node+workerd)、integration(SQLite/PostgreSQL/D1)、E2E主要フロー
- nightly: E2E全量、PostgreSQL複数バージョン
- Workers動作保証の実体はこのマトリクスの workerd/D1 列。緑でないPRはマージ不可
10. UX原則: コンテキストヘルプ
決定: 各機能画面に「この画面で何ができるか・その操作がどこに影響するか」をツールチップ/インラインヒント形式で都度提示し、ユーザーの迷いを減らす。自明な操作(出勤ボタン等)には付けない。
- 付与の目安: 影響が画面の外に及ぶ操作(締めの実行/解除、承認、権限プリセットの割当、自動控除ルールの変更)と、法制度に由来する表示(清算期間の総枠、法定休日、年5日義務、36協定の閾値)
- 初回ログイン時のオンボーディングツアーはロードマップ。まずは文脈内ヒントを優先
ビジュアルデザイン方針
決定: UIは事務的・帳票的な見た目にせず、毎日使うことに楽しさを感じられるデザインを目指す。
- カラーはビビッドなCMYK(シアン/マゼンタ/イエロー+キー)を基調とする方向で検討。印刷インキの色域は「打刻(スタンプ)」「1分単位で刻む」というプロダクトの世界観とも整合する
- 遊びを入れる場所と入れない場所を分ける: 打刻・日次表示など毎日の接点には楽しさを、締め・承認・権限管理など影響の大きい操作には明瞭さと落ち着きを優先する
- 楽しさはアクセシビリティを犠牲にしない(コントラストはWCAG AA準拠、色だけに意味を持たせない)
- 具体のデザイントークン・コンポーネント設計は v0.1 のUI実装前に別途デザイン検討を行う
ヘルプ文言の単一ソース管理
決定: ヘルプ文言はmonorepo内の独立パッケージ(packages/help-content)にMarkdown+frontmatterで一元管理し、アプリのツールチップとVitePressドキュメントの両方を同一ソースから生成する。
- 1エントリ=1ファイル。frontmatterに機能キー(例:
closing.unlock)とsummary(ツールチップ用1〜2文)、本文がドキュメント用詳細。言語はファイル並置(closing-unlock.ja.md/.en.md) - アプリ側: ビルド時に型付き辞書へ変換し、機能キーのTS型を自動生成。存在しないキーの参照や訳文の欠落はコンパイル/CIエラー
- VitePress側: 同じMarkdownをページとして取り込み。ツールチップの「詳しく見る」はdocsの該当アンカーへ
- 法令ゴールデンケース(§9)からも根拠として相互参照
11. フェーズ計画
| 版 | テーマ | 内容 |
|---|---|---|
| v0.1 | 自分打刻 | Web打刻(出退勤・休憩)、フレックス月枠集計、日次/月次画面、自前認証、日界設定、監査ログ基盤、権限エンジン(permission×scope、同梱プリセットのみ)。内部モデルはtenant_id前提、コアはランタイム非依存でworkerd上のCIも最初から |
| v0.2 | 承認と組織 | 部署ツリー・役職、修正申請→承認、権限プリセット編集UI、打刻忘れ検知+メール通知、36協定基本アラート(月45h実績・超過見込み) 実装状況(2026-08-22): 修正申請→承認・通知基盤・打刻忘れリマインド・36協定アラート・権限エンジン・通知設定画面・部署/プリセット管理API まで完了。残: 部署・プリセット管理のUI、SMTP実送信の確認 |
| v0.3 | 休暇と締め | 有給付与(法定+基準日)・残日数・年5日追跡、休暇申請、月次締め、CSVエクスポート、36協定完全版(年360h・特別条項) |
| v0.4 | 入口の拡張 | Slackコマンド打刻、Webhook通知、PWA+GPS打刻、公開打刻API(APIキー)、MCPサーバー(打刻・照会・申請) |
| v0.5 | 制度の拡張 | 固定時間制(1日8h・週40hの二段判定、法定内残業の区分)、月次一覧への打刻時刻表示(広い画面では出勤・退勤の独立列)、制度に応じた表示の出し分け、休憩不足の検知(労基法34条・勤怠日チェーン単位 — 中抜けの空白を休憩相当に算入)、休憩の自動控除(auto/both、本人が打ち消し申請できる形 — design/breaks.md)、招待式メンバー登録、手当対象時間の算出(design/allowances.md)、多言語UI(日・英・韓・中〔簡体〕) |
| v0.7 | シフト制と有給付与フロー | シフト制/1ヶ月単位の変形労働時間制(3段の時間外判定・シフト表・予実乖離の警告 — design/shift-work.md)、有給付与の予告→承認→通知フロー(下記)、シフト制ユーザーの有給1日分の分数換算(シフトのある日はその所定、無い日は基準所定) 実装状況(2026-08-24): フェーズ1〜4 完了 |
| v1.0 | 企業利用可能・OSS公開 | マルチテナント有効化、OIDC、Workers+D1動作保証(キュー層のCloudflare Queues実装込み)、Compose/Helm配布、ドキュメント整備 |
| 以降 | ロードマップ | コアタイム、3ヶ月清算、freee/MF連携、Web Push、多段承認、権限denyルール、オンボーディングツアー |
有給付与の3段フロー(v0.7 で実装、2026-08-23 決定 / 2026-08-24 実装): (1) 付与基準日の30日前に管理者へ予告通知 — 対象者・算定日数に加え、打刻・シフトから計算した出勤率の参考値(労基法39条1項の8割出勤要件の検算材料)を添える。(2) 管理者が確認のうえ承認すると、そこで初めて付与(
leave_grants)が作られる。(3) 承認時に本人へ「◯日付与されました」を leave_alert カテゴリ・個人チャネルで通知。機械が無条件に付与を確定させない — 出勤率要件の最終判断は人が行う。設計・決定の詳細は design/shift-work.md の「フェーズ4の決定事項」を参照。
リスク注記: v1.0までのスコープは個人開発として重量級。各フェーズを「その版だけで自分の運用が回る」単位に切ってあるのは、途中で止まっても価値が残るようにするため。
12. 未決事項
- 権限カタログの残レビュー論点 — カタログ本体は design/permission-catalog.md にレビュー済みドラフトあり(2026-08-21)。文末のレビュー論点(代理打刻の解放範囲、マネージャーのスコープ粒度、エクスポートの追加ガード等)の確定が残り