Lobsters

Squalk: an old-school forum engine built on Nostr (NIP-29 groups, NIP-7D threads)

Squalk: Nostr로 만든 복고풍 포럼 엔진 — NIP-29 그룹과 NIP-7D 스레드

Squalk는 Nostr의 NIP-29 그룹과 NIP-7D 스레드를 사용하는 포럼 엔진입니다. 단일 포럼부터 다중 포럼까지 지원하고, 릴레이·Blossom 서버·환경 변수만으로 정적 사이트나 SSR 서비스로 배포합니다.

AI 요약

Squalk는 Nostr 위에 구축한 오픈소스 포럼 엔진입니다. 단순한 커뮤니티는 simple 모드로 하나의 포럼만 운영하고, 여러 방을 관리하려면 full 모드를 선택합니다. 각 포럼 오른쪽 사이드바에는 채팅 영역이 붙어 있어 구성원과 빠르게 대화할 수 있습니다. 그룹과 스레드에는 각각 NIP-29와 NIP-7D를 사용합니다.

Nostr 릴레이와 파일 저장소

포럼 그룹을 호스팅할 개인 릴레이가 필요합니다. 릴레이는 NIP-29를 지원해야 합니다. 미디어 업로드에는 Blossom 서버를 사용합니다. 두 요소를 함께 제공하는 Pyramid가 권장 배포 구성으로 제시됩니다. Squalk는 PUBLIC_RELAY_URL로 그룹이 있는 WebSocket 릴레이를 지정하고, PUBLIC_BLOSSOM_URL을 설정했을 때 업로드를 활성화합니다.

설정은 전부 환경 변수로 처리합니다. 브라우저에서 읽는 값이므로 변수 이름은 모두 PUBLIC_으로 시작합니다. .env.example.env으로 복사한 뒤 값을 채우고, 개발 환경에서는 npm run dev, 빌드에서는 npm run build를 실행합니다. PUBLIC_MODE는 기본값이 simple이며, 단일 포럼의 그룹 ID는 PUBLIC_GROUP_ID에 지정합니다. 실행 중에도 관리자가 simple에서 full로 전환할 수 있습니다. 검색창은 PUBLIC_SEARCH=yes로 켜지만 NIP-50 검색을 지원하는 릴레이가 필요합니다. 라벨 목록, 초대 코드 입력창, 강조 색상도 환경 변수로 정합니다.

정적 배포와 SSR

기본 배포 방식은 정적 사이트입니다. PUBLIC_SSR=no 상태에서 npm run build를 실행하면 build/에 단일 페이지 번들이 생성됩니다. 웹 서버는 알 수 없는 경로를 index.html로 연결해야 하며, 데이터는 브라우저가 릴레이에서 가져옵니다.

PUBLIC_SSR=yes로 전환하면 Node 애플리케이션을 빌드합니다. 서버는 공개 릴레이를 읽어 스레드, 방, 리소스, 연락처 페이지를 HTML로 렌더링합니다. 설명과 Open Graph 태그, JSON-LD, robots.txt, sitemap.xml, 실제 404 응답도 함께 제공합니다. 페이지를 처음 보여준 뒤에는 브라우저가 정적 배포와 같은 방식으로 이어받습니다. 서버는 익명으로 릴레이를 조회하므로 공개 콘텐츠만 렌더링하며, 비공개 방은 클라이언트가 실행된 뒤 구성원에게 표시됩니다.

SSR에서는 클라이언트 내비게이션마다 서버가 페이지를 미리 가져와 캐시하도록 설정할 수 있습니다. 기본 캐시 신선도는 300초이고, 이후 최대 21,600초 동안 오래된 페이지를 즉시 반환하면서 백그라운드에서 갱신합니다. Cloudflare의 s-maxagestale-while-revalidate에도 같은 값을 적용합니다. SSR 배포에는 Node 22 이상, 리버스 프록시, ORIGIN을 설정한 systemd 유닛이 필요합니다. just deploy-ssr 명령은 Node 빌드와 패키지 파일을 서버로 보내고 의존성을 설치한 뒤 서비스를 재시작합니다.

Nostr 이벤트를 이용한 사이트 콘텐츠

사이드바 링크와 홈페이지, 연락처 페이지는 같은 릴레이에 게시된 NIP-23 장문 이벤트(kind 30023)에서 채웁니다. Squalk는 그룹의 NIP-29 39001 관리자 이벤트에 등록된 공개 키가 작성한 이벤트만 노출합니다. 릴레이 조회 자체는 열려 있지만 관리자 공개 키 목록을 신뢰 경계로 삼습니다.

리소스는 kind: 30023 이벤트에 t: squalk-resource 태그와 d 태그를 붙여 등록합니다. d 값은 /resource/<slug> 경로가 됩니다. title은 사이드바 라벨이고 position은 정렬 순서입니다. 위치를 지정한 항목을 먼저 오름차순으로 배치하며, 나머지는 제목 기준으로 정렬합니다. 같은 d 값을 다시 게시하면 최신 이벤트가 기존 리소스를 갱신합니다.

사용자 정의 마크다운을 넣는 partial은 homecontacts 두 슬롯만 지원합니다. t: squalk-partial과 해당 d 값을 가진 관리자 이벤트를 게시하면 됩니다. 슬롯마다 가장 최신 관리자 이벤트를 사용하며, 홈페이지 partial은 방 목록과 토론 피드 위에 표시됩니다. 첫 줄에 이미지 URL만 넣으면 배너 이미지로 렌더링합니다. 저장소 루트의 about.md, guidelines.md, homepage.md, contacts.md 파일을 시작 템플릿으로 활용할 수 있습니다.

Lobsters 반응

  • @tonyarkles — 저는 완전히 다른 무언가를 작업하고 있지만 같은 이론을 따릅니다. HTTPS는 읽기 전용 보기를 제공하고, Nostr와 키는 신원 확인, 인증, 게시에 사용합니다. Nostr를 통해 모든 내용을 볼 수도 있습니다. 개발자 친화적이고 주류에서 벗어난 모바일 앱으로 어떤 것이 있는지 추천해 주실 수 있나요? 덧붙이면, 여기서 Squalk도 살펴봤고 아이디어가 마음에 듭니다. 개방형 클라이언트와 색다른 신원·인증 방식으로 이 생태계가 어떻게 발전할지 정말 궁금합니다.
  • @conartist6 — 이름이 정말 멋집니다.

원문: GitHub / 번역·요약: Trawling