Skip to content

관리비 콘솔 "공지" — BE 참고

관리비 상용화 펀치리스트 Critical C-3 해소(최소 정직 게이팅). 설계 정본: docs/superpowers/plans/2026-07-10-notice-honest-gate.md.


1. 용어 정정 — notice ≠ 고지서(invoice)

service-charge/actual/console/notice/{general,individual} 라우트는 이름 때문에 "고지서 목록"으로 오인되기 쉽지만, 정찰 결과 고지서(invoice) 엔티티가 아니라 별도의 "공지(announcement) 게시판"이다.

  • 라우트/컴포넌트 이름: notice (i18n 라벨: 전체 공지 / 개별 공지).
  • 목록 컬럼의 content는 재무 데이터가 아니라 공지 문구 텍스트(하드코딩 예시: "입주를 환영합니다" 등 — 이번 슬라이스에서 제거됨, §2 참고).
  • 이 문구는 실제 고지서를 인쇄할 때 공지사항 블록(src/components/document/transaction/blocks/NoticeAto.vue)에 들어갈 텍스트로 설계된 것으로 보인다(현재 그 블록은 정적 placeholder — "라인1"~"라인5" — 이며 이 콘솔과 연결되어 있지 않다).
  • 재무 데이터(useInvoice/useAllocations 등 청구·배분 파생값)는 이 콘솔과 무관한 별도 엔티티다. 공지는 청구 금액이나 미납 현황과 관계없는 "안내 문구" 데이터이므로, 향후 공지 데이터모델을 설계할 때 청구 파이프라인(useInvoice 등)에 얹으면 안 된다 — 완전히 독립된 CRUD 엔티티로 설계해야 한다.

2. 이번 슬라이스에서 한 일 (C-3, as-built)

기존 상태: 목록은 ref([...3개 mock행])으로 하드코딩되어 있었고, 삭제/다운로드/지난공지/추가/편집 버튼은 전부 dead(삭제는 mutation 없는 confirm-only, 다운로드는 아무 핸들러 없음, 지난공지는 엉뚱한 업로드 시트를 빌려 열었고, 추가는 다른 도메인의 SheetCreateArt를 빌려 열었고, 편집은 <script setup>이 아예 없는 FormSheetArt.vue를 열었다). 즉 "동작하는 것처럼 보이지만 실제로는 아무것도 저장되지 않는" 가짜 표면이었다.

"최소 정직" 게이팅(오너 결정):

  • 하드코딩 mock 3행 → 빈 배열 + 빈 상태 행("등록된 공지가 없습니다 · 공지 작성 기능 준비 중").
  • 삭제·다운로드·지난공지·추가(NoticeDataToolBarOrg.vue) 및 편집(DataToolBarOrg.vue, 기본정보 영역) → disabled + title="공지 작성 기능 준비 중". 죽은 오버레이로의 commandfor 연결도 제거(더 이상 아무것도 열지 않음).
  • 행별 편집 버튼(목록 각 행) → disabled + 동일 title. form-sheet-art로의 commandfor 제거.
  • 미리보기 버튼만 유지 — 이것은 가짜가 아니라 실제로 동작하는 기능이다(§3).
  • 데이터모델·CRUD·저장은 추가되지 않았다 — 이번 작업은 순수 게이팅(가짜 제거)이지 신규 기능 구현이 아니다.

3. 유일하게 동작하는 것 — 미리보기

미리보기 버튼은 command="show-modal" commandfor="invoice-preview-art"로 이미 실제 고지서 컴포넌트(<InvoiceDynamicOrg/>, src/components/document/transaction/InvoiceDynamicOrg.vue)를 여는 canon 배선이었고, 이번 작업에서 변경하지 않았다(무변). 이 시트는 현재 콘솔의 line/edition 컨텍스트에 종속되지 않은 정적 오버레이로, 클릭 시 항상 같은 InvoiceDynamicOrg 인스턴스를 연다(이미 다른 슬라이스에서 배선된 canon 고지서 뷰 — 이 콘솔이 새로 만든 것이 아니다).

주의: InvoiceDynamicOrg가 렌더하는 고지서의 공지사항 블록(NoticeAto.vue)은 여전히 정적 placeholder이며, 이 notice 콘솔의(현재는 비어있는) 목록과 연결되어 있지 않다. 즉 "미리보기가 동작한다" = "고지서 화면을 열 수 있다"는 뜻이지, "공지 문구가 미리보기에 실제로 인쇄된다"는 뜻이 아니다.


4. 데이터모델 부재 — follow-up 계약 스케치

현재 공지(announcement) 데이터를 저장할 곳이 시스템 어디에도 없다. 향후 실 구현 시 필요한 최소 계약:

4-1. 엔티티안

Notice {
  id                  고유코드
  scope               'building' | 'unit'         // 전체공지=building, 개별공지=unit
  unitId              scope==='unit'일 때만 참조(호수)
  content             string                       // 공지 문구 본문
  startDate           string (YYYY-MM-DD)          // 게시 시작일 (옵션)
  endDate             string (YYYY-MM-DD)          // 게시 종료일 (옵션)
  order               number                       // 목록 정렬 순서
  createdDate         string
  editedDate          string
  operator            string                       // 작성/최종수정자
}
  • scope: 'building' → 전체 공지 탭. scope: 'unit' → 개별 공지 탭(이 콘솔의 notice/individual이 이미 세대 열을 갖고 있다 — 데이터모델도 세대 참조가 필요).
  • 기존 목록 컬럼(번호·내용·수정일·작성자·관리)과 1:1 대응하도록 필드명을 맞춰두었다 — FE 재작업 최소화.

4-2. CRUD 계약(스케치)

  • list(scope, unitId?) — 목록 조회(현재 목록의 "빈 상태"를 대체할 지점).
  • create(notice) — 추가 버튼(현재 disabled)의 목적지.
  • update(id, patch) — 행별 편집 버튼 + 상단 편집 버튼(현재 disabled)의 목적지.
  • remove(id[]) — 삭제 버튼(현재 disabled, 체크박스 선택 다건 삭제로 보임)의 목적지.
  • history(scope, unitId?) — 지난공지 조회(현재 disabled)의 목적지. "지난 공지"라는 이름으로 보아 게시 종료된 공지의 이력 조회로 추정된다.
  • export/download — 다운로드 버튼(현재 disabled)의 목적지. 포맷(CSV/PDF 등) 미정.

4-3. NoticeAto.vue 연동

src/components/document/transaction/blocks/NoticeAto.vue는 현재 primary/secondary 제목과 "라인15"/"라인 12" 정적 텍스트만 렌더한다. 실 연동 시:

  • 전체공지(scope: 'building') 최신 N건 → primary("공지사항") 영역.
  • 개별공지(scope: 'unit', 해당 세대) 최신 N건 → secondary("1:1 공지사항") 영역.
  • 두 영역 모두 줄 수 제한(현재 정적 마크업이 5줄/2줄 고정 그리드) — 실 데이터 연동 시 문구 길이·건수 초과 처리(말줄임/스크롤/우선순위) 정책이 필요.

4-4. 스코프 경계(follow-up, 오너 확인 필요)

  • 공지 데이터모델 자체가 없다 — 이번 슬라이스는 신규 스토어/API를 만들지 않았다.
  • 재무 파이프라인과 독립useInvoice/useAllocations 등 청구 계산 로직에 공지 데이터를 얹지 말 것. 공지는 안내 문구이지 청구 금액 파생값이 아니다.
  • 인증/권한 — 공지 작성 권한(관리소장만? 경리도?)은 미정.
  • 게시 기간(startDate/endDate) — "지난공지"라는 UI 명칭이 있는 것으로 보아 게시 기간 개념이 있을 것으로 추정되나, 확정 규칙 없음.