ubell 디자인 의뢰 · 로그인 다음 판

두 세계, 하나의 문 — 인사가 갈린다

오너의 말: "무조건 인증번호를 받게 보인다. 산토끼용과 집토끼용이 기본이고, 산토끼용은 선택해서 들어가게 해야지." 이 문서는 그 "이상하다"의 정체를 판정하고, 갈림 화면 없이 갈림을 세우는 목업입니다. 코드는 건드리지 않았습니다.

1부

판정 — 갈림 화면이 아니라, 한 화면 안의 위계와 문맥의 문제다

판정. 오너의 "이상하다"는 화면이 모자라서가 아니라 문장이 하나뿐이라서입니다. 지금 로그인은 세 종류의 사람 — 명부의 성도, 문패를 걸러 온 사장님, "이름 없이 답할 수 있다"는 약속을 읽고 온 산토끼 — 에게 똑같이 집토끼의 문장("휴대폰 번호로 문자를 받아 들어갑니다") 하나만 말하고, 번호 아닌 길은 "다른 방법"이라는 아무것도 이름하지 않는 낱말 뒤에 접어 두었습니다. 그래서 정문이 "이름 없이"를 약속해 놓고 문 앞에서 번호부터 내라는 모순이 생깁니다 — 광장의 익명은 제품에서 참인데(000089, '익명 {별칭}'만 공개) 문이 그 참을 배신하는 것처럼 보입니다. 처방은 갈림 "화면"이 아닙니다 — 그건 오늘 없앤 탭 게이트의 부활입니다. 문은 하나로 두고, 어디서 왔는지(next=·초대 토큰)로 첫 문장과 길의 순서만 바꿉니다. 감독의 감 셋은 전부 검증됐습니다: ① 갈림의 축은 정체가 아니라 목적이 맞고(사람은 "산토끼"라는 말로 자기를 부르지 않습니다), ② 묻지 않고 아는 신호는 이미 URL에 있으며(next=/shop/open · 초대 returnTo), ③ 어디서 왔는지 모를 때 필요한 수리는 화면 추가가 아니라 낱말 하나 — "다른 방법"을 "번호 없이 들어오기"로 바꿔 선택이 있음을 보이게 하는 것입니다. 단, ②에는 실측 단서가 둘 붙습니다: 미스바는 로그인으로 보낼 때 next를 안 붙이고, 휴대폰 OTP 경로는 next를 읽지 않습니다 — 갈림을 살리려면 이 두 줄부터 수리해야 합니다(5부 문장표 X 항목).
오너 문장의 번역"산토끼용은 선택해서 들어가게" = 산토끼에게 번호 아닌 길이 보이는 선택지여야 한다는 뜻이지, 산토끼 전용 화면을 세우라는 뜻이 아니라고 판정합니다. 전용 화면을 세우면 첫 화면이 "당신은 누구인가"를 묻게 되고, 그 물음이 곧 탭 게이트의 이름만 바꾼 부활입니다.

2부

"이름 없이"의 약속 — 문장은 참이다. 문이 그 문장을 따라가게 한다

정문의 문장을 고치지 않습니다. 고칠 것은 문입니다.

실측광장의 익명은 제품에서 이미 참입니다. plaza_posts_list(000089)는 글쓴이를 '익명 {별칭}'으로만 내리고, 실명 display_name은 내리지 않습니다. "이름 없이 한 줄로 답할 수 있어요"는 광장에 이름이 걸리지 않는다는 약속이고, 그 약속은 지켜지고 있습니다. 깨진 것은 문입니다 — create_plaza_post는 로그인(auth.uid())만 요구할 뿐 번호를 요구하지 않는데(이메일 매직링크·구글로도 계정은 섭니다), 로그인 화면이 번호를 유일한 길처럼 보여서 "이름 없이라더니 번호를 내라네"로 읽힙니다.
처방. 광장에서 온 사람(next=/mizpah/…)에게는 문이 약속을 의심이 생기는 바로 그 순간에 한 번 더 말합니다: 첫 문장 "이름은 광장에 걸리지 않아요", 둘째 문장 "휴대폰 번호는 필요하지 않습니다". 그리고 이메일·구글을 큰길로 올리고 번호를 조용한 줄로 내립니다. 화면과 제품이 같은 말을 하게 되므로 정문 문장은 손대지 않습니다 — 참인 문장을 고치는 것은 참을 의심하는 일입니다. 단 하나의 전제: 미스바가 로그인으로 보낼 때 next=를 붙여야 이 화면이 성립합니다(지금은 안 붙입니다 — 5부 X 항목).

3부

세 갈래의 첫 문장 — 그리고 모를 때의 기본값

첫 문장이 다른 이유는 각 사람이 문 앞에서 품는 의심이 다르기 때문입니다. 문장은 그 의심 하나에만 답합니다.

누가어떻게 아는가첫 문장왜 이 문장인가
집토끼 (초대 링크)초대 도착지가 심은 ubell:returnTo=/join/{token}"명부와 이어드릴게요"이 사람의 의심은 "내 교회가 맞나"입니다. 번호가 명부의 열쇠(link_member_by_phone)이므로 번호가 큰길인 이유를 말해 줍니다.
가게 주인next=/shop/open·/shop/sell·/shop/mine"문패를 세우러 오셨군요"이 사람의 의심은 "왜 번호를 내라는 거지"입니다. 이유를 사실로 답합니다: 골목에는 번호가 확인된 가게만 보입니다(create_market → DRAFT 잠금). 강요가 아니라 사실 고지입니다.
광장에 답하러 온 사람next=/mizpah/… (⚠지금은 안 붙음 — 수리 필요)"이름은 광장에 걸리지 않아요"이 사람의 의심은 "이름 없이라더니?"입니다. 정문의 약속을 문이 반복하고, 번호 없는 길(이메일·구글)을 큰길로 올립니다.
모를 때 (기본값)next 없음 · returnTo 없음"어서 오세요" + "휴대폰 번호가 있으면 문자 한 통으로 들어와요"기본은 지금처럼 번호가 큰길입니다 — 계정 311의 절대다수가 명부(313명)의 사람이고, 번호만이 명부와 자동으로 잇는 열쇠이기 때문입니다. 다만 "다른 방법"을 "번호 없이 들어오기"로 바꿔, 선택이 있다는 사실 자체를 문장으로 세웁니다. 오너가 본 "무조건 인증번호"는 이 낱말 하나가 만든 착시입니다.
문맥 명패문맥을 아는 세 화면에는 제목 위에 작은 명패(칩)를 답니다 — "가게 문패 걸기" · "오늘의 물음에 답하러" · "{교회}의 초대". 이 명패가 하는 일은 둘입니다: ① 묻지 않고 알았음을 사람에게 보여 주고, ② 틀렸을 때 되돌릴 손잡이("다른 일로 왔어요")를 줍니다. 명패는 화면이 아니라 한 줄이므로 게이트가 아닙니다 — 기본 화면에는 명패가 없습니다.

4부

화면 목업 — 한 화면, 네 인사

뼈대는 넷 다 같습니다: 종 마크 → 워드마크 → (명패) → 제목 → 한 줄 → 입력 → 큰 단추 → 조용한 줄. 달라지는 것은 명패·문장·길의 순서뿐입니다. 우상단 "밝음 · 어둠" 단추로 두 세계를 확인하세요.

A · 기본 — 어디서 왔는지 모름
바뀐 것은 맨 아래 낱말 하나

저녁19:24

ubell

어서 오세요

휴대폰 번호가 있으면 문자 한 통으로 들어와요.

처음이신가요?

번호 없이 들어오기이메일·Google

비밀번호로 로그인

B · 가게 주인 — next=/shop/open
번호가 필요한 이유를 사실로 말한다

14:07

ubell

가게 문패 걸기

문패를 세우러 오셨군요

골목에는 번호가 확인된 가게만 보여요. 그래서 문자로 들어오는 길이 가장 빠릅니다.

확인이 끝나면 문패 걸기로 돌아갑니다.

이메일·구글로도 들어올 수 있어요 — 다만 문패는 번호가 확인될 때까지 골목에 서지 않아요. 이메일 · Google

가게 일로 오신 게 아니면 다른 일로 왔어요

C · 광장에서 온 사람 — next=/mizpah/pangea
정문의 약속을 문이 반복한다 · 번호는 조용한 줄로

22:41

ubell

오늘의 물음에 답하러

이름은 광장에 걸리지 않아요

답은 '익명'의 별칭으로 걸려요. 휴대폰 번호는 필요하지 않습니다.

휴대폰 번호로 들어오기

답하러 오신 게 아니면 다른 일로 왔어요

D · 초대 링크로 온 집토끼 — returnTo=/join/{token}
번호가 명부의 열쇠임을 말한다 · 딴 데로 새는 길은 내밀지 않는다

주일 아침09:12

ubell

양림교회의 초대

명부와 이어드릴게요

명부에 있는 그 번호로 문자를 받으면 양림교회와 자동으로 이어집니다.

다른 번호여도 괜찮아요 — 초대장이 있어서, 들어오면 바로 합류합니다.

비밀번호로 로그인

D의 절제초대 화면에만 이메일·구글이 없습니다 — 감추기가 아니라 정직입니다. 매직링크·구글은 다른 탭으로 돌아와 sessionStorage의 초대 토큰이 못 따라가므로, 그 길로 보내면 초대가 끊깁니다(LoginForm.tsx 주석에 이미 적힌 사실). 끊어질 길은 내밀지 않습니다. 비밀번호는 같은 탭이라 returnTo가 살아 있어 남겨 둡니다.
B의 전제B의 "확인이 끝나면 문패 걸기로 돌아갑니다"는 오늘 코드에서 거짓입니다 — 휴대폰 OTP 경로(verifyCode)는 next=를 읽지 않고 returnTo(초대 전용)만 봅니다. 사장님은 지금 set-password → /my → /onboarding으로 떠내려갑니다. 이 문장을 화면에 걸려면 verifyCode가 nextParam() ?? readReturnTo()를 보게 하는 한 줄 수리가 선행돼야 합니다. 수리 전에는 이 한 줄을 화면에서 빼야 합니다 — 화면이 약속한 것을 제품이 안 지키는 그 실패를 여기서 반복하지 않기 위해서입니다.

5부

문장표 — 화면의 문장마다, 오늘 DB·코드에서 참인가

화면문장말하는 사건오늘 참인가
정문 (QuestionCard)"들어가면 이름 없이 한 줄로 답할 수 있어요."plaza_posts_list가 글쓴이를 '익명 {별칭}'으로만 공개 (000089)O
A 기본"휴대폰 번호가 있으면 문자 한 통으로 들어와요."signInWithOtp(phone) → verifyOtp → link_member_by_phoneO
A 기본"번호 없이 들어오기 — 이메일 · Google"signInWithOtp(email 매직링크) · signInWithOAuth(google)로 계정 성립O
B 가게"골목에는 번호가 확인된 가게만 보여요."create_market: profiles.phone 없으면 status=DRAFT (000158) · 골목·정문은 ACTIVE/ACTIVE_LIMITED만 노출O
B 가게"문패는 번호가 확인될 때까지 골목에 서지 않아요." (이메일·구글 경고)이메일·구글 계정에는 phone이 없어 DRAFT 잠금 · 뒤에 번호로 들어오면 market_publish_if_verified(000207)가 스스로 푼다O
B 가게 — 진입 감지(명패) "가게 문패 걸기"/shop/open·/shop/sell·/shop/mine이 next=를 붙여 보낸다O
B 가게 — 복귀 약속"확인이 끝나면 문패 걸기로 돌아갑니다."verifyCode가 next를 읽어 되돌려 보낸다X — verifyCode는 returnTo만 읽음(LoginForm.tsx:192). nextParam ?? returnTo 한 줄 수리 필요. 수리 전엔 문장 게시 금지
C 광장"이름은 광장에 걸리지 않아요."_plaza_allows_anon=true · 피드·상세·댓글 전부 익명 별칭 (000089)O
C 광장"휴대폰 번호는 필요하지 않습니다."create_plaza_post는 auth.uid()만 요구 — 이메일·구글 계정으로 충분O
C 광장 — 진입 감지(명패) "오늘의 물음에 답하러"미스바가 next=/mizpah/…를 붙여 보낸다X — mizpah/[plazaSlug]/page.tsx:14 등 5곳이 next 없이 redirect('/auth/login'). next 붙이는 한 줄 수리 필요
D 초대"명부에 있는 그 번호로 문자를 받으면 교회와 자동으로 이어집니다."verifyOtp 직후 link_member_by_phone이 명부·소속·관리자 자리까지 자동 연결O
D 초대"다른 번호여도 괜찮아요 — 초대장이 있어서, 들어오면 바로 합류합니다."join_church_by_invite(p_token)는 번호 일치와 무관하게 합류시킨다 (JoinInvite.join)O
D 초대 — 복귀(동작) 로그인 뒤 /join/{token}으로 돌아간다JoinInvite.begin이 심은 ubell:returnTo를 verifyCode·handlePassword가 읽는다O — 단 매직링크·구글은 다른 탭이라 끊김 → D에서 그 길을 내밀지 않는 이유
계약 자가검사새 게이트 없음(명패는 화면이 아니라 한 줄) · 인증 메커니즘 불변(순서만 재배치) · 가게 주인에게 번호가 필요한 이유를 사실로 고지 · 탭게이트 없음·밝은 세계·ink3 글자 없음·danger는 표식만·금색 글자는 gold-ink·본문 15px↑·입력 18px↑·글자 애니메이션 없음·한글 자간 없음 · 번호 표기 010-1234-5678 대시 포함 · 한 문장은 한 줄(구현 시 JSX 공백 함정 주의) · 거짓 활기 없음 — 5부 X 두 건은 화면에 걸기 전에 코드가 먼저 참이 되어야 합니다.