SiliconBeest 프로젝트의 종합적인 기술 문서입니다. 최종 업데이트: 2026-03-25
참고: 이 문서는 이전 분리 아키텍처(
siliconbeest-worker/+siliconbeest-vue/)를 기준으로 작성되었습니다. 현재는siliconbeest/단일 디렉토리로 통합되었습니다. 마이그레이션 방법은 UPGRADE.md를 참조하세요. API 서버는siliconbeest/server/에, Vue 프론트엔드는siliconbeest/src/에 있습니다.
- 프로젝트 개요
- 아키텍처
- 프로젝트 구조
- 데이터베이스 스키마
- ActivityPub 구현
- Mastodon API 호환성
- Misskey 호환성
- 큐 시스템
- 프론트엔드 (Vue 3)
- 관리자 기능
- 보안
- 스크립트 및 배포
- 테스트
- 알려진 제한사항 및 향후 계획
- 설정 레퍼런스
SiliconBeest는 Cloudflare 개발자 플랫폼(Workers, D1, R2, KV, Queues, Durable Objects)을 기반으로 구축된 완전 서버리스 페디버스 플랫폼입니다. Mastodon REST API와 ActivityPub 서버 간 프로토콜을 구현하여, Mastodon, Misskey, Pleroma, Akkoma, Firefish, GoToSocial 등 페디버스의 다른 서버들과 연합할 수 있습니다.
- GitHub 저장소: https://github.com/SJang1/siliconbeest
- 라이선스: GNU Affero General Public License v3.0 (AGPL-3.0)
SiliconBeest는 Cloudflare의 공식 서버리스 페디버스 서버였던 Cloudflare Wildebeest에서 영감을 받았습니다. Wildebeest는 현재 Cloudflare에 의해 중단되었습니다. SiliconBeest는 이 개념을 더욱 발전시켜 완전히 새로 작성했으며 다음 기능을 제공합니다:
- 완전한 Mastodon API v1/v2 호환성 (100개 이상의 엔드포인트)
- 최신 HTTP 서명 표준을 포함한 포괄적인 연합
- 안정성을 위한 큐 기반 비동기 처리
- 국제화를 지원하는 커스텀 Vue 3 프론트엔드
- 인스턴스 관리를 위한 관리자 대시보드
- 680개 이상의 테스트를 포함한 테스트 스위트
| 목표 | 접근 방식 |
|---|---|
| 서버 인프라 불필요 | Cloudflare 엣지 네트워크에서 완전히 실행 |
| 저비용 | Cloudflare Workers Enabled 계정 한도 내에서 운영 설계 |
| 완전한 호환성 | 기존 Mastodon 클라이언트와 호환 (Tusky, Elk, Ice Cubes, Ivory, Mona) |
| 연합 우선 | ActivityPub, WebFinger, NodeInfo, HTTP Signatures, LD Signatures, Object Integrity Proofs 구현 |
| 보안 | OAuth 2.0 + PKCE, TOTP 2FA, bcrypt 비밀번호 해싱, 속도 제한 |
| 국제화 | 지연 로딩을 지원하는 12개 언어 팩 |
SiliconBeest는 공유 데이터 저장소와 큐를 통해 협력하는 3개의 독립적인 Cloudflare Worker로 구성됩니다:
클라이언트 (Mastodon 앱, 웹 브라우저)
|
v
+---------------------------+
| Cloudflare CDN / 엣지 |
+---------------------------+
|
+----------------+----------------+
| |
v v
+------------------------+ +------------------------+
| siliconbeest-worker | | siliconbeest-vue |
| (Hono API 서버) | | (Vue 3 SPA 프론트엔드)|
| | | |
| - Mastodon API v1/v2 | | - Tailwind CSS 4 |
| - OAuth 2.0 + 2FA | | - Headless UI |
| - ActivityPub S2S | | - Pinia 스토어 |
| - Admin API | | - vue-i18n |
| - WebSocket 스트리밍 | | - Sentry (선택사항) |
+------------------------+ +------------------------+
| | |
v v v
+-----+ +----+ +--------+ +----------------------------+
| D1 | | R2 | | KV | | siliconbeest-queue-consumer|
| SQL | |블롭 | |캐시/ | | |
| DB | |저장소| |세션 | | - 연합 배달 |
+-----+ +----+ +--------+ | - 타임라인 스트리밍 |
| - 알림 |
+------------------+ | - 미디어 처리 |
| Durable Objects | | - Web Push 전송 |
| (StreamingDO) | +----------------------------+
| WebSocket 라이브 | | |
+------------------+ +------+ +------+
| 큐 | | 큐 |
| 연합 | | 내부 |
+------+ +------+
모든 HTTP 요청을 처리하는 주요 Worker입니다. Hono 웹 프레임워크로 구축되었습니다.
담당 기능:
- Mastodon REST API v1/v2 (계정, 게시물, 타임라인, 알림 등)
- OAuth 2.0 인증 서버 (인증 코드 + PKCE + client_credentials)
- ActivityPub 서버 간 엔드포인트 (actor, inbox, outbox, followers, following, featured)
- Well-known 디스커버리 (WebFinger, NodeInfo, host-meta)
- Durable Objects를 통한 WebSocket 스트리밍
- R2에서의 미디어 제공
- 관리자 API
주요 바인딩:
DB(D1) -- 주 데이터베이스MEDIA_BUCKET(R2) -- 미디어 저장소CACHE(KV) -- 캐싱, 속도 제한, 활동 중복 제거, 서명 선호도 캐싱SESSIONS(KV) -- OAuth 세션 관리QUEUE_FEDERATION(Queue) -- 연합 작업 큐잉QUEUE_INTERNAL(Queue) -- 내부 작업 큐잉STREAMING_DO(Durable Object) -- WebSocket 스트리밍
설정:
placement.mode: "smart"-- Cloudflare Smart Placement가 D1 데이터베이스 근처에 Worker를 최적 배치- 커스텀 도메인의 zone_name 기반 라우팅으로 경로 설정
두 큐의 메시지를 소비하고 비동기적으로 처리하는 전용 Worker입니다.
담당 기능:
- 원격 인박스로의 연합 활동 배달 (HTTP 서명 포함)
- 모든 팔로워 인박스로의 활동 팬아웃
- 권한이 있는 팔로워 및 공개 타임라인 실시간 스트리밍
- 알림 생성 및 Web Push 전송
- 원격 계정 및 게시물 가져오기
- 미디어 썸네일 처리
- 미리보기 카드 (OpenGraph) 가져오기
- 원본 서명 보존한 활동 전달
- CSV 가져오기 처리 (팔로우, 차단, 뮤트)
주요 바인딩:
DB(D1),MEDIA_BUCKET(R2),CACHE(KV) -- API Worker와 동일한 리소스QUEUE_FEDERATION+QUEUE_INTERNAL-- 소비자와 생산자 모두 (재큐잉 용)INTERNAL_CONNECTION_MAIN(서비스 바인딩) -- Durable Object 접근을 위해 메인 Worker의 비공개InternalRPC 엔트리포인트 호출
큐 설정:
- 연합 큐: 최대 5회 재시도, Dead Letter Queue (
siliconbeest-federation-dlq) - 내부 큐: 최대 3회 재시도, DLQ 없음
- DLQ: 컨슈머가 직접 소비 (최대 2회 재시도) — 한 번 더 재처리 후, 계속 실패하는 메시지는
federation_dlq_parkedD1 테이블에 보관하고 관리자 API(/api/v1/admin/federation/dlq)로 조회/재전송/폐기
Cloudflare Workers Sites로 제공되는 정적 Vue 3 Single Page Application입니다.
설정:
assets.directory: "./dist/client"-- 빌드된 Vue 앱 제공assets.not_found_handling: "single-page-application"-- 클라이언트 사이드 라우팅을 위해 알 수 없는 경로에index.html제공custom_domain: true라우팅으로 catch-all 패턴 사용server/index.ts-- Workers Sites용 최소 서버 진입점
| 서비스 | 용도 | 선택 이유 |
|---|---|---|
| Workers | HTTP 요청 처리, API 서버 | 글로벌 엣지 배포, 0ms 콜드 스타트, 30초 CPU 시간 |
| D1 | SQLite 데이터베이스 | 설정 불필요한 서버리스 SQL, 자동 복제 |
| R2 | 객체 저장소 (미디어, 이모지) | S3 호환, 이그레스 비용 없음, Workers와 통합 |
| KV | 키-값 캐시 | 밀리초 이하 읽기, 글로벌 분배, TTL 지원 |
| Queues | 비동기 작업 처리 | 보장된 전달, DLQ 지원, 배칭 |
| Durable Objects | WebSocket 스트리밍 | 영속적 연결, 하이버네이션 지원, 사용자별 상태 |
API Worker는 zone_name 기반 Workers Routes를 사용하여 특정 경로 패턴을 가로챕니다:
| 라우트 패턴 | Worker | 용도 |
|---|---|---|
domain/api/* |
API Worker | Mastodon REST API |
domain/oauth/* |
API Worker | OAuth 2.0 흐름 |
domain/.well-known/* |
API Worker | WebFinger, NodeInfo, host-meta |
domain/users/* |
API Worker | ActivityPub actor 엔드포인트 |
domain/inbox |
API Worker | ActivityPub 공유 인박스 |
domain/nodeinfo/* |
API Worker | NodeInfo 2.0/2.1 |
domain/media/* |
API Worker | R2 미디어 제공 |
domain/actor |
API Worker | 인스턴스 actor |
domain/authorize_interaction* |
API Worker | 원격 팔로우 |
domain/healthz |
API Worker | 헬스 체크 |
domain/thumbnail.png |
API Worker | 인스턴스 썸네일 |
domain/favicon.ico |
API Worker | 파비콘 |
domain (catch-all) |
Vue 프론트엔드 | SPA catch-all |
API Worker와 큐 소비자 모두 placement.mode: "smart"를 사용합니다. Cloudflare가 자동으로 D1 데이터베이스 근처에 Worker를 배치하여 데이터베이스 작업의 지연 시간을 최소화합니다. 각 API 요청이 일반적으로 여러 D1 쿼리를 포함하므로 이는 매우 중요합니다.
SiliconBeest는 Cloudflare Workers Enabled 계정 한도 내에서 운영되도록 설계되었습니다:
| 리소스 | 100명 사용자/월 | 1000명 사용자/월 |
|---|---|---|
| Workers 요청 | ~150만 (포함) | ~1500만 ($1.50) |
| D1 읽기 | ~30만 (포함) | ~300만 (포함) |
| D1 쓰기 | ~3만 (포함) | ~30만 (포함) |
| R2 저장소 | ~1 GB ($0.02) | ~10 GB ($0.15) |
| KV 작업 | ~50만 (포함) | ~500만 (포함) |
| DO 요청 | ~30만 (포함) | ~300만 ($0.30) |
| Queues | ~10만 (포함) | ~100만 (포함) |
| 합계 | ~$5/월 | ~$7/월 |
siliconbeest/
.gitignore
FEDERATION.md # FEP-67ff 연합 기능 문서
README.md # 프로젝트 README 및 빠른 시작 가이드
wrangler.jsonc # 루트 wrangler 설정 (레거시)
scripts/ # 설치, 배포 및 유지보수 스크립트
siliconbeest-worker/ # API 서버 (Hono on Workers)
siliconbeest-queue-consumer/ # 비동기 작업 처리기 (Queues 소비자)
siliconbeest-vue/ # 웹 프론트엔드 (Vue 3 SPA)
siliconbeest-worker/
wrangler.jsonc # Worker 설정 및 바인딩
package.json # 의존성: hono, chanfana, zod, bcryptjs, ulid, worker-mailer
vitest.config.mts # @cloudflare/vitest-pool-workers 테스트 설정
src/
index.ts # Hono 앱 진입점, 모든 라우트 마운트
env.ts # Env 바인딩 및 앱 변수 TypeScript 인터페이스
types/
activitypub.ts # ActivityPub/ActivityStreams 타입 정의
mastodon.ts # Mastodon REST API 엔티티 타입
queue.ts # 큐 메시지 판별 합집합 (15가지 타입)
db.ts # 데이터베이스 행 타입
endpoints/
activitypub/
actor.ts # GET /users/:username (AP actor 문서)
inbox.ts # POST /users/:username/inbox (개인 인박스)
sharedInbox.ts # POST /inbox (공유 인박스)
outbox.ts # GET /users/:username/outbox (페이지네이션)
followers.ts # GET /users/:username/followers (페이지네이션)
following.ts # GET /users/:username/following (페이지네이션)
featured.ts # GET /users/:username/featured (고정 게시물)
featuredTags.ts # GET /users/:username/featured_tags
instanceActor.ts # GET /actor (인스턴스 actor)
api/v1/
accounts/ # 계정 관련 엔드포인트 (생성, 조회, 수정, 팔로우 등)
statuses/ # 게시물 관련 엔드포인트 (생성, 조회, 삭제, 좋아요 등)
timelines/ # 타임라인 (홈, 공개, 해시태그, 리스트)
notifications/ # 알림 (목록, 삭제, 읽음)
conversations/ # 대화 (DM)
polls/ # 투표
lists/ # 리스트 관리
push/ # Web Push 구독
filters/ # 콘텐츠 필터
admin/ # 관리자 API
accounts/ # 계정 관리 (승인, 거부, 정지, 역할)
reports/ # 신고 관리
domainBlocks.ts # 도메인 차단
domainAllows.ts # 도메인 허용
ipBlocks.ts # IP 차단
emailDomainBlocks.ts # 이메일 도메인 차단
rules.ts # 인스턴스 규칙
announcements.ts # 공지사항
customEmojis.ts # 커스텀 이모지
settings.ts # 인스턴스 설정
relays.ts # 릴레이 관리
federation.ts # 연합 모니터링
email.ts # SMTP 이메일 설정
measures.ts # 측정/분석
trends/ # 트렌딩 태그/게시물
instance/ # 인스턴스 정보
apps.ts # 클라이언트 앱 등록
(기타 엔드포인트...)
api/v2/
instance.ts # 향상된 인스턴스 정보
search.ts # 검색 (계정, 게시물, 해시태그)
media.ts # 비동기 미디어 업로드
oauth/ # OAuth 2.0 흐름
wellknown/ # WebFinger, NodeInfo, host-meta
media.ts # R2 미디어 제공
federation/
actorSerializer.ts # 로컬 계정을 AP Actor 문서로 직렬화
noteSerializer.ts # 게시물을 AP Note 객체로 직렬화
activityBuilder.ts # AP 활동 생성 (Create, Update, Delete 등)
deliveryManager.ts # 원격 인박스로의 활동 배달 관리
httpSignatures.ts # HTTP 서명 생성 + 검증 (draft-cavage + RFC 9421)
ldSignatures.ts # Linked Data 서명 생성 + 검증
integrityProofs.ts # Object Integrity Proofs (FEP-8b32, ed25519-jcs-2022)
activityForwarder.ts # 원본 서명 보존 활동 전달
resolveRemoteAccount.ts # 원격 AP actor를 로컬 계정 레코드로 해석
webfinger.ts # 원격 계정 조회용 WebFinger 클라이언트
inboxProcessors/ # 수신 활동 타입별 처리기 (13가지 이상)
middleware/
auth.ts # Bearer 토큰 인증 (KV 캐시 + D1 폴백)
contentNegotiation.ts # ActivityPub 콘텐츠 타입 감지
cors.ts # CORS 설정
errorHandler.ts # 전역 에러 핸들러
rateLimit.ts # KV 기반 슬라이딩 윈도우 속도 제한
requestId.ts # X-Request-ID 생성
repositories/ # 데이터 접근 계층 (account, status, follow 등)
services/ # 비즈니스 로직 계층
utils/ # 유틸리티 (contentParser, crypto, sanitize, ulid 등)
webpush/ # Web Push (dispatch, encrypt, vapid)
durableObjects/
streaming.ts # StreamingDO -- Hibernatable WebSocket Durable Object
migrations/ # D1 데이터베이스 마이그레이션 (0001~0016)
test/ # 49개 테스트 파일
siliconbeest-queue-consumer/
wrangler.jsonc # 소비자 + 생산자 바인딩이 있는 Worker 설정
package.json # 최소 의존성: typescript, wrangler
src/
index.ts # 메시지 디스패치가 있는 큐 배치 핸들러
env.ts # 환경 바인딩 인터페이스
handlers/
deliverActivity.ts # 원격 인박스에 단일 활동 배달
deliverActivityFanout.ts # 모든 팔로워 인박스에 활동 팬아웃
timelineFanout.ts # 팔로워 및 공개 피드에 게시물 스트리밍
createNotification.ts # 알림 생성 + Web Push 큐잉
processMedia.ts # 미디어 썸네일 처리
fetchRemoteAccount.ts # 원격 AP actor 가져오기 및 캐싱
fetchRemoteStatus.ts # 원격 AP 객체 가져오기 및 캐싱
sendWebPush.ts # Web Push 알림 암호화 및 전송
fetchPreviewCard.ts # URL 카드용 OpenGraph 메타데이터 가져오기
forwardActivity.ts # 원본 HTTP 헤더 보존 활동 전달
importItem.ts # CSV 가져오기 항목 처리 (팔로우/차단/뮤트)
integrityProofs.ts # 아웃바운드 활동용 Object Integrity Proofs 생성
ldSignatures.ts # 릴레이 활동용 LD 서명 생성
shared/
types/queue.ts # 공유 큐 메시지 타입 정의
webpush.ts # 공유 Web Push 유틸리티
siliconbeest-vue/
wrangler.jsonc # Workers Sites 설정
package.json # Vue 3, Pinia, vue-i18n, Tailwind CSS 4 등
src/
main.ts # Vue 앱 부트스트랩
App.vue # 루트 컴포넌트
api/
client.ts # 인증 인터셉터가 있는 API 클라이언트
streaming.ts # 자동 재연결 WebSocket 스트리밍 클라이언트
mastodon/ # 도메인별 API 메서드
components/
layout/ # 앱 셸, 사이드바, 모바일 네비게이션, 관리자 레이아웃
status/ # 게시물 카드, 컨텐츠, 액션, 작성기, 미디어 갤러리
account/ # 계정 카드, 헤더, 팔로우 버튼
common/ # 아바타, 이모지 피커, 이미지 뷰어, 무한 스크롤 등
notification/ # 알림 항목
auth/ # 로그인, 가입, 2FA 폼
settings/ # 언어 선택기
timeline/ # 타임라인 피드
composables/
useEmojis.ts # 이모지 자동완성 컴포저블
stores/ # Pinia 스토어 (auth, accounts, statuses, timelines 등)
router/
index.ts # Vue Router 설정 (30개 이상 라우트)
guards.ts # 네비게이션 가드
views/ # 뷰 컴포넌트 (35개 이상)
i18n/
index.ts # 지연 로딩 i18n 설정
locales/ # 언어 파일 (en, ko + 10개 추가)
types/
mastodon.ts # 프론트엔드 Mastodon 엔티티 타입
test/ # 11개 테스트 파일
scripts/
config.sh # 공유 설정 (PROJECT_PREFIX, 리소스 이름, 색상)
config.env.example # 영구 설정 오버라이드 예시
setup.sh # 대화형 초기 설정
deploy.sh # 3개 Worker 모두 빌드 및 배포
update.sh # 풀, 테스트, 마이그레이션, 재배포 (프로덕션 업데이트)
configure-domain.sh # 커스텀 도메인 Workers Routes 설정
generate-vapid-keys.sh # VAPID 키 쌍 생성 (ECDSA P-256)
seed-admin.sh # 관리자 사용자 계정 생성
migrate.sh # D1 데이터베이스 마이그레이션 적용
backup.sh # D1 + R2 데이터 백업
delete-account.sh # AP 호환 계정 삭제
sync-config.sh # Cloudflare 리소스 ID를 wrangler.jsonc에 동기화
README.md # 스크립트 문서
SiliconBeest는 Cloudflare D1 (SQLite)을 주 데이터베이스로 사용합니다. 스키마는 16개의 마이그레이션 파일로 관리됩니다.
모든 기본 키는 ULID (Universally Unique Lexicographically Sortable Identifier)를 사용합니다:
- 26자의 Crockford Base32
- 시간 정렬 가능 (처음 48비트가 밀리초 타임스탬프)
- 조율 없이 전역적으로 고유
- SQLite TEXT 컬럼과 호환
이는 대부분의 쿼리에서 ORDER BY id가 ORDER BY created_at과 동일하며, ID를 페이지네이션 커서로 사용할 수 있음을 의미합니다.
모든 타임스탬프는 ISO 8601 형식의 TEXT로 저장됩니다 (예: 2026-03-25T12:00:00.000Z).
로컬 및 원격 actor 프로필을 나타내는 중심 엔티티입니다.
| 컬럼 | 타입 | 설명 |
|---|---|---|
id |
TEXT (PK, ULID) | 기본 키 |
username |
TEXT | 사용자명 (예: admin) |
domain |
TEXT | 로컬 계정은 NULL, 원격은 도메인 |
display_name |
TEXT | 표시 이름 |
note |
TEXT | 자기소개 (HTML) |
uri |
TEXT (UNIQUE) | ActivityPub actor URI |
url |
TEXT | 프로필 페이지 URL |
avatar_url |
TEXT | 아바타 이미지 URL |
header_url |
TEXT | 헤더 이미지 URL |
locked |
INTEGER | 수동 팔로우 승인 필요 |
bot |
INTEGER | 봇 계정 플래그 |
discoverable |
INTEGER | 디렉터리에서 발견 가능 |
statuses_count |
INTEGER | 캐시된 게시물 수 |
followers_count |
INTEGER | 캐시된 팔로워 수 |
following_count |
INTEGER | 캐시된 팔로잉 수 |
suspended_at |
TEXT | 정지 타임스탬프 |
silenced_at |
TEXT | 사일런스 타임스탬프 |
moved_to_account_id |
TEXT | 이전 대상 계정 |
inbox_url |
TEXT | AP 인박스 URL (마이그레이션 0007) |
shared_inbox_url |
TEXT | AP 공유 인박스 URL (마이그레이션 0007) |
fields |
TEXT | JSON 프로필 메타데이터 필드 (마이그레이션 0009) |
also_known_as |
TEXT | JSON 별칭 URI 배열 (마이그레이션 0016) |
moved_at |
TEXT | 이전 타임스탬프 (마이그레이션 0016) |
인덱스: idx_accounts_uri, idx_accounts_domain, idx_accounts_username_domain
로컬 인증 레코드. 로컬 사용자의 accounts와 1:1 관계입니다.
| 컬럼 | 타입 | 설명 |
|---|---|---|
id |
TEXT (PK, ULID) | 기본 키 |
account_id |
TEXT (UNIQUE, FK) | accounts(id) 참조 |
email |
TEXT (UNIQUE) | 이메일 주소 |
encrypted_password |
TEXT | bcrypt 해시 |
locale |
TEXT | 선호 언어 |
otp_secret |
TEXT | AES-GCM 암호화된 TOTP 비밀 |
otp_enabled |
INTEGER | 2FA 활성화 플래그 |
otp_backup_codes |
TEXT | JSON 해시된 백업 코드 배열 |
role |
TEXT | 역할: user/moderator/admin |
approved |
INTEGER | 로그인 승인됨 |
disabled |
INTEGER | 계정 비활성화 플래그 |
연합 서명용 RSA 및 Ed25519 키 쌍.
| 컬럼 | 타입 | 설명 |
|---|---|---|
id |
TEXT (PK, ULID) | 기본 키 |
account_id |
TEXT (UNIQUE, FK) | accounts(id) 참조 |
public_key |
TEXT | RSA-2048 공개 키 (PEM) |
private_key |
TEXT | RSA-2048 개인 키 (PEM) |
key_id |
TEXT | 키 ID URI (예: {actor_uri}#main-key) |
ed25519_public_key |
TEXT | Ed25519 공개 키 (마이그레이션 0012) |
ed25519_private_key |
TEXT | Ed25519 개인 키 (마이그레이션 0012) |
| 컬럼 | 타입 | 설명 |
|---|---|---|
id |
TEXT (PK, ULID) | 기본 키 |
uri |
TEXT (UNIQUE) | ActivityPub 객체 URI |
account_id |
TEXT (FK) | 작성자 계정 |
in_reply_to_id |
TEXT | 부모 게시물 ID |
reblog_of_id |
TEXT | 리블로그인 경우 원본 게시물 ID |
text |
TEXT | 소스 텍스트 (편집용) |
content |
TEXT | 렌더링된 HTML |
content_warning |
TEXT | 스포일러 텍스트 |
visibility |
TEXT | public/unlisted/private/direct |
sensitive |
INTEGER | 민감한 콘텐츠 플래그 |
language |
TEXT | 콘텐츠 언어 코드 |
conversation_id |
TEXT | 대화 스레드 ID |
poll_id |
TEXT | 연관된 투표 ID |
quote_id |
TEXT | 인용된 게시물 ID (마이그레이션 0013) |
인덱스: idx_statuses_account_id, idx_statuses_uri, idx_statuses_in_reply_to, idx_statuses_reblog_of, idx_statuses_account_created, idx_statuses_visibility_created, idx_statuses_local_created, idx_statuses_conversation, idx_statuses_quote
R2에 저장된 미디어 파일.
| 컬럼 | 타입 | 설명 |
|---|---|---|
id |
TEXT (PK, ULID) | 기본 키 |
status_id |
TEXT | 연관 게시물 (첨부 전에는 nullable) |
account_id |
TEXT (FK) | 소유자 계정 |
file_key |
TEXT | R2 객체 키 |
file_content_type |
TEXT | MIME 타입 |
file_size |
INTEGER | 파일 크기 (바이트) |
thumbnail_key |
TEXT | 썸네일 R2 키 |
remote_url |
TEXT | 원본 원격 URL |
description |
TEXT | 대체 텍스트 (alt text) |
blurhash |
TEXT | 플레이스홀더용 BlurHash |
width |
INTEGER | 이미지 너비 |
height |
INTEGER | 이미지 높이 |
type |
TEXT | image/video/gifv/audio |
created_at |
TEXT | 생성 타임스탬프 |
updated_at |
TEXT | 업데이트 타임스탬프 |
| 컬럼 | 타입 | 설명 |
|---|---|---|
id |
TEXT (PK, ULID) | 기본 키 |
status_id |
TEXT (UNIQUE, FK) | 연관 게시물 |
expires_at |
TEXT | 만료 타임스탬프 |
multiple |
INTEGER | 복수 선택 허용 |
votes_count |
INTEGER | 총 투표 수 |
voters_count |
INTEGER | 총 투표자 수 |
options |
TEXT | JSON 배열: [{title, votes_count}] |
created_at |
TEXT | 생성 타임스탬프 |
개별 투표로 UNIQUE(poll_id, account_id, choice) 제약 조건이 있습니다.
OpenGraph 메타데이터를 통한 URL 미리보기.
| 컬럼 | 타입 | 설명 |
|---|---|---|
id |
TEXT (PK, ULID) | 기본 키 |
url |
TEXT (UNIQUE) | 소스 URL |
title |
TEXT | 페이지 제목 |
description |
TEXT | 페이지 설명 |
type |
TEXT | link/photo/video/rich |
author_name |
TEXT | 저자 이름 |
author_url |
TEXT | 저자 URL |
provider_name |
TEXT | 제공자 이름 |
provider_url |
TEXT | 제공자 URL |
image_url |
TEXT | 미리보기 이미지 URL |
width |
INTEGER | 이미지 너비 |
height |
INTEGER | 이미지 높이 |
html |
TEXT | 임베드 HTML |
embed_url |
TEXT | 임베드 URL |
blurhash |
TEXT | 이미지 플레이스홀더 |
created_at |
TEXT | 타임스탬프 |
updated_at |
TEXT | 타임스탬프 |
status_preview_cards는 status_id + preview_card_id 조인 테이블입니다.
| 컬럼 | 타입 | 설명 |
|---|---|---|
id |
TEXT (PK, ULID) | 기본 키 |
user_id |
TEXT (FK) | 구독 사용자 |
access_token_id |
TEXT (FK) | 연관 OAuth 토큰 |
endpoint |
TEXT | Push 서비스 엔드포인트 |
key_p256dh |
TEXT | 클라이언트 공개 키 |
key_auth |
TEXT | 클라이언트 인증 비밀 |
alert_mention |
INTEGER | 멘션 알림 |
alert_follow |
INTEGER | 팔로우 알림 |
alert_favourite |
INTEGER | 좋아요 알림 |
alert_reblog |
INTEGER | 리블로그 알림 |
alert_poll |
INTEGER | 투표 결과 알림 |
alert_status |
INTEGER | 새 게시물 알림 |
alert_update |
INTEGER | 게시물 편집 알림 |
alert_follow_request |
INTEGER | 팔로우 요청 알림 |
alert_admin_sign_up |
INTEGER | 새 가입 알림 |
alert_admin_report |
INTEGER | 새 신고 알림 |
policy |
TEXT | all/followed/follower/none |
created_at |
TEXT | 타임스탬프 |
updated_at |
TEXT | 타임스탬프 |
settings 테이블에 초기 삽입되는 값:
| 키 | 기본값 | 설명 |
|---|---|---|
registration_mode |
open |
가입 모드 |
site_title |
SiliconBeest |
사이트 제목 |
site_description |
(비어있음) | 사이트 설명 |
site_contact_email |
(비어있음) | 연락처 이메일 |
site_contact_username |
(비어있음) | 연락처 사용자명 |
max_toot_chars |
500 |
최대 게시물 문자 수 |
max_media_attachments |
4 |
게시물당 최대 미디어 수 |
max_poll_options |
4 |
최대 투표 옵션 수 |
poll_max_characters_per_option |
50 |
옵션당 최대 문자 수 |
media_max_image_size |
16777216 (16 MB) |
최대 이미지 크기 |
media_max_video_size |
104857600 (100 MB) |
최대 비디오 크기 |
thumbnail_enabled |
1 |
썸네일 생성 활성화 |
trends_enabled |
1 |
트렌딩 기능 활성화 |
require_invite |
0 |
초대 필요 여부 |
min_password_length |
8 |
최소 비밀번호 길이 |
| 테이블 | 관계 | 설명 |
|---|---|---|
follows |
account -> target_account | 팔로우 관계 |
follow_requests |
account -> target_account | 대기 중인 팔로우 요청 |
favourites |
account -> status | 좋아요 |
blocks |
account -> target_account | 차단 |
mutes |
account -> target_account | 뮤트 |
bookmarks |
account -> status | 북마크 |
status_mutes |
account -> status | 게시물 알림 뮤트 (마이그레이션 0003) |
emoji_reactions |
account -> status + emoji | 이모지 반응 (마이그레이션 0004) |
타입: mention, follow, favourite, reblog, poll, follow_request, status, update, admin.sign_up, admin.report, emoji_reaction
게시물의 멘션 추출 및 저장.
tags: 해시태그 레코드status_tags: 게시물-태그 조인 테이블tag_follows: 해시태그 팔로우
oauth_applications: 클라이언트 앱 등록 (client_id, client_secret, scopes)oauth_access_tokens: 액세스 토큰 (bearer token, scopes, 만료)oauth_authorization_codes: 인증 코드 (PKCE 지원: code_challenge, code_challenge_method)
lists: 사용자 리스트 (title, replies_policy, exclusive)list_accounts: 리스트-계정 조인 테이블
instances: 알려진 원격 인스턴스 (도메인, 소프트웨어, 헬스 추적)domain_blocks: 도메인 차단 (severity: silence/suspend/noop)domain_allows: 도메인 허용 목록relays: 릴레이 구독 (마이그레이션 0002)
web_push_subscriptions: 사용자별 Web Push 구독 (endpoint, keys, alert 설정, policy)
reports: 신고 (reporter, target, status_ids, category, resolution)account_warnings: 모더레이터 조치 기록ip_blocks: IP 차단 (CIDR)email_domain_blocks: 이메일 도메인 차단
- 홈 타임라인은
statuses,follows, directmentions에서 요청 시 계산 markers: 타임라인 위치 마커user_preferences: 키-값 사용자 설정filters+filter_keywords+filter_statuses: 콘텐츠 필터링
preview_cards+status_preview_cards: URL 미리보기 카드 (마이그레이션 0008)settings: 인스턴스 키-값 설정 (registration_mode, site_title, max_toot_chars 등)custom_emojis: 커스텀 이모지 (R2 저장)announcements: 관리자 공지사항rules: 인스턴스 규칙conversations+conversation_accounts: DM 대화 추적
polls: 투표 (options JSON, multiple, expires_at)poll_votes: 개별 투표
- ActivityPub (W3C 권고안) -- 서버 간 (Server-to-Server)
- WebFinger (RFC 7033) -- 계정 디스커버리
- NodeInfo 2.0/2.1 -- 인스턴스 메타데이터
SiliconBeest는 최대 상호운용성을 위해 여러 HTTP 서명 방법을 지원합니다:
| 방법 | 방향 | 설명 |
|---|---|---|
draft-cavage-http-signatures-12 |
서명 + 검증 | 대부분의 Mastodon 호환 소프트웨어가 사용하는 레거시 표준. RSA-SHA256. |
| RFC 9421 (HTTP 메시지 서명) | 서명 + 검증 | 최신 표준. 아웃바운드 배달에 우선 사용. |
| Linked Data 서명 | 서명 + 검증 | 릴레이 전달을 위한 활동 객체의 RsaSignature2017. |
| Object Integrity Proofs (FEP-8b32) | 생성 + 검증 | ed25519-jcs-2022 암호화 스위트를 사용하는 Ed25519 기반 DataIntegrityProof. |
원격 인박스에 활동을 배달할 때:
- 첫 번째 시도: RFC 9421 HTTP 메시지 서명으로 서명 (선호하는 최신 표준)
- 거부 시 (서명 오류 응답):
draft-cavage-http-signatures-12로 재시도 (레거시) - 선호도 캐싱: 수신자의 선호 서명 방법이 KV에 7일간 캐싱됨
이는 최신 및 레거시 페디버스 서버 모두와의 호환성을 보장합니다.
- RSA (RSASSA-PKCS1-v1_5, 2048비트): HTTP 서명용 주 서명 키, Actor 문서의
publicKey를 통해 참조 - Ed25519: Object Integrity Proofs (FEP-8b32)에 사용,
assertionMethod에서Multikey타입과publicKeyMultibase인코딩으로 참조
ed25519-jcs-2022 암호화 스위트를 사용하는 DataIntegrityProof 객체를 생성하고 검증합니다:
- 아웃바운드: 모든 아웃바운드 활동이 actor의 Ed25519 키로 서명됨.
proof필드가 활동 JSON에 추가됨. - 인바운드: 수신 활동에
proof필드가 있으면 발신자의 Ed25519 공개 키로 검증. - 정규화: JCS (JSON Canonicalization Scheme, RFC 8785)가 결정적 직렬화에 사용됨.
로컬 계정은 다음 구조로 ActivityPub Actor 문서로 직렬화됩니다:
Person 타입 (일반 사용자 계정):
@context: ActivityStreams + security + toot 확장type:Person(봇의 경우Service)id:https://{domain}/users/{username}publicKey: RSA-2048 공개 키 (키 ID:{id}#main-key)assertionMethod: 무결성 증명용 Ed25519 Multikeyendpoints.sharedInbox:https://{domain}/inboxattachment:PropertyValue객체로서의 프로필 메타데이터 필드alsoKnownAs: 계정 이전용 별칭 URI
Application 타입 (인스턴스 actor):
type:ApplicationpreferredUsername: 인스턴스 도메인manuallyApprovesFollowers: true- 릴레이 활동 서명용 자체 RSA 키쌍
게시물은 ActivityPub Note 객체로 직렬화됩니다:
content: 렌더링된 HTMLcontentMap: 언어별 콘텐츠 맵summary: 콘텐츠 경고 (스포일러 텍스트)sensitive: 미디어 민감도 플래그inReplyTo: 부모 Note URIconversation: 대화 스레드 URI (로컬은 tag: URI, 원격은 보존)quoteUri: 인용 게시물 URI (FEP-e232)_misskey_quote: Misskey 하위 호환
| 가시성 | to |
cc |
|---|---|---|
| 공개(Public) | as:Public |
Followers 컬렉션 + 멘션된 actor |
| 미리스트(Unlisted) | Followers 컬렉션 | as:Public + 멘션된 actor |
| 팔로워 전용(Private) | Followers 컬렉션 | 멘션된 actor |
| 다이렉트(Direct) | 멘션된 actor | (비어있음) |
SiliconBeest는 13가지 이상의 수신 활동 타입을 처리합니다:
| 활동 | 처리기 | 설명 |
|---|---|---|
Create |
create.ts |
새 원격 Note -- 게시물 생성, 멘션/태그 추출, 타임라인 팬아웃 큐잉 |
Update |
update.ts |
업데이트된 Note 또는 Actor -- 로컬 레코드 업데이트 |
Delete |
delete.ts |
삭제된 Note 또는 Actor -- 로컬에서 소프트 삭제 |
Follow |
follow.ts |
팔로우 요청 -- 자동 수락 또는 follow_request 생성 |
Accept |
accept.ts |
수락된 Follow -- 팔로우 관계 생성 |
Reject |
reject.ts |
거부된 Follow -- follow_request 제거 |
Like |
like.ts |
좋아요 -- favourite 레코드 + 알림 생성 |
Announce |
announce.ts |
리블로그 -- 리블로그 게시물 + 알림 생성 |
Undo |
undo.ts |
Follow/Like/Announce/Block 취소 -- 원래 작업 되돌리기 |
Block |
block.ts |
차단 -- 차단 생성, 기존 팔로우 제거 |
Move |
move.ts |
계정 이전 -- alsoKnownAs 검증, 팔로워 이전 |
Flag |
flag.ts |
원격 신고 -- 로컬 신고 레코드 생성 |
EmojiReact |
emojiReact.ts |
Misskey 이모지 반응 -- emoji_reaction 레코드 + 알림 생성 |
원격 활동이 로컬 팔로워를 대상으로 할 때, SiliconBeest는 원본 HTTP 헤더를 보존하여 전달하므로 대상에서 서명 검증이 성공할 수 있습니다. 이는 릴레이 시나리오에서 중요합니다.
모든 컬렉션 엔드포인트는 first, next, prev 링크가 있는 OrderedCollection과 OrderedCollectionPage를 사용합니다:
/users/:username/followers-- 페이지네이션된 팔로워 목록/users/:username/following-- 페이지네이션된 팔로잉 목록/users/:username/outbox--Create(Note)활동이 있는 페이지네이션된 아웃박스/users/:username/featured-- 고정된 게시물 (페이지네이션 없음)
엔드포인트: /.well-known/webfinger?resource=acct:user@domain
acct:URI 스킴 지원application/jrd+json반환- 링크:
self(AP actor URI),http://webfinger.net/rel/profile-page(HTML 프로필)
엔드포인트:
/.well-known/nodeinfo--/nodeinfo/2.0으로 링크/nodeinfo/2.0-- 인스턴스 메타데이터
노출 메타데이터: 소프트웨어 이름/버전, 지원 프로토콜, 사용자 수, 게시물 수, 도메인 수, 가입 상태.
/actor에 Application 타입으로 노출:
- 릴레이 및 인스턴스 수준 활동 서명용 자체 RSA 키쌍
preferredUsername: 인스턴스 도메인manuallyApprovesFollowers: true- 공유 인박스:
/inbox
관리자 API를 통해 관리되는 ActivityPub 릴레이 구독:
- 인증에 인스턴스 actor 사용
- 릴레이 상태: idle, pending, accepted, rejected
- LD 서명을 사용한 아웃바운드 활동 서명
KV를 사용한 수신 활동 중복 제거:
- 키:
activity:{sha256(activity.id)} - TTL: 7일
- 이미 처리된 활동 ID는 자동으로 무시됨
Note 객체의 conversation 필드 지원:
- 로컬 스레드:
tag:URI 형식 사용 - 원격
conversation값은 그대로 보존 - 사용자별 읽음 상태가 있는
conversations테이블에서 추적
| FEP | 제목 | 상태 |
|---|---|---|
| FEP-8b32 | Object Integrity Proofs | 완전 지원 (Ed25519 ed25519-jcs-2022 생성 + 검증) |
| FEP-8fcf | Followers Collection Synchronization | 지원 (페이지네이션된 팔로워, actor의 alsoKnownAs) |
| FEP-67ff | FEDERATION.md | 이 문서 (프로젝트 루트의 FEDERATION.md) |
| FEP-e232 | Object Links (Quote Posts) | 지원 (quoteUri, _misskey_quote) |
SiliconBeest는 100개 이상의 Mastodon 호환 REST API 엔드포인트를 구현합니다:
| 메서드 | 엔드포인트 | 설명 |
|---|---|---|
| GET | /oauth/authorize |
인증 페이지 |
| POST | /oauth/authorize |
인증 동의 |
| POST | /oauth/token |
토큰 교환 (authorization_code, client_credentials) |
| POST | /oauth/revoke |
토큰 폐기 |
| 메서드 | 엔드포인트 | 설명 |
|---|---|---|
| POST | /api/v1/accounts |
새 계정 등록 |
| GET | /api/v1/accounts/verify_credentials |
현재 사용자 조회 |
| PATCH | /api/v1/accounts/update_credentials |
프로필 업데이트 |
| GET | /api/v1/accounts/:id |
계정 조회 |
| GET | /api/v1/accounts/:id/statuses |
계정 게시물 |
| GET | /api/v1/accounts/:id/followers |
팔로워 |
| GET | /api/v1/accounts/:id/following |
팔로잉 |
| POST | /api/v1/accounts/:id/follow |
팔로우 |
| POST | /api/v1/accounts/:id/unfollow |
언팔로우 |
| POST | /api/v1/accounts/:id/block |
차단 |
| POST | /api/v1/accounts/:id/unblock |
차단 해제 |
| POST | /api/v1/accounts/:id/mute |
뮤트 |
| POST | /api/v1/accounts/:id/unmute |
뮤트 해제 |
| GET | /api/v1/accounts/relationships |
관계 조회 |
| GET | /api/v1/accounts/search |
계정 검색 |
| GET | /api/v1/accounts/lookup |
acct로 조회 |
| GET/PUT | /api/v1/accounts/aliases |
계정 별칭 |
| POST | /api/v1/accounts/migration |
계정 이전 |
| POST | /api/v1/accounts/change_password |
비밀번호 변경 |
| 메서드 | 엔드포인트 | 설명 |
|---|---|---|
| POST | /api/v1/statuses |
게시물 작성 |
| GET | /api/v1/statuses/:id |
게시물 조회 |
| PUT | /api/v1/statuses/:id |
게시물 편집 |
| DELETE | /api/v1/statuses/:id |
게시물 삭제 |
| GET | /api/v1/statuses/:id/context |
스레드 컨텍스트 |
| POST | /api/v1/statuses/:id/favourite |
좋아요 |
| POST | /api/v1/statuses/:id/unfavourite |
좋아요 취소 |
| POST | /api/v1/statuses/:id/reblog |
리블로그 |
| POST | /api/v1/statuses/:id/unreblog |
리블로그 취소 |
| POST | /api/v1/statuses/:id/bookmark |
북마크 |
| POST | /api/v1/statuses/:id/unbookmark |
북마크 해제 |
| POST | /api/v1/statuses/:id/mute |
스레드 뮤트 |
| POST | /api/v1/statuses/:id/unmute |
스레드 뮤트 해제 |
| POST | /api/v1/statuses/:id/pin |
고정 |
| POST | /api/v1/statuses/:id/unpin |
고정 해제 |
| GET | /api/v1/statuses/:id/favourited_by |
좋아요 한 사람 |
| GET | /api/v1/statuses/:id/reblogged_by |
리블로그 한 사람 |
| GET/POST | /api/v1/statuses/:id/reactions |
이모지 반응 |
| 메서드 | 엔드포인트 | 설명 |
|---|---|---|
| GET | /api/v1/timelines/home |
홈 타임라인 |
| GET | /api/v1/timelines/public |
공개 타임라인 (로컬 + 연합) |
| GET | /api/v1/timelines/tag/:tag |
해시태그 타임라인 |
| GET | /api/v1/timelines/list/:id |
리스트 타임라인 |
| 메서드 | 엔드포인트 | 설명 |
|---|---|---|
| GET | /api/v1/notifications |
알림 목록 |
| GET | /api/v1/notifications/:id |
알림 조회 |
| POST | /api/v1/notifications/clear |
모든 알림 삭제 |
| POST | /api/v1/notifications/:id/dismiss |
단일 알림 삭제 |
| 메서드 | 엔드포인트 | 설명 |
|---|---|---|
| GET | /api/v1/conversations |
대화 목록 |
| DELETE | /api/v1/conversations/:id |
대화 삭제 |
| POST | /api/v1/conversations/:id/read |
읽음 표시 |
| GET | /api/v1/polls/:id |
투표 조회 |
| POST | /api/v1/polls/:id/votes |
투표 참여 |
| GET/POST/PUT/DELETE | /api/v1/lists |
리스트 CRUD |
| 메서드 | 엔드포인트 | 설명 |
|---|---|---|
| GET | /api/v1/favourites |
좋아요한 게시물 목록 |
| GET | /api/v1/bookmarks |
북마크한 게시물 목록 |
| GET | /api/v1/blocks |
차단 계정 목록 |
| GET | /api/v1/mutes |
뮤트 계정 목록 |
| GET | /api/v1/preferences |
사용자 설정 |
| GET | /api/v1/custom_emojis |
인스턴스 커스텀 이모지 |
| GET/POST | /api/v1/markers |
타임라인 마커 |
| POST | /api/v1/reports |
신고하기 |
| GET/POST | /api/v1/follow_requests |
팔로우 요청 관리 |
| GET/POST | /api/v1/tags |
태그 팔로우/언팔로우 |
| GET | /api/v1/suggestions |
팔로우 추천 |
| GET | /api/v1/announcements |
공지사항 |
| GET | /api/v1/instance/rules |
인스턴스 규칙 |
| GET | /api/v1/trends/tags |
트렌딩 태그 |
| GET | /api/v1/trends/statuses |
트렌딩 게시물 |
| GET | /api/v1/export |
CSV 내보내기 |
| POST | /api/v1/import |
CSV 가져오기 |
| GET | /api/v1/streaming |
WebSocket 스트리밍 업그레이드 |
| POST/GET/PUT/DELETE | /api/v1/push/subscription |
Web Push 구독 관리 |
| GET | /api/v1/instance |
인스턴스 정보 (v1) |
| GET | /api/v1/instance/peers |
알려진 피어 |
| GET | /api/v1/instance/activity |
주간 활동 |
| POST | /api/v1/auth/login |
직접 로그인 (이메일+비밀번호) |
| POST | /api/v1/auth/passwords |
비밀번호 재설정 |
| 메서드 | 엔드포인트 | 설명 |
|---|---|---|
| GET | /api/v1/admin/accounts |
계정 목록 |
| GET | /api/v1/admin/accounts/:id |
계정 상세 |
| POST | /api/v1/admin/accounts/:id/approve |
가입 승인 |
| POST | /api/v1/admin/accounts/:id/reject |
가입 거부 |
| POST | /api/v1/admin/accounts/:id/action |
계정 조치 (사일런스/정지) |
| PUT | /api/v1/admin/accounts/:id/role |
역할 변경 |
| GET | /api/v1/admin/reports |
신고 목록 |
| GET | /api/v1/admin/reports/:id |
신고 상세 |
| POST | /api/v1/admin/reports/:id/resolve |
신고 해결 |
| POST | /api/v1/admin/reports/:id/assign_to_self |
신고 할당 |
| CRUD | /api/v1/admin/domain_blocks |
도메인 차단 관리 |
| CRUD | /api/v1/admin/domain_allows |
도메인 허용 관리 |
| CRUD | /api/v1/admin/ip_blocks |
IP 차단 관리 |
| CRUD | /api/v1/admin/email_domain_blocks |
이메일 도메인 차단 관리 |
| CRUD | /api/v1/admin/instance/rules |
규칙 관리 |
| CRUD | /api/v1/admin/announcements |
공지사항 관리 |
| CRUD | /api/v1/admin/custom_emojis |
커스텀 이모지 관리 |
| GET/PATCH | /api/v1/admin/instance/settings |
인스턴스 설정 |
| CRUD | /api/v1/admin/relays |
릴레이 관리 |
| GET | /api/v1/admin/federation |
연합 모니터링 (인스턴스 헬스) |
| POST | /api/v1/admin/email |
SMTP 이메일 설정 |
| POST | /api/v1/admin/measures |
측정 데이터 조회 |
| 메서드 | 엔드포인트 | 설명 |
|---|---|---|
| GET | /api/v2/instance |
향상된 인스턴스 정보 |
| GET | /api/v2/search |
검색 (계정, 게시물, 해시태그) |
| POST | /api/v2/media |
비동기 미디어 업로드 |
| CRUD | /api/v2/filters |
콘텐츠 필터 |
표준 준수 OAuth 2.0 인증 서버:
- 클라이언트 등록:
POST /api/v1/apps--client_id와client_secret반환 - 인증:
GET /oauth/authorize-- 동의 화면 표시 - 토큰 교환:
POST /oauth/token-- 인증 코드로 교환 - PKCE 지원: 공개 클라이언트용
code_challenge와code_challenge_method(S256) - 클라이언트 자격증명:
POST /oauth/token--grant_type=client_credentials - 토큰 폐기:
POST /oauth/revoke
- RFC 6238 TOTP,
users테이블에 AES-GCM 암호화된 비밀 저장 - bcrypt로 해시된 백업 코드
- OTP 암호화 키는 Cloudflare 시크릿으로 저장 (
OTP_ENCRYPTION_KEY)
Cloudflare Durable Objects를 사용한 실시간 업데이트:
- 엔드포인트:
GET /api/v1/streaming?stream={stream_name} - 스트림:
user,public,public:local,hashtag:{tag},list:{id},direct - 이벤트:
update,notification,delete,status.update,filters_changed - 하이버네이션: Cloudflare의 Hibernatable WebSocket API로 비용 효율성
- 자동 핑/퐁:
setWebSocketAutoResponse로 설정
- VAPID (RFC 8292): 푸시 서비스 인증용 ECDSA P-256 키 쌍
- RFC 8291: 메시지 암호화 (aes128gcm 콘텐츠 인코딩)
- 알림별 설정: 사용자가 특정 알림 유형 활성화/비활성화 가능
- 정책: all/followed/follower/none
모든 목록 엔드포인트에서 커서 기반 페이지네이션 사용:
max_id/min_id/since_id쿼리 파라미터Link헤더에rel="next"와rel="prev"URL- ID가 ULID (시간 정렬 가능)이므로 커서 페이지네이션이 자연스러움
- 업로드:
POST /api/v2/media-- R2에 업로드, 미디어 첨부파일 엔티티 반환 - 제공:
GET /media/:key-- R2에서 적절한 Content-Type으로 제공 - 썸네일 처리: 큐를 통한 비동기 처리
- 크기 제한: 이미지 16 MB, 비디오 100 MB (설정으로 변경 가능)
- 타입: image, video, gifv, audio
- statuses의
quote_id컬럼을 통해 지원 quoteUri속성으로 연합 (FEP-e232)_misskey_quote와 하위 호환
- Move 활동: 모든 팔로워에게
Move(Actor)전송 - alsoKnownAs: 양방향 별칭 검증
- CSV 내보내기/가져오기: 팔로잉, 차단, 뮤트 목록
- 가져오기 처리: 큐를 통한 비동기 (한 번에 하나씩)
SiliconBeest는 상호운용성을 위해 여러 Misskey 전용 확장을 구현합니다:
| 필드 | 방향 | 설명 |
|---|---|---|
_misskey_content |
인바운드 | 수신 Note 객체의 Misskey 포맷 MFM 콘텐츠 |
_misskey_summary |
인바운드 | 콘텐츠 경고 텍스트 |
_misskey_quote |
양방향 | 인용 게시물 참조 (FEP-e232 quoteUri와 하위 호환) |
_misskey_reaction |
인바운드 | 이모지 반응 메타데이터 |
Misskey, Calckey, Firefish 및 호환 구현에서 사용하는 EmojiReact 활동 타입 지원:
- 인바운드:
EmojiReact활동 처리,emoji_reactions레코드 생성, 알림 전송 - 아웃바운드: 사용자가 이모지로 반응할 때
EmojiReact활동 전송 - 커스텀 이모지: 유니코드 이모지와 커스텀 이모지 (
:shortcode:형식) 모두 지원 - API:
GET/POST /api/v1/statuses/:id/reactions
커스텀 이모지는 Note 객체의 Emoji 태그로 연합됩니다. 원격 커스텀 이모지는 소스 인스턴스의 domain이 설정된 상태로 로컬에 캐싱됩니다.
| 큐 | 용도 | 재시도 | DLQ |
|---|---|---|---|
siliconbeest-federation |
연합 관련 작업 (배달, 가져오기, 전달) | 5 | siliconbeest-federation-dlq |
siliconbeest-internal |
내부 작업 (타임라인, 알림, 미디어, 트렌드) | 3 | 없음 |
siliconbeest-federation-dlq |
재시도 소진 메시지 재처리 후 실패 시 federation_dlq_parked D1 테이블에 보관 |
2 | 없음 (D1 보관) |
| 타입 | 큐 | 설명 |
|---|---|---|
deliver_activity |
연합 | 특정 원격 인박스에 단일 활동 배달 |
deliver_activity_fanout |
연합 | 모든 팔로워 인박스에 활동 팬아웃 |
fetch_remote_account |
연합 | 원격 AP actor 가져오기 및 캐싱 |
fetch_remote_status |
연합 | 원격 AP 객체 가져오기 및 캐싱 |
update_instance_info |
연합 | 알려진 인스턴스 메타데이터 업데이트 |
deliver_report |
연합 | 원격 인스턴스에 신고 전달 |
forward_activity |
연합 | 원본 HTTP 헤더 보존 활동 전달 |
import_item |
연합 | 단일 CSV 가져오기 항목 처리 |
timeline_fanout |
내부 | 권한이 있는 팔로워 및 공개 피드에 게시물 스트리밍 |
create_notification |
내부 | 알림 레코드 생성 및 Web Push 큐잉 |
process_media |
내부 | 미디어 썸네일 처리 |
send_web_push |
내부 | Web Push 알림 암호화 및 전송 |
fetch_preview_card |
내부 | URL 미리보기용 OpenGraph 메타데이터 가져오기 |
cleanup_expired_tokens |
내부 | 만료된 OAuth 토큰 정리 |
update_trends |
내부 | 트렌딩 태그/게시물 업데이트 |
큐 소비자는 배치의 for 루프에서 메시지를 처리합니다:
msg.body.type으로 올바른 핸들러에 디스패치- 성공 시:
msg.ack() - 오류 시:
msg.retry()(최대 재시도 후 연합 큐는 DLQ로)
instances 테이블에서 배달 성공/실패를 추적:
last_successful_at: 마지막 성공 배달 타임스탬프last_failed_at: 마지막 실패 배달 타임스탬프failure_count: 연속 실패 횟수- 도달할 수 없는 인스턴스에 대한 백오프 구현에 사용
| 기술 | 버전 | 용도 |
|---|---|---|
| Vue 3 | ^3.5.29 | 반응형 UI 프레임워크 |
| Vite | ^7.3.1 | 빌드 도구 |
| Tailwind CSS 4 | ^4.2.2 | 유틸리티 우선 CSS |
| Pinia | ^3.0.4 | 상태 관리 |
| vue-i18n | ^11.3.0 | 국제화 |
| vue-router | ^5.0.3 | 클라이언트 사이드 라우팅 |
| @headlessui/vue | ^1.7.23 | 접근성 있는 UI 컴포넌트 |
| @sentry/vue | ^10.45.0 | 에러 추적 (선택사항) |
| @vueuse/core | ^14.2.1 | Vue 컴포지션 유틸리티 |
컴포넌트는 도메인별로 구성됩니다:
| 카테고리 | 컴포넌트 | 용도 |
|---|---|---|
| layout | AppShell, Sidebar, MobileNav, AdminLayout | 애플리케이션 프레임 및 네비게이션 |
| status | StatusCard, StatusContent, StatusActions, StatusComposer, MediaGallery, PreviewCard | 게시물 표시 및 작성 |
| account | AccountCard, AccountHeader, FollowButton | 계정 표시 및 상호작용 |
| common | Avatar, EmojiPicker, ImageViewer, InfiniteScroll, LoadingSpinner, Modal, ReportDialog, Toast | 공유 UI 컴포넌트 |
| notification | NotificationItem | 알림 표시 |
| auth | LoginForm, RegisterForm, TwoFactorForm | 인증 폼 |
| settings | LanguageSelector | 설정 UI 컴포넌트 |
| timeline | TimelineFeed | 무한 스크롤 타임라인 |
| 경로 | 가드 | 뷰 |
|---|---|---|
/ |
redirectIfAuthenticated | LandingView |
/home |
requireAuth | HomeView |
/explore/:tab |
(없음) | ExploreView |
/about |
(없음) | AboutView |
/search |
(없음) | SearchView |
/tags/:tag |
(없음) | TagTimelineView |
/login |
redirectIfAuthenticated | LoginView |
/register |
redirectIfAuthenticated | RegisterView |
/notifications |
requireAuth | NotificationsView |
/conversations |
requireAuth | ConversationsView |
/bookmarks |
requireAuth | BookmarksView |
/favourites |
requireAuth | FavouritesView |
/lists |
requireAuth | ListsView |
/lists/:id |
requireAuth | ListTimelineView |
/follow-requests |
requireAuth | FollowRequestsView |
/settings/* |
requireAuth | Settings* 뷰 (6개 하위 라우트) |
/admin/* |
requireAdmin | Admin* 뷰 (10개 하위 라우트) |
/@:acct |
(없음) | ProfileView |
/@:acct/:statusId |
(없음) | StatusDetailView |
| 스토어 | 상태 | 용도 |
|---|---|---|
auth |
토큰, 현재 사용자, 2FA 상태 | 인증 및 세션 |
accounts |
계정 캐시, 관계 | 계정 데이터 및 상호작용 |
statuses |
게시물 캐시, 컨텍스트 | 게시물 데이터 및 작업 |
timelines |
홈, 로컬, 공개, 태그, 리스트 피드 | 타임라인 조립 |
notifications |
알림 목록, 읽지 않은 수 | 알림 |
compose |
초안 텍스트, 미디어, 투표, 가시성 | 게시물 작성 |
instance |
인스턴스 설정, 커스텀 이모지, 규칙 | 인스턴스 메타데이터 |
ui |
테마, 사이드바 상태, 모바일 네비, 모달, 토스트 | UI 상태 관리 |
지연 로딩을 지원하는 12개 언어:
| 코드 | 언어 | 방향 |
|---|---|---|
en |
English | LTR |
ko |
한국어 | LTR |
ja |
일본어 | LTR |
zh-CN |
중국어 간체 | LTR |
zh-TW |
중국어 번체 | LTR |
es |
스페인어 | LTR |
fr |
프랑스어 | LTR |
de |
독일어 | LTR |
pt-BR |
브라질 포르투갈어 | LTR |
ru |
러시아어 | LTR |
ar |
아랍어 | RTL |
id |
인도네시아어 | LTR |
영어는 기본값으로 즉시 로딩됩니다. 나머지 언어는 필요 시 동적 import()로 지연 로딩됩니다.
api/streaming.ts 모듈은 다음 기능의 WebSocket 클라이언트를 제공합니다:
/api/v1/streaming?stream={name}에 연결- 지수적 백오프로 자동 재연결
- Pinia 스토어에 이벤트 디스패치 (새 게시물, 알림, 삭제)
- 여러 스트림 구독 동시 처리
@sentry/vue를 통한 선택적 에러 추적:
VITE_SENTRY_DSN환경 변수로 설정- Vue 에러 핸들러와 통합
전체 화면 이미지 뷰어:
- 키보드 네비게이션 (화살표, Escape)
- 모바일 핀치 줌
- 이미지 다운로드
커스텀 이모지 피커:
- 유니코드 이모지 카테고리
- 인스턴스 커스텀 이모지
- 자동완성 (
:shortcode트리거) - 검색/필터 기능
- Tailwind CSS 4로 모바일 우선
- 모바일에서 하단 네비게이션 (
MobileNav.vue) - 데스크탑에서 사이드바 네비게이션 (
Sidebar.vue) - 시스템 인식 다크 모드 및 수동 토글
관리자 패널은 /admin에서 접근 가능하며 requireAdmin 네비게이션 가드가 필요합니다. AdminLayout.vue에 사이드바 네비게이션을 사용합니다.
- 필터링이 가능한 계정 목록 (로컬, 원격, 활성, 대기, 정지, 사일런스)
- 대기 중인 가입 요청 승인
- 대기 중인 가입 거부
- 계정 사일런스 (가시성 제한)
- 계정 정지 (완전 차단)
- 역할 변경: user, moderator, admin
- 상태 필터링이 있는 신고 목록 (열림, 해결됨)
- 신고된 게시물을 포함한 신고 상세 보기
- 모더레이터에게 신고 할당
- 조치와 함께 신고 해결
- 원격 인스턴스에 신고 전달
- 심각도별 도메인 차단 생성 (silence, suspend, noop)
- 옵션: 미디어 거부, 신고 거부, 도메인 난독화
- 공개/비공개 코멘트
- 허용 목록 모드를 위한 도메인 허용
- 커스텀 이모지 업로드 (R2에 저장)
- 이모지 카테고리 분류
- 피커 가시성 토글
- 이모지 삭제
- 선택적 시작/종료 날짜가 있는 공지사항 생성
- 공지사항 공개/비공개
- 종일 이벤트 지원
- 공지사항 편집/삭제
- 인스턴스 규칙 생성
- 우선순위별 재정렬
- 규칙 편집/삭제
- 인스턴스 헬스 대시보드
- 배달 성공/실패 통계
- 소프트웨어 정보가 포함된 알려진 인스턴스 목록
- 실패 횟수 추적
- 릴레이 구독 추가
- 릴레이 상태 모니터링 (idle, pending, accepted, rejected)
- 릴레이 구독 제거
SMTP 설정 구성: 호스트, 포트, 사용자, 비밀번호, 발신 주소. 비밀번호 재설정 이메일 및 알림 이메일에 사용됩니다.
- 브랜딩: 사이트 제목, 설명, 썸네일
- 연락처: 관리자 이메일, 관리자 사용자명
- 가입: 공개, 승인 필요, 폐쇄
- 제한: 최대 문자 수, 미디어 첨부파일, 투표 옵션
- 기능: 트렌드, 썸네일 생성
- 타임스탬프 검증: 수신 서명의 Date 헤더가 +-300초 이내인지 확인
- 다이제스트 검증: 본문 다이제스트가 Digest 헤더와 일치하는지 검증
- 키 가져오기: 발신자의 actor 문서에서 공개 키 가져오기
- 서명 알고리즘: draft-cavage용 RSA-SHA256, RFC 9421용 설정 가능
인박스 엔드포인트는 수신 요청의 ActivityPub 콘텐츠 타입을 검증:
application/activity+jsonapplication/ld+json; profile="https://www.w3.org/ns/activitystreams"
KV 기반 슬라이딩 윈도우 속도 제한기 (middleware/rateLimit.ts):
| 프리셋 | 제한 | 윈도우 |
|---|---|---|
RATE_LIMIT_GENERAL |
300 요청 | 5분 |
RATE_LIMIT_AUTH |
30 요청 | 5분 |
RATE_LIMIT_REGISTRATION |
5 요청 | 5분 |
키 형식: rl:{ip}:{endpoint}:{windowId}
응답 헤더:
X-RateLimit-Limit: 최대 요청 수X-RateLimit-Remaining: 남은 요청 수Retry-After: 윈도우 리셋까지 초 (429 시)
CORS 미들웨어는 Mastodon 클라이언트 애플리케이션의 크로스 오리진 요청을 적절한 헤더와 함께 허용합니다.
bcryptjs라이브러리를 통한 bcrypt- 가입 시 해싱, 로그인 시 검증
- RFC 6238 TOTP 구현
OTP_ENCRYPTION_KEYCloudflare 시크릿을 사용하여 AES-GCM으로 OTP 비밀 암호화- 백업 코드: bcrypt로 해시된 일회용 코드
- 활성화 시 OAuth 토큰 교환 중 적용
- RFC 8292 VAPID -- Web Push 인증용
generate-vapid-keys.sh로 생성된 ECDSA P-256 키 쌍- Cloudflare 시크릿으로 저장
Cloudflare의 Bot Fight Mode가 연합을 방해할 수 있습니다 (ActivityPub 요청을 봇으로 차단). WAF Skip 규칙이 필요합니다:
(http.request.uri.path matches "^/users/.*" or
http.request.uri.path eq "/inbox" or
http.request.uri.path eq "/actor" or
http.request.uri.path matches "^/nodeinfo/.*" or
http.request.uri.path matches "^/.well-known/.*")
사용자 생성 HTML 콘텐츠는 XSS 방지를 위해 살균됩니다:
utils/sanitize.ts가 위험한 태그 및 속성 제거- 허용된 HTML 태그와 속성만 통과
- 수신 연합 콘텐츠와 로컬 작성 게시물 모두에 적용
모든 스크립트는 PROJECT_PREFIX를 기반으로 리소스 이름을 정의하는 scripts/config.sh를 소스합니다:
| 변수 | 기본값 | 설명 |
|---|---|---|
PROJECT_PREFIX |
siliconbeest |
모든 리소스의 마스터 접두사 |
WORKER_NAME |
{prefix}-worker |
API Worker |
CONSUMER_NAME |
{prefix}-queue-consumer |
큐 소비자 |
VUE_NAME |
{prefix}-vue |
프론트엔드 Worker |
D1_DATABASE_NAME |
{prefix}-db |
D1 데이터베이스 |
R2_BUCKET_NAME |
{prefix}-media |
R2 버킷 |
KV_CACHE_TITLE |
{prefix}-CACHE |
캐시 KV |
KV_SESSIONS_TITLE |
{prefix}-SESSIONS |
세션 KV |
QUEUE_FEDERATION |
{prefix}-federation |
연합 큐 |
QUEUE_INTERNAL |
{prefix}-internal |
내부 큐 |
QUEUE_DLQ |
{prefix}-federation-dlq |
Dead Letter 큐 |
커스터마이징 옵션:
- 환경 변수:
PROJECT_PREFIX=myserver ./scripts/setup.sh - 영구 파일:
scripts/config.env - 개별 오버라이드:
export D1_DATABASE_NAME=my-custom-db
대화형 초기 설정:
- 프로젝트 접두사, 인스턴스 도메인, 제목, 가입 모드, 관리자 인증 정보, Sentry DSN 입력 요청
- D1 데이터베이스, R2 버킷, KV 네임스페이스, Queues 생성
- VAPID 키 쌍 (ECDSA P-256) 및 OTP 암호화 키 생성
- 모든
wrangler.jsonc파일에 리소스 ID 업데이트 wrangler secret put으로 시크릿 설정- D1 마이그레이션 적용
- 관리자 사용자 생성
siliconbeest-vue/.env작성
3개 Worker 모두 빌드 및 배포:
| 플래그 | 설명 |
|---|---|
--domain <domain> |
커스텀 도메인 Workers Routes 설정 |
--dry-run |
배포될 내용 표시 |
--skip-migrations |
D1 마이그레이션 단계 건너뛰기 |
프로덕션 업데이트 워크플로우:
git pull(변경 로그 표시)- 모든 프로젝트
npm install - TypeScript 타입 체크
- 테스트 실행
- D1 마이그레이션 적용
- 프론트엔드 빌드
- 모든 Worker 배포
| 플래그 | 설명 |
|---|---|
--branch <name> |
풀할 Git 브랜치 |
--skip-pull |
현재 작업 트리 사용 |
--skip-tests |
테스트 단계 건너뛰기 |
--dry-run |
배포 없이 확인 |
독립적인 도메인 설정 (재배포 없이):
- API 경로를 API Worker에 Workers Routes 생성
- Vue 프론트엔드에 catch-all 라우트 생성
VAPID Web Push용 ECDSA P-256 키 쌍 생성:
--set-secrets플래그로 Cloudflare에 저장
관리자 사용자 생성:
- 대화형 또는 인수:
./scripts/seed-admin.sh 이메일 사용자명 비밀번호
D1 마이그레이션 적용:
--local: 개발용--remote: 프로덕션 (기본값)--dry-run: 대기 중인 마이그레이션 목록만 표시
D1 + R2 백업:
--skip-r2: D1만--output-dir: 커스텀 위치
AP 호환 계정 삭제:
- 모든 알려진 연합 서버에
Delete(Actor)전송 - 로컬 데이터베이스에서 계정 제거
--all --confirm: 서버 종료 시
Cloudflare 리소스 ID를 wrangler.jsonc에 동기화:
- Cloudflare API에서 D1, KV, R2, Queue ID 가져오기
- 3개의 wrangler.jsonc 파일 모두 재생성
--apply: 파일 작성 (기본값은 드라이 런)
- Vitest +
@cloudflare/vitest-pool-workers: Workers 런타임 환경에서 테스트 - 실제 Cloudflare Workers 런타임에서 테스트 실행
- D1 데이터베이스 테스트 가능 (인메모리)
| 테스트 파일 | 커버리지 영역 |
|---|---|
accounts.test.ts |
계정 CRUD, 프로필 업데이트, 관계 |
activity-idempotency.test.ts |
KV 기반 활동 중복 제거 |
activitypub.test.ts |
AP 인박스 처리, 활동 핸들링 |
actor-serializer.test.ts |
Actor 문서 직렬화 |
admin-*.test.ts |
관리자 기능 (공지, 도메인 차단, 역할, 규칙) |
admin.test.ts |
관리자 계정 관리 |
auth.test.ts |
인증, 로그인, 토큰 관리 |
blocks-mutes.test.ts |
차단 및 뮤트 작업 |
bookmarks-favourites.test.ts |
북마크 및 좋아요 작업 |
collection-pagination.test.ts |
AP 컬렉션 페이지네이션 |
content-parser.test.ts |
멘션, 해시태그, 링크 파싱 |
conversations.test.ts |
DM 대화 관리 |
custom-emojis.test.ts |
커스텀 이모지 CRUD |
discovery.test.ts |
WebFinger, NodeInfo 디스커버리 |
ed25519-crypto.test.ts |
Ed25519 키 작업 |
emoji-reactions.test.ts |
이모지 반응 작업 |
featured-collections.test.ts |
고정/해제, featured 컬렉션 |
filters.test.ts |
콘텐츠 필터 CRUD |
http-signatures.test.ts |
HTTP 서명 생성 및 검증 |
integrity-proofs.test.ts |
FEP-8b32 Object Integrity Proofs |
ld-signatures.test.ts |
Linked Data 서명 작업 |
oauth-flow.test.ts |
전체 OAuth 2.0 흐름 + PKCE |
statuses.test.ts |
게시물 CRUD, 가시성, 스레딩 |
| (기타 테스트 파일...) | 타임라인, 검색, 미디어, 투표, 신고, 비밀번호 등 |
| 테스트 파일 | 커버리지 영역 |
|---|---|
api/client.test.ts |
API 클라이언트 설정 및 인터셉터 |
components/Avatar.test.ts |
아바타 컴포넌트 렌더링 |
components/LoadingSpinner.test.ts |
로딩 스피너 컴포넌트 |
components/StatusActions.test.ts |
게시물 액션 버튼 |
components/FollowButton.test.ts |
팔로우 버튼 상태 관리 |
stores/auth.test.ts |
인증 스토어 (로그인, 로그아웃, 토큰) |
stores/ui.test.ts |
UI 스토어 (테마, 사이드바, 모달) |
stores/statuses.test.ts |
게시물 스토어 작업 |
stores/timelines.test.ts |
타임라인 스토어 관리 |
router/guards.test.ts |
네비게이션 가드 로직 |
i18n/i18n.test.ts |
i18n 설정 및 로케일 로딩 |
# API Worker 테스트 (49개 파일)
cd siliconbeest-worker && npm test
# Vue 프론트엔드 테스트 (11개 파일)
cd siliconbeest-vue && npm test
# 모든 테스트 실행
cd siliconbeest-worker && npm test && cd ../siliconbeest-vue && npm test| 제약 | 제한 | 영향 |
|---|---|---|
| 요청당 CPU 시간 | 30초 (Paid) | 복잡한 연합 작업은 청킹이 필요할 수 있음 |
| 서브리퀘스트 제한 | 요청당 50개 (Paid: 1000) | 많은 팔로워에 대한 팬아웃은 큐 배칭 필요 |
| 본문 크기 | 100 MB | 큰 미디어 업로드가 실패할 수 있음 |
| D1 행 크기 | ~1 MB | 매우 긴 게시물 콘텐츠가 잘릴 수 있음 |
| KV 값 크기 | 25 MB | 큰 캐시 객체는 분할 필요 |
- SQLite 기반: 저장 프로시저 없음, 제한된 쿼리 복잡성
- 데이터베이스 간 JOIN 불가: 모든 데이터에 단일 D1 데이터베이스
- 최종 일관성: 글로벌 읽기 복제본이 약간 지연될 수 있음
- 전체 텍스트 검색 없음: 검색은 기본
LIKE쿼리 (FTS5 없음)
SiliconBeest는 비용을 낮추기 위해 Cloudflare Containers를 사용하지 않습니다:
- 무거운 이미지 처리 없음 (ImageMagick/Sharp 없음)
- 제한된 비디오 트랜스코딩
- 간소화된 BlurHash 생성
- 전체 텍스트 검색 (Workers AI 또는 외부 서비스 활용 가능)
- 비디오 트랜스코딩 파이프라인
- 고급 미디어 처리 (이미지 최적화, 형식 변환)
- 추가 FEP 구현
- 고팔로워 계정에 대한 성능 최적화
- 다이렉트 메시지용 E2E 암호화
- 확장을 위한 플러그인 시스템
| 변수 | Worker | 설명 | 예시 |
|---|---|---|---|
INSTANCE_DOMAIN |
API | 인스턴스 도메인명 | social.example.com |
INSTANCE_TITLE |
API | 인스턴스 표시 이름 | My Fediverse Server |
REGISTRATION_MODE |
API | open / approval / closed | open |
| 시크릿 | Worker | 설명 | 설정자 |
|---|---|---|---|
VAPID_PRIVATE_KEY |
API, 큐 소비자 | ECDSA P-256 개인 키 (base64url) | setup.sh |
VAPID_PUBLIC_KEY |
API, 큐 소비자 | ECDSA P-256 공개 키 (base64url) | setup.sh |
OTP_ENCRYPTION_KEY |
API | TOTP 비밀용 AES-GCM 키 | setup.sh |
SENTRY_DSN |
API | 워커 오류 보고용 Sentry DSN (선택사항) | 수동 (wrangler secret put) |
SMTP_HOST |
API | SMTP 서버 호스트명 (선택사항) | 관리자 설정 |
SMTP_PORT |
API | SMTP 서버 포트 (선택사항) | 관리자 설정 |
SMTP_USER |
API | SMTP 사용자명 (선택사항) | 관리자 설정 |
SMTP_PASS |
API | SMTP 비밀번호 (선택사항) | 관리자 설정 |
SMTP_FROM |
API | SMTP 발신 주소 (선택사항) | 관리자 설정 |
| 바인딩 | 타입 | 이름 |
|---|---|---|
DB |
D1 Database | siliconbeest-db |
MEDIA_BUCKET |
R2 Bucket | siliconbeest-media |
CACHE |
KV Namespace | (ID별) |
SESSIONS |
KV Namespace | (ID별) |
QUEUE_FEDERATION |
Queue Producer | siliconbeest-federation |
QUEUE_INTERNAL |
Queue Producer | siliconbeest-internal |
STREAMING_DO |
Durable Object | StreamingDO 클래스 |
| 바인딩 | 타입 | 이름 |
|---|---|---|
DB |
D1 Database | siliconbeest-db |
MEDIA_BUCKET |
R2 Bucket | siliconbeest-media |
CACHE |
KV Namespace | (ID별) |
QUEUE_FEDERATION |
Queue Producer/Consumer | siliconbeest-federation |
QUEUE_INTERNAL |
Queue Producer/Consumer | siliconbeest-internal |
INTERNAL_CONNECTION_MAIN |
Service Binding (RPC) | siliconbeest / Internal 엔트리포인트 |
서비스 바인딩 없음. 정적 자산만 제공.
| 변수 | 필수 | 설명 |
|---|---|---|
VITE_INSTANCE_DOMAIN |
예 | 인스턴스 도메인 (메타 태그용) |
VITE_VAPID_PUBLIC_KEY |
예 | VAPID 공개 키 (Web Push 구독용) |
VITE_SENTRY_DSN |
아니오 | 에러 추적용 Sentry DSN |
VITE_SENTRY_FEEDBACK |
아니오 | true로 설정 시 Sentry 사용자 피드백 위젯 표시 (VITE_SENTRY_DSN 필요) |
관리자 API를 통해 런타임에 설정 가능:
| 키 | 타입 | 기본값 | 설명 |
|---|---|---|---|
registration_mode |
string | open |
open/approval/closed |
site_title |
string | SiliconBeest |
인스턴스 이름 |
site_description |
string | (비어있음) | 인스턴스 설명 |
site_contact_email |
string | (비어있음) | 연락처 이메일 |
site_contact_username |
string | (비어있음) | 연락처 계정 |
max_toot_chars |
number | 500 |
최대 게시물 문자 수 |
max_media_attachments |
number | 4 |
게시물당 최대 미디어 수 |
max_poll_options |
number | 4 |
최대 투표 옵션 수 |
poll_max_characters_per_option |
number | 50 |
투표 옵션당 최대 문자 수 |
media_max_image_size |
number | 16777216 |
최대 이미지 크기 (바이트) |
media_max_video_size |
number | 104857600 |
최대 비디오 크기 (바이트) |
thumbnail_enabled |
boolean | 1 |
썸네일 생성 활성화 |
trends_enabled |
boolean | 1 |
트렌딩 기능 활성화 |
require_invite |
boolean | 0 |
가입에 초대 필요 |
min_password_length |
number | 8 |
최소 비밀번호 길이 |
주의: 연합 시작 후 인스턴스 도메인을 변경하지 마세요. ActivityPub actor URI에는 도메인이 포함되어 있으며 페디버스 전체에서 영구 식별자입니다. 다른 서버가 actor를 캐싱한 후 도메인을 변경하면 모든 기존 연합 관계, 팔로워 및 대화가 깨집니다. 시작 전에 도메인을 신중하게 선택하세요.