equipments / contracts / attendance 스키마 (장비대)
현장에 배정된 장비의 장비 정보, 임대 계약, 월별 가동 공수(출역)를 관리하는 스키마. 장비대 화면은
equipments문서(장비/임대인 정보) + 하위contracts(임대 계약) + 하위attendance(월별 공수)로 구성됩니다.
저장 위치
companies/{company_id}/sites/{site_id}/equipments/{equipment_id}
companies/{company_id}/sites/{site_id}/equipments/{equipment_id}/contracts/{contract_id}
companies/{company_id}/sites/{site_id}/equipments/{equipment_id}/attendance/{YYYYMM}
equipments/{equipment_id}: 현장에 배정된 장비 단위 문서.equipment_id는users/{UID}/equipments의 장비 문서 ID를 그대로 사용.contracts: 임대 기간 단위 계약. 하나의 장비에 여러 계약(기간/금액)이 시간 순으로 쌓임.attendance/{YYYYMM}: 월별 가동 공수 배열 문서 (labor_ledger와 동일한 월 단위 패턴).
상위: equipments/{equipment_id}
장비 배정(equipment_assign_request_approval 승인) 시 site_equipment_data로 최초 생성되고, 장비대 페이지의 여러 엔드포인트가 이 문서를 수정합니다.
| 필드 | 타입 | 설명 |
|---|---|---|
UID |
string | 장비 소유(운전자) UID |
name |
string | 소유자 이름 (스냅샷) |
phone_enc |
string | 소유자 전화번호 AES 암호화 |
phone_masked |
string | "010-****-XXXX" |
email_enc |
string | 소유자 이메일 AES 암호화 |
main_address |
string | 소유자 주소 (평문) |
sub_address_enc |
string | 상세주소 AES 암호화 |
birth |
timestamp | 생년월일 |
sex |
string | "male" | "female" |
equipment_type |
string | 장비 종류 (예: "굴착기", "덤프트럭") |
equipment_name |
string | 장비명 |
equipment_number |
string | 장비 번호/차량번호 |
resign |
bool | 해제 여부 (true면 이 현장에서 해제됨) |
resign_at |
timestamp? | 해제 시각 |
resign_UID |
string? | 해제 처리자 UID |
resign_reason |
string? | 해제 사유 (예: "manual_resign") |
assigned_by |
string | 배정한 관리자 UID |
assigned_at |
timestamp | 배정 시각 |
lessor_company_name |
string? | 임대인 회사명 (임대 장비인 경우) |
lessor_registration_number |
string? | 임대인 사업자등록번호 (edit_equipment_lessor_info) |
임대인 정보 업데이트 (edit_equipment_lessor_info)
장비 문서의 main_address, sub_address_enc, phone_enc를 임대인 정보로 덮어쓰는 구조입니다(초기 소유자 정보와 동일 필드 공유).
직영/임대 구분
스키마에 명시적 플래그는 없으나 lessor_company_name / lessor_registration_number의 존재 여부와 contracts의 유무로 임대 장비를 구분합니다.
하위: contracts/{contract_id}
장비의 임대 계약 단위 문서. add_equipment_contract가 database.write로 자동 ID를 부여해 생성합니다.
{
"start_date": "2026-01-01T00:00:00Z",
"end_date": "2026-03-31T00:00:00Z",
"amount": 10000000,
"tax": 1000000,
"created_at": "server timestamp",
"created_by": "uid_admin",
"updated_at": "server timestamp?",
"updated_by": "uid?"
}
| 필드 | 타입 | 단위 | 설명 |
|---|---|---|---|
start_date |
timestamp | - | 계약 시작일 |
end_date |
timestamp | - | 계약 종료일 (반드시 start_date보다 뒤) |
amount |
number | 원 | 공급가액 (세액 제외). 입력 시 계산식 참조 |
tax |
number | 원 | 부가세 (자동 계산) |
created_at |
timestamp | - | firestore.SERVER_TIMESTAMP |
created_by |
string | - | 작성자 UID |
updated_at |
timestamp? | - | 수정 시각 |
updated_by |
string? | - | 수정자 UID |
금액 계산: 클라이언트는 amount(총액)와 is_tax_included를 전송.
- is_tax_included=true: tax = amount / 11, amount = amount - tax (포함가에서 10% 부가세 역산)
- is_tax_included=false: tax = amount * 0.1, amount = amount (공급가액이 그대로, 부가세 별도)
즉 저장되는 amount는 항상 공급가액(세전) 기준.
계약서 첨부
get_equipment_contract_upload_token으로 Cloudflare 업로드 토큰을 발급받고, 파일 메타는 companies/{cid}/sites/{sid}/files/ 컬렉션에 다음과 같이 저장:
related_doc_id = contract_id
doc_type = "safe"
doc_page = "equipment"
folder_path = companies/{cid}/sites/{sid}/equipments/{equipment_id}/contracts/{contract_id}
하위: attendance/{YYYYMM}
장비 가동 공수 월 단위 문서. 근로자와 달리 장비 1대당 month 문서 1개 구조이며, 배열(31칸)에 일자별 공수가 직접 누적됩니다.
{
"man_days": [0, 0, 1, 0.5, 0, "... (31 길이)"],
"attendance_id": {
"0": [],
"1": [],
"2": ["log_id_eq_1"],
"3": ["log_id_eq_2"]
}
}
| 필드 | 타입 | 설명 |
|---|---|---|
man_days |
number[31] | 일자별 공수 (인덱스 i = i+1일) |
attendance_id |
map | 일자별 equipment_attendance_logs 문서 id 배열. 키 "0"~"30" |
갱신 로직 (add_equipment_attendance_data / delete_equipment_attendance_data):
- _equipment_task_attendance_auto_assign이 equipment_attendance_logs 생성 시 호출.
- 문서가 없으면 man_days=[0]*31, attendance_id={str(i): [] for i in range(31)}로 초기화.
- 공수 추가 시 해당 날 man_days[day-1] += man_days, attendance_id[str(day-1)]에 log_id append (중복 방지).
- 삭제 시 man_days는 0 미만으로 내려가지 않도록 보정.
상태/흐름
장비 문서의 라이프사이클:
(배정 요청) equipment_assign_requests (pending)
→ 승인 → equipments 문서 생성/갱신 (resign=false)
→ contracts 추가/수정 (선택)
→ equipment_attendance_logs 생성 → attendance/{YYYYMM} 갱신 (트리거)
→ 해제 → equipments.resign=true (문서 삭제 X, 플래그만 갱신)
첨부파일 (files) 연결
| 용도 | related_doc_id | doc_page |
|---|---|---|
| 임대 계약서 | contract_id |
equipment |
예시 문서
equipments/{equipment_id}
{
"UID": "uid_driver_1",
"name": "김장비",
"phone_enc": "AES(...)",
"phone_masked": "010-****-1234",
"email_enc": "AES(...)",
"main_address": "서울특별시 구로구",
"sub_address_enc": "AES(...)",
"birth": "1978-06-10T00:00:00Z",
"sex": "male",
"equipment_type": "굴착기",
"equipment_name": "06W",
"equipment_number": "서울12가3456",
"resign": false,
"assigned_by": "uid_admin",
"assigned_at": "2026-01-05T09:00:00Z",
"lessor_company_name": "대한중기",
"lessor_registration_number": "123-45-67890"
}
contracts/{contract_id}
{
"start_date": "2026-01-10T00:00:00Z",
"end_date": "2026-02-10T00:00:00Z",
"amount": 9090909,
"tax": 909091,
"created_at": "2026-01-05T09:30:00Z",
"created_by": "uid_admin"
}