Vibe coding으로 만드는 행낭 발송 캘린더 (2)

Yihoon·2025년 11월 13일

AWS활용기

목록 보기
10/11
post-thumbnail

지난번에 작업한 버전을 배포하면서 사용자경험에 있어 몇 가지 문제들이 보였고, 그 중 시급하다고 판단한 문제들과 그 개선 과정을 정리해 본다.

1편은 여기!

01

Problem: 정규 일정과 변동 일정의 구분 필요성

각 날짜에 발송되는 공관 목록이 태그 형태로 나열되는 UI를 구현하였는데,
문제는 원래 이 날짜에 발송되는 공관인지, 혹은 일정이 변동되어 이동된 일정인지 시각적으로 구분이 되지 않는다는 것.

예를 들어 9월 30일에 발송되는 걸로 표출되는 일정 중에는 원래 23일이나 29일, 10월 1일에 예정되어 있던 공관 일정이 들어와 있기도 하며,
거꾸로 9월 30일에 발송될 예정이던 공관 일부가 다른 날짜로 바뀐 경우도 몇 가지 존재한다.

다음 날 발송되는 공관에 대해 (상세히 밝히기 곤란한)물리적인 조치를 취해야 하는 내 입장에서, 이렇게 '원래 일정'과 '편집된 일정'이 섞여 있으면 두 일정을 구분하기 위해 개별 변동 일정을 직접 체크하는 작업을 한 번 더 거쳐야 하기 때문에 페이지의 활용성이 크게 떨어졌다.
또 해당 서비스를 참고하는 타 부서나 공급업체의 경우에도 '00 공관은 일주일 순연되었습니다'와 같은 개별 공지를 직접 확인하기 전까지는 일정이 변경되었는지를 직관적으로 알 수 없었다.

Soluiton: 색상으로 변경 여부 시각화

따라서 다음과 같은 간단한 방법으로 일정 변경 여부를 알 수 있도록 했다:

  • 먼저 일정 조회 시 (원래의 일정을 저장한) cities 테이블과 당일 최종 계산된 데이터를 대조하는 로직을 추가했다.
  • 여기서 두 데이터가 상이한 공관은 별도로 표기한다:
    cities 테이블에 존재하나 발송되지 않을 경우, 당일 발송이 취소되었다는 의미이므로 회색 취소선으로 표기하며,
    cities 테이블에 존재하지 않으나 당일 발송 일정에 포함된 경우 녹색으로 표기한다.

02

Problem: 공지사항 영역의 도입과 점점 높아지는 의존도

처음 만든 버전에서는 별도의 공지 텍스트를 띄우는 걸 고려하지 않았지만, 운영 시작과 동시에 세계 곳곳에서 분쟁이 터지며 수 개 공관의 정파 발송이 중단되었다. 이를 계기로 공지사항을 표출할 영역을 상단에 작게 추가하였다.

이때 아래와 같이 별도의 H5태그를 이용해 공지 텍스트를 하드코딩하는 단순한 접근을 택했는데,

이후 7일간의 전례없는 연휴로 인한 무수한 일정 변동을 비롯, 공지사항에의 의존도가 크게 늘어났고, 그때마다 새로 배포를 해야 하는 불편함을 근본적으로 해결해야 했다.

Solution: 공지사항을 위한 별도 아키텍처 추가

다음과 같이 기능하도록 아키텍처와 프론트 코드를 수정하였다:

  • 관리자 모드에서 공지사항 수정과 저장이 가능
  • 저장한 공지사항은 다른 동작과 마찬가지로 APIGW - Lambda - DDB를 통해 수정이 가능

Blue-Green Architecture

아키텍처 변경이 필요하므로 블루-그린 접근법을 택했다.
우선 기존의 S3 버킷 및 Cloudfront 배포, Lambda 함수를 복제하여 하나 더 준비했다.
APIGW는 별도의 Dev 스테이지를 추가하여 활용하였으며,
기존 DynamoDB 테이블 A, B는 업데이트 과정에서 별도로 건드릴 일이 없기 때문에 그대로 두었다.

DynamoDB

먼저 공지사항을 저장하기 위한 별도의 테이블'C'를 생성하였다. 이때 ID(S)를 PK로 지정하였으며 ID는 'active-notice'로 항상 저장된다. 즉 공지를 수정하면 새 공지가 'active-notice'로 지정되어 이전 값을 덮어쓴다. 굳이 예전 공지를 살려 둘 필요가 없다고 판단했기 때문.

Lambda

뒤에서 추가할, APIGW의 /notices 경로에 해당하는 메소드들의 동작을 매개하는 코드를 추가하였다.
Vibe coding 한 결과물이므로 대략적인 구조만 남긴다.

else if (path === '/notices') {
      if (method === 'GET') {
        // 공지사항 조회 ('active-notice'로 ID 고정)
      else if (method === 'POST') {
        // 공지사항 저장/업데이트
        return {
          statusCode: 201,
          headers: {
            'Access-Control-Allow-Origin': '*',
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({ message: '공지사항이 저장되었습니다.' })
        };
      }
    }

APIGW

APIGW에 /notices 리소스를 추가하고 GET, POST 메소드를 구현하였다. 지울 공지가 딱히 없는 상황이기 때문에 DELETE 메소드는 구현하지 않았다.

그리고 각 메소드는 후술할 Lambda 함수와 Lambda Integration을 수행하였다.

물론 별도 메소드를 추가하는 작업이 현재 구동되는 서비스에 영향을 미치진 않겠지만 블루그린 배포를 위해 별도의 dev 스테이지를 만들어 작업하였음을 다시 한 번 밝힌다.

테스트

다음 명령어들을 통해 새 아키텍처가 정상적으로 추가되었는지 확인하였다:

  1. GET 메소드 테스트 (기존 공지사항 조회)
curl -X GET https://******.execute-api.ap-northeast-2.amazonaws.com/dev/notices
  1. POST 메소드 테스트 (공지사항 저장)
curl -X POST https://******.execute-api.ap-northeast-2.amazonaws.com/dev/notices \
  -H "Content-Type: application/json" \
  -d '{"content":"**테스트 공지**"}'
  1. 다시 GET 메소드 테스트 (공지사항이 정상적으로 저장되었는지 테스트)
curl -X GET https://******.execute-api.ap-northeast-2.amazonaws.com/dev/notices

테스트에 성공한 후 dev스테이지에 배포한 내용을 product에 배포하는 것으로 아키텍처 수정을 마무리하였다.

Results


공지사항을 캘린더 위쪽에 표출하여 접속과 동시에 파악할 수 있게 하였으며,


관리자 모드 진입 시 '편집' 버튼을 눌러 기존 공지를 편집하고 저장할 수 있도록 하였다. 특이사항으로 해당 텍스트 박스는 마크다운 서식을 일부 지원하도록 별도 함수를 구현하였다.

const renderMarkdown = (text) => {
    if (!text) return '공지사항이 없습니다.';
    
    let html = text;
    
    // **굵게**
    html = html.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
    
    // *기울임*
    html = html.replace(/\*(.+?)\*/g, '<em>$1</em>');
    
    // [링크텍스트](URL)
    html = html.replace(/\[(.+?)\]\((.+?)\)/g, '<a href="$2" target="_blank" rel="noopener noreferrer" class="text-blue-600 hover:underline">$1</a>');
    
    // 리스트
    html = html.replace(/^[\-\*] (.+)$/gm, '<li>$1</li>');
    html = html.replace(/(<li>.*<\/li>)/s, '<ul class="list-disc pl-5">$1</ul>');
    
    // 줄바꿈
    html = html.replace(/\n/g, '<br>');
    
    return html;
  };

03: 모바일에서 특히 형편없는 UI

기존 UI는 크게

  • 캘린더 이동 버튼과 공관 검색 버튼이 있는 '헤더' 영역(분홍색)
  • 오늘/내일/모레/7일 후의 일정을 바로 볼 수 있는 '미리보기' 영역 (노란색)
  • 달력에 전체 일정을 표시해 두는 '캘린더' 영역 (초록색)

세 개의 섹션으로 구분된다.

그런데 실무 환경에서는 PC보다 모바일 환경에서의 사용 빈도가 더 높았지만, 최초로 구축한 모바일 UI는 PC UI를 깨짐 없이 구현하는 데 초점을 맞추었다. 그러다 보니 실제 사용성에서의 부족함이 많이 보였다.

Problem

미리보기 영역

우선 '미리보기' 영역의 네 개의 박스를 그대로 구현하다 보니 세로로 배치되면서 캘린더가 저 아래로 내려가게 되었고, 그 결과 캘린더가 존재하는지조차 모르는 사람들이 많았다.

22:9 비율의 극단적으로 긴 디스플레이를 가진 폰에서 앱을 실행한 화면인데, 이런 상홍에서야 겨우 캘린더가 보일락 말락 할 정도로 기형적인 UI가 탄생했다.

캘린더 영역

캘린더 영역 또한 크기상의 한계로 '격주' 및 'N째주'표시를 축약하여 표기하였는데, 업무에 익숙한 사람은 이 표기가 아무 문제가 없지만 처음 접하는 이들에게는 다소 불친절했다.

예컨대 사진에서 1일은 '격주 2' 이자 '1번째 월요일'에 해당하는데, 모바일 버전은 공간상 제약으로 인해 이를 '2 ①' 과 같이 지나치게 간소한 표기로 표현하였다.

PC/모바일을 막론하고 달력은 맨 아래에 있는데 달력을 이동하기 위한 네비게이션 버튼은 상단에 있다. PC 버전에서야 '미리보기 영역'의 높이가 차지하는 비중이 높지 않으니 크게 문제가 되지 않았지만, 모바일 버전에서는 상당한 높이를 차지하기에 이 영역이 캘린더와 연동되는 부분이라기보다는 미리보기 영역을 컨트롤하는 버튼으로 오해하는 경우가 많았다.

Solution

레이아웃을 상당 부분 수정하였는데, 사용 환경을 고려하여 아예 모바일 UI를 우선적으로 설계하고, 거의 볼 일이 없는 PC UI는 모바일 UI를 그대로 따라가되 달력 모양만 조금 손보는 쪽으로 접근했다.

01
UI에 가장 큰 걸림돌이 되던 미리보기 영역을 삭제하였다. 외교업무 일선에 종사하는 직원들은 '내가 보내고자 하는 특정 공관의 발송일이 언제인지'가 더 중요하지, '오늘 발송되는 공관 목록이 무엇인지'를 볼 일은 그렇게 많지 않음을 확인하였다. 발송을 준비하는 나의 입장에서만 필요하지, 그 외 대부분의 사람들에게는 크게 중요하지 않기 때문에 위에서 서술한 공지사항 부분을 남기고 모두 제거하였다.

02
캘린더 내부 공간 확보를 위해 공관 개수 표기를 삭제하였다. 이것도 대부분의 실무자들에게는 불필요한 정보이다.

좌측이 기존 모바일 캘린더 UI, 우측이 개선된 모바일 캘린더 UI. 공관 개수 표기를 없애고 그 공간을 활용하여 격주 유형 및 요일 카운트 표시를 개선하였다. 수정하면서 공휴일에도 음영을 칠하여 발송이 진행되지 않음을 좀 더 명확히 표현하였다.

03
상단 영역에 있던 공관 검색 섹션(보라색 영역)캘린더 월 이동 버튼을 캘린더 바로 위로 옮겼다.

  • '검색'버튼을 누른 후 공관명을 입력하던 기존 UI 대신, 입력 필드를 바로 노출시켜 공관 검색을 바로 가능하게 했다. 자동 완성을 통해 발송 일정을 바로 조회할 수 있고,

공관을 선택하면 다음 발송 일정이 표출되며 이를 캘린더에도 하이라이트되도록 했다.

04
발송 일정 모달 또한 사용성을 개선하기 위한 몇 가지 작업을 거쳤다.
먼저 모달 안에서도 날짜 이동이 가능하도록 좌우 이동 버튼을 추가했고, 특히 자주 봐야 하는 오늘/내일/모레/다음 주는 아예 버튼으로 만들어 사라진 미리보기 영역의 기능을 부분적으로 대체하도록 하였다. 이때 주말을 고려하여 주말은 건너뛰고 날짜를 이동하도록 했다.

이어지는 내용에서는 또 다른 문제인 로딩 속도 개선 과정을 정리해 보겠다.

profile
딴짓 좋아하는 데이터쟁이

0개의 댓글