---
title: "HTML 우선 사이트로 전환했더니 신청 완료자가 하룻밤 사이 2배가 된 이야기"
published: 2026-06-10T12:45:47.000Z
canonical: https://jeff.news/article/3973
---
# HTML 우선 사이트로 전환했더니 신청 완료자가 하룻밤 사이 2배가 된 이야기

한 공공성 강한 유틸리티 회사가 React 기반 신청 폼 실패 뒤, Astro와 HTML 우선 구조로 다시 만들었더니 폼 완료자가 출시 직후 2배로 늘어남. 핵심은 자바스크립트 없이도 동작하는 페이지별 폼, 서버 저장 세션, 접근성, 점진적 향상이었음.

- 한 유틸리티 회사가 고객 신청 폼을 HTML 우선 구조로 다시 만들었더니, 출시 직후 폼 완료자가 말 그대로 2배가 됨
  - 회사는 규제받는 독점 사업자였고, 고객 만족도가 약 96퍼센트 아래로 떨어지면 수백만 파운드 벌금까지 맞을 수 있는 상황이었음
  - 고객은 온라인 신청 폼을 쓰거나 더 비싼 수동 절차를 따라야 했는데, 기존 디지털 폼이 계속 문제를 일으키고 있었음

- 이전 시도는 꽤 처참했음. 특히 가장 최근의 React 앱은 온라인에 올라간 지 3일 만에 고객 불만 때문에 내려감
  - 작성자가 본 React 앱은 로딩 스피너와 전역 자바스크립트 상태가 뒤엉킨 구조였고, 접근성도 맞지 않았음
  - 더 큰 문제는 이미지 업로드가 필수인 폼인데, 이미지와 폼 데이터를 전부 로컬 저장소에 넣으려 했다는 점임
  - 로컬 저장소는 보통 5메가바이트 제한이 있어서, 이런 신청 폼의 핵심 저장소로 쓰기엔 애초에 무리였음

> [!IMPORTANT]
> 이 사례의 숫자는 단순한 성능 개선이 아님. ‘폼을 끝까지 완료한 사람’이 2배가 됐다는 건, 기존 분석 도구가 보지 못하던 실패 사용자가 실제로 꽤 많았다는 뜻임.

- 새 버전은 Astro로 만들었고, 핵심 원칙은 자바스크립트 없이도 완전히 동작하는 웹이었음
  - 자바스크립트는 웹 컴포넌트 안에서 점진적 향상용으로만 사용함
  - 기본 판단은 명확했음. 공공 서비스 성격의 폼이면 최대한 많은 기기, 나쁜 연결, 오래된 브라우저에서도 돌아가야 함
  - 한 번 입력한 데이터는 절대 날아가면 안 된다는 원칙도 같이 잡았음

- 요구사항도 그래서 프론트엔드 유행보다 실패 복구 쪽에 훨씬 가까웠음
  - 폼 세션마다 고유 아이디를 부여함
  - 사용자가 각 단계에서 제출할 때마다 업로드 파일까지 포함해 백엔드에 저장함
  - 자바스크립트 없이도 신청을 완료할 수 있어야 했음
  - 오래되고 별로인 브라우저에서도 동작해야 했고, 접근성은 WCAG AA 수준을 맞추기로 함

- 구현은 요즘 보면 오히려 신선한 고전 웹 앱 패턴임. 각 폼 단계가 별도 페이지고, 제출하면 서버 검증 뒤 다음 단계로 리다이렉트됨
  - 실시간 대시보드도 아니고 협업 편집기도 아니고, 그냥 큰 신청 폼이라서 무거운 클라이언트 앱이 필요하지 않았음
  - 사용자는 신축 주택 단지 한가운데에서 10년 된 보급형 안드로이드폰으로 신청할 수도 있음
  - 그런 사람에게 폼을 보여주기도 전에 자바스크립트 20메가바이트를 보내는 건 솔직히 좀 빡센 선택임

```mermaid
sequenceDiagram
    participant 사용자
    participant 브라우저
    participant 폼페이지
    participant 백엔드
    participant 다음단계
    사용자->>브라우저: 단계별 폼 입력
    브라우저->>폼페이지: 일반 HTML 폼 제출
    폼페이지->>백엔드: 입력값과 업로드 저장
    백엔드-->>폼페이지: 검증 결과 반환
    폼페이지-->>브라우저: 성공 시 다음 단계로 리다이렉트
    브라우저-->>다음단계: 저장된 세션으로 계속 진행
```

- 폼 검증도 ‘라이브러리로 다 갈아엎기’가 아니라 브라우저 기본 기능을 살리는 방향이었음
  - 작성자는 React 검증 라이브러리와 씨름하느라 팀들이 몇 사람월씩 쓰는 걸 많이 봤다고 함
  - 브라우저에는 이미 폼 검증 시스템이 있으니, 그걸 흉내 내는 거대한 레이어를 유지할 필요가 없다는 문제의식임

- 그래서 만든 게 HTML 폼을 감싸는 작은 웹 컴포넌트였음
  - Shadow DOM 없이 기존 HTML을 감싸고, 브라우저의 HTML 검증 결과를 가져와 더 보기 좋은 오류 표시로 바꿈
  - 기본 팝업 툴팁은 막고, 필드와 연결된 설명 영역에 오류를 표시함
  - 사용자가 입력 중 유효한 상태가 되면 오류를 지우고, blur나 submit 시점에 다시 검증함
  - 이 사용자 경험이 1킬로바이트 미만으로 구현됐고, 실패하면 브라우저 기본 검증으로 내려감

> [!TIP]
> 폼이 제품의 핵심 경로라면 ‘검증 라이브러리 고르기’보다 먼저 실패 순서를 설계하는 게 더 중요함. 클라이언트 검증, 브라우저 기본 검증, 서버 검증이 모두 각자 역할을 가져야 함.

- 결과는 꽤 강력했음. 출시하자마자 신청 완료자가 2배로 뛰었고, 분석 담당자들도 사용자가 어디서 갑자기 온 건지 몰랐다고 함
  - 자바스크립트 기반 분석 도구는 자바스크립트 실패로 튕겨 나간 사용자를 애초에 못 봄
  - 그래서 기존 데이터만 보면 문제가 작아 보이지만, 실제로는 폼에 도달하지 못한 사람이 숨어 있었던 셈임
  - 서버 세션 저장 전략도 효과가 있었고, 어떤 사용자는 폼을 시작한 지 한 달 뒤에 완료했다고 함

- 마지막 얘기가 씁쓸함. 작성자가 떠난 뒤 후임자에게 ‘자바스크립트 없이도 항상 동작한다’고 설명했더니, 후임자는 ‘그럼 우리 일이 더 많아지잖아’라고 반응함
  - 하지만 작성자는 이걸 추가 노동이 아니라 업계가 성숙해지기 위해 감당해야 할 책임으로 봄
  - 오래된 브라우저, 나쁜 네트워크, 보조 기술 사용자라는 이유로 독점적 공공 서비스에서 사람을 튕겨내는 건 받아들일 수 없다는 주장임
  - 결론은 꽤 세다. 3G 연결의 PlayStation Portable에서도 돌아가는 웹 앱을 만들면, 모든 사용자에게 돌아가고 30년 뒤에도 버틸 가능성이 높다는 것임

---

## 기술 맥락

- 여기서 선택한 핵심 기술은 Astro 자체라기보다 HTML-first 구조예요. 왜냐면 이 서비스의 본질은 화려한 인터랙션이 아니라, 사용자가 어떤 환경에서도 신청 폼을 끝까지 제출하는 거였거든요.

- React 앱이 실패한 이유도 React라는 이름 때문만은 아니에요. 상태 관리, 로딩 처리, 업로드 저장, 접근성 같은 실패 지점이 전부 클라이언트 쪽에 몰려 있었고, 그 결과 브라우저나 네트워크가 조금만 약해져도 사용자가 빠져나갔어요.

- 페이지별 폼 제출과 서버 리다이렉트는 오래된 방식처럼 보이지만, 이 맥락에서는 오히려 제일 현실적인 선택이에요. 각 단계마다 백엔드에 저장하면 브라우저가 닫히거나 연결이 끊겨도 이어서 진행할 수 있고, 업로드 파일도 로컬 저장소 제한에 묶이지 않아요.

- 웹 컴포넌트도 프레임워크 대체제가 아니라 실패해도 되는 향상 레이어로 쓰였다는 게 중요해요. 컴포넌트가 동작하면 오류 메시지가 더 좋아지고, 동작하지 않으면 브라우저 기본 검증과 서버 검증이 계속 받쳐주는 구조라서 전체 흐름이 무너지지 않거든요.

- 이 사례는 한국 서비스에도 꽤 직접적으로 와닿아요. 본인인증, 민원, 금융, 통신 가입처럼 폼이 긴 서비스일수록 최신 프론트엔드 스택보다 저장, 복구, 접근성, 저사양 대응이 전환율을 더 크게 바꿀 수 있어요.

## 핵심 포인트

- React 앱은 로딩 스피너, 전역 자바스크립트 상태, 접근성 문제, 5메가바이트 제한의 로컬 저장소 업로드 처리 때문에 3일 만에 내려감
- 새 구현은 각 단계마다 서버에 데이터를 저장하고, 자바스크립트가 없어도 제출과 이동이 가능한 전통적인 폼 제출과 리다이렉트 구조를 사용함
- 폼 검증은 브라우저 기본 검증을 활용하고 1킬로바이트 미만의 웹 컴포넌트로 사용자 경험만 개선함
- 출시 뒤 신청 완료자가 2배로 늘었고, 한 사용자는 시작 한 달 뒤에도 저장된 세션 덕분에 폼을 끝낼 수 있었음

## 인사이트

이 글의 포인트는 ‘React 쓰지 마’가 아니라, 서비스 성격에 맞게 실패 모드를 설계하라는 쪽에 가까움. 특히 공공 서비스나 독점 서비스처럼 사용자가 떠날 선택지가 없는 제품에서는 최신 스택보다 ‘끝까지 제출되는 폼’이 훨씬 큰 기술임.
