tasks 스키마 (작업 관리 마스터)
현장별 일일 작업(Task) 마스터 문서와 그 하위 서브컬렉션을 정리합니다. 작업(Task) 1개 = 현장에서 특정 날짜/시간대에 수행되는 단위 작업이며, 자재/폐기물 사용량, 위험성 평가, 특이사항 메모, 근로자·장비 출석이 모두 이 문서를 중심으로 연결됩니다.
저장 위치 및 서브컬렉션 트리
companies/{company_id}/sites/{site_id}/tasks/{task_id} # 작업 본문
├─ risk_assessment/{risk_assessment_id} # 작업 위험성 평가 (TBM)
├─ material_usage/{daily_usage_id} # 자재 일일 사용량
├─ waste_amount/{daily_amount_id} # 폐기물 일일 배출량
├─ memo/{memo_id} # 특이사항 메모
└─ attendance/{supervisor|worker|equipment} # 작업별 출석 집계 문서 (고정 ID 3개)
첨부파일과 자재/폐기물 품목 마스터는 별도 컬렉션에 저장됩니다.
companies/{company_id}/sites/{site_id}/files/{file_id} # 작업 첨부파일 메타 (related_doc_id == task_id)
companies/{company_id}/sites/{site_id}/material/{material_id} # 자재 품목 마스터 (material_usage.material_id가 참조)
companies/{company_id}/sites/{site_id}/waste/{waste_id} # 폐기물 품목 마스터 (waste_amount.waste_id가 참조)
companies/{company_id}/sites/{site_id}/dashboard/{YYYYMM} # 월별 작업 수 대시보드 (task: int[31])
companies/{company_id}/sites/{site_id}/task_summary/{YYYYMM} # 월별 자재/폐기물 사용량 집계
연결 관계 참고:
sites/{sid}본문의task_name_list(배열)와task_management_layout(배열)은 작업 관리 프론트 설정값입니다. 자세한 내용은 sites.md 참조.- 출석 로그(
attendance_logs/equipment_attendance_logs)는task_id필드로 이 문서를 참조하며, 트리거가tasks/{tid}/attendance/{role}문서의members배열을 자동 갱신합니다.
tasks/{task_id} 문서 필드
작업 본문. create_task 호출 시 생성되고, 날짜/시간/공수/타입/작업내용/공지사항이 점진적으로 채워집니다.
| 필드 | 타입 | 설명 |
|---|---|---|
task_name |
string | 작업명 (sites.task_name_list 중 하나와 일치) |
task_start_datetime |
timestamp | 작업 시작 일시 (KST) — 같은 날 같은 현장에 1시간 이내 중복 시작 불가, 하루 최대 5개 |
task_end_datetime |
timestamp? | 작업 종료 일시 (생성 시 None, update_task_end_datetime에서 채움) |
man_days |
float | 해당 작업의 기본 공수 (해당 작업에 배정된 출석 로그의 man_days로 전파) |
type |
string | 작업 시간대. "없음" \| "주간" \| "야간" \| "오전" \| "오후" \| "철야" |
task |
string | 작업 상세 내용 (리치 텍스트). <오전> / <오후> / <주간> / <야간> / <철야> 태그 허용 |
notice |
string | 공지사항 (리치 텍스트) |
opinion |
string? | 근로자 의견 (edit_task_worker_opinion으로 업데이트) |
content_attachments |
object[]? | Firebase Storage 직접 업로드 첨부(레거시) — 삭제 시 storage_path로 blob 제거 |
created_at |
timestamp | 생성 시각 (SERVER_TIMESTAMP) |
created_by |
string | 생성자 UID |
저장/업데이트 흐름
| 엔드포인트 | 동작 |
|---|---|
create_task |
문서 생성. task_end_datetime=null, task="", notice=""로 초기화 |
update_task_name_start_datetime |
task_name, task_start_datetime, man_days, type 수정 (날짜 변경은 불가, 시간만 변경 가능) |
update_task_end_datetime |
task_end_datetime 만 업데이트 |
update_task_details |
task 업데이트. <...> 태그는 허용된 5종만 가능 |
update_notice |
notice 업데이트 |
edit_task_worker_opinion |
opinion 업데이트 |
copy_task_details_from_previous |
이전 작업의 task, notice를 현재 작업에 복사 |
delete_task |
본문 + 첨부파일 + attendance 서브 문서 + 대시보드 집계 정리 |
삭제 시 연쇄 처리:
content_attachments에 있는 Firebase Storage blob 제거files컬렉션에서related_doc_id == task_id인 파일을 휴지통으로 이동tasks/{tid}/attendance/{supervisor|worker|equipment}문서의 members에 기록된 각 출석 로그의task_id를null로 초기화dashboard/{YYYYMM}의task[day-1]카운트를 -1
서브컬렉션: risk_assessment/{risk_assessment_id}
작업별 TBM용 일일 위험성 평가. 작업의 상세 화면에서 노출되며, safety/_schema/risk_assessment의 사이트 레벨 위험성 평가와는 별개입니다.
| 필드 | 타입 | 설명 |
|---|---|---|
place |
string | 장소 |
supervisor_name |
string | 담당자 이름 (문자열 스냅샷) |
type |
string | 공종 |
work |
string | 작업명 |
danger_level |
string | 위험도 등급 (예: "상", "중", "하") |
frequency |
string | 발생빈도 (예: "상", "중", "하") |
source |
string | 유해/위험 요인 |
preventive_measures |
string | 예방대책 |
created_at |
timestamp | 생성 시각 |
created_by |
string | 생성자 UID |
엔드포인트: add_task_risk_assessment, edit_task_risk_assessment, delete_task_risk_assessment, copy_task_risk_assessment_from_previous (이전 작업의 모든 항목 복사).
서브컬렉션: material_usage/{daily_usage_id}
작업 일자의 자재 사용량. 같은 material_id에 대한 중복 등록은 금지됩니다.
| 필드 | 타입 | 설명 |
|---|---|---|
material_id |
string | 참조할 자재 품목 ID (sites/{sid}/material/{material_id}) |
daily_usage |
float | 해당 작업에서의 일일 사용량 |
updated_at |
timestamp | 생성/수정 시각 |
updated_by |
string | 생성/수정자 UID |
트리거 _task_material_update → task_summary/{YYYYMM}.material_usage[material_id][day-1] 배열에 증감을 반영합니다.
서브컬렉션: waste_amount/{daily_amount_id}
작업 일자의 폐기물 배출량. 같은 waste_id에 대한 중복 등록은 금지됩니다.
| 필드 | 타입 | 설명 |
|---|---|---|
waste_id |
string | 참조할 폐기물 품목 ID (sites/{sid}/waste/{waste_id}) |
daily_amount |
float | 해당 작업에서의 일일 배출량 |
updated_at |
timestamp | 생성/수정 시각 |
updated_by |
string | 생성/수정자 UID |
트리거 _task_waste_update → task_summary/{YYYYMM}.waste_amount[waste_id][day-1] 배열에 증감을 반영합니다.
서브컬렉션: memo/{memo_id}
작업의 특이사항 메모. 여러 사용자가 여러 개 등록할 수 있으며, 삭제는 작성자 본인만 가능합니다.
| 필드 | 타입 | 설명 |
|---|---|---|
memo |
string | 메모 본문 |
created_at |
timestamp | 작성 시각 |
created_by |
string | 작성자 UID |
엔드포인트: add_task_memo, delete_task_memo.
서브컬렉션: attendance/{role}
작업에 자동 배정된 출석 로그를 역할별로 모아주는 고정 3개 문서 컬렉션입니다. 문서 ID는 아래 3가지로 고정됩니다.
| 문서 ID | 대상 | 참조하는 상위 로그 컬렉션 |
|---|---|---|
supervisor |
회사 감독자(owner/admin/manager 등) | companies/{cid}/attendance_logs/{log_id} |
worker |
현장 근로자 | companies/{cid}/sites/{sid}/attendance_logs/{log_id} |
equipment |
현장 장비 | companies/{cid}/sites/{sid}/equipment_attendance_logs/{log_id} |
각 문서의 필드:
| 필드 | 타입 | 설명 |
|---|---|---|
members |
string[] | 이 작업에 배정된 출석 로그 ID 배열 (ArrayUnion/ArrayRemove로 원자적 업데이트) |
출석 로그가 생성/변경/삭제될 때 auto_assign.py의 트리거 3종이 해당 작업/역할 문서의 members를 갱신하고, 동시에 출석 로그 본문의 task_id와 man_days를 함께 업데이트합니다.
첨부파일 연결
작업에는 세 가지 용도의 첨부가 있습니다. 모두 files/{file_id} 메타 문서의 tags.type으로 구분합니다 (related_doc_id == task_id).
| 용도 | tags.type |
발급 함수 | 저장 경로 prefix |
|---|---|---|---|
| 작업 상세 이미지 | details |
get_task_details_attachment_upload_token |
tasks/{task_id}/details_attachments |
| 공지사항 첨부 | notice |
get_task_notice_attachment_upload_token |
tasks/{task_id}/details_attachments |
| 그룹별 일반 첨부 | attachment (+ group, folder_id) |
get_task_attachment_upload_token |
tasks/{task_id}/files/{group_name} |
attachment 타입은 동일 폴더로 여러 파일을 묶어 업로드할 수 있도록 tags.folder_id(UUID)와 tags.group(그룹명)을 함께 저장합니다. folder_id가 요청에 포함되면 기존 폴더에 추가, 없으면 신규 UUID를 발급합니다.
대시보드/집계 문서
dashboard/{YYYYMM}
작업 개수 월별 집계. delete_task에서 감소, create_task에서는 (현재 코드 기준) 직접 업데이트하지 않음.
task_summary/{YYYYMM}
자재/폐기물의 월별·일별 사용량 집계. material_usage/waste_amount 서브컬렉션의 트리거가 원자적으로 갱신합니다.
{
"material_usage": {
"{material_id}": [0, 0, 10, 5, ...] // 31칸, 인덱스 = day - 1
},
"waste_amount": {
"{waste_id}": [0, 0, 2, 1, ...]
}
}
예시 문서
tasks/{task_id}
{
"task_name": "철근 배근",
"task_start_datetime": "2026-04-23T08:00:00+09:00",
"task_end_datetime": null,
"man_days": 1.0,
"type": "주간",
"task": "<주간> 2층 슬라브 철근 배근 작업",
"notice": "안전모 미착용 시 작업 불가",
"created_at": "2026-04-22T17:00:00+09:00",
"created_by": "uid_manager"
}