규로롱
07

규로롱 홈페이지

만든 것과 만든 과정을 한 줄로 엮어 두는 곳. 지금 보고 있는 이 페이지다

concept

  • 같은 오리진same-origin

    서비스를 서브도메인이 아니라 같은 도메인의 경로에 붙였다. 브라우저는 오리진이 같으면 localStorage 를 통째로 공유하고 로그인 세션이 거기 사니까, 한 번 로그인하면 나머지 서비스가 전부 알아본다 — 토큰을 주고받는 코드가 한 줄도 없다. 공짜는 아니다. 주소가 한 칸 들어가고, 그 뒤의 슬래시 하나가 앱의 자산 경로를 바꾼다.

만든 서비스와 만드는 과정을 한자리에 모아 둔 곳이다. 서비스마다 실행 링크 · 소스코드 · 만든 과정 영상이 같이 걸린다. 이 셋이 붙어 있지 않으면 그냥 링크트리라서, 사이트의 나머지는 전부 이 연결을 위한 장치다.

지금 보고 있는 이 페이지도 그 목록 안의 한 줄이다.

서브도메인 대신 경로

서비스를 app.kyulolong.com 이 아니라 kyulolong.com/navigator 에 붙였다. 이유는 하나다 — 로그인을 한 번만 하려고.

브라우저는 오리진(스킴 + 호스트 + 포트)이 같으면 localStorage 를 통째로 공유한다. 로그인 세션이 거기 사니까, 어느 서비스에서 로그인하든 나머지가 전부 알아본다. 서비스끼리 토큰을 주고받는 코드가 한 줄도 없다. 서브도메인이었으면 앱이 늘어날 때마다 쿠키 도메인을 맞춰줬어야 했다.

조건은 딱 하나, 모든 앱이 세션을 같은 키로 저장하는 것이다.

createClient(url, anon, { auth: { storageKey: 'kyulolong.auth' } })

기본값은 프로젝트마다 다른 키라서, 이걸 안 맞추면 같은 오리진인데도 서비스마다 따로 로그인하게 된다. 처음엔 이걸 몰라서 두 번 로그인했다.

공짜는 아니었다 — 슬래시 하나

/navigator 로 들어가면 그 앱 HTML 안의 <script src="app.js">/app.js 로 풀린다. 홈페이지 자리다. 404. /navigator/ 로 들어가면 멀쩡하다. 문제는 자산이 아니라 슬래시 하나다.

그런데 고칠 수 있는 자리가 생각보다 좁다. 엣지에서 프리픽스를 떼고 컨테이너로 보내기 때문에, 정작 앱 안에서는 자기가 /navigator 에 얹혀 있다는 걸 모른다. 홈페이지는 그 요청을 아예 보지도 못한다. 그래서 리다이렉트는 라우팅이 갈리는 자리, 프리픽스가 아직 살아 있는 지점에 걸어야 한다. 여기서 하루를 썼다.

그리고 이 사이트가 내보내는 링크에는 끝 슬래시가 자동으로 붙는다. 엣지에 리다이렉트가 있어도, 처음부터 옳은 주소를 주면 사용자가 308 을 한 번 덜 탄다.

대문은 DB 가 죽어도 뜬다

카드 순서를 좋아요로 정하려면 렌더할 때 숫자를 알아야 한다. 그렇다고 방문자마다 DB 를 부르면, DB 가 흔들리는 날 대문이 같이 죽는다. 그래서 하루에 한 번만 다시 굽는다. 방문자에게는 미리 구워둔 HTML 이 나가고, 굽다 실패하면 직전에 구운 게 계속 나간다. 좋아요 숫자 자체는 카드가 따로 받아온다.

선은 여기서 그어뒀다 — DB 를 부르는 페이지는 로그인 창구 하나뿐이다. 목록도 소개도 영상도 전부 파일에서 온다. 셀프호스팅한 Supabase 는 컨테이너가 열 개짜리라 안 뜨는 날이 있는데, 그날 대문이 같이 죽으면 안 된다.

서비스 하나 = 파일 하나

매주 하나씩 늘어난다. 1년이면 60개다. 그래서 서비스를 추가할 때 코드를 고쳐야 한다면 설계가 틀린 것으로 정해뒀다. MDX 한 장을 넣으면 목록·상세·사이트맵·공유 카드·구조화 데이터가 알아서 따라온다.

서비스와 영상은 서로를 가리키는데, 한쪽만 걸린 참조는 빌드가 실패한다. 60개가 되면 손으로는 못 잡는다. 카드에 붙는 #7 같은 번호도 파일에 적지 않고 발행일 순으로 매긴다 — 손으로 적는 순간 언젠가 어긋난다.

이렇게 시켰습니다

규로롱 홈페이지을 지금 다시 만든다면 AI에게 이렇게 넘기겠습니다. 그대로 복사해서 붙여넣고, 마음에 안 드는 부분만 바꾸세요.

내가 만든 서비스들을 모아 두는 개인 사이트를 만들어줘.
링크만 거는 게 아니라 서비스마다 실행 링크·소스코드·만든 과정 영상이
한 자리에 같이 붙어야 해. 그 연결이 이 사이트의 전부야.

가장 중요한 제약부터 말할게:
- 서비스가 매주 한두 개씩 늘어난다. 1년이면 60개야.
- 서비스 추가는 콘텐츠 파일 하나 추가로 끝나야 해. 코드를 고쳐야 하면 잘못 만든 거야.
- 목록에 태그 필터랑 정렬을 처음부터 넣어줘. 6개일 땐 필요 없어 보여도 30개면
  필수고, 그때 붙이면 데이터 구조부터 다시 만지게 된다.
- 썸네일이 없어도 카드가 안 깨지게 해줘. 없으면 브랜드 색 블록에 이름만 얹어서.
  매주 이미지를 손으로 만들어야 하면 그 부담 때문에 등록을 미루게 돼.

데이터는 DB 말고 MDX + frontmatter 로:
- content/services/<슬러그>.mdx, content/videos/<슬러그>.mdx
- 서비스는 영상을, 영상은 서비스를 서로 가리킨다. 한쪽만 걸린 참조는 빌드를 실패시켜줘.
- 작업 번호(#7 같은 것)는 파일에 적지 말고 발행일 오름차순으로 자동으로 매겨줘.
  손으로 적으면 언젠가 어긋난다.

URL 구조가 조금 특이한데 이건 꼭 지켜줘:
- 서비스 앱들은 서브도메인이 아니라 같은 도메인의 경로에 따로 배포된다 (도메인/navigator).
  같은 오리진이라 로그인 세션이 그냥 공유되기 때문이야.
- 그래서 이 사이트는 루트에 catch-all 이나 [slug] 동적 라우트를 만들면 안 돼.
  서비스 경로랑 충돌한다. 홈페이지가 쓰는 루트 경로는 목록으로 고정해줘.
- 경로에 얹힌 앱으로 나가는 링크는 끝 슬래시를 붙여서 내보내줘 (/navigator/).
  안 붙이면 그 앱 HTML 안의 상대경로 자산이 이 사이트 루트로 풀려서 404 난다.

페이지는 랜딩 / 서비스 목록 / 서비스 상세 / 영상 아카이브 / 영상 상세 / 소개.
로그인 없이 전부 열려야 해. 로그인은 문이 아니라 덤이야.

DB(Supabase)는 로그인 페이지 한 곳에서만 불러줘. 목록이나 랜딩을 서버에서
렌더할 때 부르면 DB 가 흔들리는 날 대문이 같이 죽는다.
좋아요만 예외인데 랜딩 카드 순서에 쓰니까, 방문자마다 부르지 말고 하루 한 번만
다시 굽는 방식으로 해줘. DB 를 못 읽으면 그냥 기본 정렬로 조용히 떨어지게.

Next.js App Router + TypeScript + Tailwind 로, 도커 이미지로 빌드되게 해줘.

여기 적힌 시간은 쓸 만한 게 처음 돌아가기까지입니다. 그 뒤에 디테일을 잡는 데 보통 하루 이틀이 더 들고, 지금도 필요할 때 업데이트 하고 있습니다.

처음이라면 — 뭘 깔고 어디에 붙여넣나

저는 Claude Code를 씁니다. 하지만 위 프롬프트는 특정 도구용이 아니라서 아무 데나 붙여넣어도 됩니다. 셋 중 편한 걸로 시작하세요.

  1. 1. 설치 없이 — 브라우저 챗봇
    쓰던 챗봇에 붙여넣고 “하나의 HTML 파일로 만들어줘”를 덧붙이세요. 나온 코드를 저장해 더블클릭하면 그 자리에서 돌아갑니다. 5분, 무료.
  2. 2. 제대로 — 터미널에서 CLI
    파일을 여러 개 만들고 스스로 고쳐가며 돌려보는 건 이쪽만 됩니다. 여기 있는 것들은 전부 이 방식으로 만들었습니다. 30분.
  3. 3. 남한테 맡기고 — 웹 빌더
    v0, Bolt, Lovable 같은 데에 붙여넣으면 화면까지 알아서 띄워줍니다. 빠른 대신 나중에 손대기가 답답해집니다.

어느 쪽이든 한 번에 완성될 거라고 기대하지 마세요. 저는 대충 돌아가는 걸 먼저 받고, 거슬리는 걸 하나씩 말해서 고칩니다. 에러가 뜨면 읽으려 하지 말고 통째로 복사해서 그대로 붙여넣으면 됩니다. 저도 1년 동안 그렇게만 했습니다.

터미널을 한 번도 안 열어보셨다면 설치부터 순서대로 적어둔 곳이 따로 있습니다. 맥·윈도우 명령어와 막혔을 때 할 일까지 있습니다.