개발 기록 2026-10-20 docs/devlog/2026-10-20-12-공통-셸과-홈-화면.md GitHub에서 보기

공통 셸과 홈 화면

목표

Phoenix 기본 홈과 헤더를 Tickmark 공통 셸로 교체한다. 로그인 전후 메뉴, 설계 색과 본문 폭, 한국어 오류 안내와 시각 형식을 맞춘다.

한 일

파일 변경
assets/css/app.css 두 테마의 hex 색, 폰트, muted와 line-strong, 포커스 링, 테이블 밀도, 입력 경계
lib/tickmark_web/components/layouts.ex 48px sticky 상단 바, 감사 대상과 감사 로그, 표시용 presence, 테마와 사용자 메뉴, 넓은 본문, 한국어 연결 안내
lib/tickmark_web/components/layouts/root.html.heex, theme_script.html.heex 한국어 문서와 제목, 영어 메뉴 제거, 공통 테마 스크립트와 tk:theme, 저장소 접근 실패 처리
lib/tickmark_web/controllers/page_controller.ex, page_html/home.html.heex 비로그인 소개와 로그인/회원가입, 로그인 사용자의 목록 리다이렉트
lib/tickmark_web/controllers/error_html.ex, error_html/404.html.heex, error_html/500.html.heex 레이아웃 없는 오류 응답에 완전한 한국어 HTML 문서와 CSS, 테마 적용
S2, S3, S4, S6 LiveView Layouts.app 여는 태그의 engagement와 active만 연결
lib/tickmark_web/live/engagement_live/components.ex kst_time/1의 title을 TickmarkWeb.Format.utc_title/1로 변경
컨트롤러 테스트 2개와 components/layouts_test.exs 홈, 오류, 로그인 전후 메뉴, active, presence 5명, 한국어 연결 안내, KST/UTC 속성 검증
  • rg로 확인한 기존 사용처: S2의 table tk-table, S3의 text-muted와 border-line-strong, S4의 text-muted와 tk-table, S5의 세 클래스, S6의 text-muted. 공통 CSS 추가로 기존 클래스가 실제 유틸리티와 규칙을 얻는다.
  • S1과 S5 본문/호출부, Presence 추적, 인증 파일과 공유 파일은 수정하지 않았다.

결정과 트레이드오프

  • 테마 플러그인의 두 블록과 속성을 유지하고 설계의 hex 값만 대입했다. oklch 변환을 검토했으나 빌드가 그대로 통과해 변환하지 않았다.
  • 테마 스크립트는 layouts/theme_script.html.heex 한 곳에서 root와 오류 문서가 재사용한다. 세 문서에 복사하는 대안보다 저장 키와 실패 처리의 차이를 막기 쉽다. 기존 phx:set-theme, storage 이벤트와 시스템 테마 변경 흐름을 유지했다.
  • 사용자 메뉴는 네이티브 details와 daisyUI dropdown으로 구현했다. 별도 JS 상태나 모달을 추가하지 않았다. 좁은 화면에서는 브랜드 텍스트와 이메일을 화면낭독기용으로 유지하고, 감사 대상 이름은 말줄임한다.
  • Presence는 계약대로 %{id, name} 목록을 받아 최대 4명과 초과 수를 표시한다. 추적과 탭 중복 제거는 메인의 4.4 작업이다.
  • 홈에는 page_title: "분개 테스트"를 지정했다. root의 default Tickmark와 접미사 | Tickmark를 유지하면서 홈 제목이 중복되지 않게 했다.
  • 404와 500은 render_errors의 layout: false 설정에 맞춰 독립 HTML로 만들었다. 500은 전달된 오류 원인을 출력하지 않는다. 비멤버와 없는 감사 대상이 모두 Engagements.get_engagement!/2에서 Ecto.NoResultsError로 처리되고, 기존 LiveView 테스트도 404를 확인한다.

막힌 점과 해결

  • 첫 대상 테스트에서는 홈 제목이 Tickmark | Tickmark여서 1건이 실패했다. 홈의 페이지 제목을 지정한 뒤 대상 97개가 모두 통과했다.
  • 전체 precommit에서는 기존 인증 테스트 3건이 로그인 후 GET /의 200 응답을 기대해 실패했다. 새 홈 계약의 응답은 /engagements로 302다. F2 소유 파일이므로 수정하지 않았고 코디네이터에게 전달했다.
  • 코디네이터 답변: F2가 같은 3곳을 수정 중이며, F1은 현재 결과를 기록하고 마무리한다. 메인이 F2와 합친 뒤 전체 통과를 확인한다. 이 확인 범위 조정에 따라 F1 변경을 커밋한다.

검증

대상 테스트의 최종 출력:

$ MIX_TEST_PARTITION=8 mix test test/tickmark_web/controllers/page_controller_test.exs test/tickmark_web/controllers/error_html_test.exs test/tickmark_web/components/layouts_test.exs test/tickmark_web/live/engagement_live_test.exs test/tickmark_web/live/import_live_test.exs test/tickmark_web/live/test_run_live_test.exs test/tickmark_web/live/audit_live_test.exs test/tickmark_web/live/finding_live_test.exs
Finished in 0.8 seconds (0.8s async, 0.00s sync)
Result: 97 passed

전체 precommit의 실제 마지막 출력:

$ MIX_TEST_PARTITION=8 mix precommit
Finished in 7.4 seconds (6.1s async, 1.3s sync)
Result: 524/527 passed
Failed: 3 tests
  • 종료 코드 2. 경고를 오류로 취급한 컴파일, 미사용 의존성 정리와 포맷은 통과했다. 실패는 user_session_controller_test.exs의 25, 89, 113행이며 F2가 조정한다.
  • mix assets.build 종료 코드 0. 실제 출력: tailwindcss v4.3.3, daisyUI 5.5.20, Done in 85ms, Done in 16ms. hex 값 그대로 성공했다.
  • 생성 CSS에 .max-w-screen-2xl, .text-muted, .border-line-strong, .tk-table과 입력 경계 규칙이 있는 것을 확인했다. 산출물은 .gitignore에 의해 제외된다.
  • Node의 vm으로 저장 테마 초기화, 테마 전환, 시스템 테마 변경, 탭 동기화와 localStorage 읽기/쓰기 예외를 검증했다. 실제 출력: Theme script checks passed: saved choice, switching, system changes, cross-tab sync, denied storage.
  • git diff --check 통과. mix.lock 변경 없음.
  • 실제 브라우저의 시각 품질, 좁은 화면의 배치와 입력 포커스/오류 상태는 검증하지 않았다. 외부 배포는 하지 않았다.

Elixir 학습 포인트

  • 함수 컴포넌트의 attr 기본값으로 공통 셸의 입력 계약을 표현한다. engagement: nil이면 대상 관련 영역을 그리지 않고 인증 화면과 S1도 같은 셸을 쓴다.
  • HEEx의 :if, :for로 영역과 아바타를 렌더링한다. 표시용 데이터만 받고 기존 LiveView의 도메인 상태와 이벤트 처리에는 손대지 않았다.
  • embed_templates는 파일을 컴포넌트 함수로 만든다. root와 오류 템플릿이 같은 테마 컴포넌트를 호출할 수 있고, ErrorHTML도 404/500 전용 템플릿을 렌더링한다.
  • DateTime.to_iso8601/1은 기계용 datetime에 남기고 utc_title/1은 사람이 읽는 UTC 툴팁에 쓴다. 화면의 KST는 기존 변환을 유지한다.
  • 컨트롤러의 redirect는 302이므로 로그인 후 홈을 재요청하는 테스트도 새 흐름을 따라야 한다. 테스트 실패가 화면 자체의 오류인지 이전 동작의 단언인지 구분했다.

다음 할 일

  • 메인: F2 브랜치와 통합한 뒤 전체 mix precommit 통과 확인, docs 색인 추가.
  • 메인: S5 상단 바 연결과 Presence 추적, 실제 브라우저와 반응형 확인.
  • 공통 flash 닫기 단추에는 소유 범위 밖 core_components.ex의 gettext("close")가 남아 있다. 해당 파일은 수정하지 않았다.
  • 계약 변경 요청: 없음. 인증 테스트 3건의 조정은 코디네이터와 F2가 처리한다.

관련 커밋

  • 기준 커밋: f5f7f78 (feature/m2-rule-engine).
  • 이 문서를 포함한 기능 커밋: feat(ui): 공통 셸과 한국어 홈 및 오류 화면 구현.