Pointly 01. 편집 프로토타입 착수와 작업 범위 경계 정리
개발자 없이 사이트를 고친다는 게 Pointly의 전제다. 말로 적어두면 그럴듯한데, 클릭에서 게시까지 실제로 이어지는지는 화면을 만들어봐야 알 수 있다. 첫 커밋을 그 흐름만 만들어보는 프로토타입에 썼다.
실제 변경은 시뮬레이션으로 두고 상호작용만 봤다
첫 커밋에 넣은 건 편집기 화면 틀과 데모 사이트, 선택 프리미티브(선택 기능의 최소 단위 부품으로, 클릭하면 그 자리가 무엇인지 사람이 읽을 수 있는 이름으로 잡힌다), 자연어 변경 시뮬레이션, 그리고 실행 취소와 재실행, 게시 흐름이다. 흐름이 끊기지 않는지만 보려던 거라 실제 변경은 시뮬레이션으로 대신했다.
@pointly/editor-core는 npm에 올린 패키지가 아니라 vendor/에 넣어둔 packed tarball(npm pack으로 압축해 만들어 둔 설치용 파일)로 설치한다. 선택 프리미티브는 pubuilder에서 떼어 온 것인데, 인터페이스가 자리 잡기 전에 사설 패키지로 올리면 버전 하나 고칠 때마다 두 레포를 왕복해야 한다. 인터페이스가 안정되면 그때 옮긴다.
로그인 화면은 빈 입력칸 하나로는 완성돼 보이지 않았다
로그인 화면에 소셜 로그인과 브랜드 마크를 붙였다. 여백만 넓고 입력칸 하나 덩그러니 있는 화면은 "아직 안 만든 화면"처럼 보인다. 실제로 사람들이 계정을 만드는 방식대로 만들어 둬야 화면이 제대로 채워진다.
가로 폭 하한과 클리핑 처리는 app-shell로 옮겼다.
리다이렉트 검사를 컴포넌트에서 빼내 테스트로 확인했다
로그인 후 돌아갈 주소를 다루는 safeRedirect를 별도 모듈로 떼어내고 테스트를 붙였다.
리다이렉트 파라미터는 외부에서 값이 들어오는 자리다. //evil.com처럼 프로토콜 상대 URL(http:, https: 없이 //로 시작해서 현재 페이지의 프로토콜을 그대로 따라가는 주소)을 그대로 넘기면 자기 사이트로 돌아가는 척하면서 남의 사이트로 보낸다. 오픈 리다이렉트(공격자가 지정한 외부 주소로 사용자를 그대로 넘겨주는 취약점)가 여기서 생긴다.
컴포넌트 안에서 그때그때 판단하면 "이 조건이 정말 다 막나?"를 눈으로만 확인하게 된다. 순수 함수로 떼어내면 그 질문을 테스트로 확인할 수 있다.
세션 쪽도 session.dom.test.ts로 같이 테스트했다.
썸네일은 Pointly가 만든 결과물에서만 찍는다
페이지 썸네일은 게시 시점에 Pointly가 빌드한 결과물에서 찍는다. 그 결과물은 정적이고, 같은 입력이면 늘 같은 화면이 나온다. 로그인해야 볼 수 있는 페이지나 리다이렉트, 영영 안 끝나는 요청 같은 것에 걸릴 수가 없다.
오너의 실제 사이트를 찍는 건 온보딩 미리보기 때 딱 한 번만 허용하고, 페이지 단위로 실패해도 되게 뒀다. 편집과 게시가 거기에 의존하는 일은 없다.
기존 사이트 가져오기는 기능이 아니라 제품 네 개였다
Pointly는 자기가 만들고 게시한 사이트를 편집한다. 오너의 기존 라이브 사이트나 소스 레포를 가져오는 건 범위 밖으로 뒀다. 임의의 프레임워크를 빌드해야 하고, 로그인 뒤의 페이지를 찍어야 하고, 도메인 소유를 검증해야 하고, 오너가 준 URL을 Pointly 서버가 대신 불러와야 한다. 각각이 자기만의 보안 경계를 가진 별개의 제품이다.
온보딩은 Pointly 템플릿에서 시작한다. 템플릿 온보딩이 전환율의 발목을 잡는 게 확인되면 그때 다시 본다.
첫날 코드보다 결정 문서를 더 오래 썼다. "기존 사이트 가져오기"는 데모에서 제일 멋있어 보이는 기능이고, 그래서 아무 생각 없이 로드맵에 올려두기 쉽다. 그게 사실 제품 네 개라는 걸 적어두지 않으면 나중에 "왜 이건 안 돼요?"를 매번 처음부터 다시 논쟁하게 된다.
안 하기로 한 것을 이유와 함께 적어두는 게 로드맵의 절반이다.