Firestore 인덱스 정리
construction24 관련 앱들이 Firestore에 생성·사용하는 composite index를 앱별로 정리한 문서.
각 앱이 "이 인덱스를 쓴다"고 명시적으로 기록해야, 추후 중복·유령 인덱스를 안전하게 삭제할 수 있다.
규칙
- 새 composite index가 필요한 쿼리를 추가할 때 해당 앱 섹션에 반드시 기재한다.
- 쿼리를 제거할 때 이 문서에서도 해당 항목을 제거한다.
- 여러 앱이 같은 인덱스를 쓰면 각 앱 섹션에 중복 기재한다 (교차 참조용).
- 자동 인덱스로 충분한 쿼리는 기재 불필요:
- 단일 필드 equality
- 단일 필드 orderBy
- 같은 필드 range + orderBy
- 단일 필드
in / array-contains
참고
- Firestore composite 인덱스는 prefix 매칭되지 않는다. 필드 튜플이 정확히 일치해야 해당 쿼리를 커버한다.
COLLECTION 스코프와 COLLECTION_GROUP 스코프는 서로 다른 인덱스다. 서브컬렉션을 전역 조회하려면 COLLECTION_GROUP이 별도로 필요하다.
- equality 필드는 쿼리에서 순서 무관하지만, 인덱스 정의에서는 orderBy 필드보다 앞에 있어야 한다.
근로자 앱 (construction24_APP_worker)
- 레포: https://github.com/KDID-Universe/construction24_APP_worker
- 마지막 검증일: 2026-04-24
- Firestore 프로젝트:
construction24-test
suspension_works
| 인덱스 필드 |
스코프 |
사용처 |
상태 |
status asc, requester.at desc |
COLLECTION |
lib/Component/Site/SiteHome/SiteIdState.dart:481 (홈 작업중지 태그 실시간 구독) lib/Screen/Site/SuspendWork/SeeMoreSuspendWorkPage.dart:84 (suspended/ended 목록) |
✅ 있음 |
requester.uid asc, status asc, requester.at desc |
COLLECTION |
lib/Screen/Site/SuspendWork/SeeMoreSuspendWorkPage.dart:92 (내 pending/rejected 신청) |
⚠️ 첫 실행 시 생성 필요 |
suggestions
| 인덱스 필드 |
스코프 |
사용처 |
상태 |
created_by asc, type asc, created_at desc |
COLLECTION |
lib/Component/Site/SiteHome/SiteMySuggestions.dart:163 (홈 내 건의사항) lib/Screen/Site/Suggestion/SeeMoreSuggestionsPage.dart:95 (건의사항 전체) lib/Screen/Site/HazopOpinion/HazopOpinionListPage.dart:97 (위험성평가 의견 전체) |
✅ 있음 |
notifications
| 인덱스 필드 |
스코프 |
사용처 |
상태 |
hidden asc, created_at desc |
COLLECTION |
lib/Screen/Notification/NotificationPage.dart:41 (알림 목록) |
✅ 있음 |
files
| 인덱스 필드 |
스코프 |
사용처 |
상태 |
related_doc_id asc, created_at asc |
COLLECTION |
lib/Component/Site/SiteCommunication/SiteMySuggestionsPopUp.dart:48 (건의사항 첨부) lib/Screen/Site/HazopOpinion/HazopOpinionDetailPage.dart:41 (위험성평가 의견 첨부) |
✅ 있음 |
related_doc_id asc, tags.type asc, uploaded_at desc |
COLLECTION |
lib/Component/Site/SuspendWork/SuspendWorkBottomSheet.dart:78 (작업중지 통지서 사진만 필터링) |
✅ 있음 |
기타
아래 경로는 자동 인덱스로 동작하므로 composite 불필요:
companies/{cid}/sites/{sid}/tasks — task_start_datetime 범위 + 같은 필드 orderBy
companies/{cid}/sites/{sid}/emergency_alert — created_at 단일 orderBy
companies/{cid}/sites/{sid}/emergency_contact — organization_name 단일 orderBy
companies/{cid}/sites — status == 'activate' 단일 equality
users/{uid}/equipments, users/{uid}/inquiries — 단일 orderBy
archives/my_site/banner, archives/workmaru/news — 단일 orderBy
관리자 앱 (construction24_APP_manager)
- 레포: https://github.com/KDID-Universe/construction24_APP_manager
- 마지막 검증일: 2026-04-24
- Firestore 프로젝트:
construction24-test
files
| 인덱스 필드 |
스코프 |
사용처 |
상태 |
related_doc_id asc, tags.type asc |
COLLECTION |
lib/Screen/Site/FileStorage/TaskFileDetailPage.dart:57 (작업 첨부에서 특정 tags.type만 필터링) |
❓ 확인 필요 |
attendance_logs (회사 단위)
| 인덱스 필드 |
스코프 |
사용처 |
상태 |
site_id asc, check_in_at desc |
COLLECTION |
lib/Component/Site/AttendanceApproval/Attendance/AttendanceApprovalList.dart:167 (관리자용 출근 로그 현장+기간 조회) lib/Component/Site/AttendanceApproval/LeaveOut/LeaveList.dart:209 (관리자용 퇴근 로그 현장+기간 조회) |
❓ 확인 필요 |
attendance_requests (회사 단위)
| 인덱스 필드 |
스코프 |
사용처 |
상태 |
type asc, status asc, site_id asc |
COLLECTION |
lib/Screen/Site/AttendManage/AttendManagePage.dart:79 (출근 승인 대기 카운트) lib/Screen/Site/AttendManage/AttendManagePage.dart:120 (퇴근 승인 대기 카운트) lib/Component/Site/AttendanceApproval/Attendance/AttendanceApprovalList.dart:276 lib/Component/Site/AttendanceApproval/LeaveOut/LeaveList.dart:323 |
❓ 확인 필요 |
attendance_requests (현장 서브컬렉션)
| 인덱스 필드 |
스코프 |
사용처 |
상태 |
type asc, status asc |
COLLECTION |
lib/Screen/Site/AttendManage/AttendManagePage.dart:92 lib/Screen/Site/AttendManage/AttendManagePage.dart:133 lib/Component/Site/AttendanceApproval/Attendance/AttendanceApprovalList.dart:284 lib/Component/Site/AttendanceApproval/LeaveOut/LeaveList.dart:331 |
❓ 확인 필요 |
equipment_attendance_requests (현장 서브컬렉션)
| 인덱스 필드 |
스코프 |
사용처 |
상태 |
type asc, status asc |
COLLECTION |
lib/Screen/Site/AttendManage/AttendManagePage.dart:105 lib/Screen/Site/AttendManage/AttendManagePage.dart:146 lib/Component/Site/AttendanceApproval/Attendance/AttendanceApprovalList.dart:292 lib/Component/Site/AttendanceApproval/LeaveOut/LeaveList.dart:339 |
❓ 확인 필요 |
notifications
| 인덱스 필드 |
스코프 |
사용처 |
상태 |
hidden asc, created_at desc |
COLLECTION |
lib/Screen/Notification/NotificationPage.dart:40 (알림 목록) |
✅ 있음 (근로자 앱과 공유) |
hidden asc, read asc |
COLLECTION |
lib/Component/Site/SiteHome/SiteIdState.dart:274 (읽지 않은 알림 배지 실시간 구독) |
❓ 확인 필요 |
requests
| 인덱스 필드 |
스코프 |
사용처 |
상태 |
request_type asc, status asc |
COLLECTION |
lib/Screen/Site/RequestSite/RequestSiteWaitingPage.dart:39 (현장 등록 대기) lib/Component/Site/SiteHome/SiteIdState.dart:298 (회사 입사 pending) lib/Component/Site/SiteHome/SiteIdState.dart:332 (회사 출근 pending) |
❓ 확인 필요 |
request_type asc, created_at desc |
COLLECTION |
lib/Component/Site/SiteAttend/OnSiteAttendanceList.dart:49 (회사 출근 기록 최신순) |
❓ 확인 필요 |
기타
아래 경로는 자동 인덱스로 동작하므로 composite 불필요:
companies/{cid}/sites/{sid}/tasks — task_start_datetime / task_datetime 범위 + 같은 필드 orderBy
companies/{cid}/sites/{sid}/tasks/{tid}/risk_assessment — created_at 단일 orderBy
companies/{cid}/sites/{sid}/risk_assessment — created_at 단일 orderBy
companies/{cid}/sites/{sid}/attendance_logs — check_in_at 범위 + 같은 필드 orderBy
companies/{cid}/sites/{sid}/equipment_attendance_logs — check_in_at 범위 + 같은 필드 orderBy
companies/{cid}/sites/{sid}/emergency_alert — created_at 단일 orderBy
companies/{cid}/sites/{sid}/emergency_contact — organization_name 단일 orderBy
companies/{cid}/sites/{sid}/files — related_doc_id, tags.folder_id, path 각각 단일 필터
companies/{cid}/sites/{sid}/membership_requests / change_requests / equipment_assign_requests / equipment_change_requests — status == 'pending' 단일 equality
companies/{cid}/sites — status == 'activate' 단일 equality
companies/{cid}/members — UID 단일 equality
users/{uid}/inquiries — created_at 단일 orderBy
users/{uid}/membership — 전체 구독
archives/my_site/banner — rank 단일 orderBy
archives/workmaru/news — create_at 단일 orderBy
건설 24 웹 (construction24_WEB)
- 레포: https://github.com/KDID-Universe/construction24_WEB
- 마지막 검증일: 2026-04-24
- Firestore 프로젝트:
construction24-test
attendance_requests (회사 단위)
| 인덱스 필드 |
스코프 |
사용처 |
상태 |
status asc, site_id asc, created_at desc |
COLLECTION |
src/pages/company_management/CompanyAttendance/hooks/usePendingRequests.js:57 (회사 공용 pending 대기 — site_id == null) src/pages/site_management/SiteAttendance/hooks/useAttendanceRequests.js:99 (현장 관리자용 pending 대기 — site_id == {siteId}) |
❓ 확인 필요 |
attendance_requests (현장 서브컬렉션)
| 인덱스 필드 |
스코프 |
사용처 |
상태 |
status asc, created_at desc |
COLLECTION |
src/pages/site_management/SiteAttendance/hooks/useAttendanceRequests.js:66 (현장 pending 목록) |
❓ 확인 필요 |
equipment_attendance_requests (현장 서브컬렉션)
| 인덱스 필드 |
스코프 |
사용처 |
상태 |
status asc, created_at desc |
COLLECTION |
src/pages/site_management/SiteAttendance/hooks/useAttendanceRequests.js:133 (현장 장비 pending 목록) |
❓ 확인 필요 |
attendance_logs (회사 단위)
| 인덱스 필드 |
스코프 |
사용처 |
상태 |
site_id asc, check_in_at asc |
COLLECTION |
src/pages/site_management/SiteAttendance/hooks/useAdminAttendanceLogs.js:41 (관리자 출석 로그 — 날짜 범위 + 현장 조건, 오름차순 정렬) |
❓ 확인 필요 |
files
| 인덱스 필드 |
스코프 |
사용처 |
상태 |
related_doc_id asc, target_date asc |
COLLECTION |
src/pages/budget_management/MaterialCost/hooks/useSupplierDetail.js:58 (자재비 파일 히스토리 — related_doc_id + target_date 범위) |
❓ 확인 필요 |
related_doc_id asc, tags.type asc, uploaded_at desc |
COLLECTION |
src/pages/safety_management/RealtimeCommunication/hooks/useAttachments.js:90 (안전 첨부파일 — tags.type 필터 포함) |
✅ 있음 (근로자 앱과 공유) |
doc_page asc, uploaded_at desc |
COLLECTION |
src/components/TempFolder/TempFolderDrawer.jsx:98 src/components/Header/Header.jsx:123 (임시 파일 목록 — doc_page == 'temp-file-system') |
❓ 확인 필요 |
기타
아래 경로는 자동 인덱스로 동작하므로 composite 불필요:
companies/{cid}/sites/{sid}/attendance_logs — check_in_at 범위 + 같은 필드 orderBy
companies/{cid}/sites/{sid}/equipment_attendance_logs — check_in_at 범위 + 같은 필드 orderBy
companies/{cid}/attendance_logs (일자 전용) — check_in_at 범위 + 같은 필드 orderBy
companies/{cid}/sites/{sid}/suspension_works / emergency_alert / suggestions — where 없음 + 단일 orderBy
companies/{cid}/sites/{sid}/tasks — task_start_datetime 범위 + orderBy 없음
companies/{cid}/sites/{sid}/equipments/{eid}/contracts — where 없음 + 단일 orderBy
companies/{cid}/sites/{sid}/files (작업 첨부, useTaskAttachments.js) — where만 있고 orderBy 없음
companies/{cid}/sites/{sid}/members / equipments / membership_requests / change_requests / equipment_assign_requests / equipment_change_requests — resign 또는 status == 'pending' 단일 equality
companies/{cid}/members — 단일 equality
companies/{cid}/attendance_requests (홈 위젯) — 클라이언트 정렬이라 orderBy 없음
- 공지사항 / 배너 컬렉션 — 단일 orderBy
사내 도구 / 백엔드 함수
🚧 배치 스크립트·Cloud Functions에서 쓰는 인덱스 별도 기재 예정.
운영 참고
서버 현재 인덱스 덤프
firebase firestore:indexes --project=construction24-test
정본 파일 권장 정책
- 각 앱 레포의
firestore.indexes.json은 현재 비어있음.
- 중장기적으로 관리자 앱 또는 별도 infra 레포에 정본 JSON을 두고,
firebase deploy --only firestore:indexes는 거기서만 실행하는 방식 권장.
- 이렇게 해야 "링크 클릭으로 우발적 생성"이 막히고 이 문서와 서버 상태가 동기화된다.
인덱스 삭제 방법
- Firebase Console → Firestore → 인덱스 → 삭제 (취소 불가)
- 또는
gcloud firestore indexes composite delete <INDEX_ID>