日報と勤怠報告の連携ツール
現在では、アルバイトの稼働について、Slackのtech-activity
チャンネルに日々の日報を記入している。作業内容の可視化だけでなく、できたこと・できなかったことを言語化して社員の方に見てもらう意味を持っている。
それとは別に、勤怠管理と給与計算のために、毎月スプレッドシートに稼働実績を自分たちで記入している。基本的にはtech-activity
に記入する日報から内容を抜き出せばよいが、1日に様々なプロジェクトで稼働していたり、休憩を多く挟んでいたりすると、そのままではスプレッドシートの記入制約を満たすことができず、フォーマットを整形しなおす必要がある。
また、日報の写し間違えがないかといったことの確認作業も発生しており、担当者に少なくはない負担がかかっているため、tech-activity
の内容と勤怠管理シートの内容を自動的に同期させる仕組みがあれば、アルバイトとプロパー社員両方にとってメリットがある。
実現したいこと
Section titled “実現したいこと”tech-activity
での日報の内容と、勤怠管理シートの内容の同期- 日報のフォーマットの統一
- スプレッドシートの記入行数制限についての管理や、制限を超えたときの対応方法について、その運用手続きをはっきりとさせる。
- プロジェクトコードを探したりする記入に関する負担軽減
- (追加で)毎月のアルバイトの稼働実績の可視化
成果物のイメージ
Section titled “成果物のイメージ”
実現のために行うこと
Section titled “実現のために行うこと”- 要件定義
- 技術選定
- テーブル設計
- 認証機能の実装
- 記入アプリのUI作成
入力とデータ反映の流れ
Section titled “入力とデータ反映の流れ”- ユーザーがUIから日報を入力
- 入力内容はSupabase上のDBで管理する
TIMESHEETS
テーブルに格納されて保存 - ボタンを押してSlackに日報、スプレッドシートに勤怠を投稿する
テーブル設計
Section titled “テーブル設計”主要テーブル
Section titled “主要テーブル”- USERS
- アプリのログインユーザー情報を格納する
- PROJECTS
- プロジェクトコードとプロジェクト名の対応を格納する
- TIMESHEETS
- 最新の日報の内容を保持。通常はこれを見れば良い。
勤怠ログ管理テーブル
Section titled “勤怠ログ管理テーブル”- TIMESHEET_REVISIONS
- 日報の更新/削除前のスナップショットを保存する。
version
は自動採番。 これにより、いつ・誰が・なぜ変更したのかを追跡できる。
- 日報の更新/削除前のスナップショットを保存する。
勤怠データとSlackメッセージの対応テーブル
Section titled “勤怠データとSlackメッセージの対応テーブル”- SLACK_MESSAGES
- 1つの勤怠に対してSLACKに投稿するメッセージと、投稿状況を保持する。
どのSlackメッセージ(
channel_id
+message_ts
)に対応するかを保持。- 新規投稿時:新しいレコードを作成し、
message_ts
を保存する。 - 編集時:
message_ts
を使ってSlackの「メッセージ編集API」を利用する。 (Slack:Web APIを利用してメッセージを編集する)
- 新規投稿時:新しいレコードを作成し、
- 1つの勤怠に対してSLACKに投稿するメッセージと、投稿状況を保持する。
どのSlackメッセージ(
勤怠データとSpreadsheet行の対応テーブル
Section titled “勤怠データとSpreadsheet行の対応テーブル”まだ設計していないが、同様に勤怠データとスプレッドシートの行を対応付けるテーブルを作成する予定。
USERSテーブル
Section titled “USERSテーブル”カラム名 | 型 | 制約 | 説明 |
---|---|---|---|
id | uuid | PK | ユーザーID |
text | UNIQUE | メールアドレス | |
password | text | NOT NULL | パスワード |
PROJECTSテーブル
Section titled “PROJECTSテーブル”カラム名 | 型 | 制約 | 説明 |
---|---|---|---|
code | text | PK | プロジェクトコード |
name | text | NOT NULL | プロジェクト名 |
TIMESHEETSテーブル
Section titled “TIMESHEETSテーブル”カラム名 | 型 | 制約 | 説明 |
---|---|---|---|
id | uuid | PK | 勤怠ID |
work_date | date | NOT NULL | 作業日 |
start_time | time | NOT NULL | 開始時間 |
end_time | time | NOT NULL | 終了時間 |
project_code | text | FK (PROJECTS.code ) | プロジェクトコード |
task | text | NOT NULL | 作業内容 |
done | text | できたこと | |
not_done | text | できなかったこと | |
next_action | text | 次にやること | |
proper | text | 担当社員 | |
user_id | uuid | FK (USERS.id ) | ユーザーID |
created_at | timestamptz | NOT NULL | 作成日時 |
updated_at | timestamptz | NOT NULL | 更新日時 |
deleted_at | timestamptz | 削除日時 |
TIMESHEET_REVISIONSテーブル
Section titled “TIMESHEET_REVISIONSテーブル”カラム名 | 型 | 制約 | 説明 |
---|---|---|---|
id | uuid | PK | スナップショットID |
timesheet_id | uuid | FK (TIMESHEETS.id ) | 勤怠ID |
version | integer | NOT NULL | バージョン |
snapshot | jsonb | NOT NULL | スナッショット |
changed_by | uuid | FK (USERS.id ) | 変更者 |
change_reason | text | 変更理由 | |
changed_at | timestamptz | NOT NULL | 変更日時 |
SLACK_MESSAGESテーブル
Section titled “SLACK_MESSAGESテーブル”カラム名 | 型 | 制約 | 説明 |
---|---|---|---|
id | uuid | PK | レコードID |
timesheet_id | uuid | FK (TIMESHEETS.id ) | 勤怠ID |
payload | jsonb | NOT NULL | Slackメッセージのペイロード |
operation | text | (create, update, delete) | 操作 |
channel_id | text | NOT NULL | チャンネルID |
message_ts | text | NOT NULL | Slackメッセージのタイムスタンプ |
status | text | (sent, failed) | 送信ステータス |
attempt_count | integer | NOT NULL | 試行回数 |
last_error | text | 最終エラー | |
last_synced_at | timestamptz | 最終同期日時 | |
created_at | timestamptz | NOT NULL | 作成日時 |
updated_at | timestamptz | NOT NULL | 更新日時 |
idempotency_key | text | UNIQUE | 冪等キー |
erDiagram
USERS {
uuid id PK "supabase auth uid"
text email
text password
}
PROJECTS {
text code PK
text name
}
TIMESHEETS {
uuid id PK
date work_date
time start_time
time end_time
text project_code
text task
text done
text not_done
text next_action
text proper
uuid user_id FK
timestamptz created_at
timestamptz updated_at
timestamptz deleted_at
}
TIMESHEET_REVISIONS {
uuid id PK
uuid timesheet_id FK
integer version
jsonb snapshot
uuid changed_by FK
text change_reason
timestamptz changed_at
}
SLACK_MESSAGES {
uuid id PK
uuid timesheet_id FK
jsonb payload
text channel_id
text message_ts
text status
integer attempt_count
text last_error
timestamptz last_synced_at
timestamptz created_at
timestamptz updated_at
text idempotency_key
}
USERS ||--o{ TIMESHEETS : has
PROJECTS ||--o{ TIMESHEETS : has
TIMESHEETS ||--|{ TIMESHEET_REVISIONS : versions
TIMESHEETS ||--|| SLACK_MESSAGES : syncs
Mermaidソースコードを表示
erDiagram USERS { uuid id PK "supabase auth uid" text email text password }
PROJECTS { text code PK text name }
TIMESHEETS { uuid id PK date work_date time start_time time end_time text project_code text task text done text not_done text next_action text proper uuid user_id FK timestamptz created_at timestamptz updated_at timestamptz deleted_at }
TIMESHEET_REVISIONS { uuid id PK uuid timesheet_id FK integer version jsonb snapshot uuid changed_by FK text change_reason timestamptz changed_at }
SLACK_MESSAGES { uuid id PK uuid timesheet_id FK jsonb payload text channel_id text message_ts text status integer attempt_count text last_error timestamptz last_synced_at timestamptz created_at timestamptz updated_at text idempotency_key }
USERS ||--o{ TIMESHEETS : has PROJECTS ||--o{ TIMESHEETS : has
TIMESHEETS ||--|{ TIMESHEET_REVISIONS : versions TIMESHEETS ||--|| SLACK_MESSAGES : syncs
ロジックフロー設計
Section titled “ロジックフロー設計”- ユーザーがUIから日報を入力
- 入力内容はSupabase上のDBで管理している
TIMESHEETS
テーブルにINSERT - Slackへの投稿ボタンを押すと、
Slack_MESSAGES
をstatus='sending'
でINSERT - SlackAPI
chat.postMessage
をawait
- 成功:
SLACK_MESSAGES
のstatus='sent', last_synced_at=now()
にUPDATE - 失敗:
status='failed' / attempt_count++ / last_error=error_msg
にUPDATEして、再送を促す
TIMESHEETS
をUPDATE(トリガーでTIMESHEET_REVISIONS
に旧値が保存)- Slackへの更新ボタンを押すと、
SLACK_MESSAGES
をstatus='sending'
にUPDATE / INSERTする。
message_ts
があればSlackAPIchat.update
をawaitして編集。- なければ
chat.postMessage
をawaitして送信。
TIMESHEETS
のdeleted_at=now()
にUPDATE(トリガーでTIMESHEET_REVISIONS
に旧値が保存)
もしSlackにメッセージ送信済みならば、
SLACK_MESSAGES
のstatus='sending'
にUPDATE- SlackAPI
chat.delete
をawait
- 成功:
TIMESHEETS
を削除する。(Slackでの削除が完了したことを確認してDB削除) - 失敗:
status='failed', last_error
にUPDATEして、再送を促す