콘텐츠로 이동

Firestore 인덱스 정리

construction24 관련 앱들이 Firestore에 생성·사용하는 composite index를 앱별로 정리한 문서.

각 앱이 "이 인덱스를 쓴다"고 명시적으로 기록해야, 추후 중복·유령 인덱스를 안전하게 삭제할 수 있다.

규칙

  1. 새 composite index가 필요한 쿼리를 추가할 때 해당 앱 섹션에 반드시 기재한다.
  2. 쿼리를 제거할 때 이 문서에서도 해당 항목을 제거한다.
  3. 여러 앱이 같은 인덱스를 쓰면 각 앱 섹션에 중복 기재한다 (교차 참조용).
  4. 자동 인덱스로 충분한 쿼리는 기재 불필요:
  5. 단일 필드 equality
  6. 단일 필드 orderBy
  7. 같은 필드 range + orderBy
  8. 단일 필드 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}/taskstask_start_datetime 범위 + 같은 필드 orderBy
  • companies/{cid}/sites/{sid}/emergency_alertcreated_at 단일 orderBy
  • companies/{cid}/sites/{sid}/emergency_contactorganization_name 단일 orderBy
  • companies/{cid}/sitesstatus == '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}/taskstask_start_datetime / task_datetime 범위 + 같은 필드 orderBy
  • companies/{cid}/sites/{sid}/tasks/{tid}/risk_assessmentcreated_at 단일 orderBy
  • companies/{cid}/sites/{sid}/risk_assessmentcreated_at 단일 orderBy
  • companies/{cid}/sites/{sid}/attendance_logscheck_in_at 범위 + 같은 필드 orderBy
  • companies/{cid}/sites/{sid}/equipment_attendance_logscheck_in_at 범위 + 같은 필드 orderBy
  • companies/{cid}/sites/{sid}/emergency_alertcreated_at 단일 orderBy
  • companies/{cid}/sites/{sid}/emergency_contactorganization_name 단일 orderBy
  • companies/{cid}/sites/{sid}/filesrelated_doc_id, tags.folder_id, path 각각 단일 필터
  • companies/{cid}/sites/{sid}/membership_requests / change_requests / equipment_assign_requests / equipment_change_requestsstatus == 'pending' 단일 equality
  • companies/{cid}/sitesstatus == 'activate' 단일 equality
  • companies/{cid}/membersUID 단일 equality
  • users/{uid}/inquiriescreated_at 단일 orderBy
  • users/{uid}/membership — 전체 구독
  • archives/my_site/bannerrank 단일 orderBy
  • archives/workmaru/newscreate_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_logscheck_in_at 범위 + 같은 필드 orderBy
  • companies/{cid}/sites/{sid}/equipment_attendance_logscheck_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}/taskstask_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_requestsresign 또는 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>