Hashtag

#연합우주

149 posts tagged with this hashtag.

@botkit@hackers.pub

Note

이 글은 BotKit의 공식 튜토리얼 Building an RSS bot(영문)을 한국어로 옮긴 것입니다. 원문은 계속 업데이트되므로, 최신 내용은 위 링크에서 확인하는 편이 좋습니다.

BotKit시작하기 안내서를 따라 하면 몇 분 만에 봇을 띄울 수 있습니다. 다만 그 봇은 인사말에 답할 뿐, 딱히 감시할 대상은 없습니다. 이 튜토리얼은 거기서 한 걸음 더 나아갑니다. RSS나 Atom, RDF 피드를 주시하다가 새 글이 올라오면 페디버스에 게시하는 봇을 만듭니다. 그 과정에서 예약 작업, 상태 저장, 멘션에 답장하기를 다루고, 나중에는 피드가 하나에서 여럿으로 늘어났을 때 필요해지는 createInstance()와 동적 봇 그룹까지 짚어 봅니다.

1부에서는 피드 하나를 감시하는 봇 하나를 만듭니다. 2부에서는 그 봇을 인스턴스로 바꿔서, 인스턴스를 멘션하며 피드 URL을 알려주는 것만으로 피드별 봇을 하나씩 등록할 수 있게 합니다. 각 부의 마지막에는 봇을 공개 인터넷에 노출시키고, ActivityPub.Academy에서 실제 Mastodon 계정으로 팔로우하고 멘션하고 지켜보며 테스트합니다.

이 튜토리얼은 시작하기를 이미 읽었다는 전제로 진행하므로, createBot()이나 Text를 처음부터 다시 설명하지는 않습니다. 완성된 프로젝트는 BotKit 저장소의 examples/rss-bot/에서도 볼 수 있습니다.

봇 하나로 시작하기

프로젝트 준비하기

새 디렉터리를 만들고, BotKit과 함께 피드의 원본 XML을 평범한 객체로 바꿔 줄 @rowanmanning/feed-parser를 설치합니다.

Deno

mkdir rss-bot && cd rss-bot
deno add jsr:@fedify/botkit npm:@rowanmanning/feed-parser

npm

mkdir rss-bot && cd rss-bot
npm init -y
npm add @fedify/botkit @rowanmanning/feed-parser

pnpm

mkdir rss-bot && cd rss-bot
pnpm init
pnpm add @fedify/botkit @rowanmanning/feed-parser

Yarn

mkdir rss-bot && cd rss-bot
yarn init -y
yarn add @fedify/botkit @rowanmanning/feed-parser

피드 가져오고 파싱하기

@rowanmanning/feed-parser는 RSS 0.9x, RSS 2.0, RDF Site Summary 1.0(RSS 1.0), Atom 0.3/1.0 피드를 모두 같은 parseFeed() 함수, 같은 Feed/FeedItem 형태로 파싱해 줍니다. 덕분에 봇 코드 쪽에서는 지금 이 피드가 어떤 포맷인지 굳이 분기할 필요가 없습니다.

parseFeed()가 하지 않는 일도 있습니다. 바로 가져오기(fetch)입니다. 이 함수는 이미 손에 쥔 XML 문자열을 객체로 바꿔 줄 뿐, 그 문자열을 어떻게 구할지는 호출하는 쪽의 몫입니다. 봇 코드도 이 구분을 그대로 따라서, 가져오기를 전담하는 feed.ts 모듈을 두고, 이를 어떤 주기로 폴링할지는 별도로 다룹니다.

feed.ts

// 피드(RSS, Atom, RDF)를 가져오고 파싱한다. 가져오기는 이 모듈의 일이고,
// 파싱은 전적으로 @rowanmanning/feed-parser의 일이다. 이 라이브러리는 피드를
// 그저 XML 문자열로만 볼 뿐, 그 문자열이 어떻게 조달됐는지는 신경 쓰지 않는다.

import { parseFeed } from "@rowanmanning/feed-parser";

// @rowanmanning/feed-parser의 공개 엔트리포인트는 parseFeed 함수만 내보낼 뿐
// 반환값인 Feed/FeedItem 타입은 내보내지 않는다. 그래서 패키지 내부 경로를
// 직접 뒤지는 대신, 함수의 반환 타입에서 역으로 타입을 끌어온다.
export type Feed = ReturnType<typeof parseFeed>;
export type FeedItem = Feed["items"][number];

export async function fetchFeed(
  url: string | URL,
  signal?: AbortSignal,
): Promise<Feed> {
  const response = await fetch(url, { signal });
  if (!response.ok) {
    throw new Error(
      `Failed to fetch feed: ${response.status} ${response.statusText}`,
    );
  }
  return parseFeed(await response.text());
}

맨 위의 타입 유도 코드는 자잘한 우회로입니다. @rowanmanning/feed-parser 패키지는 parseFeed 함수만 내보낼 뿐 그 함수가 반환하는 Feed, FeedItem 클래스는 내보내지 않으므로, type { Feed }를 패키지에서 직접 가져오려 하면 실패합니다. ReturnType<typeof parseFeed>는 타입을 직접 이름 붙여 가져오는 대신, 함수 시그니처로부터 TypeScript가 스스로 타입을 유추하게 만들어 이 문제를 피해 갑니다.

폴링하고 게시하기

봇 자체는 단순하게 시작합니다. 봇을 만들고, 일정 주기로 피드를 폴링하고, 새로 올라온 글을 게시하는 것뿐입니다. 식별자를 비롯한 나머지 설정은 시작하기에서 본 패턴을 그대로 따르는데, 다만 여기서 쓰는 kv 스토어와 queue는 로컬 개발용 인메모리 구현입니다. 재시작이 문제가 되는 시점에 다른 것으로 교체할 예정입니다.

bot.ts

// RSS/Atom/RDF 피드를 일정 주기로 폴링하다가 새 글이 올라오면 페디버스에
// 게시하는 봇.
//
// 실행:  deno serve --allow-net --allow-env --watch bot.ts
//   또는: npx srvx serve --port 8000 --entry ./bot.ts
// 설정:  ORIGIN=https://your-domain
//        FEED_URL=https://example.com/feed.xml (기본값은 Hacker News)
//        POLL_INTERVAL_MS=600000 (기본값은 10분)

import {
  createBot,
  InProcessMessageQueue,
  link,
  MemoryKvStore,
  text,
} from "@fedify/botkit";
import { fetchFeed } from "./feed.ts";
import type { FeedItem } from "./feed.ts";

const FEED_URL = process.env.FEED_URL ?? "https://news.ycombinator.com/rss";
const ORIGIN = process.env.ORIGIN ?? "http://localhost:8000";

const rawPollIntervalMs = process.env.POLL_INTERVAL_MS;
const POLL_INTERVAL_MS = rawPollIntervalMs == null || rawPollIntervalMs === ""
  ? 1000 * 60 * 10
  : Number(rawPollIntervalMs);
if (!Number.isFinite(POLL_INTERVAL_MS) || POLL_INTERVAL_MS <= 0) {
  throw new RangeError(
    `POLL_INTERVAL_MS must be a positive number of milliseconds: ${rawPollIntervalMs}`,
  );
}

const bot = createBot<void>({
  username: "rssbot",
  name: "RSS Bot",
  summary: text`I watch ${link(FEED_URL)} and post new entries here.`,
  kv: new MemoryKvStore(),
  queue: new InProcessMessageQueue(),
});

function itemKey(item: FeedItem): string | null {
  return item.id ?? item.url;
}

const posted = new Set<string>();
let firstPoll = true;

async function poll(): Promise<void> {
  const feed = await fetchFeed(FEED_URL);
  const items = [...feed.items].reverse(); // 피드는 최신 글이 맨 앞에 온다

  if (firstPoll) {
    // 봇을 맨 처음 띄운 순간 피드에 이미 올라와 있던 글 전부를 팔로워에게
    // 쏟아붓지 않기 위함이다. 이후 폴링에서 새로 나타나는 글만 "새 글"로 친다.
    firstPoll = false;
    for (const item of items) {
      const key = itemKey(item);
      if (key != null) posted.add(key);
    }
    console.log(`Baseline: ${posted.size} existing item(s) from ${FEED_URL}.`);
    return;
  }

  const session = bot.getSession(ORIGIN);
  let publishedCount = 0;
  for (const item of items) {
    const key = itemKey(item);
    if (key == null || posted.has(key)) continue;
    await session.publish(
      text`${item.title ?? "(untitled)"}

${link(item.url ?? FEED_URL)}`,
    );
    posted.add(key);
    publishedCount++;
  }
  console.log(`Posted ${publishedCount} new item(s) from ${FEED_URL}.`);
}

let polling = false;

async function pollOnce(): Promise<void> {
  if (polling) return; // 이전 폴링이 아직 진행 중이면 건너뛴다
  polling = true;
  try {
    await poll();
  } catch (error) {
    console.error("Failed to poll feed:", error);
  } finally {
    polling = false;
  }
}

pollOnce();
setInterval(pollOnce, POLL_INTERVAL_MS);

export default bot;

맨 처음 폴링에서는 피드에 이미 올라와 있던 글을 기록만 할 뿐, 게시하지는 않습니다. 이 처리가 없다면 봇을 처음 실행하는 순간 피드의 현재 첫 페이지 전체가 팔로워들에게 쏟아지는데, 이는 “새 글”이 뜻해야 할 바가 전혀 아닙니다. 다음 폴링에서 새로 나타나는 글만 새 글로 칩니다.

pollOnce()는 실제 폴링 로직을 polling 플래그로 감쌉니다. 느린 요청이 다음 예약 틱과 겹치지 않도록 하기 위해서입니다. setInterval()은 콜백이 끝나기를 기다리지 않고 다음 호출을 예약하므로, 이 방어 장치가 없으면 POLL_INTERVAL_MS보다 오래 걸리는 피드 요청 때문에 폴링 두 개가 동시에 돌면서 같은 글을 중복 게시할 수 있습니다.

POLL_INTERVAL_MS는 시작 시점에 한 번 파싱하고, 유한한 양수인지 검사합니다. 값이 비어 있거나 잘못돼서 그대로 setInterval(fn, NaN)으로 흘러 들어가면 에러도 나지 않고, 그냥 이벤트 루프의 거의 매 틱마다 실행되며 피드를 두들겨 댑니다. 실행 시점에 요란하게 실패하는 편이, 실행 중에 조용히 잘못되는 것보다 낫습니다.

FEED_URL의 기본값은 Hacker News의 첫 페이지 피드입니다. RSS든 Atom이든 RDF든 어떤 피드를 써도 되지만, 테스트하는 동안에는 자주 갱신되는 피드를 쓰는 편이 좋습니다. 봇이 실제로 뭔가 게시하는 모습을 보려고 오래 기다릴 필요가 없기 때문입니다.

봇 실행하기

시작하기에서와 마찬가지로 봇을 기본 내보내기(default export)로 내보내고 실행합니다.

Deno

deno serve --allow-net --allow-env --watch bot.ts

Node.js

npx srvx serve --port 8000 --entry ./bot.ts

콘솔에는 몇 초 안에 베이스라인 개수가 찍히고, 이후 POLL_INTERVAL_MS가 지나면 Posted 0 new item(s)가 뜨거나, 그사이 피드에 뭔가 새로 올라왔다면 실제로 글이 하나 게시됩니다. 10분을 기다리지 않고 바로 게시되는 모습을 보고 싶다면 지금은 주기를 짧게 잡아 봅니다.

POLL_INTERVAL_MS=60000 deno serve --allow-net --allow-env --watch bot.ts

Tip

fedify lookup은 URL이나 핸들로 임의의 액터나 오브젝트를 조회해서 ActivityPub 표현을 출력해 줍니다. 여기서 fedify lookup http://localhost:8000/ap/actor/bot을 실행해 보면, 더 나아가기 전에 봇의 액터 문서가 제대로 나오는지 빠르게 확인할 수 있습니다.

멘션에 답장하기

게시만 하고 응답은 전혀 하지 않는 봇은, 잘 돌아가고 있어도 죽은 것처럼 느껴집니다. onMention은 봇에게 할 말을 만들어 줍니다. 지금 어떤 피드를 보고 있는지, 얼마나 자주 확인하는지 같은 것들 말이죠.

bot.ts

function formatInterval(ms: number): string {
  if (ms < 60_000) {
    const seconds = Math.round(ms / 1000);
    return `${seconds} second${seconds === 1 ? "" : "s"}`;
  }
  const minutes = Math.round(ms / 60_000);
  return `${minutes} minute${minutes === 1 ? "" : "s"}`;
}

let feedTitle: string | null = null;

bot.onMention = async (_session, message) => {
  await message.reply(
    text`I'm watching ${
      link(feedTitle ?? FEED_URL, FEED_URL)
    } and check for new posts every ${formatInterval(POLL_INTERVAL_MS)}.`,
  );
};

feedTitlepoll()이 실행될 때마다 피드 자체의 <title>에서 값을 받아 옵니다(fetchFeed()가 반환한 직후에 feedTitle = feed.title;을 추가하면 됩니다). 그래서 답장은 언제나 봇이 방금 실제로 확인한 내용을 반영할 뿐, 한 번 타이핑해 놓고 갱신되지 않는 이름을 말하지 않습니다. 첫 폴링이 끝나기 전에는 피드의 URL을 대신 출력합니다.

formatInterval()이 존재하는 이유는, POLL_INTERVAL_MS가 테스트 중에는 60000처럼 작을 수도 있고 운영 환경에서는 기본값인 10분일 수도 있어서인데, “매 600000밀리초마다”는 봇이 사람에게 할 만한 말이 아니기 때문입니다.

재시작에도 살아남기

이 버전에는 아직 버그가 하나 남아 있는데, 재시작할 때만 드러납니다. 자주 갱신되는 피드를 감시하던 봇이 피드에 새 글이 올라온 직후, 다음 예약 폴링이 그 글에 닿기 전에 재시작되면, 그 글은 영영 게시되지 않고 실패한 흔적도 전혀 남지 않습니다. firstPollposted 둘 다 프로세스 메모리에만 있던 값이라 재시작하면 초기화되므로, 봇은 바로 다음 폴링을 마치 이전에 한 번도 실행된 적이 없는 것처럼 취급합니다. 그 시점에 피드가 보여 주는 것을 그대로 베이스라인으로 삼아 “이미 본 글” 집합에 편입시켜 버릴 뿐, 그 “새” 글을 게시하는 일은 결코 일어나지 않습니다. 겉으로는 잘 돌아가는 것처럼 보이는 봇이 재시작이나 배포 때마다 조용히 글을 흘리고 있을 수 있는 것입니다.

해법은 봇 자신의 상태와 폴러의 상태를 모두 디스크에 남기는 것입니다. 그것도 하나가 아니라 SQLite 데이터베이스 두 개로 나눠서요.

bot.db는 온전히 @fedify/botkit-sqlite의 몫입니다. 여기에는 BotKit이 액터의 암호화 키, 보낸 액티비티, 그 밖에 Repository가 책임지는 모든 것을 저장합니다. 봇 자신의 코드는 이 안에 무엇이 들었는지 알 필요가 없고, 알려고 해서도 안 됩니다.

app.db는 이 프로젝트 자체의 스키마입니다. 어떤 글을 이미 게시했는지를 담아서, 재시작해도 잊어버리지 않게 합니다.

@fedify/botkit-sqlite를 설치합니다.

Deno

deno add jsr:@fedify/botkit-sqlite

npm

npm add @fedify/botkit-sqlite

pnpm

pnpm add @fedify/botkit-sqlite

Yarn

yarn add @fedify/botkit-sqlite

app.db는 Node.js 내장 모듈인 node:sqlite로 직접 엽니다.

db.ts

// app.db: 피드 폴러 자체의 상태. @fedify/botkit-sqlite의 SqliteRepository가
// 전담하는 bot.db와는 분리되어 있다. 지금은 어떤 피드 항목을 이미 게시했는지만
// 추적해서, 재시작해도 이미 본 것을 잊지 않게 한다.
//
// node:sqlite의 DatabaseSync API는 완전히 동기식이다. 아래 호출 중 어느
// 것도 await가 필요 없고, 붙일 수도 없다.

import { DatabaseSync } from "node:sqlite";

export function openAppDb(path: string): DatabaseSync {
  const db = new DatabaseSync(path);
  db.exec(`
    CREATE TABLE IF NOT EXISTS posted_items (
      item_id TEXT PRIMARY KEY,
      posted_at TEXT NOT NULL
    )
  `);
  // 특정 항목에 관한 것이 아닌 상태를 위한 작은 키-값 테이블. 맨 처음
  // 폴링이 일어났는지 여부는 posted_items에서 추론하는 대신 여기에 둔다.
  // 그렇게 하지 않으면, 첫 폴링 시점에 피드가 마침 비어 있거나 항목들에
  // 쓸 만한 id/url이 없는 경우 베이스라인이 잡혔다는 사실 자체를 영영
  // 기록하지 못하게 된다.
  db.exec(`
    CREATE TABLE IF NOT EXISTS app_meta (
      key TEXT PRIMARY KEY,
      value TEXT NOT NULL
    )
  `);
  return db;
}

export function isBaselined(db: DatabaseSync): boolean {
  return (
    db.prepare("SELECT 1 FROM app_meta WHERE key = 'baselined'").get() != null
  );
}

export function markBaselined(db: DatabaseSync): void {
  db.prepare(
    "INSERT OR IGNORE INTO app_meta (key, value) VALUES ('baselined', '1')",
  ).run();
}

export function isPosted(db: DatabaseSync, itemId: string): boolean {
  return (
    db.prepare("SELECT 1 FROM posted_items WHERE item_id = ?").get(
      itemId,
    ) != null
  );
}

export function markPosted(db: DatabaseSync, itemId: string): void {
  db.prepare(
    "INSERT OR IGNORE INTO posted_items (item_id, posted_at) VALUES (?, ?)",
  ).run(itemId, new Date().toISOString());
}

Note

node:sqlite가 실험적 플래그에서 벗어나기 전 버전의 Node.js(22.13.0과 23.4.0 이전)에서는 시작할 때 ExperimentalWarning: SQLite is an experimental feature라는 줄이 뜹니다. 정상이니 신경 쓰지 않아도 되고, 모듈은 그대로 잘 동작합니다.

isBaselined()posted_items와 별도로 두는 데는 이유가 있습니다. “첫 폴링이 일어났는가”라는 질문의 답을 posted_items의 행 개수로 대신하려 하면 거의 항상은 맞아떨어지지만, 딱 하나 예외가 있습니다. 바로 그 첫 폴링에서 피드가 마침 항목을 하나도 반환하지 않거나, 쓸 만한 id/url이 없는 항목만 반환하는 경우입니다. app_meta는 그 시점에 표시할 수 있었던 항목이 몇 개였는지와 무관하게, “이 이정표에 도달했는가” 자체를 독립적으로 추적합니다.

bot.ts는 이제 두 데이터베이스를 모두 만들고, posted/firstPoll을 영속화된 대응물로 바꿉니다.

bot.ts

// RSS/Atom/RDF 피드를 일정 주기로 폴링하다가 새 글이 올라오면 페디버스에
// 게시하는 봇.
//
// 실행:  deno serve --allow-net --allow-env --allow-read=./data --allow-write=./data --watch bot.ts
//   또는: npx srvx serve --port 8000 --entry ./bot.ts
// 설정:  ORIGIN=https://your-domain
//        FEED_URL=https://example.com/feed.xml (기본값은 Hacker News)
//        POLL_INTERVAL_MS=600000 (기본값은 10분)

import {
  createBot,
  InProcessMessageQueue,
  link,
  MemoryKvStore,
  text,
} from "@fedify/botkit";
import { SqliteRepository } from "@fedify/botkit-sqlite";
import { mkdirSync } from "node:fs";
import { fetchFeed } from "./feed.ts";
import type { FeedItem } from "./feed.ts";
import {
  isBaselined,
  isPosted,
  markBaselined,
  markPosted,
  openAppDb,
} from "./db.ts";

mkdirSync("./data", { recursive: true });

const FEED_URL = process.env.FEED_URL ?? "https://news.ycombinator.com/rss";
const ORIGIN = process.env.ORIGIN ?? "http://localhost:8000";

// POLL_INTERVAL_MS를 환경 변수에서 파싱하고 검증하는 부분은 앞서와 똑같으므로
// 여기서는 생략한다.

const bot = createBot<void>({
  username: "rssbot",
  name: "RSS Bot",
  summary: text`I watch ${link(FEED_URL)} and post new entries here.`,
  kv: new MemoryKvStore(),
  queue: new InProcessMessageQueue(),
  repository: new SqliteRepository({ path: "./data/bot.db" }),
});

const appDb = openAppDb("./data/app.db");

function itemKey(item: FeedItem): string | null {
  return item.id ?? item.url;
}

let feedTitle: string | null = null;

async function poll(): Promise<void> {
  const feed = await fetchFeed(FEED_URL);
  feedTitle = feed.title;
  const items = [...feed.items].reverse(); // 피드는 최신 글이 맨 앞에 온다

  // 이 봇이 태어나서 처음 실행되는 순간 피드의 현재 첫 페이지 전체를
  // 팔로워에게 쏟아붓지 않기 위함이다. 이후 폴링에서 새로 나타나는 글만
  // "새 글"로 친다. 이 값은 app.db에 남기 때문에, 재시작할 때마다가 아니라
  // 통틀어 딱 한 번만 일어난다.
  const isFirstEverPoll = !isBaselined(appDb);

  const session = bot.getSession(ORIGIN);
  let publishedCount = 0;
  for (const item of items) {
    const key = itemKey(item);
    if (key == null || isPosted(appDb, key)) continue;
    if (!isFirstEverPoll) {
      await session.publish(
        text`${item.title ?? "(untitled)"}

${link(item.url ?? FEED_URL)}`,
      );
      publishedCount++;
    }
    markPosted(appDb, key);
  }
  if (isFirstEverPoll) markBaselined(appDb);
  console.log(
    isFirstEverPoll
      ? `Baseline: ${items.length} existing item(s) from ${FEED_URL}.`
      : `Posted ${publishedCount} new item(s) from ${FEED_URL}.`,
  );
}

두 데이터베이스 파일 모두 어딘가 담길 곳이 필요합니다. Deno의 권한 모델을 생각하면 프로젝트 루트에 흩어놓지 않고 전용 디렉터리 하나에 모아 두는 편이 좋습니다. mkdirSync("./data", ...)가 그 디렉터리를 만들어 주므로, 프로세스는 파일시스템 전체가 아니라 이 경로 하나에만 읽기·쓰기 권한을 가지면 됩니다.

이제 더 넓어진 권한으로 봇을 다시 실행합니다.

Deno

deno serve --allow-net --allow-env --allow-read=./data --allow-write=./data --watch bot.ts

Node.js

npx srvx serve --port 8000 --entry ./bot.ts

새 글이 올라온 직후에 예전과 같은 방식으로 재시작해 봅니다. 이번에는 그 글이 베이스라인 속으로 사라지는 대신, 다음 폴링에 그대로 나타납니다.

실제로 공개하기

지금까지 봇은 localhost에서만 동작하면 됐습니다. 다른 페디버스 서버가 이 봇에 닿으려면 공개 주소가 필요합니다.

터널링 서비스를 쓰면 아직 내 서버가 없어도 “공개 주소” 문제의 절반을 해결할 수 있습니다. 이런 서비스들은 봇 앞에서 L7 리버스 프록시처럼 동작하므로, behindProxy를 켜서 이들이 붙이는 X-Forwarded-* 헤더를 신뢰하게 하고, 로컬 개발과 터널링된 실행이 같은 코드를 쓸 수 있도록 환경 변수로 읽어들입니다.

import { createBot } from "@fedify/botkit";

const BEHIND_PROXY = process.env.BEHIND_PROXY?.trim()?.toLowerCase() ===
  "true";

const bot = createBot<void>({
  // 나머지 옵션은 지면상 생략
  behindProxy: BEHIND_PROXY,
});

그다음 터널을 띄웁니다. 이 튜토리얼에서는 fedify tunnel을 쭉 사용하지만, 이미 다른 서비스를 써 왔다면 아래 중 무엇을 써도 같은 방식으로 동작합니다.

fedify tunnel

fedify tunnel 8000

ngrok

ngrok http 8000

Tailscale Funnel

tailscale funnel 8000

Cloudflare Tunnel

cloudflared tunnel --url http://localhost:8000

fedify tunnel은 준비가 끝나면 공개 호스트명을 출력합니다.

✔ Your local server at 8000 is now publicly accessible:

https://c4d3933be87bc2.lhr.life/

Press ^C to close the tunnel.

이번에는 ORIGIN은 그 주소로, BEHIND_PROXYtrue로 맞춰서 봇을 다시 실행합니다.[1]

Deno

ORIGIN=https://c4d3933be87bc2.lhr.life BEHIND_PROXY=true \
  deno serve --allow-net --allow-env --allow-read=./data --allow-write=./data --watch bot.ts

Node.js

ORIGIN=https://c4d3933be87bc2.lhr.life BEHIND_PROXY=true \
  npx srvx serve --port 8000 --entry ./bot.ts

브라우저로 그 주소에 들어가 보면 봇 자신의 프로필 페이지가 나타납니다.

봇의 웹 프로필 페이지. 이름과 핸들, 소개, 그리고 팔로워·게시물 수가 0으로 표시되어 있다

ActivityPub.Academy로 테스트하기

ActivityPub.Academy는 몇 초 만에 임시 Mastodon 계정을 하나 내주는데, 바로 이런 용도, 즉 봇을 팔로우하고 멘션하면서 어떤 답이 돌아오는지 지켜보기에 딱 맞습니다. 계정은 하루 뒤에 지워지므로 테스트가 끝난 뒤 따로 정리할 것도 없습니다.

가입한 다음, 봇의 페디버스 핸들로 검색합니다. @rssbot@c4d3933be87bc2.lhr.life이고, 자신의 터널 호스트명으로 바꿔 넣으면 됩니다.

ActivityPub.Academy에서 봇의 핸들을 검색해서 봇이 검색 결과로 나타난 모습

검색 결과를 열고 Follow를 누릅니다.

오른쪽 위에 Follow 버튼이 있는, ActivityPub.Academy에서 본 봇의 프로필

팔로우한 뒤 같은 프로필. “1 Follower”와 Unfollow 버튼이 보인다

그다음 멘션합니다.

Hey @rssbot@c4d3933be87bc2.lhr.life, what are you up to?

답장은 몇 초 안에 도착합니다.

멘션과 봇의 답장을 보여 주는 스레드: “I'm watching Hacker News and check for new posts every 2 minutes.”

다음번에 봇의 폴링이 정말로 새로운 글을 잡아내면, 다른 여느 게시물과 마찬가지로 타임라인에 나타납니다.

ActivityPub.Academy의 홈 타임라인. 앞서의 멘션 답장 위에 봇이 새로 게시한 글이 보인다

봇 여럿, 인스턴스 하나

피드 하나로 아이디어는 확인했습니다. 하지만 FEED_URL 하나를 하드코딩하는 방식으로는 여러 피드를 동시에 돌리거나, 재배포 없이 피드를 추가하거나, 갈수록 시끄러워지는 타임라인 하나를 다 같이 쓰는 대신 피드마다 자기만의 페디버스 정체성을 갖게 하기는 어렵습니다. Instance는 바로 이럴 때를 위해 BotKit이 마련해 둔 조각입니다. 서버 하나가 여러 봇을 호스팅하되, 각 봇은 저마다 액터와 팔로워, 인박스를 가지면서도 같은 키-값 스토어, 큐, 리포지토리를 밑에서 함께 씁니다.

createBot()이 사라지는 것은 아닙니다. 딱 하나의 액터로만 존재하면 되는 봇이라면 굳이 바꿀 이유가 없습니다. 이제부터는 rssbot을, 등록된 피드마다 봇 하나씩을 호스팅하는 인스턴스로 바꾸고, 여기에 누군가 URL과 함께 멘션했을 때 피드를 추가하는 일만 하는 작은 등록 담당 봇을 하나 더합니다.

순진한 식별자, 그리고 그것이 깨지는 이유

피드별 봇은 저마다 자기만의 식별자가 필요합니다. 봇이 페디버스에 연합되는 순간 액터 URI에 새겨지는 내부 이름 말이죠. 가장 먼저 떠오르는 생각은 피드 자체에서, 이를테면 호스트명에서 하나를 뽑아내는 것입니다. https://xkcd.com/rss.xmlxkcd-com으로 바꾸는 식으로요. 이 문자열은 마침 사용자명으로도 나쁘지 않습니다. 사람이 봇을 찾으려고 실제로 입력하는, @xkcd-com@your-domain의 사람이 읽을 수 있는 절반이니까요.

문제는 이걸 둘 다에 쓰려는 데서 생깁니다. 식별자는 봇이 한 번 연합되고 나면 영원히 고정돼 있어야 합니다. 원격 서버들이 캐시해 둔 액터 URI 안에 그 식별자를 그대로 담고 있어서, 나중에 바꾸면 모든 팔로워 관계와 다른 서버가 들고 있는 모든 참조가 고아가 돼 버립니다. 그런데 피드의 호스트명에는 그런 종류의 영속성이 없습니다. 사이트는 옮겨 다닙니다. 블로그가 도메인을 하나에서 다른 곳으로 옮기고도 여전히 같은 피드, 같은 팔로워를 가진 같은 피드일 수 있는데, 이미 옛 식별자를 갖고 있는 모든 이를 깨뜨리지 않으면서 식별자만 새 이름에 맞게 바꿀 방법은 없습니다. 사용자명으로는 더할 나위 없이 좋은 성질, 즉 기억하기 쉽고 봇의 실체와 맞닿아 있다는 성질이야말로, 식별자로는 나쁜 선택이 되게 만드는 바로 그 성질입니다.

해법은 이 둘을 떼어 놓는 것입니다. 식별자는 등록 시점에 한 번 배정되고 두 번 다시 손대지 않는, 의미 없는 문자열입니다. 슬러그는 피드의 URL에서 뽑아낸 것으로, 언제든 다시 계산해도 되고, “사람이 이 봇을 찾으려고 뭐라고 입력하는가”라는 질문에만 쓰일 뿐 “이 봇의 액터 URI에는 무엇이 들어 있는가”라는 질문에는 결코 쓰이지 않습니다.

feeds 테이블

app.db는 이 구분을 담을 feeds 테이블을 새로 얻고, posted_items는 봇 하나의 이력을 추적하는 대신 피드별로 범위가 좁혀집니다.

db.ts

// app.db: 피드 폴러 자체의 상태. @fedify/botkit-sqlite의 SqliteRepository가
// 전담하는 bot.db와는 분리되어 있다.
//
// node:sqlite의 DatabaseSync API는 완전히 동기식이다. 아래 호출 중 어느
// 것도 await가 필요 없고, 붙일 수도 없다.
//
// 피드의 identifier는 의미 없이 고정된 키다. 한 번 연합되고 나면 액터 URI에
// 새겨지므로, (피드의 URL이나 제목처럼) 바뀔 수 있는 것으로부터는 절대
// 유도해서는 안 된다. slug는 핸들에서 사람이 읽는 부분으로, mapUsername을
// 거쳐 identifier와 서로 오간다.

import { DatabaseSync } from "node:sqlite";

export interface FeedRow {
  readonly identifier: string;
  readonly url: string;
  readonly slug: string;
  readonly title: string | null;
  readonly baselined: boolean;
}

function toFeedRow(row: Record<string, unknown>): FeedRow {
  return {
    identifier: row.identifier as string,
    url: row.url as string,
    slug: row.slug as string,
    title: row.title as string | null,
    baselined: (row.baselined as number) !== 0,
  };
}

export function openAppDb(path: string): DatabaseSync {
  const db = new DatabaseSync(path);
  db.exec(`
    CREATE TABLE IF NOT EXISTS feeds (
      identifier TEXT PRIMARY KEY,
      url TEXT NOT NULL UNIQUE,
      slug TEXT NOT NULL UNIQUE,
      title TEXT,
      baselined INTEGER NOT NULL DEFAULT 0,
      created_at TEXT NOT NULL
    )
  `);
  migrateLegacyPostedItems(db);
  db.exec(`
    CREATE TABLE IF NOT EXISTS posted_items (
      feed_identifier TEXT NOT NULL,
      item_id TEXT NOT NULL,
      posted_at TEXT NOT NULL,
      PRIMARY KEY (feed_identifier, item_id)
    )
  `);
  return db;
}

// 1부의 app.db에는 posted_items(item_id, posted_at)만 있었고, 어느 피드에
// 속한 항목인지 하는 개념 자체가 없었다. 피드가 하나뿐이었으니 당연했다.
// openAppDb()의 CREATE TABLE IF NOT EXISTS가 옛 테이블을 그대로 놔둘 것이므로,
// 그 행들을 (그 글을 게시했을 수 있는 유일한 식별자인) "bot" 식별자 아래로
// 옮겨서 이어받는다.
function migrateLegacyPostedItems(db: DatabaseSync): void {
  const columns = db.prepare("PRAGMA table_info(posted_items)").all() as {
    readonly name: string;
  }[];
  const isLegacy = columns.length > 0 &&
    !columns.some((column) => column.name === "feed_identifier");
  if (!isLegacy) return;
  db.exec("ALTER TABLE posted_items RENAME TO posted_items_legacy");
  db.exec(`
    CREATE TABLE posted_items (
      feed_identifier TEXT NOT NULL,
      item_id TEXT NOT NULL,
      posted_at TEXT NOT NULL,
      PRIMARY KEY (feed_identifier, item_id)
    )
  `);
  db.exec(`
    INSERT INTO posted_items (feed_identifier, item_id, posted_at)
    SELECT 'bot', item_id, posted_at FROM posted_items_legacy
  `);
  db.exec("DROP TABLE posted_items_legacy");
}

function slugify(url: string): string {
  return new URL(url).hostname.toLowerCase().replace(/\./g, "-");
}

export function getFeedByIdentifier(
  db: DatabaseSync,
  identifier: string,
): FeedRow | undefined {
  const row = db.prepare("SELECT * FROM feeds WHERE identifier = ?").get(
    identifier,
  );
  return row == null ? undefined : toFeedRow(row);
}

export function getFeedBySlug(
  db: DatabaseSync,
  slug: string,
): FeedRow | undefined {
  const row = db.prepare("SELECT * FROM feeds WHERE slug = ?").get(slug);
  return row == null ? undefined : toFeedRow(row);
}

export function getFeedByUrl(
  db: DatabaseSync,
  url: string,
): FeedRow | undefined {
  const row = db.prepare("SELECT * FROM feeds WHERE url = ?").get(url);
  return row == null ? undefined : toFeedRow(row);
}

export function listFeeds(db: DatabaseSync): readonly FeedRow[] {
  const rows = db.prepare("SELECT * FROM feeds").all();
  return rows.map(toFeedRow);
}

// 기존 단일 봇 배포의 피드를 시작 시점에 딱 한 번 이 테이블의 행으로
// 이어받는 데 쓴다. identifier가 기본 키이므로 첫 실행 이후로는 매번 아무
// 일도 하지 않는다.
export function seedFeed(
  db: DatabaseSync,
  feed: { identifier: string; url: string; slug: string },
): void {
  db.prepare(
    "INSERT OR IGNORE INTO feeds (identifier, url, slug, created_at) VALUES (?, ?, ?, ?)",
  ).run(feed.identifier, feed.url, feed.slug, new Date().toISOString());
  migrateLegacyBaselined(db, feed.identifier);
}

// 1부의 app.db는 "첫 폴링이 일어났는가"를 별도의 app_meta 테이블에
// 추적했다. 물어볼 대상이 하나뿐이었으니 그럴 만했다. 이 피드의 행이
// (바로 위에서) 생기고 나면 그 플래그를 이 행으로 옮기고 app_meta는
// 지운다. app_meta가 더 이상 확인할 대상이 아니게 되는 첫 실행 이후로는
// 매번 아무 일도 하지 않는다.
function migrateLegacyBaselined(db: DatabaseSync, identifier: string): void {
  const hasAppMeta = db.prepare(
    "SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'app_meta'",
  ).get() != null;
  if (!hasAppMeta) return;
  const wasBaselined = db.prepare(
    "SELECT 1 FROM app_meta WHERE key = 'baselined'",
  ).get() != null;
  if (wasBaselined) markFeedBaselined(db, identifier);
  db.exec("DROP TABLE app_meta");
}

// 새로 멘션된 피드 URL을 새로운, 의미 없는 식별자로 등록한다. 식별자는
// URL이나 제목처럼 나중에 바뀔 수 있는 것으로부터는 절대 유도하지 않는다.
// slug(사람이 읽는 핸들)는 유도하며, 이미 쓰이고 있는 것과 충돌하면 숫자
// 접미사를 붙인다.
export function addFeed(db: DatabaseSync, url: string): FeedRow {
  const baseSlug = slugify(url);
  let slug = baseSlug;
  for (let suffix = 2; getFeedBySlug(db, slug) != null; suffix++) {
    slug = `${baseSlug}-${suffix}`;
  }
  const identifier = `feed_${
    crypto.randomUUID().replace(/-/g, "").slice(0, 12)
  }`;
  db.prepare(
    "INSERT INTO feeds (identifier, url, slug, created_at) VALUES (?, ?, ?, ?)",
  ).run(identifier, url, slug, new Date().toISOString());
  return { identifier, url, slug, title: null, baselined: false };
}

export function updateFeedTitle(
  db: DatabaseSync,
  identifier: string,
  title: string,
): void {
  db.prepare("UPDATE feeds SET title = ? WHERE identifier = ?").run(
    title,
    identifier,
  );
}

export function markFeedBaselined(db: DatabaseSync, identifier: string): void {
  db.prepare("UPDATE feeds SET baselined = 1 WHERE identifier = ?").run(
    identifier,
  );
}

export function isPosted(
  db: DatabaseSync,
  feedIdentifier: string,
  itemId: string,
): boolean {
  return (
    db.prepare(
      "SELECT 1 FROM posted_items WHERE feed_identifier = ? AND item_id = ?",
    ).get(feedIdentifier, itemId) != null
  );
}

export function markPosted(
  db: DatabaseSync,
  feedIdentifier: string,
  itemId: string,
): void {
  db.prepare(
    "INSERT OR IGNORE INTO posted_items (feed_identifier, item_id, posted_at) VALUES (?, ?, ?)",
  ).run(feedIdentifier, itemId, new Date().toISOString());
}

identifierslug 둘 다 UNIQUE 제약을 갖지만, 충돌 시 다시 계산해서 재시도하는 것은 slug뿐입니다. identifieraddFeed()가 한 번 생성하면 그대로 놔둡니다. baselined는 1부에서는 별도의 app_meta 테이블에 있으면서 앱 전체가 폴링을 한 번이라도 한 적 있는지를 추적했지만, 이제 첫 폴링 여부가 앱 전체가 아니라 특정 피드 하나에 관한 사실이 되면서 feeds의 평범한 칼럼 하나로 합쳐집니다.

slugify()는 피드 호스트명을 소문자로 바꾸고 점을 하이픈으로 바꿉니다. news.ycombinator.comnews-ycombinator-com이 됩니다. 그리고 그 슬러그가 이미 쓰이고 있으면 addFeed()가 숫자 접미사(-2, -3, …)를 붙입니다. 반면 identifiercrypto.randomUUID()에서 생성한, feed_로 시작하는 짧은 무작위 문자열로, 피드에 관한 그 무엇으로부터도 유도되지 않습니다.

위의 두 migrateLegacy* 함수가 존재하는 이유는, 1부에서 쓰던 기존 app.db에는 여전히 옛 posted_items(item_id, posted_at) 테이블과 별도의 app_meta 키-값 테이블이 있고, CREATE TABLE IF NOT EXISTS는 이 둘 중 어느 것도 건드리지 않기 때문입니다. 이미 존재하는 테이블은 그냥 그대로 두므로, 옛 posted_items는 이 파일의 나머지 부분이 기대하는 feed_identifier 칼럼이 없는 채로 남고, isPosted()를 처음 호출하는 순간 no such column: feed_identifier로 실패하고 말 것입니다. migrateLegacyPostedItems()openAppDb()가 뭔가를 만들기 전에 그 모양을 확인해서 발견하면 마이그레이션하고, migrateLegacyBaselined()app_meta의 baselined 플래그에 대해 같은 일을 하되, 그 플래그가 속할 피드 행이 실제로 존재하게 된 다음 seedFeed()에서 호출됩니다. 둘 다 실행 전에 옛 모양인지부터 확인하므로, 기존 app.db가 아예 없는 새 설치라면 그냥 건너뛰고, 이미 마이그레이션된 것이라면 그 이후 실행마다 건너뜁니다. posted_items에는 이미 feed_identifier가 있고, app_meta는 이미 사라졌으니까요.

봇에서 인스턴스로

bot.ts는 이제 봇 하나가 아니라 여럿을 호스팅하므로 instance.ts가 됩니다.

instance.ts

import {
  createInstance,
  InProcessMessageQueue,
  MemoryKvStore,
} from "@fedify/botkit";
import { SqliteRepository } from "@fedify/botkit-sqlite";
import { mkdirSync } from "node:fs";
import { openAppDb, seedFeed } from "./db.ts";

// FEED_URL, BEHIND_PROXY는 앞서와 같은 방식으로 환경 변수에서 읽어 온다.
// 여기서는 생략한다.

mkdirSync("./data", { recursive: true });

const instance = createInstance<void>({
  kv: new MemoryKvStore(),
  queue: new InProcessMessageQueue(),
  repository: new SqliteRepository({ path: "./data/bot.db" }),
  behindProxy: BEHIND_PROXY,
  // 1부의 봇은 identifier를 명시적으로 지정한 적이 없으므로, createBot()이
  // 기본값으로 "bot"을 붙였다. "rssbot"은 어디까지나 사용자명이었을 뿐이다.
  // (아래의 legacyObjectUris가 아니라) 바로 이 identifier를 그대로 재사용하는
  // 것이 액터의 URI와 키, 팔로워 관계를 그대로 지켜 주는 열쇠다.
  // legacyObjectUris는 원격 서버가 이 봇이 인스턴스로 옮겨 오기 전부터
  // 캐시해 두고 있을 수 있는, 개별 오브젝트(게시물, 팔로우) URI의 *옛*
  // 형식만 다시 써 준다.
  legacyObjectUris: { identifier: "bot" },
});

const appDb = openAppDb("./data/app.db");

// 원래 피드를 봇의 실제(기본) identifier와 기존 사용자명 그대로 여기 행으로
// 이어받는다. 그래서 이 피드는 이제부터 등록되는 다른 모든 피드와 똑같은
// 동적 봇 그룹이 처리한다. 첫 실행 이후로는 아무 일도 하지 않는다.
seedFeed(appDb, { identifier: "bot", url: FEED_URL, slug: "rssbot" });

createInstance()createBot()이 쓰던 것과 같은 인프라 옵션들, 즉 kv, queue, repository, behindProxy를 그대로 받습니다. 새로 등장한 것은 legacyObjectUris입니다. 1부의 rssbotidentifier 옵션을 명시적으로 지정한 적이 없으므로 createBot()이 기본값으로 "bot"을 붙였습니다. "rssbot"은 어디까지나 사용자명이었을 뿐입니다. legacyObjectUris가 아니라 바로 이 같은 identifier를 재사용하는 것이, 이제 서버에 봇 하나만 있는 게 아니라 여럿 중 하나가 된 지금도 원래 봇의 액터 URI와 암호화 키, 팔로워 관계를 온전히 지켜 주는 열쇠입니다. legacyObjectUris는 좀 더 좁은 범위, 즉 createInstance()로 옮기기 전에 게시된 개별 오브젝트 URI(게시물과 팔로우)의 형식을 다룹니다. 원격 서버가 여전히 그 형식을 캐시하고 있다가 나중에 AcceptLike로 돌려보낼 수 있기 때문입니다.

seedFeed()는 이 같은 봇을 평범한 행 하나로 이어받습니다. 같은 identifier, 같은 URL, 슬러그로는 같은 사용자명을 씁니다. INSERT OR IGNORE이므로 첫 실행 이후로는 매번 아무 일도 하지 않고, 이제부터 원래 봇은 나중에 등록되는 어떤 피드와도 똑같은 동적 봇 그룹이 처리하며, 다른 어디에도 별도의 특수 처리는 없습니다.

이게 가능하려면 미리 이뤄져야 할 마이그레이션이 있는데, 이 코드 자체가 하는 일은 아닙니다. BotKit은 이미 createBot() 배포의 리포지토리 데이터를 createInstance()가 기대하는 구조로 마이그레이션해 주지만, 그 배포가 createBot() 아래에서 BotKit 0.5.0 이상으로 처음 실행될 때 딱 한 번만 그렇습니다. 여기까지 왔다면 1부의 봇은 그저 실행된 것만으로 이미 그 과정을 마쳤을 것입니다. 만약 0.5.0에서 아예 실행된 적이 없는 배포를 옮기는 중이라면, 먼저 createBot()으로 한 번 실행하거나 리포지토리의 migrate() 메서드를 직접 호출하세요. 자세한 내용은 단일 봇 배포 마이그레이션하기를 참고하세요. createInstance()로 바꾸기 전후로 액터의 URI에 fedify lookup을 직접 돌려 보는 것도 해 볼 만합니다. 공개 키와 WebFinger 핸들이 완전히 똑같이 나와야 합니다.

인스턴스 하나에 피드 여럿

// 동적 봇 그룹: feeds 테이블의 행 하나마다 봇 하나씩을, 필요할 때마다
// 해석한다. 피드가 추가될 때마다 명령형으로 createBot()을 호출하는 대신,
// "피드마다 봇 하나"를 사전에 한 번의 등록으로 바꿔 주는 것이 바로 이
// 부분이다. 아래의 registryBot.onMention을 참고할 것.
const feedBots = instance.createBot(
  (_ctx, identifier) => {
    const feed = getFeedByIdentifier(appDb, identifier);
    if (feed == null) return null;
    return { username: feed.slug, name: feed.title ?? feed.url };
  },
  {
    mapUsername(_ctx, username) {
      const feed = getFeedBySlug(appDb, username);
      return feed?.identifier ?? null;
    },
  },
);

feedBots.onMention = async (session, message) => {
  const feed = getFeedByIdentifier(appDb, session.bot.identifier);
  if (feed == null) return;
  await message.reply(
    text`I'm watching ${
      link(feed.title ?? feed.url, feed.url)
    } and check for new posts every ${formatInterval(POLL_INTERVAL_MS)}.`,
  );
};

instance.createBot()에 고정된 식별자 대신 함수를 넘기면 BotGroup이 만들어집니다. 사전에 선언해 두는 대신 필요할 때마다 해석되는 봇들의 집합인데, BotKit 자체 문서에서 지역별 날씨 봇을 만들 때 쓰는 것과 같은 동적 봇 패턴입니다. 여기 디스패처가 하는 일도 같은 종류의 조회입니다. 식별자가 주어지면 feeds에서 대응하는 행을 찾고, 없으면 null을 반환해서 BotKit에게 이 식별자는 애초에 피드 봇이 아니라고 알려 줍니다. mapUsername은 그 반대 방향으로, identifier가 아니라 slug로 같은 조회를 수행합니다. 그래서 @xkcd-com@your-domain과, 무작위로 생성된 feed_a1b2c3d4e5f6을 식별자로 가진 액터가 양쪽 방향 모두에서 같은 봇으로 해석됩니다.

BotGroup은 자기만의 단일한 식별자를 갖지 않으므로, 이를 통해 게시하려면 어느 봇인지 말해 줘야 합니다. 1부에서 쓰던 bot.getSession(origin) 대신 feedBots.getSession(origin, identifier)를 씁니다. 폴링은 feeds의 모든 행을 돌면서, 피드마다 정확히 그렇게 한 번씩 합니다.

const FETCH_TIMEOUT_MS = 30_000;

async function pollFeed(feed: FeedRow): Promise<void> {
  const parsed = await fetchFeed(
    feed.url,
    AbortSignal.timeout(FETCH_TIMEOUT_MS),
  );
  if (parsed.title != null && parsed.title !== feed.title) {
    updateFeedTitle(appDb, feed.identifier, parsed.title);
  }
  const items = [...parsed.items].reverse(); // 피드는 최신 글이 맨 앞에 온다

  // 이 피드가 처음 폴링되는 순간 현재 첫 페이지 전체를 팔로워에게
  // 쏟아붓지 않기 위함이다. 이후 폴링에서 새로 나타나는 글만 "새 글"로 친다.
  const isFirstEverPoll = !feed.baselined;

  const session = await feedBots.getSession(ORIGIN, feed.identifier);
  let publishedCount = 0;
  for (const item of items) {
    const key = itemKey(item);
    if (key == null || isPosted(appDb, feed.identifier, key)) continue;
    if (!isFirstEverPoll) {
      await session.publish(
        text`${item.title ?? "(untitled)"}

${link(item.url ?? feed.url)}`,
      );
      publishedCount++;
    }
    markPosted(appDb, feed.identifier, key);
  }
  if (isFirstEverPoll) markFeedBaselined(appDb, feed.identifier);
  console.log(
    isFirstEverPoll
      ? `Baseline: ${items.length} existing item(s) from ${feed.url}.`
      : `Posted ${publishedCount} new item(s) from ${feed.url}.`,
  );
}

async function pollAll(): Promise<void> {
  for (const feed of listFeeds(appDb)) {
    try {
      await pollFeed(feed);
    } catch (error) {
      console.error(`Failed to poll feed ${feed.url}:`, error);
    }
  }
}

여기서는 식별자와 “이미 게시했음” 상태가 어디서 오는지를 빼면 1부의 폴링 로직과 다를 게 없습니다. 바깥 스코프에서 붙잡아 온 변수 대신 feed.identifier를 쓰고, 하나로 공유하던 Set 대신 그 identifier로 범위를 좁힌 isPosted/markPosted를 쓰고, fetchFeed()에 명시적인 AbortSignal.timeout()을 건다는 점이 다를 뿐입니다.

pollAll()은 피드를 하나씩 순서대로 기다리고, pollAllOnce()polling 가드 덕분에 현재 주기가 끝나기 전까지는 어떤 나중 틱도 새 주기를 시작할 수 없습니다.

이 타임아웃이 없다면, 연결은 받아 놓고 응답은 영영 하지 않는 서버 하나 때문에 그 서버가 물려 있는 피드뿐 아니라 인스턴스의 모든 피드가 영원히 멈춰 버릴 것입니다. 타임아웃이 있으면 이는 그저 평범한 피드별 실패, 이를테면 요청 시간 초과나 피드가 갑자기 이상한 XML을 반환하는 것과 다를 바 없어지고, pollAll()try/catch가 이를 똑같은 방식으로 처리합니다. 로그를 남기고 다음 피드로 넘어가는 식으로요.

멘션으로 피드 등록하기

지금까지 그룹에 봇을 하나 더한다는 것은 결국 feeds에 행을 하나 넣는다는 뜻이었습니다. feedBots의 디스패처는 그 테이블에 나타나는 식별자라면 무엇이든, 시작할 때부터 있던 것이든 방금 삽입된 것이든 상관없이 이미 알아서 해석해 주므로, 일단 피드가 등록되고 나면 instance.createBot()을 다시 호출할 필요가 전혀 없습니다. 바로 이것이 정적 봇 그룹 대신 동적 봇 그룹을 쓰는 이유입니다. 등록이 배포가 아니라 데이터베이스 쓰기 한 번으로 끝나는 것 말이죠.

작은 정적 봇 registry가 그 쓰기를 위한 대문 역할을 합니다.

function extractUrl(input: string): string | null {
  const match = input.match(/https?:\/\/\S+/)?.[0];
  return match != null && URL.canParse(match) ? match : null;
}

// 정적 봇: 등록 창구. 피드 URL과 함께 이 봇을 멘션하면 feeds 테이블에
// 행이 하나 추가된다. feedBots의 디스패처는 그 새 행을, 다음번에 그
// identifier가 해석될 때 알아서 집어 든다.
//
// 이 코드는 누가 멘션을 보냈는지 확인하지 않고, 아래의 폴링 루프가 가져오기
// 전에 그 URL을 검증하지도 않는다. 실제 배포에 필요한 것은 튜토리얼의
// "더 해볼 만한 것들" 절을 참고할 것.
const registryBot = instance.createBot("registry", {
  username: "registry",
  name: "Feed Registry",
  summary: text`Mention me with a feed URL to register a new feed bot.`,
});

registryBot.onMention = async (_session, message) => {
  const url = extractUrl(message.text);
  if (url == null) {
    await message.reply(text`Please include a feed URL in your mention.`);
    return;
  }
  const existing = getFeedByUrl(appDb, url);
  if (existing != null) {
    await message.reply(
      text`Already watching that feed: ${
        mention(`@${existing.slug}@${new URL(ORIGIN).host}`)
      }.`,
    );
    return;
  }
  const feed = addFeed(appDb, url);
  await message.reply(
    text`Registered! Give it a few minutes, then look for ${
      mention(`@${feed.slug}@${new URL(ORIGIN).host}`)
    }.`,
  );
};

extractUrl()은 멘션 텍스트 안에서 URL처럼 생기고 URL.canParse()를 통과하는 첫 번째 것을 찾습니다. 잘린 http://%처럼 형식이 잘못된 것은 걸러 내는데, 그렇지 않으면 addFeed()new URL() 호출까지 그대로 흘러 들어가 예외를 던지게 됩니다. 이미 감시 중인 URL을 등록하려 하면 feeds.urlUNIQUE 제약에 부딪혀 죽는 대신 답장으로 알려 줍니다.

두 답장 모두 새 봇의 핸들을 mention()으로 만들지, 템플릿에 그대로 끼워 넣은 평범한 @${slug}@${host} 문자열로 만들지 않습니다. 평범한 텍스트로 적은 핸들은 그냥 텍스트일 뿐입니다. 링크로 렌더링되지도 않고, mention()이 붙여 주는 Mention 태그가 없으니 실제 멘션처럼 동작하지도 않습니다. mention()은 사람이 검색하듯 그 핸들을 실제로 찾아보고, 그 조회가 실패할 때만 평범한 텍스트로 물러나므로, 새 봇의 액터를 어쩌다 아직 해석할 수 없는 상황이라도 답장이 깨지는 대신 우아하게 낮은 수준으로 대응합니다.

registryBot.onMention이 하지 않는 일도 있습니다. 누가 묻고 있는지 확인하지 않고, pollFeed()에 곧 넘길 그 URL이 실제로 가져오기에 안전한 곳을 가리키는지도 확인하지 않습니다. 둘 다 의도적으로 남겨 둔 빈틈이고, 둘 다 여기가 아니라 아래 더 해볼 만한 것들에서 다룹니다.

두 런타임에서 인스턴스 검증하기

1부의 첫 실행과 같은 모양입니다. 다만 이제 단일 봇이 아니라 인스턴스를 호스팅하는 파일을 대상으로 합니다.

Deno

deno serve --allow-net --allow-env --allow-read=./data --allow-write=./data --watch instance.ts

Node.js

npx srvx serve --port 8000 --entry ./instance.ts

앞서와 같은 방식으로 터널을 열고, ActivityPub.Academy의 계정에서 피드 URL과 함께 등록 봇을 멘션합니다. 스킴을 포함한 전체 URL을 그대로 입력하세요. extractUrl()http://https:// 링크만 매칭하는데, Mastodon은 자동 링크된 URL을 보여 줄 때 스킴을 감춰서 표시하므로, 아래에는 스킴이 보이지 않는 것입니다.

Hey @registry, please watch https://xkcd.com/rss.xml

등록 봇에 대한 멘션과 그 답장: “Registered! Give it a few minutes, then look for @xkcd-com@…”

답장의 핸들은 mention()으로 만들어졌으므로, 그 답장을 이루는 실제 Note 객체에는 제대로 된 Mention 태그가 붙어 있고, 새 봇에게 직접 주소가 지정되어 있습니다. 그럴듯하게 보이도록 형식만 갖춘 게 아니라요. 위 스크린샷에서 ActivityPub.Academy는 이를 클릭 가능한 링크로 렌더링하지 않지만, 그 밑에 있는 데이터 자체는 정확합니다. 등록 봇 자신의 웹 페이지는 같은 답장을, 링크가 온전히 살아 있는 채로 보여 줍니다.

등록 봇 자신의 프로필 페이지. 새 봇의 핸들이 동작하는 링크로 렌더링된 같은 “Registered!” 게시물이 보인다

1~2분 뒤, 새 봇이 자기 슬러그로 나타납니다. 이 봇과 이관된 원래 봇을 둘 다 팔로우해 보면, 이 둘이 서로의 별칭이 아니라 진짜로 별개인 액터임을 확인할 수 있습니다.

세 개의 별개 봇을 보여 주는 어느 계정의 팔로잉 목록: rssbot 핸들로 이관된 원래 봇, 새로 등록된 xkcd.com 피드, 그리고 별도의 Node.js 실행에서 나온 세 번째 봇

새 봇을 직접 멘션하면, 등록 봇이 아니라 feedBots.onMention이 답합니다.

새 피드 봇에 대한 멘션과 그 답장: “I'm watching xkcd.com and check for new posts every 2 minutes.”

여기까지의 모든 과정은 Node.js에서도 똑같이 동작합니다. instance.ts를 두 번째 호스트명 뒤에서 터널링하고, 같은 방식으로 피드를 등록하면 같은 핸들이 WebFinger를 통해 그대로 해석됩니다.

서버에 배포하기

터미널이 아니라 프로세스 매니저 아래에서 instance.ts를 실행하는 것은 직접 호스팅하기의 systemd·Caddy 구성을 거의 그대로 따릅니다. 런타임 설치, botkit 사용자 만들기, Caddy 설정, 서비스 활성화까지 전체 과정은 그 문서에 있습니다. 이 봇에 특유한 것 두 가지만 짚고 넘어가면 되는데, 둘 다 examples/rss-bot/deploy/의 systemd 유닛과 Caddyfile에 이미 반영되어 있습니다.

ExecStart는 이 튜토리얼에서 쭉 써 온 것과 같은, 범위를 좁힌 Deno 권한(--allow-net --allow-env --allow-read=./data --allow-write=./data)을 쓰지, 직접 호스팅하기의 범용 -A를 쓰지 않습니다. 그리고 ProtectSystem=strictReadWritePaths에 나열되지 않은 한 작업 디렉터리 전체를 읽기 전용으로 만들어 버리는데, 이 봇은 bot.dbapp.db./data 아래에 쓰므로 유닛에 다음을 추가합니다.

ReadWritePaths=/opt/botkit/data

그 경로는 서비스가 시작되기 전에 botkit 사용자 소유로 이미 존재해야 합니다.

sudo mkdir -p /opt/botkit/data
sudo chown botkit:botkit /opt/botkit/data

직접 호스팅하기 자체의 mkdir -p /opt/botkit 단계 바로 다음에 실행하면 됩니다. 이걸 건너뛰면 유닛은 아예 시작조차 하지 못하고 종료 코드 226/NAMESPACE를 냅니다. systemd는 이미 존재하는 ReadWritePaths 항목만 허용 목록에 올리기 때문입니다.

Node.js에서는 이번에는 srvxnpx를 통해서만 실행되는 게 아니라, 실제로 봇의 의존성과 함께 배포돼야 합니다. package.json에 일반 의존성으로 들어 있으므로, npm ci(또는 배포를 빌드한 패키지 매니저에 맞는 대응 명령)가 ExecStart가 호출하는 바로 그 바이너리인 /opt/botkit/node_modules/.bin/srvx를 설치해 줍니다.

Caddyfile은 그 밖의 나머지 부분에서 직접 호스팅하기를 그대로 따릅니다. ACME 연락처 이메일을 이용한 자동 HTTPS, localhost:8000으로의 리버스 프록시, 그리고 같은 기본 보안 헤더까지요.

더 해볼 만한 것들

아래 내용은 *examples/rss-bot/*에는 구현되어 있지 않습니다. 실제 배포라면 대체로 아래 순서로 손보게 될 만한 것들입니다.

  • 피드가 알려 주는 갱신 힌트: RSS의 선택 사항인 <ttl> 엘리먼트Syndication 모듈<sy:updatePeriod>, <sy:updateFrequency>, <sy:updateBase>는 모두 피드가 봇이 모든 피드에 똑같이 POLL_INTERVAL_MS를 추측해 적용하는 대신, 스스로 폴링 주기를 제안할 수 있게 해 줍니다. Atom에는 이에 대응하는 표준이 없습니다.
  • HTTP 조건부 요청: 매 폴링마다 If-Modified-SinceIf-None-Match를 함께 보내고 304 Not Modified 응답을 처리하면, 전혀 바뀌지 않은 피드를 다시 파싱하는 일을 건너뛸 수 있습니다.
  • WebSub: <atom:link rel="hub" href="…">를 광고하는 피드라면, setInterval() 대신 웹훅으로 폴링을 기다리는 게 아니라 갱신을 직접 밀어 넣을 수 있습니다.
  • 피드를 등록할 수 있는 사람의 허용 목록: 지금은 URL이 담긴 멘션이 등록 봇에게 오기만 하면 누구든 그 URL을 등록할 수 있습니다.
  • 멘션된 URL을 가져오기 전에 검증하기: registryBot.onMentionextractUrl()이 찾은 것을 그대로 pollFeed()fetch() 호출로 넘길 뿐, localhost나 내부 주소를 가리키는 것을 막을 장치가 전혀 없습니다. @fedify/vocab-runtimevalidatePublicUrl()이 정확히 이런 용도로 존재하니, 처음부터 새로 짤 필요는 없습니다.

  1. 호스트명은 사용하는 터널링 서비스에 따라 실제로는 다르게 나옵니다. ↩︎

@botkit@hackers.pub

Note

이 글은 BotKit의 공식 튜토리얼 Building an RSS bot(영문)을 한국어로 옮긴 것입니다. 원문은 계속 업데이트되므로, 최신 내용은 위 링크에서 확인하는 편이 좋습니다.

BotKit시작하기 안내서를 따라 하면 몇 분 만에 봇을 띄울 수 있습니다. 다만 그 봇은 인사말에 답할 뿐, 딱히 감시할 대상은 없습니다. 이 튜토리얼은 거기서 한 걸음 더 나아갑니다. RSS나 Atom, RDF 피드를 주시하다가 새 글이 올라오면 페디버스에 게시하는 봇을 만듭니다. 그 과정에서 예약 작업, 상태 저장, 멘션에 답장하기를 다루고, 나중에는 피드가 하나에서 여럿으로 늘어났을 때 필요해지는 createInstance()와 동적 봇 그룹까지 짚어 봅니다.

1부에서는 피드 하나를 감시하는 봇 하나를 만듭니다. 2부에서는 그 봇을 인스턴스로 바꿔서, 인스턴스를 멘션하며 피드 URL을 알려주는 것만으로 피드별 봇을 하나씩 등록할 수 있게 합니다. 각 부의 마지막에는 봇을 공개 인터넷에 노출시키고, ActivityPub.Academy에서 실제 Mastodon 계정으로 팔로우하고 멘션하고 지켜보며 테스트합니다.

이 튜토리얼은 시작하기를 이미 읽었다는 전제로 진행하므로, createBot()이나 Text를 처음부터 다시 설명하지는 않습니다. 완성된 프로젝트는 BotKit 저장소의 examples/rss-bot/에서도 볼 수 있습니다.

봇 하나로 시작하기

프로젝트 준비하기

새 디렉터리를 만들고, BotKit과 함께 피드의 원본 XML을 평범한 객체로 바꿔 줄 @rowanmanning/feed-parser를 설치합니다.

Deno

mkdir rss-bot && cd rss-bot
deno add jsr:@fedify/botkit npm:@rowanmanning/feed-parser

npm

mkdir rss-bot && cd rss-bot
npm init -y
npm add @fedify/botkit @rowanmanning/feed-parser

pnpm

mkdir rss-bot && cd rss-bot
pnpm init
pnpm add @fedify/botkit @rowanmanning/feed-parser

Yarn

mkdir rss-bot && cd rss-bot
yarn init -y
yarn add @fedify/botkit @rowanmanning/feed-parser

피드 가져오고 파싱하기

@rowanmanning/feed-parser는 RSS 0.9x, RSS 2.0, RDF Site Summary 1.0(RSS 1.0), Atom 0.3/1.0 피드를 모두 같은 parseFeed() 함수, 같은 Feed/FeedItem 형태로 파싱해 줍니다. 덕분에 봇 코드 쪽에서는 지금 이 피드가 어떤 포맷인지 굳이 분기할 필요가 없습니다.

parseFeed()가 하지 않는 일도 있습니다. 바로 가져오기(fetch)입니다. 이 함수는 이미 손에 쥔 XML 문자열을 객체로 바꿔 줄 뿐, 그 문자열을 어떻게 구할지는 호출하는 쪽의 몫입니다. 봇 코드도 이 구분을 그대로 따라서, 가져오기를 전담하는 feed.ts 모듈을 두고, 이를 어떤 주기로 폴링할지는 별도로 다룹니다.

feed.ts

// 피드(RSS, Atom, RDF)를 가져오고 파싱한다. 가져오기는 이 모듈의 일이고,
// 파싱은 전적으로 @rowanmanning/feed-parser의 일이다. 이 라이브러리는 피드를
// 그저 XML 문자열로만 볼 뿐, 그 문자열이 어떻게 조달됐는지는 신경 쓰지 않는다.

import { parseFeed } from "@rowanmanning/feed-parser";

// @rowanmanning/feed-parser의 공개 엔트리포인트는 parseFeed 함수만 내보낼 뿐
// 반환값인 Feed/FeedItem 타입은 내보내지 않는다. 그래서 패키지 내부 경로를
// 직접 뒤지는 대신, 함수의 반환 타입에서 역으로 타입을 끌어온다.
export type Feed = ReturnType<typeof parseFeed>;
export type FeedItem = Feed["items"][number];

export async function fetchFeed(
  url: string | URL,
  signal?: AbortSignal,
): Promise<Feed> {
  const response = await fetch(url, { signal });
  if (!response.ok) {
    throw new Error(
      `Failed to fetch feed: ${response.status} ${response.statusText}`,
    );
  }
  return parseFeed(await response.text());
}

맨 위의 타입 유도 코드는 자잘한 우회로입니다. @rowanmanning/feed-parser 패키지는 parseFeed 함수만 내보낼 뿐 그 함수가 반환하는 Feed, FeedItem 클래스는 내보내지 않으므로, type { Feed }를 패키지에서 직접 가져오려 하면 실패합니다. ReturnType<typeof parseFeed>는 타입을 직접 이름 붙여 가져오는 대신, 함수 시그니처로부터 TypeScript가 스스로 타입을 유추하게 만들어 이 문제를 피해 갑니다.

폴링하고 게시하기

봇 자체는 단순하게 시작합니다. 봇을 만들고, 일정 주기로 피드를 폴링하고, 새로 올라온 글을 게시하는 것뿐입니다. 식별자를 비롯한 나머지 설정은 시작하기에서 본 패턴을 그대로 따르는데, 다만 여기서 쓰는 kv 스토어와 queue는 로컬 개발용 인메모리 구현입니다. 재시작이 문제가 되는 시점에 다른 것으로 교체할 예정입니다.

bot.ts

// RSS/Atom/RDF 피드를 일정 주기로 폴링하다가 새 글이 올라오면 페디버스에
// 게시하는 봇.
//
// 실행:  deno serve --allow-net --allow-env --watch bot.ts
//   또는: npx srvx serve --port 8000 --entry ./bot.ts
// 설정:  ORIGIN=https://your-domain
//        FEED_URL=https://example.com/feed.xml (기본값은 Hacker News)
//        POLL_INTERVAL_MS=600000 (기본값은 10분)

import {
  createBot,
  InProcessMessageQueue,
  link,
  MemoryKvStore,
  text,
} from "@fedify/botkit";
import { fetchFeed } from "./feed.ts";
import type { FeedItem } from "./feed.ts";

const FEED_URL = process.env.FEED_URL ?? "https://news.ycombinator.com/rss";
const ORIGIN = process.env.ORIGIN ?? "http://localhost:8000";

const rawPollIntervalMs = process.env.POLL_INTERVAL_MS;
const POLL_INTERVAL_MS = rawPollIntervalMs == null || rawPollIntervalMs === ""
  ? 1000 * 60 * 10
  : Number(rawPollIntervalMs);
if (!Number.isFinite(POLL_INTERVAL_MS) || POLL_INTERVAL_MS <= 0) {
  throw new RangeError(
    `POLL_INTERVAL_MS must be a positive number of milliseconds: ${rawPollIntervalMs}`,
  );
}

const bot = createBot<void>({
  username: "rssbot",
  name: "RSS Bot",
  summary: text`I watch ${link(FEED_URL)} and post new entries here.`,
  kv: new MemoryKvStore(),
  queue: new InProcessMessageQueue(),
});

function itemKey(item: FeedItem): string | null {
  return item.id ?? item.url;
}

const posted = new Set<string>();
let firstPoll = true;

async function poll(): Promise<void> {
  const feed = await fetchFeed(FEED_URL);
  const items = [...feed.items].reverse(); // 피드는 최신 글이 맨 앞에 온다

  if (firstPoll) {
    // 봇을 맨 처음 띄운 순간 피드에 이미 올라와 있던 글 전부를 팔로워에게
    // 쏟아붓지 않기 위함이다. 이후 폴링에서 새로 나타나는 글만 "새 글"로 친다.
    firstPoll = false;
    for (const item of items) {
      const key = itemKey(item);
      if (key != null) posted.add(key);
    }
    console.log(`Baseline: ${posted.size} existing item(s) from ${FEED_URL}.`);
    return;
  }

  const session = bot.getSession(ORIGIN);
  let publishedCount = 0;
  for (const item of items) {
    const key = itemKey(item);
    if (key == null || posted.has(key)) continue;
    await session.publish(
      text`${item.title ?? "(untitled)"}

${link(item.url ?? FEED_URL)}`,
    );
    posted.add(key);
    publishedCount++;
  }
  console.log(`Posted ${publishedCount} new item(s) from ${FEED_URL}.`);
}

let polling = false;

async function pollOnce(): Promise<void> {
  if (polling) return; // 이전 폴링이 아직 진행 중이면 건너뛴다
  polling = true;
  try {
    await poll();
  } catch (error) {
    console.error("Failed to poll feed:", error);
  } finally {
    polling = false;
  }
}

pollOnce();
setInterval(pollOnce, POLL_INTERVAL_MS);

export default bot;

맨 처음 폴링에서는 피드에 이미 올라와 있던 글을 기록만 할 뿐, 게시하지는 않습니다. 이 처리가 없다면 봇을 처음 실행하는 순간 피드의 현재 첫 페이지 전체가 팔로워들에게 쏟아지는데, 이는 “새 글”이 뜻해야 할 바가 전혀 아닙니다. 다음 폴링에서 새로 나타나는 글만 새 글로 칩니다.

pollOnce()는 실제 폴링 로직을 polling 플래그로 감쌉니다. 느린 요청이 다음 예약 틱과 겹치지 않도록 하기 위해서입니다. setInterval()은 콜백이 끝나기를 기다리지 않고 다음 호출을 예약하므로, 이 방어 장치가 없으면 POLL_INTERVAL_MS보다 오래 걸리는 피드 요청 때문에 폴링 두 개가 동시에 돌면서 같은 글을 중복 게시할 수 있습니다.

POLL_INTERVAL_MS는 시작 시점에 한 번 파싱하고, 유한한 양수인지 검사합니다. 값이 비어 있거나 잘못돼서 그대로 setInterval(fn, NaN)으로 흘러 들어가면 에러도 나지 않고, 그냥 이벤트 루프의 거의 매 틱마다 실행되며 피드를 두들겨 댑니다. 실행 시점에 요란하게 실패하는 편이, 실행 중에 조용히 잘못되는 것보다 낫습니다.

FEED_URL의 기본값은 Hacker News의 첫 페이지 피드입니다. RSS든 Atom이든 RDF든 어떤 피드를 써도 되지만, 테스트하는 동안에는 자주 갱신되는 피드를 쓰는 편이 좋습니다. 봇이 실제로 뭔가 게시하는 모습을 보려고 오래 기다릴 필요가 없기 때문입니다.

봇 실행하기

시작하기에서와 마찬가지로 봇을 기본 내보내기(default export)로 내보내고 실행합니다.

Deno

deno serve --allow-net --allow-env --watch bot.ts

Node.js

npx srvx serve --port 8000 --entry ./bot.ts

콘솔에는 몇 초 안에 베이스라인 개수가 찍히고, 이후 POLL_INTERVAL_MS가 지나면 Posted 0 new item(s)가 뜨거나, 그사이 피드에 뭔가 새로 올라왔다면 실제로 글이 하나 게시됩니다. 10분을 기다리지 않고 바로 게시되는 모습을 보고 싶다면 지금은 주기를 짧게 잡아 봅니다.

POLL_INTERVAL_MS=60000 deno serve --allow-net --allow-env --watch bot.ts

Tip

fedify lookup은 URL이나 핸들로 임의의 액터나 오브젝트를 조회해서 ActivityPub 표현을 출력해 줍니다. 여기서 fedify lookup http://localhost:8000/ap/actor/bot을 실행해 보면, 더 나아가기 전에 봇의 액터 문서가 제대로 나오는지 빠르게 확인할 수 있습니다.

멘션에 답장하기

게시만 하고 응답은 전혀 하지 않는 봇은, 잘 돌아가고 있어도 죽은 것처럼 느껴집니다. onMention은 봇에게 할 말을 만들어 줍니다. 지금 어떤 피드를 보고 있는지, 얼마나 자주 확인하는지 같은 것들 말이죠.

bot.ts

function formatInterval(ms: number): string {
  if (ms < 60_000) {
    const seconds = Math.round(ms / 1000);
    return `${seconds} second${seconds === 1 ? "" : "s"}`;
  }
  const minutes = Math.round(ms / 60_000);
  return `${minutes} minute${minutes === 1 ? "" : "s"}`;
}

let feedTitle: string | null = null;

bot.onMention = async (_session, message) => {
  await message.reply(
    text`I'm watching ${
      link(feedTitle ?? FEED_URL, FEED_URL)
    } and check for new posts every ${formatInterval(POLL_INTERVAL_MS)}.`,
  );
};

feedTitlepoll()이 실행될 때마다 피드 자체의 <title>에서 값을 받아 옵니다(fetchFeed()가 반환한 직후에 feedTitle = feed.title;을 추가하면 됩니다). 그래서 답장은 언제나 봇이 방금 실제로 확인한 내용을 반영할 뿐, 한 번 타이핑해 놓고 갱신되지 않는 이름을 말하지 않습니다. 첫 폴링이 끝나기 전에는 피드의 URL을 대신 출력합니다.

formatInterval()이 존재하는 이유는, POLL_INTERVAL_MS가 테스트 중에는 60000처럼 작을 수도 있고 운영 환경에서는 기본값인 10분일 수도 있어서인데, “매 600000밀리초마다”는 봇이 사람에게 할 만한 말이 아니기 때문입니다.

재시작에도 살아남기

이 버전에는 아직 버그가 하나 남아 있는데, 재시작할 때만 드러납니다. 자주 갱신되는 피드를 감시하던 봇이 피드에 새 글이 올라온 직후, 다음 예약 폴링이 그 글에 닿기 전에 재시작되면, 그 글은 영영 게시되지 않고 실패한 흔적도 전혀 남지 않습니다. firstPollposted 둘 다 프로세스 메모리에만 있던 값이라 재시작하면 초기화되므로, 봇은 바로 다음 폴링을 마치 이전에 한 번도 실행된 적이 없는 것처럼 취급합니다. 그 시점에 피드가 보여 주는 것을 그대로 베이스라인으로 삼아 “이미 본 글” 집합에 편입시켜 버릴 뿐, 그 “새” 글을 게시하는 일은 결코 일어나지 않습니다. 겉으로는 잘 돌아가는 것처럼 보이는 봇이 재시작이나 배포 때마다 조용히 글을 흘리고 있을 수 있는 것입니다.

해법은 봇 자신의 상태와 폴러의 상태를 모두 디스크에 남기는 것입니다. 그것도 하나가 아니라 SQLite 데이터베이스 두 개로 나눠서요.

bot.db는 온전히 @fedify/botkit-sqlite의 몫입니다. 여기에는 BotKit이 액터의 암호화 키, 보낸 액티비티, 그 밖에 Repository가 책임지는 모든 것을 저장합니다. 봇 자신의 코드는 이 안에 무엇이 들었는지 알 필요가 없고, 알려고 해서도 안 됩니다.

app.db는 이 프로젝트 자체의 스키마입니다. 어떤 글을 이미 게시했는지를 담아서, 재시작해도 잊어버리지 않게 합니다.

@fedify/botkit-sqlite를 설치합니다.

Deno

deno add jsr:@fedify/botkit-sqlite

npm

npm add @fedify/botkit-sqlite

pnpm

pnpm add @fedify/botkit-sqlite

Yarn

yarn add @fedify/botkit-sqlite

app.db는 Node.js 내장 모듈인 node:sqlite로 직접 엽니다.

db.ts

// app.db: 피드 폴러 자체의 상태. @fedify/botkit-sqlite의 SqliteRepository가
// 전담하는 bot.db와는 분리되어 있다. 지금은 어떤 피드 항목을 이미 게시했는지만
// 추적해서, 재시작해도 이미 본 것을 잊지 않게 한다.
//
// node:sqlite의 DatabaseSync API는 완전히 동기식이다. 아래 호출 중 어느
// 것도 await가 필요 없고, 붙일 수도 없다.

import { DatabaseSync } from "node:sqlite";

export function openAppDb(path: string): DatabaseSync {
  const db = new DatabaseSync(path);
  db.exec(`
    CREATE TABLE IF NOT EXISTS posted_items (
      item_id TEXT PRIMARY KEY,
      posted_at TEXT NOT NULL
    )
  `);
  // 특정 항목에 관한 것이 아닌 상태를 위한 작은 키-값 테이블. 맨 처음
  // 폴링이 일어났는지 여부는 posted_items에서 추론하는 대신 여기에 둔다.
  // 그렇게 하지 않으면, 첫 폴링 시점에 피드가 마침 비어 있거나 항목들에
  // 쓸 만한 id/url이 없는 경우 베이스라인이 잡혔다는 사실 자체를 영영
  // 기록하지 못하게 된다.
  db.exec(`
    CREATE TABLE IF NOT EXISTS app_meta (
      key TEXT PRIMARY KEY,
      value TEXT NOT NULL
    )
  `);
  return db;
}

export function isBaselined(db: DatabaseSync): boolean {
  return (
    db.prepare("SELECT 1 FROM app_meta WHERE key = 'baselined'").get() != null
  );
}

export function markBaselined(db: DatabaseSync): void {
  db.prepare(
    "INSERT OR IGNORE INTO app_meta (key, value) VALUES ('baselined', '1')",
  ).run();
}

export function isPosted(db: DatabaseSync, itemId: string): boolean {
  return (
    db.prepare("SELECT 1 FROM posted_items WHERE item_id = ?").get(
      itemId,
    ) != null
  );
}

export function markPosted(db: DatabaseSync, itemId: string): void {
  db.prepare(
    "INSERT OR IGNORE INTO posted_items (item_id, posted_at) VALUES (?, ?)",
  ).run(itemId, new Date().toISOString());
}

Note

node:sqlite가 실험적 플래그에서 벗어나기 전 버전의 Node.js(22.13.0과 23.4.0 이전)에서는 시작할 때 ExperimentalWarning: SQLite is an experimental feature라는 줄이 뜹니다. 정상이니 신경 쓰지 않아도 되고, 모듈은 그대로 잘 동작합니다.

isBaselined()posted_items와 별도로 두는 데는 이유가 있습니다. “첫 폴링이 일어났는가”라는 질문의 답을 posted_items의 행 개수로 대신하려 하면 거의 항상은 맞아떨어지지만, 딱 하나 예외가 있습니다. 바로 그 첫 폴링에서 피드가 마침 항목을 하나도 반환하지 않거나, 쓸 만한 id/url이 없는 항목만 반환하는 경우입니다. app_meta는 그 시점에 표시할 수 있었던 항목이 몇 개였는지와 무관하게, “이 이정표에 도달했는가” 자체를 독립적으로 추적합니다.

bot.ts는 이제 두 데이터베이스를 모두 만들고, posted/firstPoll을 영속화된 대응물로 바꿉니다.

bot.ts

// RSS/Atom/RDF 피드를 일정 주기로 폴링하다가 새 글이 올라오면 페디버스에
// 게시하는 봇.
//
// 실행:  deno serve --allow-net --allow-env --allow-read=./data --allow-write=./data --watch bot.ts
//   또는: npx srvx serve --port 8000 --entry ./bot.ts
// 설정:  ORIGIN=https://your-domain
//        FEED_URL=https://example.com/feed.xml (기본값은 Hacker News)
//        POLL_INTERVAL_MS=600000 (기본값은 10분)

import {
  createBot,
  InProcessMessageQueue,
  link,
  MemoryKvStore,
  text,
} from "@fedify/botkit";
import { SqliteRepository } from "@fedify/botkit-sqlite";
import { mkdirSync } from "node:fs";
import { fetchFeed } from "./feed.ts";
import type { FeedItem } from "./feed.ts";
import {
  isBaselined,
  isPosted,
  markBaselined,
  markPosted,
  openAppDb,
} from "./db.ts";

mkdirSync("./data", { recursive: true });

const FEED_URL = process.env.FEED_URL ?? "https://news.ycombinator.com/rss";
const ORIGIN = process.env.ORIGIN ?? "http://localhost:8000";

// POLL_INTERVAL_MS를 환경 변수에서 파싱하고 검증하는 부분은 앞서와 똑같으므로
// 여기서는 생략한다.

const bot = createBot<void>({
  username: "rssbot",
  name: "RSS Bot",
  summary: text`I watch ${link(FEED_URL)} and post new entries here.`,
  kv: new MemoryKvStore(),
  queue: new InProcessMessageQueue(),
  repository: new SqliteRepository({ path: "./data/bot.db" }),
});

const appDb = openAppDb("./data/app.db");

function itemKey(item: FeedItem): string | null {
  return item.id ?? item.url;
}

let feedTitle: string | null = null;

async function poll(): Promise<void> {
  const feed = await fetchFeed(FEED_URL);
  feedTitle = feed.title;
  const items = [...feed.items].reverse(); // 피드는 최신 글이 맨 앞에 온다

  // 이 봇이 태어나서 처음 실행되는 순간 피드의 현재 첫 페이지 전체를
  // 팔로워에게 쏟아붓지 않기 위함이다. 이후 폴링에서 새로 나타나는 글만
  // "새 글"로 친다. 이 값은 app.db에 남기 때문에, 재시작할 때마다가 아니라
  // 통틀어 딱 한 번만 일어난다.
  const isFirstEverPoll = !isBaselined(appDb);

  const session = bot.getSession(ORIGIN);
  let publishedCount = 0;
  for (const item of items) {
    const key = itemKey(item);
    if (key == null || isPosted(appDb, key)) continue;
    if (!isFirstEverPoll) {
      await session.publish(
        text`${item.title ?? "(untitled)"}

${link(item.url ?? FEED_URL)}`,
      );
      publishedCount++;
    }
    markPosted(appDb, key);
  }
  if (isFirstEverPoll) markBaselined(appDb);
  console.log(
    isFirstEverPoll
      ? `Baseline: ${items.length} existing item(s) from ${FEED_URL}.`
      : `Posted ${publishedCount} new item(s) from ${FEED_URL}.`,
  );
}

두 데이터베이스 파일 모두 어딘가 담길 곳이 필요합니다. Deno의 권한 모델을 생각하면 프로젝트 루트에 흩어놓지 않고 전용 디렉터리 하나에 모아 두는 편이 좋습니다. mkdirSync("./data", ...)가 그 디렉터리를 만들어 주므로, 프로세스는 파일시스템 전체가 아니라 이 경로 하나에만 읽기·쓰기 권한을 가지면 됩니다.

이제 더 넓어진 권한으로 봇을 다시 실행합니다.

Deno

deno serve --allow-net --allow-env --allow-read=./data --allow-write=./data --watch bot.ts

Node.js

npx srvx serve --port 8000 --entry ./bot.ts

새 글이 올라온 직후에 예전과 같은 방식으로 재시작해 봅니다. 이번에는 그 글이 베이스라인 속으로 사라지는 대신, 다음 폴링에 그대로 나타납니다.

실제로 공개하기

지금까지 봇은 localhost에서만 동작하면 됐습니다. 다른 페디버스 서버가 이 봇에 닿으려면 공개 주소가 필요합니다.

터널링 서비스를 쓰면 아직 내 서버가 없어도 “공개 주소” 문제의 절반을 해결할 수 있습니다. 이런 서비스들은 봇 앞에서 L7 리버스 프록시처럼 동작하므로, behindProxy를 켜서 이들이 붙이는 X-Forwarded-* 헤더를 신뢰하게 하고, 로컬 개발과 터널링된 실행이 같은 코드를 쓸 수 있도록 환경 변수로 읽어들입니다.

import { createBot } from "@fedify/botkit";

const BEHIND_PROXY = process.env.BEHIND_PROXY?.trim()?.toLowerCase() ===
  "true";

const bot = createBot<void>({
  // 나머지 옵션은 지면상 생략
  behindProxy: BEHIND_PROXY,
});

그다음 터널을 띄웁니다. 이 튜토리얼에서는 fedify tunnel을 쭉 사용하지만, 이미 다른 서비스를 써 왔다면 아래 중 무엇을 써도 같은 방식으로 동작합니다.

fedify tunnel

fedify tunnel 8000

ngrok

ngrok http 8000

Tailscale Funnel

tailscale funnel 8000

Cloudflare Tunnel

cloudflared tunnel --url http://localhost:8000

fedify tunnel은 준비가 끝나면 공개 호스트명을 출력합니다.

✔ Your local server at 8000 is now publicly accessible:

https://c4d3933be87bc2.lhr.life/

Press ^C to close the tunnel.

이번에는 ORIGIN은 그 주소로, BEHIND_PROXYtrue로 맞춰서 봇을 다시 실행합니다.[1]

Deno

ORIGIN=https://c4d3933be87bc2.lhr.life BEHIND_PROXY=true \
  deno serve --allow-net --allow-env --allow-read=./data --allow-write=./data --watch bot.ts

Node.js

ORIGIN=https://c4d3933be87bc2.lhr.life BEHIND_PROXY=true \
  npx srvx serve --port 8000 --entry ./bot.ts

브라우저로 그 주소에 들어가 보면 봇 자신의 프로필 페이지가 나타납니다.

봇의 웹 프로필 페이지. 이름과 핸들, 소개, 그리고 팔로워·게시물 수가 0으로 표시되어 있다

ActivityPub.Academy로 테스트하기

ActivityPub.Academy는 몇 초 만에 임시 Mastodon 계정을 하나 내주는데, 바로 이런 용도, 즉 봇을 팔로우하고 멘션하면서 어떤 답이 돌아오는지 지켜보기에 딱 맞습니다. 계정은 하루 뒤에 지워지므로 테스트가 끝난 뒤 따로 정리할 것도 없습니다.

가입한 다음, 봇의 페디버스 핸들로 검색합니다. @rssbot@c4d3933be87bc2.lhr.life이고, 자신의 터널 호스트명으로 바꿔 넣으면 됩니다.

ActivityPub.Academy에서 봇의 핸들을 검색해서 봇이 검색 결과로 나타난 모습

검색 결과를 열고 Follow를 누릅니다.

오른쪽 위에 Follow 버튼이 있는, ActivityPub.Academy에서 본 봇의 프로필

팔로우한 뒤 같은 프로필. “1 Follower”와 Unfollow 버튼이 보인다

그다음 멘션합니다.

Hey @rssbot@c4d3933be87bc2.lhr.life, what are you up to?

답장은 몇 초 안에 도착합니다.

멘션과 봇의 답장을 보여 주는 스레드: “I'm watching Hacker News and check for new posts every 2 minutes.”

다음번에 봇의 폴링이 정말로 새로운 글을 잡아내면, 다른 여느 게시물과 마찬가지로 타임라인에 나타납니다.

ActivityPub.Academy의 홈 타임라인. 앞서의 멘션 답장 위에 봇이 새로 게시한 글이 보인다

봇 여럿, 인스턴스 하나

피드 하나로 아이디어는 확인했습니다. 하지만 FEED_URL 하나를 하드코딩하는 방식으로는 여러 피드를 동시에 돌리거나, 재배포 없이 피드를 추가하거나, 갈수록 시끄러워지는 타임라인 하나를 다 같이 쓰는 대신 피드마다 자기만의 페디버스 정체성을 갖게 하기는 어렵습니다. Instance는 바로 이럴 때를 위해 BotKit이 마련해 둔 조각입니다. 서버 하나가 여러 봇을 호스팅하되, 각 봇은 저마다 액터와 팔로워, 인박스를 가지면서도 같은 키-값 스토어, 큐, 리포지토리를 밑에서 함께 씁니다.

createBot()이 사라지는 것은 아닙니다. 딱 하나의 액터로만 존재하면 되는 봇이라면 굳이 바꿀 이유가 없습니다. 이제부터는 rssbot을, 등록된 피드마다 봇 하나씩을 호스팅하는 인스턴스로 바꾸고, 여기에 누군가 URL과 함께 멘션했을 때 피드를 추가하는 일만 하는 작은 등록 담당 봇을 하나 더합니다.

순진한 식별자, 그리고 그것이 깨지는 이유

피드별 봇은 저마다 자기만의 식별자가 필요합니다. 봇이 페디버스에 연합되는 순간 액터 URI에 새겨지는 내부 이름 말이죠. 가장 먼저 떠오르는 생각은 피드 자체에서, 이를테면 호스트명에서 하나를 뽑아내는 것입니다. https://xkcd.com/rss.xmlxkcd-com으로 바꾸는 식으로요. 이 문자열은 마침 사용자명으로도 나쁘지 않습니다. 사람이 봇을 찾으려고 실제로 입력하는, @xkcd-com@your-domain의 사람이 읽을 수 있는 절반이니까요.

문제는 이걸 둘 다에 쓰려는 데서 생깁니다. 식별자는 봇이 한 번 연합되고 나면 영원히 고정돼 있어야 합니다. 원격 서버들이 캐시해 둔 액터 URI 안에 그 식별자를 그대로 담고 있어서, 나중에 바꾸면 모든 팔로워 관계와 다른 서버가 들고 있는 모든 참조가 고아가 돼 버립니다. 그런데 피드의 호스트명에는 그런 종류의 영속성이 없습니다. 사이트는 옮겨 다닙니다. 블로그가 도메인을 하나에서 다른 곳으로 옮기고도 여전히 같은 피드, 같은 팔로워를 가진 같은 피드일 수 있는데, 이미 옛 식별자를 갖고 있는 모든 이를 깨뜨리지 않으면서 식별자만 새 이름에 맞게 바꿀 방법은 없습니다. 사용자명으로는 더할 나위 없이 좋은 성질, 즉 기억하기 쉽고 봇의 실체와 맞닿아 있다는 성질이야말로, 식별자로는 나쁜 선택이 되게 만드는 바로 그 성질입니다.

해법은 이 둘을 떼어 놓는 것입니다. 식별자는 등록 시점에 한 번 배정되고 두 번 다시 손대지 않는, 의미 없는 문자열입니다. 슬러그는 피드의 URL에서 뽑아낸 것으로, 언제든 다시 계산해도 되고, “사람이 이 봇을 찾으려고 뭐라고 입력하는가”라는 질문에만 쓰일 뿐 “이 봇의 액터 URI에는 무엇이 들어 있는가”라는 질문에는 결코 쓰이지 않습니다.

feeds 테이블

app.db는 이 구분을 담을 feeds 테이블을 새로 얻고, posted_items는 봇 하나의 이력을 추적하는 대신 피드별로 범위가 좁혀집니다.

db.ts

// app.db: 피드 폴러 자체의 상태. @fedify/botkit-sqlite의 SqliteRepository가
// 전담하는 bot.db와는 분리되어 있다.
//
// node:sqlite의 DatabaseSync API는 완전히 동기식이다. 아래 호출 중 어느
// 것도 await가 필요 없고, 붙일 수도 없다.
//
// 피드의 identifier는 의미 없이 고정된 키다. 한 번 연합되고 나면 액터 URI에
// 새겨지므로, (피드의 URL이나 제목처럼) 바뀔 수 있는 것으로부터는 절대
// 유도해서는 안 된다. slug는 핸들에서 사람이 읽는 부분으로, mapUsername을
// 거쳐 identifier와 서로 오간다.

import { DatabaseSync } from "node:sqlite";

export interface FeedRow {
  readonly identifier: string;
  readonly url: string;
  readonly slug: string;
  readonly title: string | null;
  readonly baselined: boolean;
}

function toFeedRow(row: Record<string, unknown>): FeedRow {
  return {
    identifier: row.identifier as string,
    url: row.url as string,
    slug: row.slug as string,
    title: row.title as string | null,
    baselined: (row.baselined as number) !== 0,
  };
}

export function openAppDb(path: string): DatabaseSync {
  const db = new DatabaseSync(path);
  db.exec(`
    CREATE TABLE IF NOT EXISTS feeds (
      identifier TEXT PRIMARY KEY,
      url TEXT NOT NULL UNIQUE,
      slug TEXT NOT NULL UNIQUE,
      title TEXT,
      baselined INTEGER NOT NULL DEFAULT 0,
      created_at TEXT NOT NULL
    )
  `);
  migrateLegacyPostedItems(db);
  db.exec(`
    CREATE TABLE IF NOT EXISTS posted_items (
      feed_identifier TEXT NOT NULL,
      item_id TEXT NOT NULL,
      posted_at TEXT NOT NULL,
      PRIMARY KEY (feed_identifier, item_id)
    )
  `);
  return db;
}

// 1부의 app.db에는 posted_items(item_id, posted_at)만 있었고, 어느 피드에
// 속한 항목인지 하는 개념 자체가 없었다. 피드가 하나뿐이었으니 당연했다.
// openAppDb()의 CREATE TABLE IF NOT EXISTS가 옛 테이블을 그대로 놔둘 것이므로,
// 그 행들을 (그 글을 게시했을 수 있는 유일한 식별자인) "bot" 식별자 아래로
// 옮겨서 이어받는다.
function migrateLegacyPostedItems(db: DatabaseSync): void {
  const columns = db.prepare("PRAGMA table_info(posted_items)").all() as {
    readonly name: string;
  }[];
  const isLegacy = columns.length > 0 &&
    !columns.some((column) => column.name === "feed_identifier");
  if (!isLegacy) return;
  db.exec("ALTER TABLE posted_items RENAME TO posted_items_legacy");
  db.exec(`
    CREATE TABLE posted_items (
      feed_identifier TEXT NOT NULL,
      item_id TEXT NOT NULL,
      posted_at TEXT NOT NULL,
      PRIMARY KEY (feed_identifier, item_id)
    )
  `);
  db.exec(`
    INSERT INTO posted_items (feed_identifier, item_id, posted_at)
    SELECT 'bot', item_id, posted_at FROM posted_items_legacy
  `);
  db.exec("DROP TABLE posted_items_legacy");
}

function slugify(url: string): string {
  return new URL(url).hostname.toLowerCase().replace(/\./g, "-");
}

export function getFeedByIdentifier(
  db: DatabaseSync,
  identifier: string,
): FeedRow | undefined {
  const row = db.prepare("SELECT * FROM feeds WHERE identifier = ?").get(
    identifier,
  );
  return row == null ? undefined : toFeedRow(row);
}

export function getFeedBySlug(
  db: DatabaseSync,
  slug: string,
): FeedRow | undefined {
  const row = db.prepare("SELECT * FROM feeds WHERE slug = ?").get(slug);
  return row == null ? undefined : toFeedRow(row);
}

export function getFeedByUrl(
  db: DatabaseSync,
  url: string,
): FeedRow | undefined {
  const row = db.prepare("SELECT * FROM feeds WHERE url = ?").get(url);
  return row == null ? undefined : toFeedRow(row);
}

export function listFeeds(db: DatabaseSync): readonly FeedRow[] {
  const rows = db.prepare("SELECT * FROM feeds").all();
  return rows.map(toFeedRow);
}

// 기존 단일 봇 배포의 피드를 시작 시점에 딱 한 번 이 테이블의 행으로
// 이어받는 데 쓴다. identifier가 기본 키이므로 첫 실행 이후로는 매번 아무
// 일도 하지 않는다.
export function seedFeed(
  db: DatabaseSync,
  feed: { identifier: string; url: string; slug: string },
): void {
  db.prepare(
    "INSERT OR IGNORE INTO feeds (identifier, url, slug, created_at) VALUES (?, ?, ?, ?)",
  ).run(feed.identifier, feed.url, feed.slug, new Date().toISOString());
  migrateLegacyBaselined(db, feed.identifier);
}

// 1부의 app.db는 "첫 폴링이 일어났는가"를 별도의 app_meta 테이블에
// 추적했다. 물어볼 대상이 하나뿐이었으니 그럴 만했다. 이 피드의 행이
// (바로 위에서) 생기고 나면 그 플래그를 이 행으로 옮기고 app_meta는
// 지운다. app_meta가 더 이상 확인할 대상이 아니게 되는 첫 실행 이후로는
// 매번 아무 일도 하지 않는다.
function migrateLegacyBaselined(db: DatabaseSync, identifier: string): void {
  const hasAppMeta = db.prepare(
    "SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'app_meta'",
  ).get() != null;
  if (!hasAppMeta) return;
  const wasBaselined = db.prepare(
    "SELECT 1 FROM app_meta WHERE key = 'baselined'",
  ).get() != null;
  if (wasBaselined) markFeedBaselined(db, identifier);
  db.exec("DROP TABLE app_meta");
}

// 새로 멘션된 피드 URL을 새로운, 의미 없는 식별자로 등록한다. 식별자는
// URL이나 제목처럼 나중에 바뀔 수 있는 것으로부터는 절대 유도하지 않는다.
// slug(사람이 읽는 핸들)는 유도하며, 이미 쓰이고 있는 것과 충돌하면 숫자
// 접미사를 붙인다.
export function addFeed(db: DatabaseSync, url: string): FeedRow {
  const baseSlug = slugify(url);
  let slug = baseSlug;
  for (let suffix = 2; getFeedBySlug(db, slug) != null; suffix++) {
    slug = `${baseSlug}-${suffix}`;
  }
  const identifier = `feed_${
    crypto.randomUUID().replace(/-/g, "").slice(0, 12)
  }`;
  db.prepare(
    "INSERT INTO feeds (identifier, url, slug, created_at) VALUES (?, ?, ?, ?)",
  ).run(identifier, url, slug, new Date().toISOString());
  return { identifier, url, slug, title: null, baselined: false };
}

export function updateFeedTitle(
  db: DatabaseSync,
  identifier: string,
  title: string,
): void {
  db.prepare("UPDATE feeds SET title = ? WHERE identifier = ?").run(
    title,
    identifier,
  );
}

export function markFeedBaselined(db: DatabaseSync, identifier: string): void {
  db.prepare("UPDATE feeds SET baselined = 1 WHERE identifier = ?").run(
    identifier,
  );
}

export function isPosted(
  db: DatabaseSync,
  feedIdentifier: string,
  itemId: string,
): boolean {
  return (
    db.prepare(
      "SELECT 1 FROM posted_items WHERE feed_identifier = ? AND item_id = ?",
    ).get(feedIdentifier, itemId) != null
  );
}

export function markPosted(
  db: DatabaseSync,
  feedIdentifier: string,
  itemId: string,
): void {
  db.prepare(
    "INSERT OR IGNORE INTO posted_items (feed_identifier, item_id, posted_at) VALUES (?, ?, ?)",
  ).run(feedIdentifier, itemId, new Date().toISOString());
}

identifierslug 둘 다 UNIQUE 제약을 갖지만, 충돌 시 다시 계산해서 재시도하는 것은 slug뿐입니다. identifieraddFeed()가 한 번 생성하면 그대로 놔둡니다. baselined는 1부에서는 별도의 app_meta 테이블에 있으면서 앱 전체가 폴링을 한 번이라도 한 적 있는지를 추적했지만, 이제 첫 폴링 여부가 앱 전체가 아니라 특정 피드 하나에 관한 사실이 되면서 feeds의 평범한 칼럼 하나로 합쳐집니다.

slugify()는 피드 호스트명을 소문자로 바꾸고 점을 하이픈으로 바꿉니다. news.ycombinator.comnews-ycombinator-com이 됩니다. 그리고 그 슬러그가 이미 쓰이고 있으면 addFeed()가 숫자 접미사(-2, -3, …)를 붙입니다. 반면 identifiercrypto.randomUUID()에서 생성한, feed_로 시작하는 짧은 무작위 문자열로, 피드에 관한 그 무엇으로부터도 유도되지 않습니다.

위의 두 migrateLegacy* 함수가 존재하는 이유는, 1부에서 쓰던 기존 app.db에는 여전히 옛 posted_items(item_id, posted_at) 테이블과 별도의 app_meta 키-값 테이블이 있고, CREATE TABLE IF NOT EXISTS는 이 둘 중 어느 것도 건드리지 않기 때문입니다. 이미 존재하는 테이블은 그냥 그대로 두므로, 옛 posted_items는 이 파일의 나머지 부분이 기대하는 feed_identifier 칼럼이 없는 채로 남고, isPosted()를 처음 호출하는 순간 no such column: feed_identifier로 실패하고 말 것입니다. migrateLegacyPostedItems()openAppDb()가 뭔가를 만들기 전에 그 모양을 확인해서 발견하면 마이그레이션하고, migrateLegacyBaselined()app_meta의 baselined 플래그에 대해 같은 일을 하되, 그 플래그가 속할 피드 행이 실제로 존재하게 된 다음 seedFeed()에서 호출됩니다. 둘 다 실행 전에 옛 모양인지부터 확인하므로, 기존 app.db가 아예 없는 새 설치라면 그냥 건너뛰고, 이미 마이그레이션된 것이라면 그 이후 실행마다 건너뜁니다. posted_items에는 이미 feed_identifier가 있고, app_meta는 이미 사라졌으니까요.

봇에서 인스턴스로

bot.ts는 이제 봇 하나가 아니라 여럿을 호스팅하므로 instance.ts가 됩니다.

instance.ts

import {
  createInstance,
  InProcessMessageQueue,
  MemoryKvStore,
} from "@fedify/botkit";
import { SqliteRepository } from "@fedify/botkit-sqlite";
import { mkdirSync } from "node:fs";
import { openAppDb, seedFeed } from "./db.ts";

// FEED_URL, BEHIND_PROXY는 앞서와 같은 방식으로 환경 변수에서 읽어 온다.
// 여기서는 생략한다.

mkdirSync("./data", { recursive: true });

const instance = createInstance<void>({
  kv: new MemoryKvStore(),
  queue: new InProcessMessageQueue(),
  repository: new SqliteRepository({ path: "./data/bot.db" }),
  behindProxy: BEHIND_PROXY,
  // 1부의 봇은 identifier를 명시적으로 지정한 적이 없으므로, createBot()이
  // 기본값으로 "bot"을 붙였다. "rssbot"은 어디까지나 사용자명이었을 뿐이다.
  // (아래의 legacyObjectUris가 아니라) 바로 이 identifier를 그대로 재사용하는
  // 것이 액터의 URI와 키, 팔로워 관계를 그대로 지켜 주는 열쇠다.
  // legacyObjectUris는 원격 서버가 이 봇이 인스턴스로 옮겨 오기 전부터
  // 캐시해 두고 있을 수 있는, 개별 오브젝트(게시물, 팔로우) URI의 *옛*
  // 형식만 다시 써 준다.
  legacyObjectUris: { identifier: "bot" },
});

const appDb = openAppDb("./data/app.db");

// 원래 피드를 봇의 실제(기본) identifier와 기존 사용자명 그대로 여기 행으로
// 이어받는다. 그래서 이 피드는 이제부터 등록되는 다른 모든 피드와 똑같은
// 동적 봇 그룹이 처리한다. 첫 실행 이후로는 아무 일도 하지 않는다.
seedFeed(appDb, { identifier: "bot", url: FEED_URL, slug: "rssbot" });

createInstance()createBot()이 쓰던 것과 같은 인프라 옵션들, 즉 kv, queue, repository, behindProxy를 그대로 받습니다. 새로 등장한 것은 legacyObjectUris입니다. 1부의 rssbotidentifier 옵션을 명시적으로 지정한 적이 없으므로 createBot()이 기본값으로 "bot"을 붙였습니다. "rssbot"은 어디까지나 사용자명이었을 뿐입니다. legacyObjectUris가 아니라 바로 이 같은 identifier를 재사용하는 것이, 이제 서버에 봇 하나만 있는 게 아니라 여럿 중 하나가 된 지금도 원래 봇의 액터 URI와 암호화 키, 팔로워 관계를 온전히 지켜 주는 열쇠입니다. legacyObjectUris는 좀 더 좁은 범위, 즉 createInstance()로 옮기기 전에 게시된 개별 오브젝트 URI(게시물과 팔로우)의 형식을 다룹니다. 원격 서버가 여전히 그 형식을 캐시하고 있다가 나중에 AcceptLike로 돌려보낼 수 있기 때문입니다.

seedFeed()는 이 같은 봇을 평범한 행 하나로 이어받습니다. 같은 identifier, 같은 URL, 슬러그로는 같은 사용자명을 씁니다. INSERT OR IGNORE이므로 첫 실행 이후로는 매번 아무 일도 하지 않고, 이제부터 원래 봇은 나중에 등록되는 어떤 피드와도 똑같은 동적 봇 그룹이 처리하며, 다른 어디에도 별도의 특수 처리는 없습니다.

이게 가능하려면 미리 이뤄져야 할 마이그레이션이 있는데, 이 코드 자체가 하는 일은 아닙니다. BotKit은 이미 createBot() 배포의 리포지토리 데이터를 createInstance()가 기대하는 구조로 마이그레이션해 주지만, 그 배포가 createBot() 아래에서 BotKit 0.5.0 이상으로 처음 실행될 때 딱 한 번만 그렇습니다. 여기까지 왔다면 1부의 봇은 그저 실행된 것만으로 이미 그 과정을 마쳤을 것입니다. 만약 0.5.0에서 아예 실행된 적이 없는 배포를 옮기는 중이라면, 먼저 createBot()으로 한 번 실행하거나 리포지토리의 migrate() 메서드를 직접 호출하세요. 자세한 내용은 단일 봇 배포 마이그레이션하기를 참고하세요. createInstance()로 바꾸기 전후로 액터의 URI에 fedify lookup을 직접 돌려 보는 것도 해 볼 만합니다. 공개 키와 WebFinger 핸들이 완전히 똑같이 나와야 합니다.

인스턴스 하나에 피드 여럿

// 동적 봇 그룹: feeds 테이블의 행 하나마다 봇 하나씩을, 필요할 때마다
// 해석한다. 피드가 추가될 때마다 명령형으로 createBot()을 호출하는 대신,
// "피드마다 봇 하나"를 사전에 한 번의 등록으로 바꿔 주는 것이 바로 이
// 부분이다. 아래의 registryBot.onMention을 참고할 것.
const feedBots = instance.createBot(
  (_ctx, identifier) => {
    const feed = getFeedByIdentifier(appDb, identifier);
    if (feed == null) return null;
    return { username: feed.slug, name: feed.title ?? feed.url };
  },
  {
    mapUsername(_ctx, username) {
      const feed = getFeedBySlug(appDb, username);
      return feed?.identifier ?? null;
    },
  },
);

feedBots.onMention = async (session, message) => {
  const feed = getFeedByIdentifier(appDb, session.bot.identifier);
  if (feed == null) return;
  await message.reply(
    text`I'm watching ${
      link(feed.title ?? feed.url, feed.url)
    } and check for new posts every ${formatInterval(POLL_INTERVAL_MS)}.`,
  );
};

instance.createBot()에 고정된 식별자 대신 함수를 넘기면 BotGroup이 만들어집니다. 사전에 선언해 두는 대신 필요할 때마다 해석되는 봇들의 집합인데, BotKit 자체 문서에서 지역별 날씨 봇을 만들 때 쓰는 것과 같은 동적 봇 패턴입니다. 여기 디스패처가 하는 일도 같은 종류의 조회입니다. 식별자가 주어지면 feeds에서 대응하는 행을 찾고, 없으면 null을 반환해서 BotKit에게 이 식별자는 애초에 피드 봇이 아니라고 알려 줍니다. mapUsername은 그 반대 방향으로, identifier가 아니라 slug로 같은 조회를 수행합니다. 그래서 @xkcd-com@your-domain과, 무작위로 생성된 feed_a1b2c3d4e5f6을 식별자로 가진 액터가 양쪽 방향 모두에서 같은 봇으로 해석됩니다.

BotGroup은 자기만의 단일한 식별자를 갖지 않으므로, 이를 통해 게시하려면 어느 봇인지 말해 줘야 합니다. 1부에서 쓰던 bot.getSession(origin) 대신 feedBots.getSession(origin, identifier)를 씁니다. 폴링은 feeds의 모든 행을 돌면서, 피드마다 정확히 그렇게 한 번씩 합니다.

const FETCH_TIMEOUT_MS = 30_000;

async function pollFeed(feed: FeedRow): Promise<void> {
  const parsed = await fetchFeed(
    feed.url,
    AbortSignal.timeout(FETCH_TIMEOUT_MS),
  );
  if (parsed.title != null && parsed.title !== feed.title) {
    updateFeedTitle(appDb, feed.identifier, parsed.title);
  }
  const items = [...parsed.items].reverse(); // 피드는 최신 글이 맨 앞에 온다

  // 이 피드가 처음 폴링되는 순간 현재 첫 페이지 전체를 팔로워에게
  // 쏟아붓지 않기 위함이다. 이후 폴링에서 새로 나타나는 글만 "새 글"로 친다.
  const isFirstEverPoll = !feed.baselined;

  const session = await feedBots.getSession(ORIGIN, feed.identifier);
  let publishedCount = 0;
  for (const item of items) {
    const key = itemKey(item);
    if (key == null || isPosted(appDb, feed.identifier, key)) continue;
    if (!isFirstEverPoll) {
      await session.publish(
        text`${item.title ?? "(untitled)"}

${link(item.url ?? feed.url)}`,
      );
      publishedCount++;
    }
    markPosted(appDb, feed.identifier, key);
  }
  if (isFirstEverPoll) markFeedBaselined(appDb, feed.identifier);
  console.log(
    isFirstEverPoll
      ? `Baseline: ${items.length} existing item(s) from ${feed.url}.`
      : `Posted ${publishedCount} new item(s) from ${feed.url}.`,
  );
}

async function pollAll(): Promise<void> {
  for (const feed of listFeeds(appDb)) {
    try {
      await pollFeed(feed);
    } catch (error) {
      console.error(`Failed to poll feed ${feed.url}:`, error);
    }
  }
}

여기서는 식별자와 “이미 게시했음” 상태가 어디서 오는지를 빼면 1부의 폴링 로직과 다를 게 없습니다. 바깥 스코프에서 붙잡아 온 변수 대신 feed.identifier를 쓰고, 하나로 공유하던 Set 대신 그 identifier로 범위를 좁힌 isPosted/markPosted를 쓰고, fetchFeed()에 명시적인 AbortSignal.timeout()을 건다는 점이 다를 뿐입니다.

pollAll()은 피드를 하나씩 순서대로 기다리고, pollAllOnce()polling 가드 덕분에 현재 주기가 끝나기 전까지는 어떤 나중 틱도 새 주기를 시작할 수 없습니다.

이 타임아웃이 없다면, 연결은 받아 놓고 응답은 영영 하지 않는 서버 하나 때문에 그 서버가 물려 있는 피드뿐 아니라 인스턴스의 모든 피드가 영원히 멈춰 버릴 것입니다. 타임아웃이 있으면 이는 그저 평범한 피드별 실패, 이를테면 요청 시간 초과나 피드가 갑자기 이상한 XML을 반환하는 것과 다를 바 없어지고, pollAll()try/catch가 이를 똑같은 방식으로 처리합니다. 로그를 남기고 다음 피드로 넘어가는 식으로요.

멘션으로 피드 등록하기

지금까지 그룹에 봇을 하나 더한다는 것은 결국 feeds에 행을 하나 넣는다는 뜻이었습니다. feedBots의 디스패처는 그 테이블에 나타나는 식별자라면 무엇이든, 시작할 때부터 있던 것이든 방금 삽입된 것이든 상관없이 이미 알아서 해석해 주므로, 일단 피드가 등록되고 나면 instance.createBot()을 다시 호출할 필요가 전혀 없습니다. 바로 이것이 정적 봇 그룹 대신 동적 봇 그룹을 쓰는 이유입니다. 등록이 배포가 아니라 데이터베이스 쓰기 한 번으로 끝나는 것 말이죠.

작은 정적 봇 registry가 그 쓰기를 위한 대문 역할을 합니다.

function extractUrl(input: string): string | null {
  const match = input.match(/https?:\/\/\S+/)?.[0];
  return match != null && URL.canParse(match) ? match : null;
}

// 정적 봇: 등록 창구. 피드 URL과 함께 이 봇을 멘션하면 feeds 테이블에
// 행이 하나 추가된다. feedBots의 디스패처는 그 새 행을, 다음번에 그
// identifier가 해석될 때 알아서 집어 든다.
//
// 이 코드는 누가 멘션을 보냈는지 확인하지 않고, 아래의 폴링 루프가 가져오기
// 전에 그 URL을 검증하지도 않는다. 실제 배포에 필요한 것은 튜토리얼의
// "더 해볼 만한 것들" 절을 참고할 것.
const registryBot = instance.createBot("registry", {
  username: "registry",
  name: "Feed Registry",
  summary: text`Mention me with a feed URL to register a new feed bot.`,
});

registryBot.onMention = async (_session, message) => {
  const url = extractUrl(message.text);
  if (url == null) {
    await message.reply(text`Please include a feed URL in your mention.`);
    return;
  }
  const existing = getFeedByUrl(appDb, url);
  if (existing != null) {
    await message.reply(
      text`Already watching that feed: ${
        mention(`@${existing.slug}@${new URL(ORIGIN).host}`)
      }.`,
    );
    return;
  }
  const feed = addFeed(appDb, url);
  await message.reply(
    text`Registered! Give it a few minutes, then look for ${
      mention(`@${feed.slug}@${new URL(ORIGIN).host}`)
    }.`,
  );
};

extractUrl()은 멘션 텍스트 안에서 URL처럼 생기고 URL.canParse()를 통과하는 첫 번째 것을 찾습니다. 잘린 http://%처럼 형식이 잘못된 것은 걸러 내는데, 그렇지 않으면 addFeed()new URL() 호출까지 그대로 흘러 들어가 예외를 던지게 됩니다. 이미 감시 중인 URL을 등록하려 하면 feeds.urlUNIQUE 제약에 부딪혀 죽는 대신 답장으로 알려 줍니다.

두 답장 모두 새 봇의 핸들을 mention()으로 만들지, 템플릿에 그대로 끼워 넣은 평범한 @${slug}@${host} 문자열로 만들지 않습니다. 평범한 텍스트로 적은 핸들은 그냥 텍스트일 뿐입니다. 링크로 렌더링되지도 않고, mention()이 붙여 주는 Mention 태그가 없으니 실제 멘션처럼 동작하지도 않습니다. mention()은 사람이 검색하듯 그 핸들을 실제로 찾아보고, 그 조회가 실패할 때만 평범한 텍스트로 물러나므로, 새 봇의 액터를 어쩌다 아직 해석할 수 없는 상황이라도 답장이 깨지는 대신 우아하게 낮은 수준으로 대응합니다.

registryBot.onMention이 하지 않는 일도 있습니다. 누가 묻고 있는지 확인하지 않고, pollFeed()에 곧 넘길 그 URL이 실제로 가져오기에 안전한 곳을 가리키는지도 확인하지 않습니다. 둘 다 의도적으로 남겨 둔 빈틈이고, 둘 다 여기가 아니라 아래 더 해볼 만한 것들에서 다룹니다.

두 런타임에서 인스턴스 검증하기

1부의 첫 실행과 같은 모양입니다. 다만 이제 단일 봇이 아니라 인스턴스를 호스팅하는 파일을 대상으로 합니다.

Deno

deno serve --allow-net --allow-env --allow-read=./data --allow-write=./data --watch instance.ts

Node.js

npx srvx serve --port 8000 --entry ./instance.ts

앞서와 같은 방식으로 터널을 열고, ActivityPub.Academy의 계정에서 피드 URL과 함께 등록 봇을 멘션합니다. 스킴을 포함한 전체 URL을 그대로 입력하세요. extractUrl()http://https:// 링크만 매칭하는데, Mastodon은 자동 링크된 URL을 보여 줄 때 스킴을 감춰서 표시하므로, 아래에는 스킴이 보이지 않는 것입니다.

Hey @registry, please watch https://xkcd.com/rss.xml

등록 봇에 대한 멘션과 그 답장: “Registered! Give it a few minutes, then look for @xkcd-com@…”

답장의 핸들은 mention()으로 만들어졌으므로, 그 답장을 이루는 실제 Note 객체에는 제대로 된 Mention 태그가 붙어 있고, 새 봇에게 직접 주소가 지정되어 있습니다. 그럴듯하게 보이도록 형식만 갖춘 게 아니라요. 위 스크린샷에서 ActivityPub.Academy는 이를 클릭 가능한 링크로 렌더링하지 않지만, 그 밑에 있는 데이터 자체는 정확합니다. 등록 봇 자신의 웹 페이지는 같은 답장을, 링크가 온전히 살아 있는 채로 보여 줍니다.

등록 봇 자신의 프로필 페이지. 새 봇의 핸들이 동작하는 링크로 렌더링된 같은 “Registered!” 게시물이 보인다

1~2분 뒤, 새 봇이 자기 슬러그로 나타납니다. 이 봇과 이관된 원래 봇을 둘 다 팔로우해 보면, 이 둘이 서로의 별칭이 아니라 진짜로 별개인 액터임을 확인할 수 있습니다.

세 개의 별개 봇을 보여 주는 어느 계정의 팔로잉 목록: rssbot 핸들로 이관된 원래 봇, 새로 등록된 xkcd.com 피드, 그리고 별도의 Node.js 실행에서 나온 세 번째 봇

새 봇을 직접 멘션하면, 등록 봇이 아니라 feedBots.onMention이 답합니다.

새 피드 봇에 대한 멘션과 그 답장: “I'm watching xkcd.com and check for new posts every 2 minutes.”

여기까지의 모든 과정은 Node.js에서도 똑같이 동작합니다. instance.ts를 두 번째 호스트명 뒤에서 터널링하고, 같은 방식으로 피드를 등록하면 같은 핸들이 WebFinger를 통해 그대로 해석됩니다.

서버에 배포하기

터미널이 아니라 프로세스 매니저 아래에서 instance.ts를 실행하는 것은 직접 호스팅하기의 systemd·Caddy 구성을 거의 그대로 따릅니다. 런타임 설치, botkit 사용자 만들기, Caddy 설정, 서비스 활성화까지 전체 과정은 그 문서에 있습니다. 이 봇에 특유한 것 두 가지만 짚고 넘어가면 되는데, 둘 다 examples/rss-bot/deploy/의 systemd 유닛과 Caddyfile에 이미 반영되어 있습니다.

ExecStart는 이 튜토리얼에서 쭉 써 온 것과 같은, 범위를 좁힌 Deno 권한(--allow-net --allow-env --allow-read=./data --allow-write=./data)을 쓰지, 직접 호스팅하기의 범용 -A를 쓰지 않습니다. 그리고 ProtectSystem=strictReadWritePaths에 나열되지 않은 한 작업 디렉터리 전체를 읽기 전용으로 만들어 버리는데, 이 봇은 bot.dbapp.db./data 아래에 쓰므로 유닛에 다음을 추가합니다.

ReadWritePaths=/opt/botkit/data

그 경로는 서비스가 시작되기 전에 botkit 사용자 소유로 이미 존재해야 합니다.

sudo mkdir -p /opt/botkit/data
sudo chown botkit:botkit /opt/botkit/data

직접 호스팅하기 자체의 mkdir -p /opt/botkit 단계 바로 다음에 실행하면 됩니다. 이걸 건너뛰면 유닛은 아예 시작조차 하지 못하고 종료 코드 226/NAMESPACE를 냅니다. systemd는 이미 존재하는 ReadWritePaths 항목만 허용 목록에 올리기 때문입니다.

Node.js에서는 이번에는 srvxnpx를 통해서만 실행되는 게 아니라, 실제로 봇의 의존성과 함께 배포돼야 합니다. package.json에 일반 의존성으로 들어 있으므로, npm ci(또는 배포를 빌드한 패키지 매니저에 맞는 대응 명령)가 ExecStart가 호출하는 바로 그 바이너리인 /opt/botkit/node_modules/.bin/srvx를 설치해 줍니다.

Caddyfile은 그 밖의 나머지 부분에서 직접 호스팅하기를 그대로 따릅니다. ACME 연락처 이메일을 이용한 자동 HTTPS, localhost:8000으로의 리버스 프록시, 그리고 같은 기본 보안 헤더까지요.

더 해볼 만한 것들

아래 내용은 *examples/rss-bot/*에는 구현되어 있지 않습니다. 실제 배포라면 대체로 아래 순서로 손보게 될 만한 것들입니다.

  • 피드가 알려 주는 갱신 힌트: RSS의 선택 사항인 <ttl> 엘리먼트Syndication 모듈<sy:updatePeriod>, <sy:updateFrequency>, <sy:updateBase>는 모두 피드가 봇이 모든 피드에 똑같이 POLL_INTERVAL_MS를 추측해 적용하는 대신, 스스로 폴링 주기를 제안할 수 있게 해 줍니다. Atom에는 이에 대응하는 표준이 없습니다.
  • HTTP 조건부 요청: 매 폴링마다 If-Modified-SinceIf-None-Match를 함께 보내고 304 Not Modified 응답을 처리하면, 전혀 바뀌지 않은 피드를 다시 파싱하는 일을 건너뛸 수 있습니다.
  • WebSub: <atom:link rel="hub" href="…">를 광고하는 피드라면, setInterval() 대신 웹훅으로 폴링을 기다리는 게 아니라 갱신을 직접 밀어 넣을 수 있습니다.
  • 피드를 등록할 수 있는 사람의 허용 목록: 지금은 URL이 담긴 멘션이 등록 봇에게 오기만 하면 누구든 그 URL을 등록할 수 있습니다.
  • 멘션된 URL을 가져오기 전에 검증하기: registryBot.onMentionextractUrl()이 찾은 것을 그대로 pollFeed()fetch() 호출로 넘길 뿐, localhost나 내부 주소를 가리키는 것을 막을 장치가 전혀 없습니다. @fedify/vocab-runtimevalidatePublicUrl()이 정확히 이런 용도로 존재하니, 처음부터 새로 짤 필요는 없습니다.

  1. 호스트명은 사용하는 터널링 서비스에 따라 실제로는 다르게 나옵니다. ↩︎

@paperbox@hackers.pub

안녕하세요. 그간 실리콘 숲이나 다른 서버에서 만난 분도, 새롭게 인사드리는 분도 잘 부탁드립니다. 본 계정은 다소 담담하게, 블로그보다는 짧고 소셜 미디어보다는 긴 글을 쓸 목적으로 사용하고자 합니다. 그 시작으로 이 글을 첫 돌로 놓아 둡니다.

주소 표시줄을 관심 있게 보시는 분들이라면 주소는 starting-my-seventh-fediverse-account 인데 어째서 한국어 제목은 통산 아홉 번째인가. 하실지도 모르겠습니다. 이는 제가 총 아홉 개의 연합우주 계정을 만들었고, 그 중 두 개의 서버가 문을 닫아 일곱 개가 남았기 때문입니다.

어째서 이렇게나 많은 계정을 만들게 된 것일까요? 이 사람은 소셜 미디어 계정을 서비스 별로 모으는 취미라도 있는 걸까요?

네, 예전에는 비슷한 취미를 가지고 있었습니다. 하지만 10년이면 강산이 변한다고, 10년은 커녕 1년을 넘기는 서비스도 찾기 어려운 시대에 조금은 허무한 마음이 들어 지금은 더 모으지 않고 있습니다.

여기에 대해 자세히 설명하기 시작하면, 저의 10934번째 블로그가 되어 버리고 또 별안간 제 쓰임을 찾지 못한 채 장식장에 고이 모셔진 펄기아 피규어처럼 장식이 될테니 조금 짧게 연합우주 이야기 위주로 하려 합니다.

저는 무슨 대안, 게 섰거라. 이런 걸 좋아합니다. 삼성 갤럭시, 애플 아이폰 게 섰거라. LG G 시리즈 나가신다. 스마트폰 사업을 손 털고 나갔지만요. 아니 그게 아니라, 저는 미친 세상으로 갑니다. 이것도 아닌데. 아무튼 네이버가 미투데이를 접고 남은 자리에 만들어 진 미소일기를 종종 안부 인사하듯 들러 왔습니다. 그렇지만 운영진의 사비와 자비로 운영되는 작고 아늑한 공간이 언제까지나 튼튼하기란 어려운 법입니다.

미소일기가 조용히 사라지고 문득, 트잉여가 생각났습니다. 그때는 서비스하고 있었고, 아직 잠깐의 트위터 대안 찾기 붐이 일기 전이었어요.

별다른 흐름도 없이 돌연 뉴비다 뉴비, 입맞에 잘 맞네요! 지금은 찾기 힘든 그런 분위기 속에 천천히 적응하다 1년 5개월이 지나 너무 많은 파일 업로드를 하는 것 같아 의도치 않게 베짱이처럼 놀고 있던 도메인 위에 감자를 올려 연결하기, 아니 와플 토핑하기, 도 아니고 작고 소중한 서버를 시작했습니다.

그러다 보니 또 제 마음에 안 드는 부분을 여기저기 고치고, 혹시 저어기서 넘어오는 이야기가 제겐 잘 전달이 안 될까 싶어 몇 개 더 계정을 만들거나 관리 공지용 계정을 몇 개 만들다 보니 어느새 아홉 번을 만들게 되었고, 아홉 번째가 바로 이 고양이가 귀여운 해커들의 술집입니다. 늘 눈독 들이면서도 주저했지만, Fedify 오픈소스 컨트리뷰션 아카데미 참여를 계기로 정착에 도전해 봅니다.

앞으로 이 계정에서도 종종 뵙게 될 예정입니다. 조금 긴 글을 쓰는 만큼 자주 나타나지는 않을 예정이지만, 애정을 붙여 작게나마 가꿔 나가 보겠습니다. 아직 프로필 사진 원본을 잃어버린 채 찾지 못해 완전한 설정까지는 시간이 좀 걸리겠지만, 다시 한 번 잘 부탁드립니다.

@paperbox@hackers.pub

안녕하세요. 그간 실리콘 숲이나 다른 서버에서 만난 분도, 새롭게 인사드리는 분도 잘 부탁드립니다. 본 계정은 다소 담담하게, 블로그보다는 짧고 소셜 미디어보다는 긴 글을 쓸 목적으로 사용하고자 합니다. 그 시작으로 이 글을 첫 돌로 놓아 둡니다.

주소 표시줄을 관심 있게 보시는 분들이라면 주소는 starting-my-seventh-fediverse-account 인데 어째서 한국어 제목은 통산 아홉 번째인가. 하실지도 모르겠습니다. 이는 제가 총 아홉 개의 연합우주 계정을 만들었고, 그 중 두 개의 서버가 문을 닫아 일곱 개가 남았기 때문입니다.

어째서 이렇게나 많은 계정을 만들게 된 것일까요? 이 사람은 소셜 미디어 계정을 서비스 별로 모으는 취미라도 있는 걸까요?

네, 예전에는 비슷한 취미를 가지고 있었습니다. 하지만 10년이면 강산이 변한다고, 10년은 커녕 1년을 넘기는 서비스도 찾기 어려운 시대에 조금은 허무한 마음이 들어 지금은 더 모으지 않고 있습니다.

여기에 대해 자세히 설명하기 시작하면, 저의 10934번째 블로그가 되어 버리고 또 별안간 제 쓰임을 찾지 못한 채 장식장에 고이 모셔진 펄기아 피규어처럼 장식이 될테니 조금 짧게 연합우주 이야기 위주로 하려 합니다.

저는 무슨 대안, 게 섰거라. 이런 걸 좋아합니다. 삼성 갤럭시, 애플 아이폰 게 섰거라. LG G 시리즈 나가신다. 스마트폰 사업을 손 털고 나갔지만요. 아니 그게 아니라, 저는 미친 세상으로 갑니다. 이것도 아닌데. 아무튼 네이버가 미투데이를 접고 남은 자리에 만들어 진 미소일기를 종종 안부 인사하듯 들러 왔습니다. 그렇지만 운영진의 사비와 자비로 운영되는 작고 아늑한 공간이 언제까지나 튼튼하기란 어려운 법입니다.

미소일기가 조용히 사라지고 문득, 트잉여가 생각났습니다. 그때는 서비스하고 있었고, 아직 잠깐의 트위터 대안 찾기 붐이 일기 전이었어요.

별다른 흐름도 없이 돌연 뉴비다 뉴비, 입맞에 잘 맞네요! 지금은 찾기 힘든 그런 분위기 속에 천천히 적응하다 1년 5개월이 지나 너무 많은 파일 업로드를 하는 것 같아 의도치 않게 베짱이처럼 놀고 있던 도메인 위에 감자를 올려 연결하기, 아니 와플 토핑하기, 도 아니고 작고 소중한 서버를 시작했습니다.

그러다 보니 또 제 마음에 안 드는 부분을 여기저기 고치고, 혹시 저어기서 넘어오는 이야기가 제겐 잘 전달이 안 될까 싶어 몇 개 더 계정을 만들거나 관리 공지용 계정을 몇 개 만들다 보니 어느새 아홉 번을 만들게 되었고, 아홉 번째가 바로 이 고양이가 귀여운 해커들의 술집입니다. 늘 눈독 들이면서도 주저했지만, Fedify 오픈소스 컨트리뷰션 아카데미 참여를 계기로 정착에 도전해 봅니다.

앞으로 이 계정에서도 종종 뵙게 될 예정입니다. 조금 긴 글을 쓰는 만큼 자주 나타나지는 않을 예정이지만, 애정을 붙여 작게나마 가꿔 나가 보겠습니다. 아직 프로필 사진 원본을 잃어버린 채 찾지 못해 완전한 설정까지는 시간이 좀 걸리겠지만, 다시 한 번 잘 부탁드립니다.

@paperbox@hackers.pub

안녕하세요. 그간 실리콘 숲이나 다른 서버에서 만난 분도, 새롭게 인사드리는 분도 잘 부탁드립니다. 본 계정은 다소 담담하게, 블로그보다는 짧고 소셜 미디어보다는 긴 글을 쓸 목적으로 사용하고자 합니다. 그 시작으로 이 글을 첫 돌로 놓아 둡니다.

주소 표시줄을 관심 있게 보시는 분들이라면 주소는 starting-my-seventh-fediverse-account 인데 어째서 한국어 제목은 통산 아홉 번째인가. 하실지도 모르겠습니다. 이는 제가 총 아홉 개의 연합우주 계정을 만들었고, 그 중 두 개의 서버가 문을 닫아 일곱 개가 남았기 때문입니다.

어째서 이렇게나 많은 계정을 만들게 된 것일까요? 이 사람은 소셜 미디어 계정을 서비스 별로 모으는 취미라도 있는 걸까요?

네, 예전에는 비슷한 취미를 가지고 있었습니다. 하지만 10년이면 강산이 변한다고, 10년은 커녕 1년을 넘기는 서비스도 찾기 어려운 시대에 조금은 허무한 마음이 들어 지금은 더 모으지 않고 있습니다.

여기에 대해 자세히 설명하기 시작하면, 저의 10934번째 블로그가 되어 버리고 또 별안간 제 쓰임을 찾지 못한 채 장식장에 고이 모셔진 펄기아 피규어처럼 장식이 될테니 조금 짧게 연합우주 이야기 위주로 하려 합니다.

저는 무슨 대안, 게 섰거라. 이런 걸 좋아합니다. 삼성 갤럭시, 애플 아이폰 게 섰거라. LG G 시리즈 나가신다. 스마트폰 사업을 손 털고 나갔지만요. 아니 그게 아니라, 저는 미친 세상으로 갑니다. 이것도 아닌데. 아무튼 네이버가 미투데이를 접고 남은 자리에 만들어 진 미소일기를 종종 안부 인사하듯 들러 왔습니다. 그렇지만 운영진의 사비와 자비로 운영되는 작고 아늑한 공간이 언제까지나 튼튼하기란 어려운 법입니다.

미소일기가 조용히 사라지고 문득, 트잉여가 생각났습니다. 그때는 서비스하고 있었고, 아직 잠깐의 트위터 대안 찾기 붐이 일기 전이었어요.

별다른 흐름도 없이 돌연 뉴비다 뉴비, 입맞에 잘 맞네요! 지금은 찾기 힘든 그런 분위기 속에 천천히 적응하다 1년 5개월이 지나 너무 많은 파일 업로드를 하는 것 같아 의도치 않게 베짱이처럼 놀고 있던 도메인 위에 감자를 올려 연결하기, 아니 와플 토핑하기, 도 아니고 작고 소중한 서버를 시작했습니다.

그러다 보니 또 제 마음에 안 드는 부분을 여기저기 고치고, 혹시 저어기서 넘어오는 이야기가 제겐 잘 전달이 안 될까 싶어 몇 개 더 계정을 만들거나 관리 공지용 계정을 몇 개 만들다 보니 어느새 아홉 번을 만들게 되었고, 아홉 번째가 바로 이 고양이가 귀여운 해커들의 술집입니다. 늘 눈독 들이면서도 주저했지만, Fedify 오픈소스 컨트리뷰션 아카데미 참여를 계기로 정착에 도전해 봅니다.

앞으로 이 계정에서도 종종 뵙게 될 예정입니다. 조금 긴 글을 쓰는 만큼 자주 나타나지는 않을 예정이지만, 애정을 붙여 작게나마 가꿔 나가 보겠습니다. 아직 프로필 사진 원본을 잃어버린 채 찾지 못해 완전한 설정까지는 시간이 좀 걸리겠지만, 다시 한 번 잘 부탁드립니다.

@paperbox@hackers.pub

안녕하세요. 그간 실리콘 숲이나 다른 서버에서 만난 분도, 새롭게 인사드리는 분도 잘 부탁드립니다. 본 계정은 다소 담담하게, 블로그보다는 짧고 소셜 미디어보다는 긴 글을 쓸 목적으로 사용하고자 합니다. 그 시작으로 이 글을 첫 돌로 놓아 둡니다.

주소 표시줄을 관심 있게 보시는 분들이라면 주소는 starting-my-seventh-fediverse-account 인데 어째서 한국어 제목은 통산 아홉 번째인가. 하실지도 모르겠습니다. 이는 제가 총 아홉 개의 연합우주 계정을 만들었고, 그 중 두 개의 서버가 문을 닫아 일곱 개가 남았기 때문입니다.

어째서 이렇게나 많은 계정을 만들게 된 것일까요? 이 사람은 소셜 미디어 계정을 서비스 별로 모으는 취미라도 있는 걸까요?

네, 예전에는 비슷한 취미를 가지고 있었습니다. 하지만 10년이면 강산이 변한다고, 10년은 커녕 1년을 넘기는 서비스도 찾기 어려운 시대에 조금은 허무한 마음이 들어 지금은 더 모으지 않고 있습니다.

여기에 대해 자세히 설명하기 시작하면, 저의 10934번째 블로그가 되어 버리고 또 별안간 제 쓰임을 찾지 못한 채 장식장에 고이 모셔진 펄기아 피규어처럼 장식이 될테니 조금 짧게 연합우주 이야기 위주로 하려 합니다.

저는 무슨 대안, 게 섰거라. 이런 걸 좋아합니다. 삼성 갤럭시, 애플 아이폰 게 섰거라. LG G 시리즈 나가신다. 스마트폰 사업을 손 털고 나갔지만요. 아니 그게 아니라, 저는 미친 세상으로 갑니다. 이것도 아닌데. 아무튼 네이버가 미투데이를 접고 남은 자리에 만들어 진 미소일기를 종종 안부 인사하듯 들러 왔습니다. 그렇지만 운영진의 사비와 자비로 운영되는 작고 아늑한 공간이 언제까지나 튼튼하기란 어려운 법입니다.

미소일기가 조용히 사라지고 문득, 트잉여가 생각났습니다. 그때는 서비스하고 있었고, 아직 잠깐의 트위터 대안 찾기 붐이 일기 전이었어요.

별다른 흐름도 없이 돌연 뉴비다 뉴비, 입맞에 잘 맞네요! 지금은 찾기 힘든 그런 분위기 속에 천천히 적응하다 1년 5개월이 지나 너무 많은 파일 업로드를 하는 것 같아 의도치 않게 베짱이처럼 놀고 있던 도메인 위에 감자를 올려 연결하기, 아니 와플 토핑하기, 도 아니고 작고 소중한 서버를 시작했습니다.

그러다 보니 또 제 마음에 안 드는 부분을 여기저기 고치고, 혹시 저어기서 넘어오는 이야기가 제겐 잘 전달이 안 될까 싶어 몇 개 더 계정을 만들거나 관리 공지용 계정을 몇 개 만들다 보니 어느새 아홉 번을 만들게 되었고, 아홉 번째가 바로 이 고양이가 귀여운 해커들의 술집입니다. 늘 눈독 들이면서도 주저했지만, Fedify 오픈소스 컨트리뷰션 아카데미 참여를 계기로 정착에 도전해 봅니다.

앞으로 이 계정에서도 종종 뵙게 될 예정입니다. 조금 긴 글을 쓰는 만큼 자주 나타나지는 않을 예정이지만, 애정을 붙여 작게나마 가꿔 나가 보겠습니다. 아직 프로필 사진 원본을 잃어버린 채 찾지 못해 완전한 설정까지는 시간이 좀 걸리겠지만, 다시 한 번 잘 부탁드립니다.

@hackerspub@hackers.pub

Hackers' Pub에 드디어 개인 계정 외에 조직(organization) 계정을 만들 수 있게 되었습니다. 조직 계정은 Hackers' Pub에서 특정 조직·프로젝트의 공식 계정을 만들기 위한 용도입니다. GitHub이나 GitLab, Codeberg 등에서 조직 기능을 사용해 보셨다면, 혹은 Facebook에서 페이지 기능을 사용해 보셨다면, 비슷한 개념으로 받아들이셔도 됩니다. 조직 계정에는 하나 이상의 개인 계정이 속하게 되며, 구성원들 누구나 조직 명의로 단문(note) 및 게시글(article)을 올릴 수 있게 됩니다. 단, 조직 기능은 새 웹 프런트엔드(web-next)에서만 사용 가능합니다.

조직 계정은 개인 계정과 많은 면에서 공통점이 있습니다. 이름과 아바타도 가질 수 있고, 약력(bio)도 입력 가능합니다. 다른 계정을 팔로할 수도 있고, 팔로워도 가질 수 있습니다. 댓글도 쓸 수 있고 에모지 리액션도 달 수 있습니다.

반면, 조직 계정은 개인 계정과는 달리 로그인할 수 없습니다. 로그인 할 수 없으니 이메일이나 패스키 등도 갖지 않습니다. 대신, 조직 구성원의 개인 계정으로 로그인한 뒤, 조직 명의를 선택하는 식으로 동작합니다. 또한, 북마크나 초고(draft)는 여전히 개인 계정에만 저장할 수 있습니다.

여러분 조직·프로젝트의 구성원이 단 한 명이라고 하더라도, 공식 계정을 만들 때는 조직 계정으로 생성하는 것을 권장합니다.

ActivityPub

개인 계정의 경우 ActivityPub 객체 상으로 Person 타입으로 표현되는 반면, 조직 계정의 경우에는 Organization 타입으로 표현됩니다.

"type": "Organization"

조직 만들기

조직은 누구나 설정계정조직 만들기에 가셔서 만드실 수 있습니다. 개인 계정과 마찬가지로, 조직 계정 역시 하나의 초대장을 소모합니다.

설정 → 계정 → 조직 만들기 폼

개인 계정 ↔ 조직 계정 사이의 스위치

조직 구성원은 언제든지 자신의 개인 계정과 조직 계정 사이에서 스위치가 가능합니다. 하나 이상의 조직에 몸 담고 있을 경우, 좌측 사이드바의 하단에 계정 스위치 UI가 보이게 됩니다.

계정 스위치 UI

단문 및 게시글 작성

조직 구성원은 단문 및 게시글을 작성할 때 해당 콘텐츠를 어떤 명의로 올릴 것인지 결정할 수 있습니다. 크게 세 종류의 선택지가 있습니다.

개인 명의

이전과 같이, 개인 계정이 쓴 콘텐츠로 올라갑니다.

조직 명의

조직으로서 작성한 콘텐츠로 올라가며, 다른 사람은 이 콘텐츠가 조직 구성원 중 누가 작성했는지 알 수 없습니다.

공동 저자

조직을 대표하여 개인 계정이 쓴 콘텐츠로 올라갑니다. 다른 사람에게는 해당 조직의 어느 구성원이 작성했는지 보입니다. 이 게시글이 바로 @hackerspub 조직 계정과 @hongminhee 개인 계정의 공동 명의로 쓰여진 예입니다.

ActivityPub

공동 저자는 ActivityPub 객체에서는 attributedTo 속성Organization 타입의 액터와 Person 타입의 액터가 함께 들어가는 것으로 표현됩니다.

"attributedTo": [
  "https://hackers.pub/ap/actors/019efc7c-70ad-7e2b-87dd-b1d36190cdee",
  "https://hackers.pub/ap/actors/019382d3-63d7-7cf7-86e8-91e2551c306c"
]

단, 아직 복수의 attributedTo 속성을 올바르게 해석하지 못하는 ActivityPub 소프트웨어가 많습니다. 그런 소프트웨어에서는 조직 계정의 명의로만 보일 수 있습니다.

콘텐츠 명의 선택 UI

이미 있는 조직 계정들

다음은 Hackers' Pub에 이미 개설된 조직 계정들의 목록입니다:

fedidev.kr

한국 연합우주 개발자 모임

한국에 거주하거나 한국어를 사용하는 연합우주(fediverse) 개발자들의 모임입니다.

@hackerspub@hackers.pub

Hackers' Pub에 드디어 개인 계정 외에 조직(organization) 계정을 만들 수 있게 되었습니다. 조직 계정은 Hackers' Pub에서 특정 조직·프로젝트의 공식 계정을 만들기 위한 용도입니다. GitHub이나 GitLab, Codeberg 등에서 조직 기능을 사용해 보셨다면, 혹은 Facebook에서 페이지 기능을 사용해 보셨다면, 비슷한 개념으로 받아들이셔도 됩니다. 조직 계정에는 하나 이상의 개인 계정이 속하게 되며, 구성원들 누구나 조직 명의로 단문(note) 및 게시글(article)을 올릴 수 있게 됩니다. 단, 조직 기능은 새 웹 프런트엔드(web-next)에서만 사용 가능합니다.

조직 계정은 개인 계정과 많은 면에서 공통점이 있습니다. 이름과 아바타도 가질 수 있고, 약력(bio)도 입력 가능합니다. 다른 계정을 팔로할 수도 있고, 팔로워도 가질 수 있습니다. 댓글도 쓸 수 있고 에모지 리액션도 달 수 있습니다.

반면, 조직 계정은 개인 계정과는 달리 로그인할 수 없습니다. 로그인 할 수 없으니 이메일이나 패스키 등도 갖지 않습니다. 대신, 조직 구성원의 개인 계정으로 로그인한 뒤, 조직 명의를 선택하는 식으로 동작합니다. 또한, 북마크나 초고(draft)는 여전히 개인 계정에만 저장할 수 있습니다.

여러분 조직·프로젝트의 구성원이 단 한 명이라고 하더라도, 공식 계정을 만들 때는 조직 계정으로 생성하는 것을 권장합니다.

ActivityPub

개인 계정의 경우 ActivityPub 객체 상으로 Person 타입으로 표현되는 반면, 조직 계정의 경우에는 Organization 타입으로 표현됩니다.

"type": "Organization"

조직 만들기

조직은 누구나 설정계정조직 만들기에 가셔서 만드실 수 있습니다. 개인 계정과 마찬가지로, 조직 계정 역시 하나의 초대장을 소모합니다.

설정 → 계정 → 조직 만들기 폼

개인 계정 ↔ 조직 계정 사이의 스위치

조직 구성원은 언제든지 자신의 개인 계정과 조직 계정 사이에서 스위치가 가능합니다. 하나 이상의 조직에 몸 담고 있을 경우, 좌측 사이드바의 하단에 계정 스위치 UI가 보이게 됩니다.

계정 스위치 UI

단문 및 게시글 작성

조직 구성원은 단문 및 게시글을 작성할 때 해당 콘텐츠를 어떤 명의로 올릴 것인지 결정할 수 있습니다. 크게 세 종류의 선택지가 있습니다.

개인 명의

이전과 같이, 개인 계정이 쓴 콘텐츠로 올라갑니다.

조직 명의

조직으로서 작성한 콘텐츠로 올라가며, 다른 사람은 이 콘텐츠가 조직 구성원 중 누가 작성했는지 알 수 없습니다.

공동 저자

조직을 대표하여 개인 계정이 쓴 콘텐츠로 올라갑니다. 다른 사람에게는 해당 조직의 어느 구성원이 작성했는지 보입니다. 이 게시글이 바로 @hackerspub 조직 계정과 @hongminhee 개인 계정의 공동 명의로 쓰여진 예입니다.

ActivityPub

공동 저자는 ActivityPub 객체에서는 attributedTo 속성Organization 타입의 액터와 Person 타입의 액터가 함께 들어가는 것으로 표현됩니다.

"attributedTo": [
  "https://hackers.pub/ap/actors/019efc7c-70ad-7e2b-87dd-b1d36190cdee",
  "https://hackers.pub/ap/actors/019382d3-63d7-7cf7-86e8-91e2551c306c"
]

단, 아직 복수의 attributedTo 속성을 올바르게 해석하지 못하는 ActivityPub 소프트웨어가 많습니다. 그런 소프트웨어에서는 조직 계정의 명의로만 보일 수 있습니다.

콘텐츠 명의 선택 UI

이미 있는 조직 계정들

다음은 Hackers' Pub에 이미 개설된 조직 계정들의 목록입니다:

fedidev.kr

한국 연합우주 개발자 모임

한국에 거주하거나 한국어를 사용하는 연합우주(fediverse) 개발자들의 모임입니다.

@hackerspub@hackers.pub

Hackers' Pub에 드디어 개인 계정 외에 조직(organization) 계정을 만들 수 있게 되었습니다. 조직 계정은 Hackers' Pub에서 특정 조직·프로젝트의 공식 계정을 만들기 위한 용도입니다. GitHub이나 GitLab, Codeberg 등에서 조직 기능을 사용해 보셨다면, 혹은 Facebook에서 페이지 기능을 사용해 보셨다면, 비슷한 개념으로 받아들이셔도 됩니다. 조직 계정에는 하나 이상의 개인 계정이 속하게 되며, 구성원들 누구나 조직 명의로 단문(note) 및 게시글(article)을 올릴 수 있게 됩니다. 단, 조직 기능은 새 웹 프런트엔드(web-next)에서만 사용 가능합니다.

조직 계정은 개인 계정과 많은 면에서 공통점이 있습니다. 이름과 아바타도 가질 수 있고, 약력(bio)도 입력 가능합니다. 다른 계정을 팔로할 수도 있고, 팔로워도 가질 수 있습니다. 댓글도 쓸 수 있고 에모지 리액션도 달 수 있습니다.

반면, 조직 계정은 개인 계정과는 달리 로그인할 수 없습니다. 로그인 할 수 없으니 이메일이나 패스키 등도 갖지 않습니다. 대신, 조직 구성원의 개인 계정으로 로그인한 뒤, 조직 명의를 선택하는 식으로 동작합니다. 또한, 북마크나 초고(draft)는 여전히 개인 계정에만 저장할 수 있습니다.

여러분 조직·프로젝트의 구성원이 단 한 명이라고 하더라도, 공식 계정을 만들 때는 조직 계정으로 생성하는 것을 권장합니다.

ActivityPub

개인 계정의 경우 ActivityPub 객체 상으로 Person 타입으로 표현되는 반면, 조직 계정의 경우에는 Organization 타입으로 표현됩니다.

"type": "Organization"

조직 만들기

조직은 누구나 설정계정조직 만들기에 가셔서 만드실 수 있습니다. 개인 계정과 마찬가지로, 조직 계정 역시 하나의 초대장을 소모합니다.

설정 → 계정 → 조직 만들기 폼

개인 계정 ↔ 조직 계정 사이의 스위치

조직 구성원은 언제든지 자신의 개인 계정과 조직 계정 사이에서 스위치가 가능합니다. 하나 이상의 조직에 몸 담고 있을 경우, 좌측 사이드바의 하단에 계정 스위치 UI가 보이게 됩니다.

계정 스위치 UI

단문 및 게시글 작성

조직 구성원은 단문 및 게시글을 작성할 때 해당 콘텐츠를 어떤 명의로 올릴 것인지 결정할 수 있습니다. 크게 세 종류의 선택지가 있습니다.

개인 명의

이전과 같이, 개인 계정이 쓴 콘텐츠로 올라갑니다.

조직 명의

조직으로서 작성한 콘텐츠로 올라가며, 다른 사람은 이 콘텐츠가 조직 구성원 중 누가 작성했는지 알 수 없습니다.

공동 저자

조직을 대표하여 개인 계정이 쓴 콘텐츠로 올라갑니다. 다른 사람에게는 해당 조직의 어느 구성원이 작성했는지 보입니다. 이 게시글이 바로 @hackerspub 조직 계정과 @hongminhee 개인 계정의 공동 명의로 쓰여진 예입니다.

ActivityPub

공동 저자는 ActivityPub 객체에서는 attributedTo 속성Organization 타입의 액터와 Person 타입의 액터가 함께 들어가는 것으로 표현됩니다.

"attributedTo": [
  "https://hackers.pub/ap/actors/019efc7c-70ad-7e2b-87dd-b1d36190cdee",
  "https://hackers.pub/ap/actors/019382d3-63d7-7cf7-86e8-91e2551c306c"
]

단, 아직 복수의 attributedTo 속성을 올바르게 해석하지 못하는 ActivityPub 소프트웨어가 많습니다. 그런 소프트웨어에서는 조직 계정의 명의로만 보일 수 있습니다.

콘텐츠 명의 선택 UI

이미 있는 조직 계정들

다음은 Hackers' Pub에 이미 개설된 조직 계정들의 목록입니다:

fedidev.kr

한국 연합우주 개발자 모임

한국에 거주하거나 한국어를 사용하는 연합우주(fediverse) 개발자들의 모임입니다.

@hackerspub@hackers.pub

Hackers' Pub에 드디어 개인 계정 외에 조직(organization) 계정을 만들 수 있게 되었습니다. 조직 계정은 Hackers' Pub에서 특정 조직·프로젝트의 공식 계정을 만들기 위한 용도입니다. GitHub이나 GitLab, Codeberg 등에서 조직 기능을 사용해 보셨다면, 혹은 Facebook에서 페이지 기능을 사용해 보셨다면, 비슷한 개념으로 받아들이셔도 됩니다. 조직 계정에는 하나 이상의 개인 계정이 속하게 되며, 구성원들 누구나 조직 명의로 단문(note) 및 게시글(article)을 올릴 수 있게 됩니다. 단, 조직 기능은 새 웹 프런트엔드(web-next)에서만 사용 가능합니다.

조직 계정은 개인 계정과 많은 면에서 공통점이 있습니다. 이름과 아바타도 가질 수 있고, 약력(bio)도 입력 가능합니다. 다른 계정을 팔로할 수도 있고, 팔로워도 가질 수 있습니다. 댓글도 쓸 수 있고 에모지 리액션도 달 수 있습니다.

반면, 조직 계정은 개인 계정과는 달리 로그인할 수 없습니다. 로그인 할 수 없으니 이메일이나 패스키 등도 갖지 않습니다. 대신, 조직 구성원의 개인 계정으로 로그인한 뒤, 조직 명의를 선택하는 식으로 동작합니다. 또한, 북마크나 초고(draft)는 여전히 개인 계정에만 저장할 수 있습니다.

여러분 조직·프로젝트의 구성원이 단 한 명이라고 하더라도, 공식 계정을 만들 때는 조직 계정으로 생성하는 것을 권장합니다.

ActivityPub

개인 계정의 경우 ActivityPub 객체 상으로 Person 타입으로 표현되는 반면, 조직 계정의 경우에는 Organization 타입으로 표현됩니다.

"type": "Organization"

조직 만들기

조직은 누구나 설정계정조직 만들기에 가셔서 만드실 수 있습니다. 개인 계정과 마찬가지로, 조직 계정 역시 하나의 초대장을 소모합니다.

설정 → 계정 → 조직 만들기 폼

개인 계정 ↔ 조직 계정 사이의 스위치

조직 구성원은 언제든지 자신의 개인 계정과 조직 계정 사이에서 스위치가 가능합니다. 하나 이상의 조직에 몸 담고 있을 경우, 좌측 사이드바의 하단에 계정 스위치 UI가 보이게 됩니다.

계정 스위치 UI

단문 및 게시글 작성

조직 구성원은 단문 및 게시글을 작성할 때 해당 콘텐츠를 어떤 명의로 올릴 것인지 결정할 수 있습니다. 크게 세 종류의 선택지가 있습니다.

개인 명의

이전과 같이, 개인 계정이 쓴 콘텐츠로 올라갑니다.

조직 명의

조직으로서 작성한 콘텐츠로 올라가며, 다른 사람은 이 콘텐츠가 조직 구성원 중 누가 작성했는지 알 수 없습니다.

공동 저자

조직을 대표하여 개인 계정이 쓴 콘텐츠로 올라갑니다. 다른 사람에게는 해당 조직의 어느 구성원이 작성했는지 보입니다. 이 게시글이 바로 @hackerspub 조직 계정과 @hongminhee 개인 계정의 공동 명의로 쓰여진 예입니다.

ActivityPub

공동 저자는 ActivityPub 객체에서는 attributedTo 속성Organization 타입의 액터와 Person 타입의 액터가 함께 들어가는 것으로 표현됩니다.

"attributedTo": [
  "https://hackers.pub/ap/actors/019efc7c-70ad-7e2b-87dd-b1d36190cdee",
  "https://hackers.pub/ap/actors/019382d3-63d7-7cf7-86e8-91e2551c306c"
]

단, 아직 복수의 attributedTo 속성을 올바르게 해석하지 못하는 ActivityPub 소프트웨어가 많습니다. 그런 소프트웨어에서는 조직 계정의 명의로만 보일 수 있습니다.

콘텐츠 명의 선택 UI

이미 있는 조직 계정들

다음은 Hackers' Pub에 이미 개설된 조직 계정들의 목록입니다:

fedidev.kr

한국 연합우주 개발자 모임

한국에 거주하거나 한국어를 사용하는 연합우주(fediverse) 개발자들의 모임입니다.

@hackerspub@hackers.pub

Hackers' Pub에 드디어 개인 계정 외에 조직(organization) 계정을 만들 수 있게 되었습니다. 조직 계정은 Hackers' Pub에서 특정 조직·프로젝트의 공식 계정을 만들기 위한 용도입니다. GitHub이나 GitLab, Codeberg 등에서 조직 기능을 사용해 보셨다면, 혹은 Facebook에서 페이지 기능을 사용해 보셨다면, 비슷한 개념으로 받아들이셔도 됩니다. 조직 계정에는 하나 이상의 개인 계정이 속하게 되며, 구성원들 누구나 조직 명의로 단문(note) 및 게시글(article)을 올릴 수 있게 됩니다. 단, 조직 기능은 새 웹 프런트엔드(web-next)에서만 사용 가능합니다.

조직 계정은 개인 계정과 많은 면에서 공통점이 있습니다. 이름과 아바타도 가질 수 있고, 약력(bio)도 입력 가능합니다. 다른 계정을 팔로할 수도 있고, 팔로워도 가질 수 있습니다. 댓글도 쓸 수 있고 에모지 리액션도 달 수 있습니다.

반면, 조직 계정은 개인 계정과는 달리 로그인할 수 없습니다. 로그인 할 수 없으니 이메일이나 패스키 등도 갖지 않습니다. 대신, 조직 구성원의 개인 계정으로 로그인한 뒤, 조직 명의를 선택하는 식으로 동작합니다. 또한, 북마크나 초고(draft)는 여전히 개인 계정에만 저장할 수 있습니다.

여러분 조직·프로젝트의 구성원이 단 한 명이라고 하더라도, 공식 계정을 만들 때는 조직 계정으로 생성하는 것을 권장합니다.

ActivityPub

개인 계정의 경우 ActivityPub 객체 상으로 Person 타입으로 표현되는 반면, 조직 계정의 경우에는 Organization 타입으로 표현됩니다.

"type": "Organization"

조직 만들기

조직은 누구나 설정계정조직 만들기에 가셔서 만드실 수 있습니다. 개인 계정과 마찬가지로, 조직 계정 역시 하나의 초대장을 소모합니다.

설정 → 계정 → 조직 만들기 폼

개인 계정 ↔ 조직 계정 사이의 스위치

조직 구성원은 언제든지 자신의 개인 계정과 조직 계정 사이에서 스위치가 가능합니다. 하나 이상의 조직에 몸 담고 있을 경우, 좌측 사이드바의 하단에 계정 스위치 UI가 보이게 됩니다.

계정 스위치 UI

단문 및 게시글 작성

조직 구성원은 단문 및 게시글을 작성할 때 해당 콘텐츠를 어떤 명의로 올릴 것인지 결정할 수 있습니다. 크게 세 종류의 선택지가 있습니다.

개인 명의

이전과 같이, 개인 계정이 쓴 콘텐츠로 올라갑니다.

조직 명의

조직으로서 작성한 콘텐츠로 올라가며, 다른 사람은 이 콘텐츠가 조직 구성원 중 누가 작성했는지 알 수 없습니다.

공동 저자

조직을 대표하여 개인 계정이 쓴 콘텐츠로 올라갑니다. 다른 사람에게는 해당 조직의 어느 구성원이 작성했는지 보입니다. 이 게시글이 바로 @hackerspub 조직 계정과 @hongminhee 개인 계정의 공동 명의로 쓰여진 예입니다.

ActivityPub

공동 저자는 ActivityPub 객체에서는 attributedTo 속성Organization 타입의 액터와 Person 타입의 액터가 함께 들어가는 것으로 표현됩니다.

"attributedTo": [
  "https://hackers.pub/ap/actors/019efc7c-70ad-7e2b-87dd-b1d36190cdee",
  "https://hackers.pub/ap/actors/019382d3-63d7-7cf7-86e8-91e2551c306c"
]

단, 아직 복수의 attributedTo 속성을 올바르게 해석하지 못하는 ActivityPub 소프트웨어가 많습니다. 그런 소프트웨어에서는 조직 계정의 명의로만 보일 수 있습니다.

콘텐츠 명의 선택 UI

이미 있는 조직 계정들

다음은 Hackers' Pub에 이미 개설된 조직 계정들의 목록입니다:

fedidev.kr

한국 연합우주 개발자 모임

한국에 거주하거나 한국어를 사용하는 연합우주(fediverse) 개발자들의 모임입니다.

@hackerspub@hackers.pub

Hackers' Pub에 드디어 개인 계정 외에 조직(organization) 계정을 만들 수 있게 되었습니다. 조직 계정은 Hackers' Pub에서 특정 조직·프로젝트의 공식 계정을 만들기 위한 용도입니다. GitHub이나 GitLab, Codeberg 등에서 조직 기능을 사용해 보셨다면, 혹은 Facebook에서 페이지 기능을 사용해 보셨다면, 비슷한 개념으로 받아들이셔도 됩니다. 조직 계정에는 하나 이상의 개인 계정이 속하게 되며, 구성원들 누구나 조직 명의로 단문(note) 및 게시글(article)을 올릴 수 있게 됩니다. 단, 조직 기능은 새 웹 프런트엔드(web-next)에서만 사용 가능합니다.

조직 계정은 개인 계정과 많은 면에서 공통점이 있습니다. 이름과 아바타도 가질 수 있고, 약력(bio)도 입력 가능합니다. 다른 계정을 팔로할 수도 있고, 팔로워도 가질 수 있습니다. 댓글도 쓸 수 있고 에모지 리액션도 달 수 있습니다.

반면, 조직 계정은 개인 계정과는 달리 로그인할 수 없습니다. 로그인 할 수 없으니 이메일이나 패스키 등도 갖지 않습니다. 대신, 조직 구성원의 개인 계정으로 로그인한 뒤, 조직 명의를 선택하는 식으로 동작합니다. 또한, 북마크나 초고(draft)는 여전히 개인 계정에만 저장할 수 있습니다.

여러분 조직·프로젝트의 구성원이 단 한 명이라고 하더라도, 공식 계정을 만들 때는 조직 계정으로 생성하는 것을 권장합니다.

ActivityPub

개인 계정의 경우 ActivityPub 객체 상으로 Person 타입으로 표현되는 반면, 조직 계정의 경우에는 Organization 타입으로 표현됩니다.

"type": "Organization"

조직 만들기

조직은 누구나 설정계정조직 만들기에 가셔서 만드실 수 있습니다. 개인 계정과 마찬가지로, 조직 계정 역시 하나의 초대장을 소모합니다.

설정 → 계정 → 조직 만들기 폼

개인 계정 ↔ 조직 계정 사이의 스위치

조직 구성원은 언제든지 자신의 개인 계정과 조직 계정 사이에서 스위치가 가능합니다. 하나 이상의 조직에 몸 담고 있을 경우, 좌측 사이드바의 하단에 계정 스위치 UI가 보이게 됩니다.

계정 스위치 UI

단문 및 게시글 작성

조직 구성원은 단문 및 게시글을 작성할 때 해당 콘텐츠를 어떤 명의로 올릴 것인지 결정할 수 있습니다. 크게 세 종류의 선택지가 있습니다.

개인 명의

이전과 같이, 개인 계정이 쓴 콘텐츠로 올라갑니다.

조직 명의

조직으로서 작성한 콘텐츠로 올라가며, 다른 사람은 이 콘텐츠가 조직 구성원 중 누가 작성했는지 알 수 없습니다.

공동 저자

조직을 대표하여 개인 계정이 쓴 콘텐츠로 올라갑니다. 다른 사람에게는 해당 조직의 어느 구성원이 작성했는지 보입니다. 이 게시글이 바로 @hackerspub 조직 계정과 @hongminhee 개인 계정의 공동 명의로 쓰여진 예입니다.

ActivityPub

공동 저자는 ActivityPub 객체에서는 attributedTo 속성Organization 타입의 액터와 Person 타입의 액터가 함께 들어가는 것으로 표현됩니다.

"attributedTo": [
  "https://hackers.pub/ap/actors/019efc7c-70ad-7e2b-87dd-b1d36190cdee",
  "https://hackers.pub/ap/actors/019382d3-63d7-7cf7-86e8-91e2551c306c"
]

단, 아직 복수의 attributedTo 속성을 올바르게 해석하지 못하는 ActivityPub 소프트웨어가 많습니다. 그런 소프트웨어에서는 조직 계정의 명의로만 보일 수 있습니다.

콘텐츠 명의 선택 UI

이미 있는 조직 계정들

다음은 Hackers' Pub에 이미 개설된 조직 계정들의 목록입니다:

fedidev.kr

한국 연합우주 개발자 모임

한국에 거주하거나 한국어를 사용하는 연합우주(fediverse) 개발자들의 모임입니다.

知人(지인)@siliconsjang 님이 오늘 SiliconBeest v1.0.0을 公開(공개)했습니다. Fedify와 Cloudflare를 基盤(기반)으로 만든 소프트웨어인데, Workers, D1, R2, Queues 등 서버리스 스택 위에서 全部(전부) 돌아갑니다.

發想(발상)出發點(출발점)이 재밌습니다. Cloudflare 障礙(장애)聯合宇宙(연합우주) 서버들이 덩달아 다운되는 걸 보고, 「그럼 아예 Cloudflare 위에서 돌리면 되지 않나?」라는 생각에서 始作(시작)했다고 하네요.

費用(비용) ()에서는 小規模(소규모) 인스턴스는 Cloudflare 無料(무료) 플랜, 조금 더 큰 規模(규모)() $5 플랜으로 堪當(감당)할 수 있도록 하는 게 目標(목표)라고 합니다. 아직 初期(초기) 버전이라 未具顯(미구현) 機能(기능)이 많고, Mastodon 및 Misskey API 互換(호환)長期(장기) 目標(목표)로 보고 있다네요.

Fedify를 써주시는 분이라 반갑기도 하고, 應援(응원)하고 싶어 紹介(소개)합니다.

소스 코드는 AGPL 3.0으로 GitHub에 공개되어 있습니다.

github.com

GitHub - SJang1/siliconbeest: Fediverse in Cloudflare Workers + live serverless code

Fediverse in Cloudflare Workers + live serverless code - SJang1/siliconbeest

@siliconsjang@hackers.pub

안녕하세요! Hello everyone!

SiliconBeest v1.0.0 공개

마스토돈 API 호환을 목표로 하는 Cloudflare 엣지 컴퓨팅 기반 서버리스 연합우주 소프트웨어, SiliconBeest v1.0.0을 공개하게 되어 기쁩니다.

I'm pleased to announce SiliconBeest v1.0.0, a serverless fediverse software project built on Cloudflare edge computing, aiming for Mastodon API compatibility.

SiliconBeest Logo - a wildebeest with silicon on it


설명 (Description)

ko

  • SiliconBeest는 Cloudflare Workers 환경에서 동작하는 연합우주 프로젝트입니다.
  • Cloudflare 장애가 발생했을 때 다수의 연합우주 서버가 함께 접속 불가 상태가 되는 것을 보며, 연합우주 역시 Cloudflare 인프라에 상당히 의존하고 있다는 점에 착안했습니다.
  • 그렇다면 아예 Cloudflare 위에서 동작하는 연합우주 소프트웨어를 만들어보자는 생각에서 시작했습니다.
  • Cloudflare Inc.에서 개발했던 Wildebeest 프로젝트의 아이디어와 일부 코드를 참고했습니다.
  • 프로젝트 이름은 제 닉네임인 silicon(sjang) 이랑 Cloudflare의 Wildebeest를 조합해 SiliconBeest로 정했습니다.
  • 적은 사용자 수와 작은 규모의 연합을 기준으로는 Cloudflare 무료 플랜에서도 운영할 수 있도록, 조금 더 큰 규모의 연합에서는 월 $5 플랜으로도 감당할 수 있도록 만드는 것을 목표로 하고 있습니다.
  • API 측면에서 SiliconBeest의 목표는 Mastodon 및 Misskey API와의 호환입니다. 다만 이론적으로 가능한 것과 실제 구현은 별개의 문제이기 때문에, 해당 부분은 아직 개발 중이며 장기적인 목표로 보고 있습니다.

en

  • SiliconBeest is a fediverse project designed to run on Cloudflare Workers.
  • After seeing many fediverse servers become unavailable when Cloudflare had outages, I realized that the fediverse already relies heavily on Cloudflare infrastructure.
  • So I thought: why not build fediverse software directly on top of Cloudflare?
  • This project was inspired by Cloudflare Inc.’s Wildebeest project, and it also references some of its ideas and code.
  • The project name, SiliconBeest, comes from my nickname silicon(sjang) combined with Cloudflare’s Wildebeest.
  • I’m still working on making it as inexpensive to run as possible. For now, the goal is to support a small number of users with a small federation footprint on the free plan, and a medium federation footprint on the $5 plan.
  • From an API perspective, SiliconBeest aims to be compatible with both Mastodon and Misskey APIs. However, as many people know, full compatibility is difficult in practice, so this remains a long-term goal rather than something fully implemented today.

아직은 초기 버전이라 구현되지 않은 부분도 많지만, Cloudflare Workers, D1, R2, Queues 등 Cloudflare의 서버리스 인프라 위에서 연합우주 소프트웨어를 얼마나 가볍고 저렴하게 운영할 수 있는지 실험하고 있습니다.

This is still an early version, and many parts are not implemented yet. However, SiliconBeest is an experiment in how lightweight and affordable fediverse software can be when built on top of Cloudflare’s serverless infrastructure, such as Workers, D1, R2, and Queues.

현재 v1.0.0에서는 기본적인 구조와 핵심 기능을 먼저 정리하는 데 집중했으며, 앞으로 Mastodon API 호환성, federation 안정성, 관리 도구, 문서화 등을 점진적으로 개선해나갈 예정입니다.

In v1.0.0, I focused on organizing the basic architecture and core functionality first. Going forward, I plan to gradually improve Mastodon API compatibility, federation stability, admin tooling, and documentation.

관심 있으신 분들은 GitHub 저장소를 확인해주시고, 이슈나 피드백도 언제든 환영합니다.

If you’re interested, please check out the GitHub repository. Issues, feedback, and suggestions are always welcome.

https://github.com/SJang1/siliconbeest


설치 및 배포 방법 (Installation and Deployment)

SiliconBeest는 GitHub 템플릿과 Cloudflare를 이용해 비교적 간단하게 배포할 수 있습니다.

  1. GitHub 템플릿에서 새 저장소를 생성합니다.
  2. Cloudflare에서 필요한 리소스와 환경을 설정합니다.
  3. Cloudflare API 토큰과 필요한 환경변수를 GitHub Secrets에 저장합니다.
  4. GitHub Actions를 통해 자동 배포를 진행합니다.
  5. 배포가 완료되면 인스턴스 설정을 마무리합니다.

아직 설치 과정은 계속 다듬고 있으며, 개선사항이 많음을 알고 있습니다. 추후 보강해 나갈 예정이며, 이에 대한 PR도 환영입니다.

SiliconBeest can be deployed relatively easily using a GitHub template and Cloudflare.

  1. Create a new repository from the GitHub template.
  2. Set up the required resources and environment on Cloudflare.
  3. Store the Cloudflare API token and required environment variables in GitHub Secrets.
  4. Deploy automatically using GitHub Actions.
  5. Once deployment is complete, finish configuring your instance.

The installation process is still being refined, and I’m aware that there is plenty of room for improvement. I plan to keep improving the documentation and deployment flow over time, and related PRs are always welcome.

知人(지인)@siliconsjang 님이 오늘 SiliconBeest v1.0.0을 公開(공개)했습니다. Fedify와 Cloudflare를 基盤(기반)으로 만든 소프트웨어인데, Workers, D1, R2, Queues 등 서버리스 스택 위에서 全部(전부) 돌아갑니다.

發想(발상)出發點(출발점)이 재밌습니다. Cloudflare 障礙(장애)聯合宇宙(연합우주) 서버들이 덩달아 다운되는 걸 보고, 「그럼 아예 Cloudflare 위에서 돌리면 되지 않나?」라는 생각에서 始作(시작)했다고 하네요.

費用(비용) ()에서는 小規模(소규모) 인스턴스는 Cloudflare 無料(무료) 플랜, 조금 더 큰 規模(규모)() $5 플랜으로 堪當(감당)할 수 있도록 하는 게 目標(목표)라고 합니다. 아직 初期(초기) 버전이라 未具顯(미구현) 機能(기능)이 많고, Mastodon 및 Misskey API 互換(호환)長期(장기) 目標(목표)로 보고 있다네요.

Fedify를 써주시는 분이라 반갑기도 하고, 應援(응원)하고 싶어 紹介(소개)합니다.

소스 코드는 AGPL 3.0으로 GitHub에 공개되어 있습니다.

github.com

GitHub - SJang1/siliconbeest: Fediverse in Cloudflare Workers + live serverless code

Fediverse in Cloudflare Workers + live serverless code - SJang1/siliconbeest

@siliconsjang@hackers.pub

안녕하세요! Hello everyone!

SiliconBeest v1.0.0 공개

마스토돈 API 호환을 목표로 하는 Cloudflare 엣지 컴퓨팅 기반 서버리스 연합우주 소프트웨어, SiliconBeest v1.0.0을 공개하게 되어 기쁩니다.

I'm pleased to announce SiliconBeest v1.0.0, a serverless fediverse software project built on Cloudflare edge computing, aiming for Mastodon API compatibility.

SiliconBeest Logo - a wildebeest with silicon on it


설명 (Description)

ko

  • SiliconBeest는 Cloudflare Workers 환경에서 동작하는 연합우주 프로젝트입니다.
  • Cloudflare 장애가 발생했을 때 다수의 연합우주 서버가 함께 접속 불가 상태가 되는 것을 보며, 연합우주 역시 Cloudflare 인프라에 상당히 의존하고 있다는 점에 착안했습니다.
  • 그렇다면 아예 Cloudflare 위에서 동작하는 연합우주 소프트웨어를 만들어보자는 생각에서 시작했습니다.
  • Cloudflare Inc.에서 개발했던 Wildebeest 프로젝트의 아이디어와 일부 코드를 참고했습니다.
  • 프로젝트 이름은 제 닉네임인 silicon(sjang) 이랑 Cloudflare의 Wildebeest를 조합해 SiliconBeest로 정했습니다.
  • 적은 사용자 수와 작은 규모의 연합을 기준으로는 Cloudflare 무료 플랜에서도 운영할 수 있도록, 조금 더 큰 규모의 연합에서는 월 $5 플랜으로도 감당할 수 있도록 만드는 것을 목표로 하고 있습니다.
  • API 측면에서 SiliconBeest의 목표는 Mastodon 및 Misskey API와의 호환입니다. 다만 이론적으로 가능한 것과 실제 구현은 별개의 문제이기 때문에, 해당 부분은 아직 개발 중이며 장기적인 목표로 보고 있습니다.

en

  • SiliconBeest is a fediverse project designed to run on Cloudflare Workers.
  • After seeing many fediverse servers become unavailable when Cloudflare had outages, I realized that the fediverse already relies heavily on Cloudflare infrastructure.
  • So I thought: why not build fediverse software directly on top of Cloudflare?
  • This project was inspired by Cloudflare Inc.’s Wildebeest project, and it also references some of its ideas and code.
  • The project name, SiliconBeest, comes from my nickname silicon(sjang) combined with Cloudflare’s Wildebeest.
  • I’m still working on making it as inexpensive to run as possible. For now, the goal is to support a small number of users with a small federation footprint on the free plan, and a medium federation footprint on the $5 plan.
  • From an API perspective, SiliconBeest aims to be compatible with both Mastodon and Misskey APIs. However, as many people know, full compatibility is difficult in practice, so this remains a long-term goal rather than something fully implemented today.

아직은 초기 버전이라 구현되지 않은 부분도 많지만, Cloudflare Workers, D1, R2, Queues 등 Cloudflare의 서버리스 인프라 위에서 연합우주 소프트웨어를 얼마나 가볍고 저렴하게 운영할 수 있는지 실험하고 있습니다.

This is still an early version, and many parts are not implemented yet. However, SiliconBeest is an experiment in how lightweight and affordable fediverse software can be when built on top of Cloudflare’s serverless infrastructure, such as Workers, D1, R2, and Queues.

현재 v1.0.0에서는 기본적인 구조와 핵심 기능을 먼저 정리하는 데 집중했으며, 앞으로 Mastodon API 호환성, federation 안정성, 관리 도구, 문서화 등을 점진적으로 개선해나갈 예정입니다.

In v1.0.0, I focused on organizing the basic architecture and core functionality first. Going forward, I plan to gradually improve Mastodon API compatibility, federation stability, admin tooling, and documentation.

관심 있으신 분들은 GitHub 저장소를 확인해주시고, 이슈나 피드백도 언제든 환영합니다.

If you’re interested, please check out the GitHub repository. Issues, feedback, and suggestions are always welcome.

https://github.com/SJang1/siliconbeest


설치 및 배포 방법 (Installation and Deployment)

SiliconBeest는 GitHub 템플릿과 Cloudflare를 이용해 비교적 간단하게 배포할 수 있습니다.

  1. GitHub 템플릿에서 새 저장소를 생성합니다.
  2. Cloudflare에서 필요한 리소스와 환경을 설정합니다.
  3. Cloudflare API 토큰과 필요한 환경변수를 GitHub Secrets에 저장합니다.
  4. GitHub Actions를 통해 자동 배포를 진행합니다.
  5. 배포가 완료되면 인스턴스 설정을 마무리합니다.

아직 설치 과정은 계속 다듬고 있으며, 개선사항이 많음을 알고 있습니다. 추후 보강해 나갈 예정이며, 이에 대한 PR도 환영입니다.

SiliconBeest can be deployed relatively easily using a GitHub template and Cloudflare.

  1. Create a new repository from the GitHub template.
  2. Set up the required resources and environment on Cloudflare.
  3. Store the Cloudflare API token and required environment variables in GitHub Secrets.
  4. Deploy automatically using GitHub Actions.
  5. Once deployment is complete, finish configuring your instance.

The installation process is still being refined, and I’m aware that there is plenty of room for improvement. I plan to keep improving the documentation and deployment flow over time, and related PRs are always welcome.

知人(지인)@siliconsjang 님이 오늘 SiliconBeest v1.0.0을 公開(공개)했습니다. Fedify와 Cloudflare를 基盤(기반)으로 만든 소프트웨어인데, Workers, D1, R2, Queues 등 서버리스 스택 위에서 全部(전부) 돌아갑니다.

發想(발상)出發點(출발점)이 재밌습니다. Cloudflare 障礙(장애)聯合宇宙(연합우주) 서버들이 덩달아 다운되는 걸 보고, 「그럼 아예 Cloudflare 위에서 돌리면 되지 않나?」라는 생각에서 始作(시작)했다고 하네요.

費用(비용) ()에서는 小規模(소규모) 인스턴스는 Cloudflare 無料(무료) 플랜, 조금 더 큰 規模(규모)() $5 플랜으로 堪當(감당)할 수 있도록 하는 게 目標(목표)라고 합니다. 아직 初期(초기) 버전이라 未具顯(미구현) 機能(기능)이 많고, Mastodon 및 Misskey API 互換(호환)長期(장기) 目標(목표)로 보고 있다네요.

Fedify를 써주시는 분이라 반갑기도 하고, 應援(응원)하고 싶어 紹介(소개)합니다.

소스 코드는 AGPL 3.0으로 GitHub에 공개되어 있습니다.

github.com

GitHub - SJang1/siliconbeest: Fediverse in Cloudflare Workers + live serverless code

Fediverse in Cloudflare Workers + live serverless code - SJang1/siliconbeest

@siliconsjang@hackers.pub

안녕하세요! Hello everyone!

SiliconBeest v1.0.0 공개

마스토돈 API 호환을 목표로 하는 Cloudflare 엣지 컴퓨팅 기반 서버리스 연합우주 소프트웨어, SiliconBeest v1.0.0을 공개하게 되어 기쁩니다.

I'm pleased to announce SiliconBeest v1.0.0, a serverless fediverse software project built on Cloudflare edge computing, aiming for Mastodon API compatibility.

SiliconBeest Logo - a wildebeest with silicon on it


설명 (Description)

ko

  • SiliconBeest는 Cloudflare Workers 환경에서 동작하는 연합우주 프로젝트입니다.
  • Cloudflare 장애가 발생했을 때 다수의 연합우주 서버가 함께 접속 불가 상태가 되는 것을 보며, 연합우주 역시 Cloudflare 인프라에 상당히 의존하고 있다는 점에 착안했습니다.
  • 그렇다면 아예 Cloudflare 위에서 동작하는 연합우주 소프트웨어를 만들어보자는 생각에서 시작했습니다.
  • Cloudflare Inc.에서 개발했던 Wildebeest 프로젝트의 아이디어와 일부 코드를 참고했습니다.
  • 프로젝트 이름은 제 닉네임인 silicon(sjang) 이랑 Cloudflare의 Wildebeest를 조합해 SiliconBeest로 정했습니다.
  • 적은 사용자 수와 작은 규모의 연합을 기준으로는 Cloudflare 무료 플랜에서도 운영할 수 있도록, 조금 더 큰 규모의 연합에서는 월 $5 플랜으로도 감당할 수 있도록 만드는 것을 목표로 하고 있습니다.
  • API 측면에서 SiliconBeest의 목표는 Mastodon 및 Misskey API와의 호환입니다. 다만 이론적으로 가능한 것과 실제 구현은 별개의 문제이기 때문에, 해당 부분은 아직 개발 중이며 장기적인 목표로 보고 있습니다.

en

  • SiliconBeest is a fediverse project designed to run on Cloudflare Workers.
  • After seeing many fediverse servers become unavailable when Cloudflare had outages, I realized that the fediverse already relies heavily on Cloudflare infrastructure.
  • So I thought: why not build fediverse software directly on top of Cloudflare?
  • This project was inspired by Cloudflare Inc.’s Wildebeest project, and it also references some of its ideas and code.
  • The project name, SiliconBeest, comes from my nickname silicon(sjang) combined with Cloudflare’s Wildebeest.
  • I’m still working on making it as inexpensive to run as possible. For now, the goal is to support a small number of users with a small federation footprint on the free plan, and a medium federation footprint on the $5 plan.
  • From an API perspective, SiliconBeest aims to be compatible with both Mastodon and Misskey APIs. However, as many people know, full compatibility is difficult in practice, so this remains a long-term goal rather than something fully implemented today.

아직은 초기 버전이라 구현되지 않은 부분도 많지만, Cloudflare Workers, D1, R2, Queues 등 Cloudflare의 서버리스 인프라 위에서 연합우주 소프트웨어를 얼마나 가볍고 저렴하게 운영할 수 있는지 실험하고 있습니다.

This is still an early version, and many parts are not implemented yet. However, SiliconBeest is an experiment in how lightweight and affordable fediverse software can be when built on top of Cloudflare’s serverless infrastructure, such as Workers, D1, R2, and Queues.

현재 v1.0.0에서는 기본적인 구조와 핵심 기능을 먼저 정리하는 데 집중했으며, 앞으로 Mastodon API 호환성, federation 안정성, 관리 도구, 문서화 등을 점진적으로 개선해나갈 예정입니다.

In v1.0.0, I focused on organizing the basic architecture and core functionality first. Going forward, I plan to gradually improve Mastodon API compatibility, federation stability, admin tooling, and documentation.

관심 있으신 분들은 GitHub 저장소를 확인해주시고, 이슈나 피드백도 언제든 환영합니다.

If you’re interested, please check out the GitHub repository. Issues, feedback, and suggestions are always welcome.

https://github.com/SJang1/siliconbeest


설치 및 배포 방법 (Installation and Deployment)

SiliconBeest는 GitHub 템플릿과 Cloudflare를 이용해 비교적 간단하게 배포할 수 있습니다.

  1. GitHub 템플릿에서 새 저장소를 생성합니다.
  2. Cloudflare에서 필요한 리소스와 환경을 설정합니다.
  3. Cloudflare API 토큰과 필요한 환경변수를 GitHub Secrets에 저장합니다.
  4. GitHub Actions를 통해 자동 배포를 진행합니다.
  5. 배포가 완료되면 인스턴스 설정을 마무리합니다.

아직 설치 과정은 계속 다듬고 있으며, 개선사항이 많음을 알고 있습니다. 추후 보강해 나갈 예정이며, 이에 대한 PR도 환영입니다.

SiliconBeest can be deployed relatively easily using a GitHub template and Cloudflare.

  1. Create a new repository from the GitHub template.
  2. Set up the required resources and environment on Cloudflare.
  3. Store the Cloudflare API token and required environment variables in GitHub Secrets.
  4. Deploy automatically using GitHub Actions.
  5. Once deployment is complete, finish configuring your instance.

The installation process is still being refined, and I’m aware that there is plenty of room for improvement. I plan to keep improving the documentation and deployment flow over time, and related PRs are always welcome.

知人(지인)@siliconsjang 님이 오늘 SiliconBeest v1.0.0을 公開(공개)했습니다. Fedify와 Cloudflare를 基盤(기반)으로 만든 소프트웨어인데, Workers, D1, R2, Queues 등 서버리스 스택 위에서 全部(전부) 돌아갑니다.

發想(발상)出發點(출발점)이 재밌습니다. Cloudflare 障礙(장애)聯合宇宙(연합우주) 서버들이 덩달아 다운되는 걸 보고, 「그럼 아예 Cloudflare 위에서 돌리면 되지 않나?」라는 생각에서 始作(시작)했다고 하네요.

費用(비용) ()에서는 小規模(소규모) 인스턴스는 Cloudflare 無料(무료) 플랜, 조금 더 큰 規模(규모)() $5 플랜으로 堪當(감당)할 수 있도록 하는 게 目標(목표)라고 합니다. 아직 初期(초기) 버전이라 未具顯(미구현) 機能(기능)이 많고, Mastodon 및 Misskey API 互換(호환)長期(장기) 目標(목표)로 보고 있다네요.

Fedify를 써주시는 분이라 반갑기도 하고, 應援(응원)하고 싶어 紹介(소개)합니다.

소스 코드는 AGPL 3.0으로 GitHub에 공개되어 있습니다.

github.com

GitHub - SJang1/siliconbeest: Fediverse in Cloudflare Workers + live serverless code

Fediverse in Cloudflare Workers + live serverless code - SJang1/siliconbeest

@siliconsjang@hackers.pub

안녕하세요! Hello everyone!

SiliconBeest v1.0.0 공개

마스토돈 API 호환을 목표로 하는 Cloudflare 엣지 컴퓨팅 기반 서버리스 연합우주 소프트웨어, SiliconBeest v1.0.0을 공개하게 되어 기쁩니다.

I'm pleased to announce SiliconBeest v1.0.0, a serverless fediverse software project built on Cloudflare edge computing, aiming for Mastodon API compatibility.

SiliconBeest Logo - a wildebeest with silicon on it


설명 (Description)

ko

  • SiliconBeest는 Cloudflare Workers 환경에서 동작하는 연합우주 프로젝트입니다.
  • Cloudflare 장애가 발생했을 때 다수의 연합우주 서버가 함께 접속 불가 상태가 되는 것을 보며, 연합우주 역시 Cloudflare 인프라에 상당히 의존하고 있다는 점에 착안했습니다.
  • 그렇다면 아예 Cloudflare 위에서 동작하는 연합우주 소프트웨어를 만들어보자는 생각에서 시작했습니다.
  • Cloudflare Inc.에서 개발했던 Wildebeest 프로젝트의 아이디어와 일부 코드를 참고했습니다.
  • 프로젝트 이름은 제 닉네임인 silicon(sjang) 이랑 Cloudflare의 Wildebeest를 조합해 SiliconBeest로 정했습니다.
  • 적은 사용자 수와 작은 규모의 연합을 기준으로는 Cloudflare 무료 플랜에서도 운영할 수 있도록, 조금 더 큰 규모의 연합에서는 월 $5 플랜으로도 감당할 수 있도록 만드는 것을 목표로 하고 있습니다.
  • API 측면에서 SiliconBeest의 목표는 Mastodon 및 Misskey API와의 호환입니다. 다만 이론적으로 가능한 것과 실제 구현은 별개의 문제이기 때문에, 해당 부분은 아직 개발 중이며 장기적인 목표로 보고 있습니다.

en

  • SiliconBeest is a fediverse project designed to run on Cloudflare Workers.
  • After seeing many fediverse servers become unavailable when Cloudflare had outages, I realized that the fediverse already relies heavily on Cloudflare infrastructure.
  • So I thought: why not build fediverse software directly on top of Cloudflare?
  • This project was inspired by Cloudflare Inc.’s Wildebeest project, and it also references some of its ideas and code.
  • The project name, SiliconBeest, comes from my nickname silicon(sjang) combined with Cloudflare’s Wildebeest.
  • I’m still working on making it as inexpensive to run as possible. For now, the goal is to support a small number of users with a small federation footprint on the free plan, and a medium federation footprint on the $5 plan.
  • From an API perspective, SiliconBeest aims to be compatible with both Mastodon and Misskey APIs. However, as many people know, full compatibility is difficult in practice, so this remains a long-term goal rather than something fully implemented today.

아직은 초기 버전이라 구현되지 않은 부분도 많지만, Cloudflare Workers, D1, R2, Queues 등 Cloudflare의 서버리스 인프라 위에서 연합우주 소프트웨어를 얼마나 가볍고 저렴하게 운영할 수 있는지 실험하고 있습니다.

This is still an early version, and many parts are not implemented yet. However, SiliconBeest is an experiment in how lightweight and affordable fediverse software can be when built on top of Cloudflare’s serverless infrastructure, such as Workers, D1, R2, and Queues.

현재 v1.0.0에서는 기본적인 구조와 핵심 기능을 먼저 정리하는 데 집중했으며, 앞으로 Mastodon API 호환성, federation 안정성, 관리 도구, 문서화 등을 점진적으로 개선해나갈 예정입니다.

In v1.0.0, I focused on organizing the basic architecture and core functionality first. Going forward, I plan to gradually improve Mastodon API compatibility, federation stability, admin tooling, and documentation.

관심 있으신 분들은 GitHub 저장소를 확인해주시고, 이슈나 피드백도 언제든 환영합니다.

If you’re interested, please check out the GitHub repository. Issues, feedback, and suggestions are always welcome.

https://github.com/SJang1/siliconbeest


설치 및 배포 방법 (Installation and Deployment)

SiliconBeest는 GitHub 템플릿과 Cloudflare를 이용해 비교적 간단하게 배포할 수 있습니다.

  1. GitHub 템플릿에서 새 저장소를 생성합니다.
  2. Cloudflare에서 필요한 리소스와 환경을 설정합니다.
  3. Cloudflare API 토큰과 필요한 환경변수를 GitHub Secrets에 저장합니다.
  4. GitHub Actions를 통해 자동 배포를 진행합니다.
  5. 배포가 완료되면 인스턴스 설정을 마무리합니다.

아직 설치 과정은 계속 다듬고 있으며, 개선사항이 많음을 알고 있습니다. 추후 보강해 나갈 예정이며, 이에 대한 PR도 환영입니다.

SiliconBeest can be deployed relatively easily using a GitHub template and Cloudflare.

  1. Create a new repository from the GitHub template.
  2. Set up the required resources and environment on Cloudflare.
  3. Store the Cloudflare API token and required environment variables in GitHub Secrets.
  4. Deploy automatically using GitHub Actions.
  5. Once deployment is complete, finish configuring your instance.

The installation process is still being refined, and I’m aware that there is plenty of room for improvement. I plan to keep improving the documentation and deployment flow over time, and related PRs are always welcome.

知人(지인)@siliconsjang 님이 오늘 SiliconBeest v1.0.0을 公開(공개)했습니다. Fedify와 Cloudflare를 基盤(기반)으로 만든 소프트웨어인데, Workers, D1, R2, Queues 등 서버리스 스택 위에서 全部(전부) 돌아갑니다.

發想(발상)出發點(출발점)이 재밌습니다. Cloudflare 障礙(장애)聯合宇宙(연합우주) 서버들이 덩달아 다운되는 걸 보고, 「그럼 아예 Cloudflare 위에서 돌리면 되지 않나?」라는 생각에서 始作(시작)했다고 하네요.

費用(비용) ()에서는 小規模(소규모) 인스턴스는 Cloudflare 無料(무료) 플랜, 조금 더 큰 規模(규모)() $5 플랜으로 堪當(감당)할 수 있도록 하는 게 目標(목표)라고 합니다. 아직 初期(초기) 버전이라 未具顯(미구현) 機能(기능)이 많고, Mastodon 및 Misskey API 互換(호환)長期(장기) 目標(목표)로 보고 있다네요.

Fedify를 써주시는 분이라 반갑기도 하고, 應援(응원)하고 싶어 紹介(소개)합니다.

소스 코드는 AGPL 3.0으로 GitHub에 공개되어 있습니다.

github.com

GitHub - SJang1/siliconbeest: Fediverse in Cloudflare Workers + live serverless code

Fediverse in Cloudflare Workers + live serverless code - SJang1/siliconbeest

@siliconsjang@hackers.pub

안녕하세요! Hello everyone!

SiliconBeest v1.0.0 공개

마스토돈 API 호환을 목표로 하는 Cloudflare 엣지 컴퓨팅 기반 서버리스 연합우주 소프트웨어, SiliconBeest v1.0.0을 공개하게 되어 기쁩니다.

I'm pleased to announce SiliconBeest v1.0.0, a serverless fediverse software project built on Cloudflare edge computing, aiming for Mastodon API compatibility.

SiliconBeest Logo - a wildebeest with silicon on it


설명 (Description)

ko

  • SiliconBeest는 Cloudflare Workers 환경에서 동작하는 연합우주 프로젝트입니다.
  • Cloudflare 장애가 발생했을 때 다수의 연합우주 서버가 함께 접속 불가 상태가 되는 것을 보며, 연합우주 역시 Cloudflare 인프라에 상당히 의존하고 있다는 점에 착안했습니다.
  • 그렇다면 아예 Cloudflare 위에서 동작하는 연합우주 소프트웨어를 만들어보자는 생각에서 시작했습니다.
  • Cloudflare Inc.에서 개발했던 Wildebeest 프로젝트의 아이디어와 일부 코드를 참고했습니다.
  • 프로젝트 이름은 제 닉네임인 silicon(sjang) 이랑 Cloudflare의 Wildebeest를 조합해 SiliconBeest로 정했습니다.
  • 적은 사용자 수와 작은 규모의 연합을 기준으로는 Cloudflare 무료 플랜에서도 운영할 수 있도록, 조금 더 큰 규모의 연합에서는 월 $5 플랜으로도 감당할 수 있도록 만드는 것을 목표로 하고 있습니다.
  • API 측면에서 SiliconBeest의 목표는 Mastodon 및 Misskey API와의 호환입니다. 다만 이론적으로 가능한 것과 실제 구현은 별개의 문제이기 때문에, 해당 부분은 아직 개발 중이며 장기적인 목표로 보고 있습니다.

en

  • SiliconBeest is a fediverse project designed to run on Cloudflare Workers.
  • After seeing many fediverse servers become unavailable when Cloudflare had outages, I realized that the fediverse already relies heavily on Cloudflare infrastructure.
  • So I thought: why not build fediverse software directly on top of Cloudflare?
  • This project was inspired by Cloudflare Inc.’s Wildebeest project, and it also references some of its ideas and code.
  • The project name, SiliconBeest, comes from my nickname silicon(sjang) combined with Cloudflare’s Wildebeest.
  • I’m still working on making it as inexpensive to run as possible. For now, the goal is to support a small number of users with a small federation footprint on the free plan, and a medium federation footprint on the $5 plan.
  • From an API perspective, SiliconBeest aims to be compatible with both Mastodon and Misskey APIs. However, as many people know, full compatibility is difficult in practice, so this remains a long-term goal rather than something fully implemented today.

아직은 초기 버전이라 구현되지 않은 부분도 많지만, Cloudflare Workers, D1, R2, Queues 등 Cloudflare의 서버리스 인프라 위에서 연합우주 소프트웨어를 얼마나 가볍고 저렴하게 운영할 수 있는지 실험하고 있습니다.

This is still an early version, and many parts are not implemented yet. However, SiliconBeest is an experiment in how lightweight and affordable fediverse software can be when built on top of Cloudflare’s serverless infrastructure, such as Workers, D1, R2, and Queues.

현재 v1.0.0에서는 기본적인 구조와 핵심 기능을 먼저 정리하는 데 집중했으며, 앞으로 Mastodon API 호환성, federation 안정성, 관리 도구, 문서화 등을 점진적으로 개선해나갈 예정입니다.

In v1.0.0, I focused on organizing the basic architecture and core functionality first. Going forward, I plan to gradually improve Mastodon API compatibility, federation stability, admin tooling, and documentation.

관심 있으신 분들은 GitHub 저장소를 확인해주시고, 이슈나 피드백도 언제든 환영합니다.

If you’re interested, please check out the GitHub repository. Issues, feedback, and suggestions are always welcome.

https://github.com/SJang1/siliconbeest


설치 및 배포 방법 (Installation and Deployment)

SiliconBeest는 GitHub 템플릿과 Cloudflare를 이용해 비교적 간단하게 배포할 수 있습니다.

  1. GitHub 템플릿에서 새 저장소를 생성합니다.
  2. Cloudflare에서 필요한 리소스와 환경을 설정합니다.
  3. Cloudflare API 토큰과 필요한 환경변수를 GitHub Secrets에 저장합니다.
  4. GitHub Actions를 통해 자동 배포를 진행합니다.
  5. 배포가 완료되면 인스턴스 설정을 마무리합니다.

아직 설치 과정은 계속 다듬고 있으며, 개선사항이 많음을 알고 있습니다. 추후 보강해 나갈 예정이며, 이에 대한 PR도 환영입니다.

SiliconBeest can be deployed relatively easily using a GitHub template and Cloudflare.

  1. Create a new repository from the GitHub template.
  2. Set up the required resources and environment on Cloudflare.
  3. Store the Cloudflare API token and required environment variables in GitHub Secrets.
  4. Deploy automatically using GitHub Actions.
  5. Once deployment is complete, finish configuring your instance.

The installation process is still being refined, and I’m aware that there is plenty of room for improvement. I plan to keep improving the documentation and deployment flow over time, and related PRs are always welcome.

知人(지인)@siliconsjang 님이 오늘 SiliconBeest v1.0.0을 公開(공개)했습니다. Fedify와 Cloudflare를 基盤(기반)으로 만든 소프트웨어인데, Workers, D1, R2, Queues 등 서버리스 스택 위에서 全部(전부) 돌아갑니다.

發想(발상)出發點(출발점)이 재밌습니다. Cloudflare 障礙(장애)聯合宇宙(연합우주) 서버들이 덩달아 다운되는 걸 보고, 「그럼 아예 Cloudflare 위에서 돌리면 되지 않나?」라는 생각에서 始作(시작)했다고 하네요.

費用(비용) ()에서는 小規模(소규모) 인스턴스는 Cloudflare 無料(무료) 플랜, 조금 더 큰 規模(규모)() $5 플랜으로 堪當(감당)할 수 있도록 하는 게 目標(목표)라고 합니다. 아직 初期(초기) 버전이라 未具顯(미구현) 機能(기능)이 많고, Mastodon 및 Misskey API 互換(호환)長期(장기) 目標(목표)로 보고 있다네요.

Fedify를 써주시는 분이라 반갑기도 하고, 應援(응원)하고 싶어 紹介(소개)합니다.

소스 코드는 AGPL 3.0으로 GitHub에 공개되어 있습니다.

github.com

GitHub - SJang1/siliconbeest: Fediverse in Cloudflare Workers + live serverless code

Fediverse in Cloudflare Workers + live serverless code - SJang1/siliconbeest

@siliconsjang@hackers.pub

안녕하세요! Hello everyone!

SiliconBeest v1.0.0 공개

마스토돈 API 호환을 목표로 하는 Cloudflare 엣지 컴퓨팅 기반 서버리스 연합우주 소프트웨어, SiliconBeest v1.0.0을 공개하게 되어 기쁩니다.

I'm pleased to announce SiliconBeest v1.0.0, a serverless fediverse software project built on Cloudflare edge computing, aiming for Mastodon API compatibility.

SiliconBeest Logo - a wildebeest with silicon on it


설명 (Description)

ko

  • SiliconBeest는 Cloudflare Workers 환경에서 동작하는 연합우주 프로젝트입니다.
  • Cloudflare 장애가 발생했을 때 다수의 연합우주 서버가 함께 접속 불가 상태가 되는 것을 보며, 연합우주 역시 Cloudflare 인프라에 상당히 의존하고 있다는 점에 착안했습니다.
  • 그렇다면 아예 Cloudflare 위에서 동작하는 연합우주 소프트웨어를 만들어보자는 생각에서 시작했습니다.
  • Cloudflare Inc.에서 개발했던 Wildebeest 프로젝트의 아이디어와 일부 코드를 참고했습니다.
  • 프로젝트 이름은 제 닉네임인 silicon(sjang) 이랑 Cloudflare의 Wildebeest를 조합해 SiliconBeest로 정했습니다.
  • 적은 사용자 수와 작은 규모의 연합을 기준으로는 Cloudflare 무료 플랜에서도 운영할 수 있도록, 조금 더 큰 규모의 연합에서는 월 $5 플랜으로도 감당할 수 있도록 만드는 것을 목표로 하고 있습니다.
  • API 측면에서 SiliconBeest의 목표는 Mastodon 및 Misskey API와의 호환입니다. 다만 이론적으로 가능한 것과 실제 구현은 별개의 문제이기 때문에, 해당 부분은 아직 개발 중이며 장기적인 목표로 보고 있습니다.

en

  • SiliconBeest is a fediverse project designed to run on Cloudflare Workers.
  • After seeing many fediverse servers become unavailable when Cloudflare had outages, I realized that the fediverse already relies heavily on Cloudflare infrastructure.
  • So I thought: why not build fediverse software directly on top of Cloudflare?
  • This project was inspired by Cloudflare Inc.’s Wildebeest project, and it also references some of its ideas and code.
  • The project name, SiliconBeest, comes from my nickname silicon(sjang) combined with Cloudflare’s Wildebeest.
  • I’m still working on making it as inexpensive to run as possible. For now, the goal is to support a small number of users with a small federation footprint on the free plan, and a medium federation footprint on the $5 plan.
  • From an API perspective, SiliconBeest aims to be compatible with both Mastodon and Misskey APIs. However, as many people know, full compatibility is difficult in practice, so this remains a long-term goal rather than something fully implemented today.

아직은 초기 버전이라 구현되지 않은 부분도 많지만, Cloudflare Workers, D1, R2, Queues 등 Cloudflare의 서버리스 인프라 위에서 연합우주 소프트웨어를 얼마나 가볍고 저렴하게 운영할 수 있는지 실험하고 있습니다.

This is still an early version, and many parts are not implemented yet. However, SiliconBeest is an experiment in how lightweight and affordable fediverse software can be when built on top of Cloudflare’s serverless infrastructure, such as Workers, D1, R2, and Queues.

현재 v1.0.0에서는 기본적인 구조와 핵심 기능을 먼저 정리하는 데 집중했으며, 앞으로 Mastodon API 호환성, federation 안정성, 관리 도구, 문서화 등을 점진적으로 개선해나갈 예정입니다.

In v1.0.0, I focused on organizing the basic architecture and core functionality first. Going forward, I plan to gradually improve Mastodon API compatibility, federation stability, admin tooling, and documentation.

관심 있으신 분들은 GitHub 저장소를 확인해주시고, 이슈나 피드백도 언제든 환영합니다.

If you’re interested, please check out the GitHub repository. Issues, feedback, and suggestions are always welcome.

https://github.com/SJang1/siliconbeest


설치 및 배포 방법 (Installation and Deployment)

SiliconBeest는 GitHub 템플릿과 Cloudflare를 이용해 비교적 간단하게 배포할 수 있습니다.

  1. GitHub 템플릿에서 새 저장소를 생성합니다.
  2. Cloudflare에서 필요한 리소스와 환경을 설정합니다.
  3. Cloudflare API 토큰과 필요한 환경변수를 GitHub Secrets에 저장합니다.
  4. GitHub Actions를 통해 자동 배포를 진행합니다.
  5. 배포가 완료되면 인스턴스 설정을 마무리합니다.

아직 설치 과정은 계속 다듬고 있으며, 개선사항이 많음을 알고 있습니다. 추후 보강해 나갈 예정이며, 이에 대한 PR도 환영입니다.

SiliconBeest can be deployed relatively easily using a GitHub template and Cloudflare.

  1. Create a new repository from the GitHub template.
  2. Set up the required resources and environment on Cloudflare.
  3. Store the Cloudflare API token and required environment variables in GitHub Secrets.
  4. Deploy automatically using GitHub Actions.
  5. Once deployment is complete, finish configuring your instance.

The installation process is still being refined, and I’m aware that there is plenty of room for improvement. I plan to keep improving the documentation and deployment flow over time, and related PRs are always welcome.

知人(지인)@siliconsjang 님이 오늘 SiliconBeest v1.0.0을 公開(공개)했습니다. Fedify와 Cloudflare를 基盤(기반)으로 만든 소프트웨어인데, Workers, D1, R2, Queues 등 서버리스 스택 위에서 全部(전부) 돌아갑니다.

發想(발상)出發點(출발점)이 재밌습니다. Cloudflare 障礙(장애)聯合宇宙(연합우주) 서버들이 덩달아 다운되는 걸 보고, 「그럼 아예 Cloudflare 위에서 돌리면 되지 않나?」라는 생각에서 始作(시작)했다고 하네요.

費用(비용) ()에서는 小規模(소규모) 인스턴스는 Cloudflare 無料(무료) 플랜, 조금 더 큰 規模(규모)() $5 플랜으로 堪當(감당)할 수 있도록 하는 게 目標(목표)라고 합니다. 아직 初期(초기) 버전이라 未具顯(미구현) 機能(기능)이 많고, Mastodon 및 Misskey API 互換(호환)長期(장기) 目標(목표)로 보고 있다네요.

Fedify를 써주시는 분이라 반갑기도 하고, 應援(응원)하고 싶어 紹介(소개)합니다.

소스 코드는 AGPL 3.0으로 GitHub에 공개되어 있습니다.

github.com

GitHub - SJang1/siliconbeest: Fediverse in Cloudflare Workers + live serverless code

Fediverse in Cloudflare Workers + live serverless code - SJang1/siliconbeest

@siliconsjang@hackers.pub

안녕하세요! Hello everyone!

SiliconBeest v1.0.0 공개

마스토돈 API 호환을 목표로 하는 Cloudflare 엣지 컴퓨팅 기반 서버리스 연합우주 소프트웨어, SiliconBeest v1.0.0을 공개하게 되어 기쁩니다.

I'm pleased to announce SiliconBeest v1.0.0, a serverless fediverse software project built on Cloudflare edge computing, aiming for Mastodon API compatibility.

SiliconBeest Logo - a wildebeest with silicon on it


설명 (Description)

ko

  • SiliconBeest는 Cloudflare Workers 환경에서 동작하는 연합우주 프로젝트입니다.
  • Cloudflare 장애가 발생했을 때 다수의 연합우주 서버가 함께 접속 불가 상태가 되는 것을 보며, 연합우주 역시 Cloudflare 인프라에 상당히 의존하고 있다는 점에 착안했습니다.
  • 그렇다면 아예 Cloudflare 위에서 동작하는 연합우주 소프트웨어를 만들어보자는 생각에서 시작했습니다.
  • Cloudflare Inc.에서 개발했던 Wildebeest 프로젝트의 아이디어와 일부 코드를 참고했습니다.
  • 프로젝트 이름은 제 닉네임인 silicon(sjang) 이랑 Cloudflare의 Wildebeest를 조합해 SiliconBeest로 정했습니다.
  • 적은 사용자 수와 작은 규모의 연합을 기준으로는 Cloudflare 무료 플랜에서도 운영할 수 있도록, 조금 더 큰 규모의 연합에서는 월 $5 플랜으로도 감당할 수 있도록 만드는 것을 목표로 하고 있습니다.
  • API 측면에서 SiliconBeest의 목표는 Mastodon 및 Misskey API와의 호환입니다. 다만 이론적으로 가능한 것과 실제 구현은 별개의 문제이기 때문에, 해당 부분은 아직 개발 중이며 장기적인 목표로 보고 있습니다.

en

  • SiliconBeest is a fediverse project designed to run on Cloudflare Workers.
  • After seeing many fediverse servers become unavailable when Cloudflare had outages, I realized that the fediverse already relies heavily on Cloudflare infrastructure.
  • So I thought: why not build fediverse software directly on top of Cloudflare?
  • This project was inspired by Cloudflare Inc.’s Wildebeest project, and it also references some of its ideas and code.
  • The project name, SiliconBeest, comes from my nickname silicon(sjang) combined with Cloudflare’s Wildebeest.
  • I’m still working on making it as inexpensive to run as possible. For now, the goal is to support a small number of users with a small federation footprint on the free plan, and a medium federation footprint on the $5 plan.
  • From an API perspective, SiliconBeest aims to be compatible with both Mastodon and Misskey APIs. However, as many people know, full compatibility is difficult in practice, so this remains a long-term goal rather than something fully implemented today.

아직은 초기 버전이라 구현되지 않은 부분도 많지만, Cloudflare Workers, D1, R2, Queues 등 Cloudflare의 서버리스 인프라 위에서 연합우주 소프트웨어를 얼마나 가볍고 저렴하게 운영할 수 있는지 실험하고 있습니다.

This is still an early version, and many parts are not implemented yet. However, SiliconBeest is an experiment in how lightweight and affordable fediverse software can be when built on top of Cloudflare’s serverless infrastructure, such as Workers, D1, R2, and Queues.

현재 v1.0.0에서는 기본적인 구조와 핵심 기능을 먼저 정리하는 데 집중했으며, 앞으로 Mastodon API 호환성, federation 안정성, 관리 도구, 문서화 등을 점진적으로 개선해나갈 예정입니다.

In v1.0.0, I focused on organizing the basic architecture and core functionality first. Going forward, I plan to gradually improve Mastodon API compatibility, federation stability, admin tooling, and documentation.

관심 있으신 분들은 GitHub 저장소를 확인해주시고, 이슈나 피드백도 언제든 환영합니다.

If you’re interested, please check out the GitHub repository. Issues, feedback, and suggestions are always welcome.

https://github.com/SJang1/siliconbeest


설치 및 배포 방법 (Installation and Deployment)

SiliconBeest는 GitHub 템플릿과 Cloudflare를 이용해 비교적 간단하게 배포할 수 있습니다.

  1. GitHub 템플릿에서 새 저장소를 생성합니다.
  2. Cloudflare에서 필요한 리소스와 환경을 설정합니다.
  3. Cloudflare API 토큰과 필요한 환경변수를 GitHub Secrets에 저장합니다.
  4. GitHub Actions를 통해 자동 배포를 진행합니다.
  5. 배포가 완료되면 인스턴스 설정을 마무리합니다.

아직 설치 과정은 계속 다듬고 있으며, 개선사항이 많음을 알고 있습니다. 추후 보강해 나갈 예정이며, 이에 대한 PR도 환영입니다.

SiliconBeest can be deployed relatively easily using a GitHub template and Cloudflare.

  1. Create a new repository from the GitHub template.
  2. Set up the required resources and environment on Cloudflare.
  3. Store the Cloudflare API token and required environment variables in GitHub Secrets.
  4. Deploy automatically using GitHub Actions.
  5. Once deployment is complete, finish configuring your instance.

The installation process is still being refined, and I’m aware that there is plenty of room for improvement. I plan to keep improving the documentation and deployment flow over time, and related PRs are always welcome.

2026(타이베이, 8월 8–9일) Fediverse & Social Web 트랙 발표자 모집이 시작되었습니다! , , 오픈 소셜 웹 관련 주제라면 무엇이든 환영합니다. 마감은 5월 9일이고, COSCUP 참가는 무료입니다.

👉 https://hackers.pub/@fedidevkr/2026/fediverse-social-web-track-at-coscup-2026-cfp-ko

hackers.pub

COSCUP 2026 연합우주 & 소셜 웹 트랙: 발표자 모집

한국 연합우주 개발자 모임(FediDev KR)과 일본의 FediLUG가 2026년 대만 타이베이에서 개최되는 COSCUP 2026의 연합우주(Fediverse) 및 소셜 웹 트랙 발표자를 모집합니다. 이번 트랙은 액티비티펍(ActivityPub) 프로토콜 구현, 전용 클라이언트 및 라이브러리 개발, 인스턴스 운영 노하우, 그리고 연합 커뮤니티의 거버넌스와 같은 다양한 주제를 폭넓게 다룹니다. 동아시아 주요 오픈소스 컨퍼런스에서 처음으로 열리는 연합우주 전용 세션인 만큼, 개발자와 운영자들이 모여 기술적 통찰을 나누고 지역 커뮤니티의 결속을 다지는 중요한 기회가 될 것입니다.

다른 언어로 읽기: English (영어), 日本語 (일본어).


한국 연합우주 개발자 모임(FediDev KR)과 FediLUG(일본)이 COSCUP 2026 연합우주(fediverse) & 소셜 웹 트랙을 열고, 발표 제안을 받습니다.

COSCUP은 매년 대만 타이베이에서 열리는 참가비 무료의 자유·오픈 소스 소프트웨어 컨퍼런스입니다. FOSDEM의 동아시아판이라고 생각하시면 됩니다. 올해는 8월 8–9일 국립대만과학기술대학교에서 UbuCon Asia 2026과 공동 개최됩니다.

연합우주 & 소셜 웹 트랙은 하루 종일, 총 6시간 진행됩니다. 동아시아의 주요 오픈소스 컨퍼런스에서 열리는 첫 번째 연합우주 전용 트랙으로, 이 자리가 동아시아 연합우주 커뮤니티의 정기적인 모임으로 이어지기를 바랍니다.

발표 형식

기본 발표 시간은 30분입니다. 더 길거나 짧은 시간이 필요하다면 제출 시 희망 시간을 적어주세요.

주제

연합우주 및 오픈 소셜 웹과 관련된 주제라면 무엇이든 환영합니다.

  • ActivityPub 또는 관련 프로토콜 구현
  • ActivityPub 기반 소프트웨어용 클라이언트
  • 연합우주 개발을 위한 라이브러리, 툴킷, 프레임워크
  • 검색, 온보딩, 모더레이션 등 지원 서비스
  • 인스턴스 운영 및 관리
  • 거버넌스, 정책, 연합 커뮤니티 운영의 사회적 측면
  • 더 넓은 의미의 오픈 소셜 웹과 상호운용성

주요 일정

  • 제출 시작: 2026년 3월 28일
  • 제출 마감: 2026년 5월 9일 (AoE, 세계 어느 시간대 기준으로도 해당 날짜 내)
  • 결과 통보: 2026년 6월 9일
  • 컨퍼런스: 2026년 8월 8–9일

제출 방법

https://pretalx.coscup.org/coscup-2026/cfp에서 제출하실 수 있습니다. 트랙 드롭다운에서 Fediverse & Social Web을 선택해 주세요.

발표 제안은 영어 또는 중국어로 작성해 주세요. COSCUP은 세션 설명을 영어와 중국어로 함께 게시하지만, 번역은 채택 이후에 이루어지므로 제출 시 두 언어를 모두 작성할 필요는 없습니다.

모든 세션은 녹화되어 CC BY-SA 4.0으로 공개됩니다. 녹화하거나 해당 조건으로 공개할 수 없는 내용이 포함되어 있다면 제출 시 명시해 주세요.

행동 강령

모든 발표자와 참가자는 COSCUP 행동 강령(영문)을 숙지하고 준수해야 합니다.

문의

트랙, 주제, 연합우주 전반에 대한 문의는 contact@fedidev.kr 또는 연합우주 계정 @fedidevkr 쪽으로 연락해 주세요.

2026(타이베이, 8월 8–9일) Fediverse & Social Web 트랙 발표자 모집이 시작되었습니다! , , 오픈 소셜 웹 관련 주제라면 무엇이든 환영합니다. 마감은 5월 9일이고, COSCUP 참가는 무료입니다.

👉 https://hackers.pub/@fedidevkr/2026/fediverse-social-web-track-at-coscup-2026-cfp-ko

hackers.pub

COSCUP 2026 연합우주 & 소셜 웹 트랙: 발표자 모집

한국 연합우주 개발자 모임(FediDev KR)과 일본의 FediLUG가 2026년 대만 타이베이에서 개최되는 COSCUP 2026의 연합우주(Fediverse) 및 소셜 웹 트랙 발표자를 모집합니다. 이번 트랙은 액티비티펍(ActivityPub) 프로토콜 구현, 전용 클라이언트 및 라이브러리 개발, 인스턴스 운영 노하우, 그리고 연합 커뮤니티의 거버넌스와 같은 다양한 주제를 폭넓게 다룹니다. 동아시아 주요 오픈소스 컨퍼런스에서 처음으로 열리는 연합우주 전용 세션인 만큼, 개발자와 운영자들이 모여 기술적 통찰을 나누고 지역 커뮤니티의 결속을 다지는 중요한 기회가 될 것입니다.

다른 언어로 읽기: English (영어), 日本語 (일본어).


한국 연합우주 개발자 모임(FediDev KR)과 FediLUG(일본)이 COSCUP 2026 연합우주(fediverse) & 소셜 웹 트랙을 열고, 발표 제안을 받습니다.

COSCUP은 매년 대만 타이베이에서 열리는 참가비 무료의 자유·오픈 소스 소프트웨어 컨퍼런스입니다. FOSDEM의 동아시아판이라고 생각하시면 됩니다. 올해는 8월 8–9일 국립대만과학기술대학교에서 UbuCon Asia 2026과 공동 개최됩니다.

연합우주 & 소셜 웹 트랙은 하루 종일, 총 6시간 진행됩니다. 동아시아의 주요 오픈소스 컨퍼런스에서 열리는 첫 번째 연합우주 전용 트랙으로, 이 자리가 동아시아 연합우주 커뮤니티의 정기적인 모임으로 이어지기를 바랍니다.

발표 형식

기본 발표 시간은 30분입니다. 더 길거나 짧은 시간이 필요하다면 제출 시 희망 시간을 적어주세요.

주제

연합우주 및 오픈 소셜 웹과 관련된 주제라면 무엇이든 환영합니다.

  • ActivityPub 또는 관련 프로토콜 구현
  • ActivityPub 기반 소프트웨어용 클라이언트
  • 연합우주 개발을 위한 라이브러리, 툴킷, 프레임워크
  • 검색, 온보딩, 모더레이션 등 지원 서비스
  • 인스턴스 운영 및 관리
  • 거버넌스, 정책, 연합 커뮤니티 운영의 사회적 측면
  • 더 넓은 의미의 오픈 소셜 웹과 상호운용성

주요 일정

  • 제출 시작: 2026년 3월 28일
  • 제출 마감: 2026년 5월 9일 (AoE, 세계 어느 시간대 기준으로도 해당 날짜 내)
  • 결과 통보: 2026년 6월 9일
  • 컨퍼런스: 2026년 8월 8–9일

제출 방법

https://pretalx.coscup.org/coscup-2026/cfp에서 제출하실 수 있습니다. 트랙 드롭다운에서 Fediverse & Social Web을 선택해 주세요.

발표 제안은 영어 또는 중국어로 작성해 주세요. COSCUP은 세션 설명을 영어와 중국어로 함께 게시하지만, 번역은 채택 이후에 이루어지므로 제출 시 두 언어를 모두 작성할 필요는 없습니다.

모든 세션은 녹화되어 CC BY-SA 4.0으로 공개됩니다. 녹화하거나 해당 조건으로 공개할 수 없는 내용이 포함되어 있다면 제출 시 명시해 주세요.

행동 강령

모든 발표자와 참가자는 COSCUP 행동 강령(영문)을 숙지하고 준수해야 합니다.

문의

트랙, 주제, 연합우주 전반에 대한 문의는 contact@fedidev.kr 또는 연합우주 계정 @fedidevkr 쪽으로 연락해 주세요.

2026(타이베이, 8월 8–9일) Fediverse & Social Web 트랙 발표자 모집이 시작되었습니다! , , 오픈 소셜 웹 관련 주제라면 무엇이든 환영합니다. 마감은 5월 9일이고, COSCUP 참가는 무료입니다.

👉 https://hackers.pub/@fedidevkr/2026/fediverse-social-web-track-at-coscup-2026-cfp-ko

hackers.pub

COSCUP 2026 연합우주 & 소셜 웹 트랙: 발표자 모집

한국 연합우주 개발자 모임(FediDev KR)과 일본의 FediLUG가 2026년 대만 타이베이에서 개최되는 COSCUP 2026의 연합우주(Fediverse) 및 소셜 웹 트랙 발표자를 모집합니다. 이번 트랙은 액티비티펍(ActivityPub) 프로토콜 구현, 전용 클라이언트 및 라이브러리 개발, 인스턴스 운영 노하우, 그리고 연합 커뮤니티의 거버넌스와 같은 다양한 주제를 폭넓게 다룹니다. 동아시아 주요 오픈소스 컨퍼런스에서 처음으로 열리는 연합우주 전용 세션인 만큼, 개발자와 운영자들이 모여 기술적 통찰을 나누고 지역 커뮤니티의 결속을 다지는 중요한 기회가 될 것입니다.

다른 언어로 읽기: English (영어), 日本語 (일본어).


한국 연합우주 개발자 모임(FediDev KR)과 FediLUG(일본)이 COSCUP 2026 연합우주(fediverse) & 소셜 웹 트랙을 열고, 발표 제안을 받습니다.

COSCUP은 매년 대만 타이베이에서 열리는 참가비 무료의 자유·오픈 소스 소프트웨어 컨퍼런스입니다. FOSDEM의 동아시아판이라고 생각하시면 됩니다. 올해는 8월 8–9일 국립대만과학기술대학교에서 UbuCon Asia 2026과 공동 개최됩니다.

연합우주 & 소셜 웹 트랙은 하루 종일, 총 6시간 진행됩니다. 동아시아의 주요 오픈소스 컨퍼런스에서 열리는 첫 번째 연합우주 전용 트랙으로, 이 자리가 동아시아 연합우주 커뮤니티의 정기적인 모임으로 이어지기를 바랍니다.

발표 형식

기본 발표 시간은 30분입니다. 더 길거나 짧은 시간이 필요하다면 제출 시 희망 시간을 적어주세요.

주제

연합우주 및 오픈 소셜 웹과 관련된 주제라면 무엇이든 환영합니다.

  • ActivityPub 또는 관련 프로토콜 구현
  • ActivityPub 기반 소프트웨어용 클라이언트
  • 연합우주 개발을 위한 라이브러리, 툴킷, 프레임워크
  • 검색, 온보딩, 모더레이션 등 지원 서비스
  • 인스턴스 운영 및 관리
  • 거버넌스, 정책, 연합 커뮤니티 운영의 사회적 측면
  • 더 넓은 의미의 오픈 소셜 웹과 상호운용성

주요 일정

  • 제출 시작: 2026년 3월 28일
  • 제출 마감: 2026년 5월 9일 (AoE, 세계 어느 시간대 기준으로도 해당 날짜 내)
  • 결과 통보: 2026년 6월 9일
  • 컨퍼런스: 2026년 8월 8–9일

제출 방법

https://pretalx.coscup.org/coscup-2026/cfp에서 제출하실 수 있습니다. 트랙 드롭다운에서 Fediverse & Social Web을 선택해 주세요.

발표 제안은 영어 또는 중국어로 작성해 주세요. COSCUP은 세션 설명을 영어와 중국어로 함께 게시하지만, 번역은 채택 이후에 이루어지므로 제출 시 두 언어를 모두 작성할 필요는 없습니다.

모든 세션은 녹화되어 CC BY-SA 4.0으로 공개됩니다. 녹화하거나 해당 조건으로 공개할 수 없는 내용이 포함되어 있다면 제출 시 명시해 주세요.

행동 강령

모든 발표자와 참가자는 COSCUP 행동 강령(영문)을 숙지하고 준수해야 합니다.

문의

트랙, 주제, 연합우주 전반에 대한 문의는 contact@fedidev.kr 또는 연합우주 계정 @fedidevkr 쪽으로 연락해 주세요.

2026(타이베이, 8월 8–9일) Fediverse & Social Web 트랙 발표자 모집이 시작되었습니다! , , 오픈 소셜 웹 관련 주제라면 무엇이든 환영합니다. 마감은 5월 9일이고, COSCUP 참가는 무료입니다.

👉 https://hackers.pub/@fedidevkr/2026/fediverse-social-web-track-at-coscup-2026-cfp-ko

hackers.pub

COSCUP 2026 연합우주 & 소셜 웹 트랙: 발표자 모집

한국 연합우주 개발자 모임(FediDev KR)과 일본의 FediLUG가 2026년 대만 타이베이에서 개최되는 COSCUP 2026의 연합우주(Fediverse) 및 소셜 웹 트랙 발표자를 모집합니다. 이번 트랙은 액티비티펍(ActivityPub) 프로토콜 구현, 전용 클라이언트 및 라이브러리 개발, 인스턴스 운영 노하우, 그리고 연합 커뮤니티의 거버넌스와 같은 다양한 주제를 폭넓게 다룹니다. 동아시아 주요 오픈소스 컨퍼런스에서 처음으로 열리는 연합우주 전용 세션인 만큼, 개발자와 운영자들이 모여 기술적 통찰을 나누고 지역 커뮤니티의 결속을 다지는 중요한 기회가 될 것입니다.

다른 언어로 읽기: English (영어), 日本語 (일본어).


한국 연합우주 개발자 모임(FediDev KR)과 FediLUG(일본)이 COSCUP 2026 연합우주(fediverse) & 소셜 웹 트랙을 열고, 발표 제안을 받습니다.

COSCUP은 매년 대만 타이베이에서 열리는 참가비 무료의 자유·오픈 소스 소프트웨어 컨퍼런스입니다. FOSDEM의 동아시아판이라고 생각하시면 됩니다. 올해는 8월 8–9일 국립대만과학기술대학교에서 UbuCon Asia 2026과 공동 개최됩니다.

연합우주 & 소셜 웹 트랙은 하루 종일, 총 6시간 진행됩니다. 동아시아의 주요 오픈소스 컨퍼런스에서 열리는 첫 번째 연합우주 전용 트랙으로, 이 자리가 동아시아 연합우주 커뮤니티의 정기적인 모임으로 이어지기를 바랍니다.

발표 형식

기본 발표 시간은 30분입니다. 더 길거나 짧은 시간이 필요하다면 제출 시 희망 시간을 적어주세요.

주제

연합우주 및 오픈 소셜 웹과 관련된 주제라면 무엇이든 환영합니다.

  • ActivityPub 또는 관련 프로토콜 구현
  • ActivityPub 기반 소프트웨어용 클라이언트
  • 연합우주 개발을 위한 라이브러리, 툴킷, 프레임워크
  • 검색, 온보딩, 모더레이션 등 지원 서비스
  • 인스턴스 운영 및 관리
  • 거버넌스, 정책, 연합 커뮤니티 운영의 사회적 측면
  • 더 넓은 의미의 오픈 소셜 웹과 상호운용성

주요 일정

  • 제출 시작: 2026년 3월 28일
  • 제출 마감: 2026년 5월 9일 (AoE, 세계 어느 시간대 기준으로도 해당 날짜 내)
  • 결과 통보: 2026년 6월 9일
  • 컨퍼런스: 2026년 8월 8–9일

제출 방법

https://pretalx.coscup.org/coscup-2026/cfp에서 제출하실 수 있습니다. 트랙 드롭다운에서 Fediverse & Social Web을 선택해 주세요.

발표 제안은 영어 또는 중국어로 작성해 주세요. COSCUP은 세션 설명을 영어와 중국어로 함께 게시하지만, 번역은 채택 이후에 이루어지므로 제출 시 두 언어를 모두 작성할 필요는 없습니다.

모든 세션은 녹화되어 CC BY-SA 4.0으로 공개됩니다. 녹화하거나 해당 조건으로 공개할 수 없는 내용이 포함되어 있다면 제출 시 명시해 주세요.

행동 강령

모든 발표자와 참가자는 COSCUP 행동 강령(영문)을 숙지하고 준수해야 합니다.

문의

트랙, 주제, 연합우주 전반에 대한 문의는 contact@fedidev.kr 또는 연합우주 계정 @fedidevkr 쪽으로 연락해 주세요.

2026(타이베이, 8월 8–9일) Fediverse & Social Web 트랙 발표자 모집이 시작되었습니다! , , 오픈 소셜 웹 관련 주제라면 무엇이든 환영합니다. 마감은 5월 9일이고, COSCUP 참가는 무료입니다.

👉 https://hackers.pub/@fedidevkr/2026/fediverse-social-web-track-at-coscup-2026-cfp-ko

hackers.pub

COSCUP 2026 연합우주 & 소셜 웹 트랙: 발표자 모집

한국 연합우주 개발자 모임(FediDev KR)과 일본의 FediLUG가 2026년 대만 타이베이에서 개최되는 COSCUP 2026의 연합우주(Fediverse) 및 소셜 웹 트랙 발표자를 모집합니다. 이번 트랙은 액티비티펍(ActivityPub) 프로토콜 구현, 전용 클라이언트 및 라이브러리 개발, 인스턴스 운영 노하우, 그리고 연합 커뮤니티의 거버넌스와 같은 다양한 주제를 폭넓게 다룹니다. 동아시아 주요 오픈소스 컨퍼런스에서 처음으로 열리는 연합우주 전용 세션인 만큼, 개발자와 운영자들이 모여 기술적 통찰을 나누고 지역 커뮤니티의 결속을 다지는 중요한 기회가 될 것입니다.

다른 언어로 읽기: English (영어), 日本語 (일본어).


한국 연합우주 개발자 모임(FediDev KR)과 FediLUG(일본)이 COSCUP 2026 연합우주(fediverse) & 소셜 웹 트랙을 열고, 발표 제안을 받습니다.

COSCUP은 매년 대만 타이베이에서 열리는 참가비 무료의 자유·오픈 소스 소프트웨어 컨퍼런스입니다. FOSDEM의 동아시아판이라고 생각하시면 됩니다. 올해는 8월 8–9일 국립대만과학기술대학교에서 UbuCon Asia 2026과 공동 개최됩니다.

연합우주 & 소셜 웹 트랙은 하루 종일, 총 6시간 진행됩니다. 동아시아의 주요 오픈소스 컨퍼런스에서 열리는 첫 번째 연합우주 전용 트랙으로, 이 자리가 동아시아 연합우주 커뮤니티의 정기적인 모임으로 이어지기를 바랍니다.

발표 형식

기본 발표 시간은 30분입니다. 더 길거나 짧은 시간이 필요하다면 제출 시 희망 시간을 적어주세요.

주제

연합우주 및 오픈 소셜 웹과 관련된 주제라면 무엇이든 환영합니다.

  • ActivityPub 또는 관련 프로토콜 구현
  • ActivityPub 기반 소프트웨어용 클라이언트
  • 연합우주 개발을 위한 라이브러리, 툴킷, 프레임워크
  • 검색, 온보딩, 모더레이션 등 지원 서비스
  • 인스턴스 운영 및 관리
  • 거버넌스, 정책, 연합 커뮤니티 운영의 사회적 측면
  • 더 넓은 의미의 오픈 소셜 웹과 상호운용성

주요 일정

  • 제출 시작: 2026년 3월 28일
  • 제출 마감: 2026년 5월 9일 (AoE, 세계 어느 시간대 기준으로도 해당 날짜 내)
  • 결과 통보: 2026년 6월 9일
  • 컨퍼런스: 2026년 8월 8–9일

제출 방법

https://pretalx.coscup.org/coscup-2026/cfp에서 제출하실 수 있습니다. 트랙 드롭다운에서 Fediverse & Social Web을 선택해 주세요.

발표 제안은 영어 또는 중국어로 작성해 주세요. COSCUP은 세션 설명을 영어와 중국어로 함께 게시하지만, 번역은 채택 이후에 이루어지므로 제출 시 두 언어를 모두 작성할 필요는 없습니다.

모든 세션은 녹화되어 CC BY-SA 4.0으로 공개됩니다. 녹화하거나 해당 조건으로 공개할 수 없는 내용이 포함되어 있다면 제출 시 명시해 주세요.

행동 강령

모든 발표자와 참가자는 COSCUP 행동 강령(영문)을 숙지하고 준수해야 합니다.

문의

트랙, 주제, 연합우주 전반에 대한 문의는 contact@fedidev.kr 또는 연합우주 계정 @fedidevkr 쪽으로 연락해 주세요.

2026(타이베이, 8월 8–9일) Fediverse & Social Web 트랙 발표자 모집이 시작되었습니다! , , 오픈 소셜 웹 관련 주제라면 무엇이든 환영합니다. 마감은 5월 9일이고, COSCUP 참가는 무료입니다.

👉 https://hackers.pub/@fedidevkr/2026/fediverse-social-web-track-at-coscup-2026-cfp-ko

hackers.pub

COSCUP 2026 연합우주 & 소셜 웹 트랙: 발표자 모집

한국 연합우주 개발자 모임(FediDev KR)과 일본의 FediLUG가 2026년 대만 타이베이에서 개최되는 COSCUP 2026의 연합우주(Fediverse) 및 소셜 웹 트랙 발표자를 모집합니다. 이번 트랙은 액티비티펍(ActivityPub) 프로토콜 구현, 전용 클라이언트 및 라이브러리 개발, 인스턴스 운영 노하우, 그리고 연합 커뮤니티의 거버넌스와 같은 다양한 주제를 폭넓게 다룹니다. 동아시아 주요 오픈소스 컨퍼런스에서 처음으로 열리는 연합우주 전용 세션인 만큼, 개발자와 운영자들이 모여 기술적 통찰을 나누고 지역 커뮤니티의 결속을 다지는 중요한 기회가 될 것입니다.

다른 언어로 읽기: English (영어), 日本語 (일본어).


한국 연합우주 개발자 모임(FediDev KR)과 FediLUG(일본)이 COSCUP 2026 연합우주(fediverse) & 소셜 웹 트랙을 열고, 발표 제안을 받습니다.

COSCUP은 매년 대만 타이베이에서 열리는 참가비 무료의 자유·오픈 소스 소프트웨어 컨퍼런스입니다. FOSDEM의 동아시아판이라고 생각하시면 됩니다. 올해는 8월 8–9일 국립대만과학기술대학교에서 UbuCon Asia 2026과 공동 개최됩니다.

연합우주 & 소셜 웹 트랙은 하루 종일, 총 6시간 진행됩니다. 동아시아의 주요 오픈소스 컨퍼런스에서 열리는 첫 번째 연합우주 전용 트랙으로, 이 자리가 동아시아 연합우주 커뮤니티의 정기적인 모임으로 이어지기를 바랍니다.

발표 형식

기본 발표 시간은 30분입니다. 더 길거나 짧은 시간이 필요하다면 제출 시 희망 시간을 적어주세요.

주제

연합우주 및 오픈 소셜 웹과 관련된 주제라면 무엇이든 환영합니다.

  • ActivityPub 또는 관련 프로토콜 구현
  • ActivityPub 기반 소프트웨어용 클라이언트
  • 연합우주 개발을 위한 라이브러리, 툴킷, 프레임워크
  • 검색, 온보딩, 모더레이션 등 지원 서비스
  • 인스턴스 운영 및 관리
  • 거버넌스, 정책, 연합 커뮤니티 운영의 사회적 측면
  • 더 넓은 의미의 오픈 소셜 웹과 상호운용성

주요 일정

  • 제출 시작: 2026년 3월 28일
  • 제출 마감: 2026년 5월 9일 (AoE, 세계 어느 시간대 기준으로도 해당 날짜 내)
  • 결과 통보: 2026년 6월 9일
  • 컨퍼런스: 2026년 8월 8–9일

제출 방법

https://pretalx.coscup.org/coscup-2026/cfp에서 제출하실 수 있습니다. 트랙 드롭다운에서 Fediverse & Social Web을 선택해 주세요.

발표 제안은 영어 또는 중국어로 작성해 주세요. COSCUP은 세션 설명을 영어와 중국어로 함께 게시하지만, 번역은 채택 이후에 이루어지므로 제출 시 두 언어를 모두 작성할 필요는 없습니다.

모든 세션은 녹화되어 CC BY-SA 4.0으로 공개됩니다. 녹화하거나 해당 조건으로 공개할 수 없는 내용이 포함되어 있다면 제출 시 명시해 주세요.

행동 강령

모든 발표자와 참가자는 COSCUP 행동 강령(영문)을 숙지하고 준수해야 합니다.

문의

트랙, 주제, 연합우주 전반에 대한 문의는 contact@fedidev.kr 또는 연합우주 계정 @fedidevkr 쪽으로 연락해 주세요.

2026(타이베이, 8월 8–9일) Fediverse & Social Web 트랙 발표자 모집이 시작되었습니다! , , 오픈 소셜 웹 관련 주제라면 무엇이든 환영합니다. 마감은 5월 9일이고, COSCUP 참가는 무료입니다.

👉 https://hackers.pub/@fedidevkr/2026/fediverse-social-web-track-at-coscup-2026-cfp-ko

hackers.pub

COSCUP 2026 연합우주 & 소셜 웹 트랙: 발표자 모집

한국 연합우주 개발자 모임(FediDev KR)과 일본의 FediLUG가 2026년 대만 타이베이에서 개최되는 COSCUP 2026의 연합우주(Fediverse) 및 소셜 웹 트랙 발표자를 모집합니다. 이번 트랙은 액티비티펍(ActivityPub) 프로토콜 구현, 전용 클라이언트 및 라이브러리 개발, 인스턴스 운영 노하우, 그리고 연합 커뮤니티의 거버넌스와 같은 다양한 주제를 폭넓게 다룹니다. 동아시아 주요 오픈소스 컨퍼런스에서 처음으로 열리는 연합우주 전용 세션인 만큼, 개발자와 운영자들이 모여 기술적 통찰을 나누고 지역 커뮤니티의 결속을 다지는 중요한 기회가 될 것입니다.

다른 언어로 읽기: English (영어), 日本語 (일본어).


한국 연합우주 개발자 모임(FediDev KR)과 FediLUG(일본)이 COSCUP 2026 연합우주(fediverse) & 소셜 웹 트랙을 열고, 발표 제안을 받습니다.

COSCUP은 매년 대만 타이베이에서 열리는 참가비 무료의 자유·오픈 소스 소프트웨어 컨퍼런스입니다. FOSDEM의 동아시아판이라고 생각하시면 됩니다. 올해는 8월 8–9일 국립대만과학기술대학교에서 UbuCon Asia 2026과 공동 개최됩니다.

연합우주 & 소셜 웹 트랙은 하루 종일, 총 6시간 진행됩니다. 동아시아의 주요 오픈소스 컨퍼런스에서 열리는 첫 번째 연합우주 전용 트랙으로, 이 자리가 동아시아 연합우주 커뮤니티의 정기적인 모임으로 이어지기를 바랍니다.

발표 형식

기본 발표 시간은 30분입니다. 더 길거나 짧은 시간이 필요하다면 제출 시 희망 시간을 적어주세요.

주제

연합우주 및 오픈 소셜 웹과 관련된 주제라면 무엇이든 환영합니다.

  • ActivityPub 또는 관련 프로토콜 구현
  • ActivityPub 기반 소프트웨어용 클라이언트
  • 연합우주 개발을 위한 라이브러리, 툴킷, 프레임워크
  • 검색, 온보딩, 모더레이션 등 지원 서비스
  • 인스턴스 운영 및 관리
  • 거버넌스, 정책, 연합 커뮤니티 운영의 사회적 측면
  • 더 넓은 의미의 오픈 소셜 웹과 상호운용성

주요 일정

  • 제출 시작: 2026년 3월 28일
  • 제출 마감: 2026년 5월 9일 (AoE, 세계 어느 시간대 기준으로도 해당 날짜 내)
  • 결과 통보: 2026년 6월 9일
  • 컨퍼런스: 2026년 8월 8–9일

제출 방법

https://pretalx.coscup.org/coscup-2026/cfp에서 제출하실 수 있습니다. 트랙 드롭다운에서 Fediverse & Social Web을 선택해 주세요.

발표 제안은 영어 또는 중국어로 작성해 주세요. COSCUP은 세션 설명을 영어와 중국어로 함께 게시하지만, 번역은 채택 이후에 이루어지므로 제출 시 두 언어를 모두 작성할 필요는 없습니다.

모든 세션은 녹화되어 CC BY-SA 4.0으로 공개됩니다. 녹화하거나 해당 조건으로 공개할 수 없는 내용이 포함되어 있다면 제출 시 명시해 주세요.

행동 강령

모든 발표자와 참가자는 COSCUP 행동 강령(영문)을 숙지하고 준수해야 합니다.

문의

트랙, 주제, 연합우주 전반에 대한 문의는 contact@fedidev.kr 또는 연합우주 계정 @fedidevkr 쪽으로 연락해 주세요.

다른 언어로 읽기: English (영어), 日本語 (일본어).


한국 연합우주 개발자 모임(FediDev KR)과 FediLUG(일본)이 COSCUP 2026 연합우주(fediverse) & 소셜 웹 트랙을 열고, 발표 제안을 받습니다.

COSCUP은 매년 대만 타이베이에서 열리는 참가비 무료의 자유·오픈 소스 소프트웨어 컨퍼런스입니다. FOSDEM의 동아시아판이라고 생각하시면 됩니다. 올해는 8월 8–9일 국립대만과학기술대학교에서 UbuCon Asia 2026과 공동 개최됩니다.

연합우주 & 소셜 웹 트랙은 하루 종일, 총 6시간 진행됩니다. 동아시아의 주요 오픈소스 컨퍼런스에서 열리는 첫 번째 연합우주 전용 트랙으로, 이 자리가 동아시아 연합우주 커뮤니티의 정기적인 모임으로 이어지기를 바랍니다.

발표 형식

기본 발표 시간은 30분입니다. 더 길거나 짧은 시간이 필요하다면 제출 시 희망 시간을 적어주세요.

주제

연합우주 및 오픈 소셜 웹과 관련된 주제라면 무엇이든 환영합니다.

  • ActivityPub 또는 관련 프로토콜 구현
  • ActivityPub 기반 소프트웨어용 클라이언트
  • 연합우주 개발을 위한 라이브러리, 툴킷, 프레임워크
  • 검색, 온보딩, 모더레이션 등 지원 서비스
  • 인스턴스 운영 및 관리
  • 거버넌스, 정책, 연합 커뮤니티 운영의 사회적 측면
  • 더 넓은 의미의 오픈 소셜 웹과 상호운용성

주요 일정

  • 제출 시작: 2026년 3월 28일
  • 제출 마감: 2026년 5월 9일 (AoE, 세계 어느 시간대 기준으로도 해당 날짜 내)
  • 결과 통보: 2026년 6월 9일
  • 컨퍼런스: 2026년 8월 8–9일

제출 방법

https://pretalx.coscup.org/coscup-2026/cfp에서 제출하실 수 있습니다. 트랙 드롭다운에서 Fediverse & Social Web을 선택해 주세요.

발표 제안은 영어 또는 중국어로 작성해 주세요. COSCUP은 세션 설명을 영어와 중국어로 함께 게시하지만, 번역은 채택 이후에 이루어지므로 제출 시 두 언어를 모두 작성할 필요는 없습니다.

모든 세션은 녹화되어 CC BY-SA 4.0으로 공개됩니다. 녹화하거나 해당 조건으로 공개할 수 없는 내용이 포함되어 있다면 제출 시 명시해 주세요.

행동 강령

모든 발표자와 참가자는 COSCUP 행동 강령(영문)을 숙지하고 준수해야 합니다.

문의

트랙, 주제, 연합우주 전반에 대한 문의는 contact@fedidev.kr 또는 연합우주 계정 @fedidevkr 쪽으로 연락해 주세요.

다른 언어로 읽기: English (영어), 日本語 (일본어).


한국 연합우주 개발자 모임(FediDev KR)과 FediLUG(일본)이 COSCUP 2026 연합우주(fediverse) & 소셜 웹 트랙을 열고, 발표 제안을 받습니다.

COSCUP은 매년 대만 타이베이에서 열리는 참가비 무료의 자유·오픈 소스 소프트웨어 컨퍼런스입니다. FOSDEM의 동아시아판이라고 생각하시면 됩니다. 올해는 8월 8–9일 국립대만과학기술대학교에서 UbuCon Asia 2026과 공동 개최됩니다.

연합우주 & 소셜 웹 트랙은 하루 종일, 총 6시간 진행됩니다. 동아시아의 주요 오픈소스 컨퍼런스에서 열리는 첫 번째 연합우주 전용 트랙으로, 이 자리가 동아시아 연합우주 커뮤니티의 정기적인 모임으로 이어지기를 바랍니다.

발표 형식

기본 발표 시간은 30분입니다. 더 길거나 짧은 시간이 필요하다면 제출 시 희망 시간을 적어주세요.

주제

연합우주 및 오픈 소셜 웹과 관련된 주제라면 무엇이든 환영합니다.

  • ActivityPub 또는 관련 프로토콜 구현
  • ActivityPub 기반 소프트웨어용 클라이언트
  • 연합우주 개발을 위한 라이브러리, 툴킷, 프레임워크
  • 검색, 온보딩, 모더레이션 등 지원 서비스
  • 인스턴스 운영 및 관리
  • 거버넌스, 정책, 연합 커뮤니티 운영의 사회적 측면
  • 더 넓은 의미의 오픈 소셜 웹과 상호운용성

주요 일정

  • 제출 시작: 2026년 3월 28일
  • 제출 마감: 2026년 5월 9일 (AoE, 세계 어느 시간대 기준으로도 해당 날짜 내)
  • 결과 통보: 2026년 6월 9일
  • 컨퍼런스: 2026년 8월 8–9일

제출 방법

https://pretalx.coscup.org/coscup-2026/cfp에서 제출하실 수 있습니다. 트랙 드롭다운에서 Fediverse & Social Web을 선택해 주세요.

발표 제안은 영어 또는 중국어로 작성해 주세요. COSCUP은 세션 설명을 영어와 중국어로 함께 게시하지만, 번역은 채택 이후에 이루어지므로 제출 시 두 언어를 모두 작성할 필요는 없습니다.

모든 세션은 녹화되어 CC BY-SA 4.0으로 공개됩니다. 녹화하거나 해당 조건으로 공개할 수 없는 내용이 포함되어 있다면 제출 시 명시해 주세요.

행동 강령

모든 발표자와 참가자는 COSCUP 행동 강령(영문)을 숙지하고 준수해야 합니다.

문의

트랙, 주제, 연합우주 전반에 대한 문의는 contact@fedidev.kr 또는 연합우주 계정 @fedidevkr 쪽으로 연락해 주세요.

다른 언어로 읽기: English (영어), 日本語 (일본어).


한국 연합우주 개발자 모임(FediDev KR)과 FediLUG(일본)이 COSCUP 2026 연합우주(fediverse) & 소셜 웹 트랙을 열고, 발표 제안을 받습니다.

COSCUP은 매년 대만 타이베이에서 열리는 참가비 무료의 자유·오픈 소스 소프트웨어 컨퍼런스입니다. FOSDEM의 동아시아판이라고 생각하시면 됩니다. 올해는 8월 8–9일 국립대만과학기술대학교에서 UbuCon Asia 2026과 공동 개최됩니다.

연합우주 & 소셜 웹 트랙은 하루 종일, 총 6시간 진행됩니다. 동아시아의 주요 오픈소스 컨퍼런스에서 열리는 첫 번째 연합우주 전용 트랙으로, 이 자리가 동아시아 연합우주 커뮤니티의 정기적인 모임으로 이어지기를 바랍니다.

발표 형식

기본 발표 시간은 30분입니다. 더 길거나 짧은 시간이 필요하다면 제출 시 희망 시간을 적어주세요.

주제

연합우주 및 오픈 소셜 웹과 관련된 주제라면 무엇이든 환영합니다.

  • ActivityPub 또는 관련 프로토콜 구현
  • ActivityPub 기반 소프트웨어용 클라이언트
  • 연합우주 개발을 위한 라이브러리, 툴킷, 프레임워크
  • 검색, 온보딩, 모더레이션 등 지원 서비스
  • 인스턴스 운영 및 관리
  • 거버넌스, 정책, 연합 커뮤니티 운영의 사회적 측면
  • 더 넓은 의미의 오픈 소셜 웹과 상호운용성

주요 일정

  • 제출 시작: 2026년 3월 28일
  • 제출 마감: 2026년 5월 9일 (AoE, 세계 어느 시간대 기준으로도 해당 날짜 내)
  • 결과 통보: 2026년 6월 9일
  • 컨퍼런스: 2026년 8월 8–9일

제출 방법

https://pretalx.coscup.org/coscup-2026/cfp에서 제출하실 수 있습니다. 트랙 드롭다운에서 Fediverse & Social Web을 선택해 주세요.

발표 제안은 영어 또는 중국어로 작성해 주세요. COSCUP은 세션 설명을 영어와 중국어로 함께 게시하지만, 번역은 채택 이후에 이루어지므로 제출 시 두 언어를 모두 작성할 필요는 없습니다.

모든 세션은 녹화되어 CC BY-SA 4.0으로 공개됩니다. 녹화하거나 해당 조건으로 공개할 수 없는 내용이 포함되어 있다면 제출 시 명시해 주세요.

행동 강령

모든 발표자와 참가자는 COSCUP 행동 강령(영문)을 숙지하고 준수해야 합니다.

문의

트랙, 주제, 연합우주 전반에 대한 문의는 contact@fedidev.kr 또는 연합우주 계정 @fedidevkr 쪽으로 연락해 주세요.

다른 언어로 읽기: English (영어), 日本語 (일본어).


한국 연합우주 개발자 모임(FediDev KR)과 FediLUG(일본)이 COSCUP 2026 연합우주(fediverse) & 소셜 웹 트랙을 열고, 발표 제안을 받습니다.

COSCUP은 매년 대만 타이베이에서 열리는 참가비 무료의 자유·오픈 소스 소프트웨어 컨퍼런스입니다. FOSDEM의 동아시아판이라고 생각하시면 됩니다. 올해는 8월 8–9일 국립대만과학기술대학교에서 UbuCon Asia 2026과 공동 개최됩니다.

연합우주 & 소셜 웹 트랙은 하루 종일, 총 6시간 진행됩니다. 동아시아의 주요 오픈소스 컨퍼런스에서 열리는 첫 번째 연합우주 전용 트랙으로, 이 자리가 동아시아 연합우주 커뮤니티의 정기적인 모임으로 이어지기를 바랍니다.

발표 형식

기본 발표 시간은 30분입니다. 더 길거나 짧은 시간이 필요하다면 제출 시 희망 시간을 적어주세요.

주제

연합우주 및 오픈 소셜 웹과 관련된 주제라면 무엇이든 환영합니다.

  • ActivityPub 또는 관련 프로토콜 구현
  • ActivityPub 기반 소프트웨어용 클라이언트
  • 연합우주 개발을 위한 라이브러리, 툴킷, 프레임워크
  • 검색, 온보딩, 모더레이션 등 지원 서비스
  • 인스턴스 운영 및 관리
  • 거버넌스, 정책, 연합 커뮤니티 운영의 사회적 측면
  • 더 넓은 의미의 오픈 소셜 웹과 상호운용성

주요 일정

  • 제출 시작: 2026년 3월 28일
  • 제출 마감: 2026년 5월 9일 (AoE, 세계 어느 시간대 기준으로도 해당 날짜 내)
  • 결과 통보: 2026년 6월 9일
  • 컨퍼런스: 2026년 8월 8–9일

제출 방법

https://pretalx.coscup.org/coscup-2026/cfp에서 제출하실 수 있습니다. 트랙 드롭다운에서 Fediverse & Social Web을 선택해 주세요.

발표 제안은 영어 또는 중국어로 작성해 주세요. COSCUP은 세션 설명을 영어와 중국어로 함께 게시하지만, 번역은 채택 이후에 이루어지므로 제출 시 두 언어를 모두 작성할 필요는 없습니다.

모든 세션은 녹화되어 CC BY-SA 4.0으로 공개됩니다. 녹화하거나 해당 조건으로 공개할 수 없는 내용이 포함되어 있다면 제출 시 명시해 주세요.

행동 강령

모든 발표자와 참가자는 COSCUP 행동 강령(영문)을 숙지하고 준수해야 합니다.

문의

트랙, 주제, 연합우주 전반에 대한 문의는 contact@fedidev.kr 또는 연합우주 계정 @fedidevkr 쪽으로 연락해 주세요.

@COSCUP 2026(臺北(타이베이), 8() 8–9())에서 저희 Fediverse & Social Web 트랙이 承認(승인)되었습니다! , , 오픈 소셜 웹을 主題(주제)로 하루 終日(종일), () 6時間(시간)進行(진행)豫定(예정)입니다.

發表者(발표자) 募集(모집) CFP는 아직 열리지 않았지만, 始作(시작)되는 대로 바로 公知(공지)하겠습니다. 期待(기대)해 주세요!

@COSCUP 2026(臺北(타이베이), 8() 8–9())에서 저희 Fediverse & Social Web 트랙이 承認(승인)되었습니다! , , 오픈 소셜 웹을 主題(주제)로 하루 終日(종일), () 6時間(시간)進行(진행)豫定(예정)입니다.

發表者(발표자) 募集(모집) CFP는 아직 열리지 않았지만, 始作(시작)되는 대로 바로 公知(공지)하겠습니다. 期待(기대)해 주세요!

@COSCUP 2026(臺北(타이베이), 8() 8–9())에서 저희 Fediverse & Social Web 트랙이 承認(승인)되었습니다! , , 오픈 소셜 웹을 主題(주제)로 하루 終日(종일), () 6時間(시간)進行(진행)豫定(예정)입니다.

發表者(발표자) 募集(모집) CFP는 아직 열리지 않았지만, 始作(시작)되는 대로 바로 公知(공지)하겠습니다. 期待(기대)해 주세요!

@COSCUP 2026(臺北(타이베이), 8() 8–9())에서 저희 Fediverse & Social Web 트랙이 承認(승인)되었습니다! , , 오픈 소셜 웹을 主題(주제)로 하루 終日(종일), () 6時間(시간)進行(진행)豫定(예정)입니다.

發表者(발표자) 募集(모집) CFP는 아직 열리지 않았지만, 始作(시작)되는 대로 바로 公知(공지)하겠습니다. 期待(기대)해 주세요!

()아시아에도 FediCon 같은 行事(행사)가 있으면 좋겠다는 말을 여러 () 해왔는데요. 獨立的(독립적)인 컨퍼런스는 아직 어렵더라도, 작은 첫걸음으로 생각해보고 있는 게 있습니다.

@COSCUP 2026(臺北(타이베이), 8() 8()–9())이 커뮤니티 트랙 提案(제안)을 받고 있어요. FOSDEM의 Social Web devroom 같은 느낌으로, 거기서 Social Web 트랙을 열 수 있지 않을까 하고 構想(구상) 중입니다.

아직 確定(확정)된 건 아무것도 없지만, , , ()은 소셜 웹 全般(전반)을 다루고 있고 發表(발표)共同(공동) 오거나이징에 關心(관심)이 있으신 분이 있다면 이야기 걸어주세요.

https://floss.social/@COSCUP/116152356550445285

floss.social

COSCUP (@COSCUP@floss.social)

🚀 COSCUP 2026 Call for Participation is now open! 🎤 Community Tracks – Run a open-source agenda with talks, panels, or workshops. Apply by Mar 23. Spots are limited. 🛠 Community Booths – Showcase your project, recruit members, and connect. Apply by Jun 9. First come, first served. 👉 Apply here: https://s.coscup.org/26communityen #COSCUP2026 #OpenSource #Community

@COSCUP@floss.social

🚀 COSCUP 2026 Call for Participation is now open!

🎤 Community Tracks – Run a open-source agenda with talks, panels, or workshops. Apply by Mar 23. Spots are limited.

🛠 Community Booths – Showcase your project, recruit members, and connect. Apply by Jun 9. First come, first served.

👉 Apply here: s.coscup.org/26communityen

blog.coscup.org

COSCUP 2026 Call for Participation, 議程軌與攤位即日起開放申請

無論您是開放原始碼的開發者、推廣者、使用者,都歡迎您來參加 COSCUP「開源人年會」

()아시아에도 FediCon 같은 行事(행사)가 있으면 좋겠다는 말을 여러 () 해왔는데요. 獨立的(독립적)인 컨퍼런스는 아직 어렵더라도, 작은 첫걸음으로 생각해보고 있는 게 있습니다.

@COSCUP 2026(臺北(타이베이), 8() 8()–9())이 커뮤니티 트랙 提案(제안)을 받고 있어요. FOSDEM의 Social Web devroom 같은 느낌으로, 거기서 Social Web 트랙을 열 수 있지 않을까 하고 構想(구상) 중입니다.

아직 確定(확정)된 건 아무것도 없지만, , , ()은 소셜 웹 全般(전반)을 다루고 있고 發表(발표)共同(공동) 오거나이징에 關心(관심)이 있으신 분이 있다면 이야기 걸어주세요.

https://floss.social/@COSCUP/116152356550445285

floss.social

COSCUP (@COSCUP@floss.social)

🚀 COSCUP 2026 Call for Participation is now open! 🎤 Community Tracks – Run a open-source agenda with talks, panels, or workshops. Apply by Mar 23. Spots are limited. 🛠 Community Booths – Showcase your project, recruit members, and connect. Apply by Jun 9. First come, first served. 👉 Apply here: https://s.coscup.org/26communityen #COSCUP2026 #OpenSource #Community

@COSCUP@floss.social

🚀 COSCUP 2026 Call for Participation is now open!

🎤 Community Tracks – Run a open-source agenda with talks, panels, or workshops. Apply by Mar 23. Spots are limited.

🛠 Community Booths – Showcase your project, recruit members, and connect. Apply by Jun 9. First come, first served.

👉 Apply here: s.coscup.org/26communityen

blog.coscup.org

COSCUP 2026 Call for Participation, 議程軌與攤位即日起開放申請

無論您是開放原始碼的開發者、推廣者、使用者,都歡迎您來參加 COSCUP「開源人年會」

()아시아에도 FediCon 같은 行事(행사)가 있으면 좋겠다는 말을 여러 () 해왔는데요. 獨立的(독립적)인 컨퍼런스는 아직 어렵더라도, 작은 첫걸음으로 생각해보고 있는 게 있습니다.

@COSCUP 2026(臺北(타이베이), 8() 8()–9())이 커뮤니티 트랙 提案(제안)을 받고 있어요. FOSDEM의 Social Web devroom 같은 느낌으로, 거기서 Social Web 트랙을 열 수 있지 않을까 하고 構想(구상) 중입니다.

아직 確定(확정)된 건 아무것도 없지만, , , ()은 소셜 웹 全般(전반)을 다루고 있고 發表(발표)共同(공동) 오거나이징에 關心(관심)이 있으신 분이 있다면 이야기 걸어주세요.

https://floss.social/@COSCUP/116152356550445285

floss.social

COSCUP (@COSCUP@floss.social)

🚀 COSCUP 2026 Call for Participation is now open! 🎤 Community Tracks – Run a open-source agenda with talks, panels, or workshops. Apply by Mar 23. Spots are limited. 🛠 Community Booths – Showcase your project, recruit members, and connect. Apply by Jun 9. First come, first served. 👉 Apply here: https://s.coscup.org/26communityen #COSCUP2026 #OpenSource #Community

@COSCUP@floss.social

🚀 COSCUP 2026 Call for Participation is now open!

🎤 Community Tracks – Run a open-source agenda with talks, panels, or workshops. Apply by Mar 23. Spots are limited.

🛠 Community Booths – Showcase your project, recruit members, and connect. Apply by Jun 9. First come, first served.

👉 Apply here: s.coscup.org/26communityen

blog.coscup.org

COSCUP 2026 Call for Participation, 議程軌與攤位即日起開放申請

無論您是開放原始碼的開發者、推廣者、使用者,都歡迎您來參加 COSCUP「開源人年會」

()아시아에도 FediCon 같은 行事(행사)가 있으면 좋겠다는 말을 여러 () 해왔는데요. 獨立的(독립적)인 컨퍼런스는 아직 어렵더라도, 작은 첫걸음으로 생각해보고 있는 게 있습니다.

@COSCUP 2026(臺北(타이베이), 8() 8()–9())이 커뮤니티 트랙 提案(제안)을 받고 있어요. FOSDEM의 Social Web devroom 같은 느낌으로, 거기서 Social Web 트랙을 열 수 있지 않을까 하고 構想(구상) 중입니다.

아직 確定(확정)된 건 아무것도 없지만, , , ()은 소셜 웹 全般(전반)을 다루고 있고 發表(발표)共同(공동) 오거나이징에 關心(관심)이 있으신 분이 있다면 이야기 걸어주세요.

https://floss.social/@COSCUP/116152356550445285

floss.social

COSCUP (@COSCUP@floss.social)

🚀 COSCUP 2026 Call for Participation is now open! 🎤 Community Tracks – Run a open-source agenda with talks, panels, or workshops. Apply by Mar 23. Spots are limited. 🛠 Community Booths – Showcase your project, recruit members, and connect. Apply by Jun 9. First come, first served. 👉 Apply here: https://s.coscup.org/26communityen #COSCUP2026 #OpenSource #Community

@COSCUP@floss.social

🚀 COSCUP 2026 Call for Participation is now open!

🎤 Community Tracks – Run a open-source agenda with talks, panels, or workshops. Apply by Mar 23. Spots are limited.

🛠 Community Booths – Showcase your project, recruit members, and connect. Apply by Jun 9. First come, first served.

👉 Apply here: s.coscup.org/26communityen

blog.coscup.org

COSCUP 2026 Call for Participation, 議程軌與攤位即日起開放申請

無論您是開放原始碼的開發者、推廣者、使用者,都歡迎您來參加 COSCUP「開源人年會」

()아시아에도 FediCon 같은 行事(행사)가 있으면 좋겠다는 말을 여러 () 해왔는데요. 獨立的(독립적)인 컨퍼런스는 아직 어렵더라도, 작은 첫걸음으로 생각해보고 있는 게 있습니다.

@COSCUP 2026(臺北(타이베이), 8() 8()–9())이 커뮤니티 트랙 提案(제안)을 받고 있어요. FOSDEM의 Social Web devroom 같은 느낌으로, 거기서 Social Web 트랙을 열 수 있지 않을까 하고 構想(구상) 중입니다.

아직 確定(확정)된 건 아무것도 없지만, , , ()은 소셜 웹 全般(전반)을 다루고 있고 發表(발표)共同(공동) 오거나이징에 關心(관심)이 있으신 분이 있다면 이야기 걸어주세요.

https://floss.social/@COSCUP/116152356550445285

floss.social

COSCUP (@COSCUP@floss.social)

🚀 COSCUP 2026 Call for Participation is now open! 🎤 Community Tracks – Run a open-source agenda with talks, panels, or workshops. Apply by Mar 23. Spots are limited. 🛠 Community Booths – Showcase your project, recruit members, and connect. Apply by Jun 9. First come, first served. 👉 Apply here: https://s.coscup.org/26communityen #COSCUP2026 #OpenSource #Community

@COSCUP@floss.social

🚀 COSCUP 2026 Call for Participation is now open!

🎤 Community Tracks – Run a open-source agenda with talks, panels, or workshops. Apply by Mar 23. Spots are limited.

🛠 Community Booths – Showcase your project, recruit members, and connect. Apply by Jun 9. First come, first served.

👉 Apply here: s.coscup.org/26communityen

blog.coscup.org

COSCUP 2026 Call for Participation, 議程軌與攤位即日起開放申請

無論您是開放原始碼的開發者、推廣者、使用者,都歡迎您來參加 COSCUP「開源人年會」

()아시아에도 FediCon 같은 行事(행사)가 있으면 좋겠다는 말을 여러 () 해왔는데요. 獨立的(독립적)인 컨퍼런스는 아직 어렵더라도, 작은 첫걸음으로 생각해보고 있는 게 있습니다.

@COSCUP 2026(臺北(타이베이), 8() 8()–9())이 커뮤니티 트랙 提案(제안)을 받고 있어요. FOSDEM의 Social Web devroom 같은 느낌으로, 거기서 Social Web 트랙을 열 수 있지 않을까 하고 構想(구상) 중입니다.

아직 確定(확정)된 건 아무것도 없지만, , , ()은 소셜 웹 全般(전반)을 다루고 있고 發表(발표)共同(공동) 오거나이징에 關心(관심)이 있으신 분이 있다면 이야기 걸어주세요.

https://floss.social/@COSCUP/116152356550445285

floss.social

COSCUP (@COSCUP@floss.social)

🚀 COSCUP 2026 Call for Participation is now open! 🎤 Community Tracks – Run a open-source agenda with talks, panels, or workshops. Apply by Mar 23. Spots are limited. 🛠 Community Booths – Showcase your project, recruit members, and connect. Apply by Jun 9. First come, first served. 👉 Apply here: https://s.coscup.org/26communityen #COSCUP2026 #OpenSource #Community

@COSCUP@floss.social

🚀 COSCUP 2026 Call for Participation is now open!

🎤 Community Tracks – Run a open-source agenda with talks, panels, or workshops. Apply by Mar 23. Spots are limited.

🛠 Community Booths – Showcase your project, recruit members, and connect. Apply by Jun 9. First come, first served.

👉 Apply here: s.coscup.org/26communityen

blog.coscup.org

COSCUP 2026 Call for Participation, 議程軌與攤位即日起開放申請

無論您是開放原始碼的開發者、推廣者、使用者,都歡迎您來參加 COSCUP「開源人年會」

()아시아에도 FediCon 같은 行事(행사)가 있으면 좋겠다는 말을 여러 () 해왔는데요. 獨立的(독립적)인 컨퍼런스는 아직 어렵더라도, 작은 첫걸음으로 생각해보고 있는 게 있습니다.

@COSCUP 2026(臺北(타이베이), 8() 8()–9())이 커뮤니티 트랙 提案(제안)을 받고 있어요. FOSDEM의 Social Web devroom 같은 느낌으로, 거기서 Social Web 트랙을 열 수 있지 않을까 하고 構想(구상) 중입니다.

아직 確定(확정)된 건 아무것도 없지만, , , ()은 소셜 웹 全般(전반)을 다루고 있고 發表(발표)共同(공동) 오거나이징에 關心(관심)이 있으신 분이 있다면 이야기 걸어주세요.

https://floss.social/@COSCUP/116152356550445285

floss.social

COSCUP (@COSCUP@floss.social)

🚀 COSCUP 2026 Call for Participation is now open! 🎤 Community Tracks – Run a open-source agenda with talks, panels, or workshops. Apply by Mar 23. Spots are limited. 🛠 Community Booths – Showcase your project, recruit members, and connect. Apply by Jun 9. First come, first served. 👉 Apply here: https://s.coscup.org/26communityen #COSCUP2026 #OpenSource #Community

@COSCUP@floss.social

🚀 COSCUP 2026 Call for Participation is now open!

🎤 Community Tracks – Run a open-source agenda with talks, panels, or workshops. Apply by Mar 23. Spots are limited.

🛠 Community Booths – Showcase your project, recruit members, and connect. Apply by Jun 9. First come, first served.

👉 Apply here: s.coscup.org/26communityen

blog.coscup.org

COSCUP 2026 Call for Participation, 議程軌與攤位即日起開放申請

無論您是開放原始碼的開發者、推廣者、使用者,都歡迎您來參加 COSCUP「開源人年會」

()아시아에도 FediCon 같은 行事(행사)가 있으면 좋겠다는 말을 여러 () 해왔는데요. 獨立的(독립적)인 컨퍼런스는 아직 어렵더라도, 작은 첫걸음으로 생각해보고 있는 게 있습니다.

@COSCUP 2026(臺北(타이베이), 8() 8()–9())이 커뮤니티 트랙 提案(제안)을 받고 있어요. FOSDEM의 Social Web devroom 같은 느낌으로, 거기서 Social Web 트랙을 열 수 있지 않을까 하고 構想(구상) 중입니다.

아직 確定(확정)된 건 아무것도 없지만, , , ()은 소셜 웹 全般(전반)을 다루고 있고 發表(발표)共同(공동) 오거나이징에 關心(관심)이 있으신 분이 있다면 이야기 걸어주세요.

https://floss.social/@COSCUP/116152356550445285

floss.social

COSCUP (@COSCUP@floss.social)

🚀 COSCUP 2026 Call for Participation is now open! 🎤 Community Tracks – Run a open-source agenda with talks, panels, or workshops. Apply by Mar 23. Spots are limited. 🛠 Community Booths – Showcase your project, recruit members, and connect. Apply by Jun 9. First come, first served. 👉 Apply here: https://s.coscup.org/26communityen #COSCUP2026 #OpenSource #Community

@COSCUP@floss.social

🚀 COSCUP 2026 Call for Participation is now open!

🎤 Community Tracks – Run a open-source agenda with talks, panels, or workshops. Apply by Mar 23. Spots are limited.

🛠 Community Booths – Showcase your project, recruit members, and connect. Apply by Jun 9. First come, first served.

👉 Apply here: s.coscup.org/26communityen

blog.coscup.org

COSCUP 2026 Call for Participation, 議程軌與攤位即日起開放申請

無論您是開放原始碼的開發者、推廣者、使用者,都歡迎您來參加 COSCUP「開源人年會」

@hollo@hollo.social · Reply to Hollo :hollo:

보안 업데이트: Hollo 0.6.19 릴리스

Fedify의 HTML 파싱 코드에서 발견된 보안 취약점을 수정한 Hollo 0.6.19를 릴리스했습니다.

이 취약점(CVE-2025-68475)은 ReDoS(정규 표현식 서비스 거부) 문제로, 공격자가 연합 작업 중 특수하게 조작된 HTML 응답을 보내 서비스 장애를 유발할 수 있습니다. 악성 페이로드는 작지만(약 170바이트), Node.js 이벤트 루프를 장시간 차단할 수 있습니다.

모든 Hollo 운영자분들께 즉시 버전 0.6.19로 업그레이드하실 것을 강력히 권고드립니다.

항목 상세
CVE CVE-2025-68475
심각도 높음 (CVSS 7.5)
조치 Hollo 0.6.19로 업그레이드

github.com

ReDoS Vulnerability in HTML Parsing Regex

Hi Fedify team! 👋 Thank you for your work on Fedify—it's a fantastic library for building federated applications. While reviewing the codebase, I discovered a Regular Expression Denial of Servic...

@hollo@hollo.social · Reply to Hollo :hollo:

보안 업데이트: Hollo 0.6.19 릴리스

Fedify의 HTML 파싱 코드에서 발견된 보안 취약점을 수정한 Hollo 0.6.19를 릴리스했습니다.

이 취약점(CVE-2025-68475)은 ReDoS(정규 표현식 서비스 거부) 문제로, 공격자가 연합 작업 중 특수하게 조작된 HTML 응답을 보내 서비스 장애를 유발할 수 있습니다. 악성 페이로드는 작지만(약 170바이트), Node.js 이벤트 루프를 장시간 차단할 수 있습니다.

모든 Hollo 운영자분들께 즉시 버전 0.6.19로 업그레이드하실 것을 강력히 권고드립니다.

항목 상세
CVE CVE-2025-68475
심각도 높음 (CVSS 7.5)
조치 Hollo 0.6.19로 업그레이드

github.com

ReDoS Vulnerability in HTML Parsing Regex

Hi Fedify team! 👋 Thank you for your work on Fedify—it's a fantastic library for building federated applications. While reviewing the codebase, I discovered a Regular Expression Denial of Servic...

Fedify는 새로운 후원 파트너를 찾고 있습니다!

:fedify: Fedify란?

Fedify는 기반 연합형 서버 프레임워크로, 개발자들이 분산형 소셜 네트워크인 ()에 애플리케이션을 쉽게 통합할 수 있도록 돕습니다. 복잡한 ActivityPub 프로토콜 구현을 단순화하여 개발 시간을 크게 단축시킵니다. MIT 라이선스 하에 제공되는 오픈 소스 프로젝트입니다.

💼 Fedify를 활용하는 프로젝트들

다양한 프로젝트들이 이미 Fedify를 활용하고 있습니다:

  • Ghost: 수백만 사용자를 보유한 전문적인 오픈 소스(MIT 라이선스) 퍼블리싱 플랫폼으로, Fedify의 주요 후원사이자 파트너입니다.
  • Hollo: 개인 사용자를 위한 경량 마이크로블로그 (오픈 소스, AGPL-3.0)
  • Hackers' Pub: 소프트웨어 엔지니어를 위한 연합우주 블로그 플랫폼 (오픈 소스, AGPL-3.0)
  • Encyclia: ORCID 학술 기록을 ActivityPub을 통해 제공하는 브리지 서비스

🚀 Fedify가 제공하는 가치

  • 개발 시간 80% 단축: ActivityPub의 복잡한 구현 대신 검증된 프레임워크 활용
  • 즉각적인 연합우주 호환성: Mastodon, Misskey, Pleroma, Pixelfed, PeerTube 등 다양한 연합우주 서비스와 즉시 호환
  • 전문 기술 지원: ActivityPub 및 연합 프로토콜 전문가의 직접 지원
  • 맞춤형 개발: 귀사의 특정 요구사항에 맞는 맞춤형 기능 개발

🤝 가능한 협력 모델

  • 맞춤형 컨설팅 및 통합 지원: 귀사 플랫폼에 통합을 위한 전문적 지원
  • 맞춤형 기능 개발 의뢰: 귀사에 필요한 특정 기능의 개발 및 구현
  • 장기적인 기술 파트너십: 지속적인 개발 및 유지보수를 위한 장기 협력 관계

🌟 Fedify와 협력했을 때의 이점

  • 기술적 이점: 자체 구현 대비 시간과 리소스 절약
  • 브랜드 이미지: 오픈 소스 생태계 지원을 통한 기업 이미지 강화
  • 분산형 소셜 네트워크 진입: 연합우주 생태계에 쉽게 참여
  • 경쟁 우위: 소셜 기능을 통한 제품 경쟁력 강화

📩 관심이 있으신가요?

ActivityPub 구현을 고려 중이시거나, Fedify 프로젝트와 협력하고 싶으시다면 연락 주세요:

귀사의 요구사항과 목표에 맞는 맞춤형 협력 방안을 함께 모색하겠습니다.

github.com

GitHub - fedify-dev/fedify: ActivityPub server framework in TypeScript

ActivityPub server framework in TypeScript. Contribute to fedify-dev/fedify development by creating an account on GitHub.

Fedify는 새로운 후원 파트너를 찾고 있습니다!

:fedify: Fedify란?

Fedify는 기반 연합형 서버 프레임워크로, 개발자들이 분산형 소셜 네트워크인 ()에 애플리케이션을 쉽게 통합할 수 있도록 돕습니다. 복잡한 ActivityPub 프로토콜 구현을 단순화하여 개발 시간을 크게 단축시킵니다. MIT 라이선스 하에 제공되는 오픈 소스 프로젝트입니다.

💼 Fedify를 활용하는 프로젝트들

다양한 프로젝트들이 이미 Fedify를 활용하고 있습니다:

  • Ghost: 수백만 사용자를 보유한 전문적인 오픈 소스(MIT 라이선스) 퍼블리싱 플랫폼으로, Fedify의 주요 후원사이자 파트너입니다.
  • Hollo: 개인 사용자를 위한 경량 마이크로블로그 (오픈 소스, AGPL-3.0)
  • Hackers' Pub: 소프트웨어 엔지니어를 위한 연합우주 블로그 플랫폼 (오픈 소스, AGPL-3.0)
  • Encyclia: ORCID 학술 기록을 ActivityPub을 통해 제공하는 브리지 서비스

🚀 Fedify가 제공하는 가치

  • 개발 시간 80% 단축: ActivityPub의 복잡한 구현 대신 검증된 프레임워크 활용
  • 즉각적인 연합우주 호환성: Mastodon, Misskey, Pleroma, Pixelfed, PeerTube 등 다양한 연합우주 서비스와 즉시 호환
  • 전문 기술 지원: ActivityPub 및 연합 프로토콜 전문가의 직접 지원
  • 맞춤형 개발: 귀사의 특정 요구사항에 맞는 맞춤형 기능 개발

🤝 가능한 협력 모델

  • 맞춤형 컨설팅 및 통합 지원: 귀사 플랫폼에 통합을 위한 전문적 지원
  • 맞춤형 기능 개발 의뢰: 귀사에 필요한 특정 기능의 개발 및 구현
  • 장기적인 기술 파트너십: 지속적인 개발 및 유지보수를 위한 장기 협력 관계

🌟 Fedify와 협력했을 때의 이점

  • 기술적 이점: 자체 구현 대비 시간과 리소스 절약
  • 브랜드 이미지: 오픈 소스 생태계 지원을 통한 기업 이미지 강화
  • 분산형 소셜 네트워크 진입: 연합우주 생태계에 쉽게 참여
  • 경쟁 우위: 소셜 기능을 통한 제품 경쟁력 강화

📩 관심이 있으신가요?

ActivityPub 구현을 고려 중이시거나, Fedify 프로젝트와 협력하고 싶으시다면 연락 주세요:

귀사의 요구사항과 목표에 맞는 맞춤형 협력 방안을 함께 모색하겠습니다.

github.com

GitHub - fedify-dev/fedify: ActivityPub server framework in TypeScript

ActivityPub server framework in TypeScript. Contribute to fedify-dev/fedify development by creating an account on GitHub.

Fedify는 새로운 후원 파트너를 찾고 있습니다!

:fedify: Fedify란?

Fedify는 기반 연합형 서버 프레임워크로, 개발자들이 분산형 소셜 네트워크인 ()에 애플리케이션을 쉽게 통합할 수 있도록 돕습니다. 복잡한 ActivityPub 프로토콜 구현을 단순화하여 개발 시간을 크게 단축시킵니다. MIT 라이선스 하에 제공되는 오픈 소스 프로젝트입니다.

💼 Fedify를 활용하는 프로젝트들

다양한 프로젝트들이 이미 Fedify를 활용하고 있습니다:

  • Ghost: 수백만 사용자를 보유한 전문적인 오픈 소스(MIT 라이선스) 퍼블리싱 플랫폼으로, Fedify의 주요 후원사이자 파트너입니다.
  • Hollo: 개인 사용자를 위한 경량 마이크로블로그 (오픈 소스, AGPL-3.0)
  • Hackers' Pub: 소프트웨어 엔지니어를 위한 연합우주 블로그 플랫폼 (오픈 소스, AGPL-3.0)
  • Encyclia: ORCID 학술 기록을 ActivityPub을 통해 제공하는 브리지 서비스

🚀 Fedify가 제공하는 가치

  • 개발 시간 80% 단축: ActivityPub의 복잡한 구현 대신 검증된 프레임워크 활용
  • 즉각적인 연합우주 호환성: Mastodon, Misskey, Pleroma, Pixelfed, PeerTube 등 다양한 연합우주 서비스와 즉시 호환
  • 전문 기술 지원: ActivityPub 및 연합 프로토콜 전문가의 직접 지원
  • 맞춤형 개발: 귀사의 특정 요구사항에 맞는 맞춤형 기능 개발

🤝 가능한 협력 모델

  • 맞춤형 컨설팅 및 통합 지원: 귀사 플랫폼에 통합을 위한 전문적 지원
  • 맞춤형 기능 개발 의뢰: 귀사에 필요한 특정 기능의 개발 및 구현
  • 장기적인 기술 파트너십: 지속적인 개발 및 유지보수를 위한 장기 협력 관계

🌟 Fedify와 협력했을 때의 이점

  • 기술적 이점: 자체 구현 대비 시간과 리소스 절약
  • 브랜드 이미지: 오픈 소스 생태계 지원을 통한 기업 이미지 강화
  • 분산형 소셜 네트워크 진입: 연합우주 생태계에 쉽게 참여
  • 경쟁 우위: 소셜 기능을 통한 제품 경쟁력 강화

📩 관심이 있으신가요?

ActivityPub 구현을 고려 중이시거나, Fedify 프로젝트와 협력하고 싶으시다면 연락 주세요:

귀사의 요구사항과 목표에 맞는 맞춤형 협력 방안을 함께 모색하겠습니다.

github.com

GitHub - fedify-dev/fedify: ActivityPub server framework in TypeScript

ActivityPub server framework in TypeScript. Contribute to fedify-dev/fedify development by creating an account on GitHub.

Fedify는 새로운 후원 파트너를 찾고 있습니다!

:fedify: Fedify란?

Fedify는 기반 연합형 서버 프레임워크로, 개발자들이 분산형 소셜 네트워크인 ()에 애플리케이션을 쉽게 통합할 수 있도록 돕습니다. 복잡한 ActivityPub 프로토콜 구현을 단순화하여 개발 시간을 크게 단축시킵니다. MIT 라이선스 하에 제공되는 오픈 소스 프로젝트입니다.

💼 Fedify를 활용하는 프로젝트들

다양한 프로젝트들이 이미 Fedify를 활용하고 있습니다:

  • Ghost: 수백만 사용자를 보유한 전문적인 오픈 소스(MIT 라이선스) 퍼블리싱 플랫폼으로, Fedify의 주요 후원사이자 파트너입니다.
  • Hollo: 개인 사용자를 위한 경량 마이크로블로그 (오픈 소스, AGPL-3.0)
  • Hackers' Pub: 소프트웨어 엔지니어를 위한 연합우주 블로그 플랫폼 (오픈 소스, AGPL-3.0)
  • Encyclia: ORCID 학술 기록을 ActivityPub을 통해 제공하는 브리지 서비스

🚀 Fedify가 제공하는 가치

  • 개발 시간 80% 단축: ActivityPub의 복잡한 구현 대신 검증된 프레임워크 활용
  • 즉각적인 연합우주 호환성: Mastodon, Misskey, Pleroma, Pixelfed, PeerTube 등 다양한 연합우주 서비스와 즉시 호환
  • 전문 기술 지원: ActivityPub 및 연합 프로토콜 전문가의 직접 지원
  • 맞춤형 개발: 귀사의 특정 요구사항에 맞는 맞춤형 기능 개발

🤝 가능한 협력 모델

  • 맞춤형 컨설팅 및 통합 지원: 귀사 플랫폼에 통합을 위한 전문적 지원
  • 맞춤형 기능 개발 의뢰: 귀사에 필요한 특정 기능의 개발 및 구현
  • 장기적인 기술 파트너십: 지속적인 개발 및 유지보수를 위한 장기 협력 관계

🌟 Fedify와 협력했을 때의 이점

  • 기술적 이점: 자체 구현 대비 시간과 리소스 절약
  • 브랜드 이미지: 오픈 소스 생태계 지원을 통한 기업 이미지 강화
  • 분산형 소셜 네트워크 진입: 연합우주 생태계에 쉽게 참여
  • 경쟁 우위: 소셜 기능을 통한 제품 경쟁력 강화

📩 관심이 있으신가요?

ActivityPub 구현을 고려 중이시거나, Fedify 프로젝트와 협력하고 싶으시다면 연락 주세요:

귀사의 요구사항과 목표에 맞는 맞춤형 협력 방안을 함께 모색하겠습니다.

github.com

GitHub - fedify-dev/fedify: ActivityPub server framework in TypeScript

ActivityPub server framework in TypeScript. Contribute to fedify-dev/fedify development by creating an account on GitHub.

Fedify는 새로운 후원 파트너를 찾고 있습니다!

:fedify: Fedify란?

Fedify는 기반 연합형 서버 프레임워크로, 개발자들이 분산형 소셜 네트워크인 ()에 애플리케이션을 쉽게 통합할 수 있도록 돕습니다. 복잡한 ActivityPub 프로토콜 구현을 단순화하여 개발 시간을 크게 단축시킵니다. MIT 라이선스 하에 제공되는 오픈 소스 프로젝트입니다.

💼 Fedify를 활용하는 프로젝트들

다양한 프로젝트들이 이미 Fedify를 활용하고 있습니다:

  • Ghost: 수백만 사용자를 보유한 전문적인 오픈 소스(MIT 라이선스) 퍼블리싱 플랫폼으로, Fedify의 주요 후원사이자 파트너입니다.
  • Hollo: 개인 사용자를 위한 경량 마이크로블로그 (오픈 소스, AGPL-3.0)
  • Hackers' Pub: 소프트웨어 엔지니어를 위한 연합우주 블로그 플랫폼 (오픈 소스, AGPL-3.0)
  • Encyclia: ORCID 학술 기록을 ActivityPub을 통해 제공하는 브리지 서비스

🚀 Fedify가 제공하는 가치

  • 개발 시간 80% 단축: ActivityPub의 복잡한 구현 대신 검증된 프레임워크 활용
  • 즉각적인 연합우주 호환성: Mastodon, Misskey, Pleroma, Pixelfed, PeerTube 등 다양한 연합우주 서비스와 즉시 호환
  • 전문 기술 지원: ActivityPub 및 연합 프로토콜 전문가의 직접 지원
  • 맞춤형 개발: 귀사의 특정 요구사항에 맞는 맞춤형 기능 개발

🤝 가능한 협력 모델

  • 맞춤형 컨설팅 및 통합 지원: 귀사 플랫폼에 통합을 위한 전문적 지원
  • 맞춤형 기능 개발 의뢰: 귀사에 필요한 특정 기능의 개발 및 구현
  • 장기적인 기술 파트너십: 지속적인 개발 및 유지보수를 위한 장기 협력 관계

🌟 Fedify와 협력했을 때의 이점

  • 기술적 이점: 자체 구현 대비 시간과 리소스 절약
  • 브랜드 이미지: 오픈 소스 생태계 지원을 통한 기업 이미지 강화
  • 분산형 소셜 네트워크 진입: 연합우주 생태계에 쉽게 참여
  • 경쟁 우위: 소셜 기능을 통한 제품 경쟁력 강화

📩 관심이 있으신가요?

ActivityPub 구현을 고려 중이시거나, Fedify 프로젝트와 협력하고 싶으시다면 연락 주세요:

귀사의 요구사항과 목표에 맞는 맞춤형 협력 방안을 함께 모색하겠습니다.

github.com

GitHub - fedify-dev/fedify: ActivityPub server framework in TypeScript

ActivityPub server framework in TypeScript. Contribute to fedify-dev/fedify development by creating an account on GitHub.

@hongminhee@hackers.pub

최근 X(구 Twitter)를 떠나는 사람들이 늘면서 Bluesky에 대한 관심이 뜨겁습니다. Bluesky는 깔끔한 인터페이스와 과거 Twitter와 유사한 사용자 경험을 제공하며, 신뢰할 수 있는 이탈(credible exit)이라는 매력적인 개념을 내세워 X의 유력한 대안으로 떠오르고 있습니다. 하지만 Bluesky와 그 기반 프로토콜인 AT Protocol을 연합우주(fediverse)의 대안으로 보기에는 근본적인 차이가 존재합니다. 이 글에서는 Christine Lemmer-Webber 씨(@cwebber)의 날카로운 분석(〈Bluesky는 실제로 얼마나 탈중앙화 되어 있나〉 및 〈답장: 답장: Bluesky와 탈중앙화〉)을 바탕으로, Bryan Newbold 씨(@bnewbold)의 반론(〈Bluesky와 탈중앙화에 대한 답변〉)을 충분히 고려하면서 Bluesky가 어째서 X의 대안은 될 수 있어도 연합우주의 대안은 될 수 없는지 이야기를 풀어볼까 합니다.

메시지 전달 對 공유 힙: 근본적인 설계 차이

Bluesky와 연합우주의 가장 큰 차이점 중 하나는 설계입니다. 연합우주는 이메일이나 XMPP와 유사한 메시지 전달(message passing) 방식을 채택하고 있습니다. 이는 특정 수신자에게 메시지를 직접 전달하는 방식으로, 효율성이 높습니다. 예를 들어, 수많은 서버 중 단 몇 곳의 사용자만 특정 메시지에 관심을 있다면 해당 서버에만 메시지를 전달하면 됩니다. 비유하자면, 철수가 영희에게 편지를 보내려면 직접 영희의 집으로 편지를 보내고, 영희가 회신하고 싶으면 직접 철수에게 회신하는 것과 같은 방식입니다.

반면, Bluesky는 공유 힙(shared heap) 방식을 사용합니다. 이는 메시지를 특정 수신자에게 직접 보내는 대신, 모든 메시지를 중앙의 “릴레이”라는 곳에 저장하고, 관심 있는 사용자가 릴레이에서 자신에게 필요한 정보를 필터링하는 방식입니다. 이는 마치 모든 편지가 하나의 거대한 우체국(릴레이)에 쌓이고, 각자가 이 우체국에 방문하여 자신에게 관련된 편지를 직접 찾아야 하는 것과 같습니다. 이런 방식에서는 메시지가 직접 전달되지 않기 때문에, 답글이 어떤 메시지에 대한 것인지 파악하려면 모든 가능한 메시지를 알고 있어야 합니다.

이 설계는 데이터와 색인을 분리하여 유연성을 제공한다는 주장도 있지만, 필연적으로 대규모 중앙 집권화된 릴레이에 의존하게 되어 탈중앙화의 이상과는 거리가 멀어진다는 한계가 있습니다.

결국 Bluesky가 공유 힙 방식을 채택하고 중앙 집권화된 릴레이에 의존하게 되는 데에는 운영 비용이라는 현실적인 이유가 크게 작용합니다. Christine Lemmer-Webber 씨의 분석에 따르면, Bluesky에서 전체 네트워크 기록을 저장하는 릴레이를 운영하는 데에는 상당한 스토리지를 요구하며, 이는 빠르게 증가하고 있습니다. 2024년 7월에는 약 1TB의 저장 공간이 필요했지만, 불과 4개월 후인 11월에는 약 5TB로 증가했습니다. 상업용 호스팅 서비스 기준으로 이는 연간 수만 달러(약 $55,000)에 달하는 비용이 발생할 수 있습니다.

반면, 연합우주에서는 개인이나 소규모 단체가 Raspberry Pi와 같은 저렴한 장비로도 GoToSocial과 같은 소프트웨어를 실행하여 독립적인 노드를 운영할 수 있습니다. 물론 대규모 연합우주 인스턴스는 더 많은 비용이 들겠지만, Bluesky의 전체 릴레이 운영 비용과는 비교하기 어려울 정도로 저렴합니다. 이처럼 운영 비용의 현격한 차이는 Bluesky가 분산된 구조를 채택하기 어렵게 만들고, 결국 중앙 집권화된 릴레이에 의존하게 만드는 주요 원인이라고 볼 수 있습니다.

전역 뷰에 대한 집착과 중앙 집권화의 심화

Bluesky는 댓글 누락과 같은 문제를 피하기 위해 네트워크 전체의 일관된 전역 뷰를 유지하는 데 집중하는 것으로 보입니다. 이러한 목표는 사용자 경험 측면에서 긍정적일 수 있지만, 필연적으로 중앙 집권화를 야기합니다. 대표적인 예가 차단 목록의 전체 공개입니다. 네트워크 전체의 일관성을 유지하기 위해 누가 누구를 차단했는지 모든 앱뷰가 알아야 하므로, 차단 정보가 공개되는 것입니다.

이는 개인 정보 보호 측면에서 심각한 우려를 낳을 수 있습니다. 단순히 누군가의 게시물을 보고 차단된 사람을 추측하는 것과, 네트워크에 “J. K. Rowling[1]을 차단한 모든 사람”을 직접 질의할 수 있는 것 사이에는 큰 차이가 있습니다. 실제로 ActivityPub 개발 과정에서는 이런 문제를 고려하여 서버 간에 차단 활동을 전달하지 않도록 명시적으로 설계했습니다. 이는 차단한 사람이 차단당한 사람의 보복을 받을 위험을 줄이기 위함입니다.

반면 연합우주에서는 각 서버가 독립적으로 차단 정책을 시행하며, 사용자에게 더 많은 자율성을 제공합니다.

AT Protocol과 개방형 표준으로서의 ActivityPub

연합우주의 핵심 프로토콜인 ActivityPub은 W3C의 채택 권고안으로, 개방형 표준입니다. 이는 누구나 자유롭게 구현하고 사용할 수 있으며, 다양한 소프트웨어 간의 상호 운용성을 보장합니다. 현재 페디버스 커뮤니티는 FEP를 중심으로 활발하게 프로토콜을 개선하고 발전시켜 나가고 있습니다. 반면, Bluesky의 AT Protocol은 아직 특정 사기업에 의해 주도되고 있으며, 개방형 표준으로서의 지위는 아직 확립되지 않았습니다. 이는 페디버스가 가진 확장성과 지속 가능성 측면에서 중요한 차이점이라고 할 수 있습니다.

DM의 중앙화

Bluesky는 콘텐츠 주소 지정이나 이동 가능한 아이덴티티와 같은 탈중앙화 요소를 도입했지만, DM은 완전히 중앙화되어 있습니다. 사용자가 어떤 PDS를 사용하든, 어떤 릴레이를 사용하든 상관없이 모든 DM은 Bluesky 회사를 통해 전송됩니다.

이는 Bluesky가 아직 기능적으로 완전한 Twitter 대체품이 되기 위해 속도를 우선시했다는 증거입니다. Bluesky는 이 DM 시스템이 장기적인 솔루션이 아니라고 밝혔지만, 대부분의 사용자들은 이 사실을 인지하지 못하고 있으며 DM도 AT Protocol의 다른 기능처럼 작동한다고 가정합니다.

이러한 중앙화된 DM 구현은 “신뢰할 수 있는 이탈”이라는 Bluesky의 핵심 가치와도 모순됩니다. 만약 Bluesky社가 적대적인 인수나 정책 변경을 겪게 된다면, 사용자들의 개인 대화는 완전히 회사의 통제 하에 남게 됩니다.

이동 가능한 아이덴티티와 DID: Bluesky 방식의 한계

Bluesky는 이동 가능한 아이덴티티(portable identity)를 핵심적인 장점 중 하나로 내세우며, 이를 위해 DIDs, 즉 분산 식별자를 활용합니다. 이는 사용자가 자신의 계정과 데이터를 다른 플랫폼으로 쉽게 이동할 수 있도록 하는 중요한 기능입니다. 하지만 Christine Lemmer-Webber는 AT Protocol이 채택한 did:webdid:plc 방식이 여전히 DNS와 Bluesky社가 관리하는 중앙 집권화된 PLC 레지스트리에 의존하고 있어 완전한 사용자 통제하의 독립적인 아이덴티티를 제공하는지 의문을 제기합니다.

더 놀라운 점은 Bluesky社가 초기에 모든 계정에 대해 동일한 rotationKeys를 사용했다는 사실입니다. 이는 클라우드 HSM 제품이 키별로 비용을 청구해서 각 사용자에게 고유한 키를 제공하는 것이 금전적으로 비용이 많이 들었기 때문이라고 합니다. 이러한 접근 방식은 DIDs 시스템을 구축하는 근본적인 목표와 모순되는 것으로 보입니다.

중요한 점은 DIDs 기술 자체가 탈중앙화된 아이덴티티를 위한 잠재력을 가지고 있음에도, Bluesky와 AT Protocol이 채택한 특정 방식이 중앙 집권화된 요소에 의존한다는 것입니다. 블록체인 기반의 DIDs와 같은 진정으로 탈중앙화된 방식도 존재하지만, AT Protocol은 비교적 구현이 쉬운 did:webdid:plc를 선택했습니다. 따라서 사용자가 Bluesky 생태계를 벗어나 자신의 아이덴티티를 완전히 독립적으로 관리하고자 할 때 제약이 발생할 수 있습니다.

또한 현재 시스템에서는 Bluesky社가 사용자의 키를 대신 관리하고 있어, 사용자가 현재는 Bluesky社를 신뢰하더라도 미래에 신뢰하지 않게 된 경우에도 여전히 회사에 의존해야 합니다. Bluesky社가 사용자를 대신하여 이동을 수행하도록 신뢰해야 하며, 심지어 Bluesky社가 사용자에게 향후 신원 정보를 제어할 권한을 위임하더라도 Bluesky社는 항상 해당 사용자의 키를 통제할 것입니다.

한편, 연합우주에서는 이미 노마딕 아이덴티티(nomadic identity)라는 개념을 통해 이동 가능한 아이덴티티에 대한 논의와 연구가 활발하게 진행되어 왔습니다. 이는 단순히 계정을 이전하는 것을 넘어, 사용자의 데이터와 관계, 심지어 평판까지도 자유롭게 이동할 수 있도록 하는 더 포괄적인 개념입니다. 《We Distribute》에 실린 기사 〈오, Zot! ActivityPub에 노마딕 아이덴티티가 도입된다〉에 소개된 Zot 프로토콜과 같은 기술은 이미 연합우주 안에서 이러한 노마딕 아이덴티티를 구현하기 위한 메커니즘을 제공하고 있습니다. 또한, FEP-ef61와 같은 제안을 통해 ActivityPub 자체를 개선하여 더 나은 이동 가능한 아이덴티티 기능을 추가하려는 노력도 진행 중입니다.

그래서, 결론은?

결론적으로, Bluesky는 사용자 친화적인 인터페이스와 신뢰할 수 있는 이탈 기능을 통해 X의 훌륭한 대안이 될 수 있습니다. Bluesky는 콘텐츠 주소 지정 방식을 통해 노드가 다운되더라도 콘텐츠가 살아남을 수 있게 하는 등 연합우주가 아직 충분히 활용하지 못하는 몇 가지 강점도 가지고 있습니다.

하지만 중앙 집권화된 설계, 전역 뷰에 대한 집착으로 인한 부작용, 개방형 표준으로서의 한계, DM의 중앙화, 그리고 이동 가능한 아이덴티티 구현의 제한점 등 여러 측면에서 연합우주의 대안으로 보기는 어렵습니다. 연합우주는 메시지 전달 방식의 분산된 아키텍처, 낮은 참여 장벽, 개방형 표준 기반의 활발한 커뮤니티 개발, 그리고 사용자에게 더 많은 자율성과 통제권을 제공하는 철학을 바탕으로 구축된, 근본적으로 다른 종류의 탈중앙화 소셜 네트워크입니다.

또한, Bluesky社가 벤처 캐피털 자금을 확보함에 따라 “조직은 미래의 적이다”라는 그들의 자체 인식에도 불구하고, 투자자 수익과 플랫폼 성장이라는 상업적 압력이 진정한 탈중앙화 추구보다 우선시될 위험이 있습니다. 특히 유료 계정과 광고가 도입되면서 이러한 우려는 더욱 커질 수 있습니다.

따라서 Bluesky는 X를 대체할 수 있을지 모르지만, 연합우주가 제공하는 탈중앙화된 가치와 경험을 대체하기는 어려울 것이라고 생각합니다. 두 시스템은 근본적으로 다른 목표와 설계 철학을 가지고 있으며, 이상적으로는 서로를 보완하는 방향으로 발전해 나갈 수 있을 것입니다.


  1. 판타지 소설 시리즈 《해리 포터》의 작가. ↩︎

@botkit@hollo.social · Reply to BotKit by Fedify :botkit:

BotKit 0.2.0 릴리스

BotKit 0.2.0 버전이 릴리스되었습니다! BotKit을 처음 접하시는 분들을 위해 간단히 소개하자면, BotKit은 TypeScript로 개발된 독립형 봇 프레임워크입니다. Mastodon, Misskey 등 다양한 () 플랫폼과 상호작용할 수 있으며, 기존 플랫폼의 제약에서 벗어나 자유롭게 봇을 만들 수 있습니다.

이번 릴리스는 연합우주 봇 개발을 더 쉽고 강력하게 만들기 위한 여정에서 중요한 발걸음입니다. 커뮤니티에서 요청해 왔던 여러 기능들을 새롭게 선보입니다.

더 나은 봇 상호작용을 위한 여정

BotKit을 개발하면서 우리는 항상 봇이 더 표현력 있고 상호작용이 풍부하도록 만드는 데 집중해 왔습니다. 0.2.0 버전에서는 연합우주의 사회적 측면을 봇에 접목시켜 한 단계 더 발전시켰습니다.

커스텀 에모지로 봇의 개성 표현하기

가장 많이 요청받았던 기능 중 하나가 지원입니다. 이제 봇은 독특한 시각적 요소로 메시지를 돋보이게 하며 자신만의 개성을 표현할 수 있습니다.

// 봇의 커스텀 에모지 정의하기
const emojis = bot.addCustomEmojis({
  botkit: { 
    file: `${import.meta.dirname}/images/botkit.png`, 
    type: "image/png" 
  },
  fedify: { 
    url: "https://fedify.dev/logo.png", 
    type: "image/png" 
  }
});

// 메시지에 커스텀 에모지 사용하기
await session.publish(
  text`BotKit ${customEmoji(emojis.botkit)}은 Fedify ${customEmoji(emojis.fedify)}의 지원을 받습니다`
);

이 새로운 API를 통해 다음과 같은 기능을 사용할 수 있습니다.

반응을 통한 소통

소통은 단순히 메시지를 게시하는 것만이 아닙니다. 다른 사람의 메시지에 반응하는 것도 중요합니다. 새로운 반응 시스템은 봇과 팔로워 사이에 자연스러운 상호작용 지점을 만들어 줍니다.

// 표준 유니코드 에모지로 메시지에 반응하기
await message.react(emoji`👍`);

// 또는 정의한 커스텀 에모지로 반응하기
await message.react(emojis.botkit);

// 반응을 인식하고 응답하는 봇 만들기
bot.onReact = async (session, reaction) => {
  await session.publish(
    text`${reaction.actor}님, 제 메시지에 ${reaction.emoji} 반응을 남겨주셔서 감사합니다!`,
    { visibility: "direct" }
  );
};

이 기능을 통해 봇은 다음과 같은 작업을 수행할 수 있습니다.

  • Message.react()를 사용하여 유니코드 에모지로 메시지에 반응하기
  • 정의한 커스텀 에모지로 반응하기
  • Bot.onReactBot.onUnreact 핸들러로 반응 이벤트 처리하기

인용을 통한 대화

토론에서는 종종 다른 사람이 말한 내용을 참조해야 할 때가 있습니다. 새로운 기능은 더 응집력 있는 대화 스레드를 만들어 줍니다.

// 봇의 게시물에서 다른 메시지 인용하기
await session.publish(
  text`이 흥미로운 관점에 대한 답변입니다...`,
  { quoteTarget: originalMessage }
);

// 사용자가 봇의 메시지를 인용할 때 처리하기
bot.onQuote = async (session, quoteMessage) => {
  await session.publish(
    text`${quoteMessage.actor}님, 제 생각을 공유해 주셔서 감사합니다!`,
    { visibility: "direct" }
  );
};

인용 기능을 통해 봇은 다음과 같은 작업을 수행할 수 있습니다.

시각적 개선

소통은 시각적인 요소도 중요하기 때문에 봇의 표현 방식을 개선했습니다.

  • 웹 인터페이스에서 이미지 첨부파일이 제대로 표시됩니다
  • 봇의 콘텐츠가 더 보기 좋아지고 풍부한 경험을 제공합니다

내부 개선: 향상된 액티비티 전파

연합우주에서 액티비티가 전파되는 방식도 개선했습니다.

  • 답글, 공유, 업데이트, 삭제의 더 정확한 전파
  • 원본 메시지 작성자에게 액티비티가 제대로 전송됩니다

이러한 개선 사항은 다양한 연합우주 플랫폼에서 봇의 상호작용이 일관되고 안정적으로 이루어지도록 보장합니다.

BotKit 0.2.0으로 첫 걸음 떼기

이러한 새로운 기능을 경험해 보고 싶으신가요? BotKit 0.2.0은 JSR에서 받을 수 있으며 간단한 명령어로 설치할 수 있습니다.

deno add jsr:@fedify/botkit@0.2.0

BotKit은 Temporal API(JavaScript에서 아직 시범적인 기능)를 사용하므로 deno.json에서 이를 활성화해야 합니다.

{
  "imports": {
    "@fedify/botkit": "jsr:@fedify/botkit@0.2.0"
  },
  "unstable": ["temporal"]
}

이 간단한 단계를 통해 최신 기능으로 연합우주 봇을 만들거나 업그레이드할 준비가 완료되었습니다.

앞으로의 전망

BotKit 0.2.0은 연합우주 봇 개발을 접근하기 쉽고, 강력하며, 즐겁게 만들기 위한 우리의 지속적인 노력을 보여줍니다. 이러한 새로운 기능들이 여러분의 봇이 연합우주 커뮤니티에서 더 매력적이고 상호작용이 풍부한 구성원이 되는 데 도움이 될 것이라고 믿습니다.

전체 문서와 더 많은 예제는 저희 문서 사이트에서 확인하실 수 있습니다.

피드백, 기능 요청, 코드 기여를 통해 이번 릴리스에 도움을 주신 모든 분들께 감사드립니다. BotKit 커뮤니티는 계속 성장하고 있으며, 여러분이 만들어낼 작품들을 기대합니다!


BotKit은 ActivityPub 서버 애플리케이션을 만들기 위한 하위 레벨 프레임워크인 Fedify의 지원을 받습니다.

fedify.dev

Fedify

Fedify is a TypeScript library for building federated server apps powered by ActivityPub and other standards, so-called fediverse.

@botkit@hollo.social · Reply to BotKit by Fedify :botkit:

BotKit 0.2.0 릴리스

BotKit 0.2.0 버전이 릴리스되었습니다! BotKit을 처음 접하시는 분들을 위해 간단히 소개하자면, BotKit은 TypeScript로 개발된 독립형 봇 프레임워크입니다. Mastodon, Misskey 등 다양한 () 플랫폼과 상호작용할 수 있으며, 기존 플랫폼의 제약에서 벗어나 자유롭게 봇을 만들 수 있습니다.

이번 릴리스는 연합우주 봇 개발을 더 쉽고 강력하게 만들기 위한 여정에서 중요한 발걸음입니다. 커뮤니티에서 요청해 왔던 여러 기능들을 새롭게 선보입니다.

더 나은 봇 상호작용을 위한 여정

BotKit을 개발하면서 우리는 항상 봇이 더 표현력 있고 상호작용이 풍부하도록 만드는 데 집중해 왔습니다. 0.2.0 버전에서는 연합우주의 사회적 측면을 봇에 접목시켜 한 단계 더 발전시켰습니다.

커스텀 에모지로 봇의 개성 표현하기

가장 많이 요청받았던 기능 중 하나가 지원입니다. 이제 봇은 독특한 시각적 요소로 메시지를 돋보이게 하며 자신만의 개성을 표현할 수 있습니다.

// 봇의 커스텀 에모지 정의하기
const emojis = bot.addCustomEmojis({
  botkit: { 
    file: `${import.meta.dirname}/images/botkit.png`, 
    type: "image/png" 
  },
  fedify: { 
    url: "https://fedify.dev/logo.png", 
    type: "image/png" 
  }
});

// 메시지에 커스텀 에모지 사용하기
await session.publish(
  text`BotKit ${customEmoji(emojis.botkit)}은 Fedify ${customEmoji(emojis.fedify)}의 지원을 받습니다`
);

이 새로운 API를 통해 다음과 같은 기능을 사용할 수 있습니다.

반응을 통한 소통

소통은 단순히 메시지를 게시하는 것만이 아닙니다. 다른 사람의 메시지에 반응하는 것도 중요합니다. 새로운 반응 시스템은 봇과 팔로워 사이에 자연스러운 상호작용 지점을 만들어 줍니다.

// 표준 유니코드 에모지로 메시지에 반응하기
await message.react(emoji`👍`);

// 또는 정의한 커스텀 에모지로 반응하기
await message.react(emojis.botkit);

// 반응을 인식하고 응답하는 봇 만들기
bot.onReact = async (session, reaction) => {
  await session.publish(
    text`${reaction.actor}님, 제 메시지에 ${reaction.emoji} 반응을 남겨주셔서 감사합니다!`,
    { visibility: "direct" }
  );
};

이 기능을 통해 봇은 다음과 같은 작업을 수행할 수 있습니다.

  • Message.react()를 사용하여 유니코드 에모지로 메시지에 반응하기
  • 정의한 커스텀 에모지로 반응하기
  • Bot.onReactBot.onUnreact 핸들러로 반응 이벤트 처리하기

인용을 통한 대화

토론에서는 종종 다른 사람이 말한 내용을 참조해야 할 때가 있습니다. 새로운 기능은 더 응집력 있는 대화 스레드를 만들어 줍니다.

// 봇의 게시물에서 다른 메시지 인용하기
await session.publish(
  text`이 흥미로운 관점에 대한 답변입니다...`,
  { quoteTarget: originalMessage }
);

// 사용자가 봇의 메시지를 인용할 때 처리하기
bot.onQuote = async (session, quoteMessage) => {
  await session.publish(
    text`${quoteMessage.actor}님, 제 생각을 공유해 주셔서 감사합니다!`,
    { visibility: "direct" }
  );
};

인용 기능을 통해 봇은 다음과 같은 작업을 수행할 수 있습니다.

시각적 개선

소통은 시각적인 요소도 중요하기 때문에 봇의 표현 방식을 개선했습니다.

  • 웹 인터페이스에서 이미지 첨부파일이 제대로 표시됩니다
  • 봇의 콘텐츠가 더 보기 좋아지고 풍부한 경험을 제공합니다

내부 개선: 향상된 액티비티 전파

연합우주에서 액티비티가 전파되는 방식도 개선했습니다.

  • 답글, 공유, 업데이트, 삭제의 더 정확한 전파
  • 원본 메시지 작성자에게 액티비티가 제대로 전송됩니다

이러한 개선 사항은 다양한 연합우주 플랫폼에서 봇의 상호작용이 일관되고 안정적으로 이루어지도록 보장합니다.

BotKit 0.2.0으로 첫 걸음 떼기

이러한 새로운 기능을 경험해 보고 싶으신가요? BotKit 0.2.0은 JSR에서 받을 수 있으며 간단한 명령어로 설치할 수 있습니다.

deno add jsr:@fedify/botkit@0.2.0

BotKit은 Temporal API(JavaScript에서 아직 시범적인 기능)를 사용하므로 deno.json에서 이를 활성화해야 합니다.

{
  "imports": {
    "@fedify/botkit": "jsr:@fedify/botkit@0.2.0"
  },
  "unstable": ["temporal"]
}

이 간단한 단계를 통해 최신 기능으로 연합우주 봇을 만들거나 업그레이드할 준비가 완료되었습니다.

앞으로의 전망

BotKit 0.2.0은 연합우주 봇 개발을 접근하기 쉽고, 강력하며, 즐겁게 만들기 위한 우리의 지속적인 노력을 보여줍니다. 이러한 새로운 기능들이 여러분의 봇이 연합우주 커뮤니티에서 더 매력적이고 상호작용이 풍부한 구성원이 되는 데 도움이 될 것이라고 믿습니다.

전체 문서와 더 많은 예제는 저희 문서 사이트에서 확인하실 수 있습니다.

피드백, 기능 요청, 코드 기여를 통해 이번 릴리스에 도움을 주신 모든 분들께 감사드립니다. BotKit 커뮤니티는 계속 성장하고 있으며, 여러분이 만들어낼 작품들을 기대합니다!


BotKit은 ActivityPub 서버 애플리케이션을 만들기 위한 하위 레벨 프레임워크인 Fedify의 지원을 받습니다.

fedify.dev

Fedify

Fedify is a TypeScript library for building federated server apps powered by ActivityPub and other standards, so-called fediverse.

@botkit@hollo.social · Reply to BotKit by Fedify :botkit:

BotKit 0.2.0 릴리스

BotKit 0.2.0 버전이 릴리스되었습니다! BotKit을 처음 접하시는 분들을 위해 간단히 소개하자면, BotKit은 TypeScript로 개발된 독립형 봇 프레임워크입니다. Mastodon, Misskey 등 다양한 () 플랫폼과 상호작용할 수 있으며, 기존 플랫폼의 제약에서 벗어나 자유롭게 봇을 만들 수 있습니다.

이번 릴리스는 연합우주 봇 개발을 더 쉽고 강력하게 만들기 위한 여정에서 중요한 발걸음입니다. 커뮤니티에서 요청해 왔던 여러 기능들을 새롭게 선보입니다.

더 나은 봇 상호작용을 위한 여정

BotKit을 개발하면서 우리는 항상 봇이 더 표현력 있고 상호작용이 풍부하도록 만드는 데 집중해 왔습니다. 0.2.0 버전에서는 연합우주의 사회적 측면을 봇에 접목시켜 한 단계 더 발전시켰습니다.

커스텀 에모지로 봇의 개성 표현하기

가장 많이 요청받았던 기능 중 하나가 지원입니다. 이제 봇은 독특한 시각적 요소로 메시지를 돋보이게 하며 자신만의 개성을 표현할 수 있습니다.

// 봇의 커스텀 에모지 정의하기
const emojis = bot.addCustomEmojis({
  botkit: { 
    file: `${import.meta.dirname}/images/botkit.png`, 
    type: "image/png" 
  },
  fedify: { 
    url: "https://fedify.dev/logo.png", 
    type: "image/png" 
  }
});

// 메시지에 커스텀 에모지 사용하기
await session.publish(
  text`BotKit ${customEmoji(emojis.botkit)}은 Fedify ${customEmoji(emojis.fedify)}의 지원을 받습니다`
);

이 새로운 API를 통해 다음과 같은 기능을 사용할 수 있습니다.

반응을 통한 소통

소통은 단순히 메시지를 게시하는 것만이 아닙니다. 다른 사람의 메시지에 반응하는 것도 중요합니다. 새로운 반응 시스템은 봇과 팔로워 사이에 자연스러운 상호작용 지점을 만들어 줍니다.

// 표준 유니코드 에모지로 메시지에 반응하기
await message.react(emoji`👍`);

// 또는 정의한 커스텀 에모지로 반응하기
await message.react(emojis.botkit);

// 반응을 인식하고 응답하는 봇 만들기
bot.onReact = async (session, reaction) => {
  await session.publish(
    text`${reaction.actor}님, 제 메시지에 ${reaction.emoji} 반응을 남겨주셔서 감사합니다!`,
    { visibility: "direct" }
  );
};

이 기능을 통해 봇은 다음과 같은 작업을 수행할 수 있습니다.

  • Message.react()를 사용하여 유니코드 에모지로 메시지에 반응하기
  • 정의한 커스텀 에모지로 반응하기
  • Bot.onReactBot.onUnreact 핸들러로 반응 이벤트 처리하기

인용을 통한 대화

토론에서는 종종 다른 사람이 말한 내용을 참조해야 할 때가 있습니다. 새로운 기능은 더 응집력 있는 대화 스레드를 만들어 줍니다.

// 봇의 게시물에서 다른 메시지 인용하기
await session.publish(
  text`이 흥미로운 관점에 대한 답변입니다...`,
  { quoteTarget: originalMessage }
);

// 사용자가 봇의 메시지를 인용할 때 처리하기
bot.onQuote = async (session, quoteMessage) => {
  await session.publish(
    text`${quoteMessage.actor}님, 제 생각을 공유해 주셔서 감사합니다!`,
    { visibility: "direct" }
  );
};

인용 기능을 통해 봇은 다음과 같은 작업을 수행할 수 있습니다.

시각적 개선

소통은 시각적인 요소도 중요하기 때문에 봇의 표현 방식을 개선했습니다.

  • 웹 인터페이스에서 이미지 첨부파일이 제대로 표시됩니다
  • 봇의 콘텐츠가 더 보기 좋아지고 풍부한 경험을 제공합니다

내부 개선: 향상된 액티비티 전파

연합우주에서 액티비티가 전파되는 방식도 개선했습니다.

  • 답글, 공유, 업데이트, 삭제의 더 정확한 전파
  • 원본 메시지 작성자에게 액티비티가 제대로 전송됩니다

이러한 개선 사항은 다양한 연합우주 플랫폼에서 봇의 상호작용이 일관되고 안정적으로 이루어지도록 보장합니다.

BotKit 0.2.0으로 첫 걸음 떼기

이러한 새로운 기능을 경험해 보고 싶으신가요? BotKit 0.2.0은 JSR에서 받을 수 있으며 간단한 명령어로 설치할 수 있습니다.

deno add jsr:@fedify/botkit@0.2.0

BotKit은 Temporal API(JavaScript에서 아직 시범적인 기능)를 사용하므로 deno.json에서 이를 활성화해야 합니다.

{
  "imports": {
    "@fedify/botkit": "jsr:@fedify/botkit@0.2.0"
  },
  "unstable": ["temporal"]
}

이 간단한 단계를 통해 최신 기능으로 연합우주 봇을 만들거나 업그레이드할 준비가 완료되었습니다.

앞으로의 전망

BotKit 0.2.0은 연합우주 봇 개발을 접근하기 쉽고, 강력하며, 즐겁게 만들기 위한 우리의 지속적인 노력을 보여줍니다. 이러한 새로운 기능들이 여러분의 봇이 연합우주 커뮤니티에서 더 매력적이고 상호작용이 풍부한 구성원이 되는 데 도움이 될 것이라고 믿습니다.

전체 문서와 더 많은 예제는 저희 문서 사이트에서 확인하실 수 있습니다.

피드백, 기능 요청, 코드 기여를 통해 이번 릴리스에 도움을 주신 모든 분들께 감사드립니다. BotKit 커뮤니티는 계속 성장하고 있으며, 여러분이 만들어낼 작품들을 기대합니다!


BotKit은 ActivityPub 서버 애플리케이션을 만들기 위한 하위 레벨 프레임워크인 Fedify의 지원을 받습니다.

fedify.dev

Fedify

Fedify is a TypeScript library for building federated server apps powered by ActivityPub and other standards, so-called fediverse.

@botkit@hollo.social · Reply to BotKit by Fedify :botkit:

BotKit 0.2.0 릴리스

BotKit 0.2.0 버전이 릴리스되었습니다! BotKit을 처음 접하시는 분들을 위해 간단히 소개하자면, BotKit은 TypeScript로 개발된 독립형 봇 프레임워크입니다. Mastodon, Misskey 등 다양한 () 플랫폼과 상호작용할 수 있으며, 기존 플랫폼의 제약에서 벗어나 자유롭게 봇을 만들 수 있습니다.

이번 릴리스는 연합우주 봇 개발을 더 쉽고 강력하게 만들기 위한 여정에서 중요한 발걸음입니다. 커뮤니티에서 요청해 왔던 여러 기능들을 새롭게 선보입니다.

더 나은 봇 상호작용을 위한 여정

BotKit을 개발하면서 우리는 항상 봇이 더 표현력 있고 상호작용이 풍부하도록 만드는 데 집중해 왔습니다. 0.2.0 버전에서는 연합우주의 사회적 측면을 봇에 접목시켜 한 단계 더 발전시켰습니다.

커스텀 에모지로 봇의 개성 표현하기

가장 많이 요청받았던 기능 중 하나가 지원입니다. 이제 봇은 독특한 시각적 요소로 메시지를 돋보이게 하며 자신만의 개성을 표현할 수 있습니다.

// 봇의 커스텀 에모지 정의하기
const emojis = bot.addCustomEmojis({
  botkit: { 
    file: `${import.meta.dirname}/images/botkit.png`, 
    type: "image/png" 
  },
  fedify: { 
    url: "https://fedify.dev/logo.png", 
    type: "image/png" 
  }
});

// 메시지에 커스텀 에모지 사용하기
await session.publish(
  text`BotKit ${customEmoji(emojis.botkit)}은 Fedify ${customEmoji(emojis.fedify)}의 지원을 받습니다`
);

이 새로운 API를 통해 다음과 같은 기능을 사용할 수 있습니다.

반응을 통한 소통

소통은 단순히 메시지를 게시하는 것만이 아닙니다. 다른 사람의 메시지에 반응하는 것도 중요합니다. 새로운 반응 시스템은 봇과 팔로워 사이에 자연스러운 상호작용 지점을 만들어 줍니다.

// 표준 유니코드 에모지로 메시지에 반응하기
await message.react(emoji`👍`);

// 또는 정의한 커스텀 에모지로 반응하기
await message.react(emojis.botkit);

// 반응을 인식하고 응답하는 봇 만들기
bot.onReact = async (session, reaction) => {
  await session.publish(
    text`${reaction.actor}님, 제 메시지에 ${reaction.emoji} 반응을 남겨주셔서 감사합니다!`,
    { visibility: "direct" }
  );
};

이 기능을 통해 봇은 다음과 같은 작업을 수행할 수 있습니다.

  • Message.react()를 사용하여 유니코드 에모지로 메시지에 반응하기
  • 정의한 커스텀 에모지로 반응하기
  • Bot.onReactBot.onUnreact 핸들러로 반응 이벤트 처리하기

인용을 통한 대화

토론에서는 종종 다른 사람이 말한 내용을 참조해야 할 때가 있습니다. 새로운 기능은 더 응집력 있는 대화 스레드를 만들어 줍니다.

// 봇의 게시물에서 다른 메시지 인용하기
await session.publish(
  text`이 흥미로운 관점에 대한 답변입니다...`,
  { quoteTarget: originalMessage }
);

// 사용자가 봇의 메시지를 인용할 때 처리하기
bot.onQuote = async (session, quoteMessage) => {
  await session.publish(
    text`${quoteMessage.actor}님, 제 생각을 공유해 주셔서 감사합니다!`,
    { visibility: "direct" }
  );
};

인용 기능을 통해 봇은 다음과 같은 작업을 수행할 수 있습니다.

시각적 개선

소통은 시각적인 요소도 중요하기 때문에 봇의 표현 방식을 개선했습니다.

  • 웹 인터페이스에서 이미지 첨부파일이 제대로 표시됩니다
  • 봇의 콘텐츠가 더 보기 좋아지고 풍부한 경험을 제공합니다

내부 개선: 향상된 액티비티 전파

연합우주에서 액티비티가 전파되는 방식도 개선했습니다.

  • 답글, 공유, 업데이트, 삭제의 더 정확한 전파
  • 원본 메시지 작성자에게 액티비티가 제대로 전송됩니다

이러한 개선 사항은 다양한 연합우주 플랫폼에서 봇의 상호작용이 일관되고 안정적으로 이루어지도록 보장합니다.

BotKit 0.2.0으로 첫 걸음 떼기

이러한 새로운 기능을 경험해 보고 싶으신가요? BotKit 0.2.0은 JSR에서 받을 수 있으며 간단한 명령어로 설치할 수 있습니다.

deno add jsr:@fedify/botkit@0.2.0

BotKit은 Temporal API(JavaScript에서 아직 시범적인 기능)를 사용하므로 deno.json에서 이를 활성화해야 합니다.

{
  "imports": {
    "@fedify/botkit": "jsr:@fedify/botkit@0.2.0"
  },
  "unstable": ["temporal"]
}

이 간단한 단계를 통해 최신 기능으로 연합우주 봇을 만들거나 업그레이드할 준비가 완료되었습니다.

앞으로의 전망

BotKit 0.2.0은 연합우주 봇 개발을 접근하기 쉽고, 강력하며, 즐겁게 만들기 위한 우리의 지속적인 노력을 보여줍니다. 이러한 새로운 기능들이 여러분의 봇이 연합우주 커뮤니티에서 더 매력적이고 상호작용이 풍부한 구성원이 되는 데 도움이 될 것이라고 믿습니다.

전체 문서와 더 많은 예제는 저희 문서 사이트에서 확인하실 수 있습니다.

피드백, 기능 요청, 코드 기여를 통해 이번 릴리스에 도움을 주신 모든 분들께 감사드립니다. BotKit 커뮤니티는 계속 성장하고 있으며, 여러분이 만들어낼 작품들을 기대합니다!


BotKit은 ActivityPub 서버 애플리케이션을 만들기 위한 하위 레벨 프레임워크인 Fedify의 지원을 받습니다.

fedify.dev

Fedify

Fedify is a TypeScript library for building federated server apps powered by ActivityPub and other standards, so-called fediverse.

@botkit@hollo.social · Reply to BotKit by Fedify :botkit:

BotKit 0.2.0 릴리스

BotKit 0.2.0 버전이 릴리스되었습니다! BotKit을 처음 접하시는 분들을 위해 간단히 소개하자면, BotKit은 TypeScript로 개발된 독립형 봇 프레임워크입니다. Mastodon, Misskey 등 다양한 () 플랫폼과 상호작용할 수 있으며, 기존 플랫폼의 제약에서 벗어나 자유롭게 봇을 만들 수 있습니다.

이번 릴리스는 연합우주 봇 개발을 더 쉽고 강력하게 만들기 위한 여정에서 중요한 발걸음입니다. 커뮤니티에서 요청해 왔던 여러 기능들을 새롭게 선보입니다.

더 나은 봇 상호작용을 위한 여정

BotKit을 개발하면서 우리는 항상 봇이 더 표현력 있고 상호작용이 풍부하도록 만드는 데 집중해 왔습니다. 0.2.0 버전에서는 연합우주의 사회적 측면을 봇에 접목시켜 한 단계 더 발전시켰습니다.

커스텀 에모지로 봇의 개성 표현하기

가장 많이 요청받았던 기능 중 하나가 지원입니다. 이제 봇은 독특한 시각적 요소로 메시지를 돋보이게 하며 자신만의 개성을 표현할 수 있습니다.

// 봇의 커스텀 에모지 정의하기
const emojis = bot.addCustomEmojis({
  botkit: { 
    file: `${import.meta.dirname}/images/botkit.png`, 
    type: "image/png" 
  },
  fedify: { 
    url: "https://fedify.dev/logo.png", 
    type: "image/png" 
  }
});

// 메시지에 커스텀 에모지 사용하기
await session.publish(
  text`BotKit ${customEmoji(emojis.botkit)}은 Fedify ${customEmoji(emojis.fedify)}의 지원을 받습니다`
);

이 새로운 API를 통해 다음과 같은 기능을 사용할 수 있습니다.

반응을 통한 소통

소통은 단순히 메시지를 게시하는 것만이 아닙니다. 다른 사람의 메시지에 반응하는 것도 중요합니다. 새로운 반응 시스템은 봇과 팔로워 사이에 자연스러운 상호작용 지점을 만들어 줍니다.

// 표준 유니코드 에모지로 메시지에 반응하기
await message.react(emoji`👍`);

// 또는 정의한 커스텀 에모지로 반응하기
await message.react(emojis.botkit);

// 반응을 인식하고 응답하는 봇 만들기
bot.onReact = async (session, reaction) => {
  await session.publish(
    text`${reaction.actor}님, 제 메시지에 ${reaction.emoji} 반응을 남겨주셔서 감사합니다!`,
    { visibility: "direct" }
  );
};

이 기능을 통해 봇은 다음과 같은 작업을 수행할 수 있습니다.

  • Message.react()를 사용하여 유니코드 에모지로 메시지에 반응하기
  • 정의한 커스텀 에모지로 반응하기
  • Bot.onReactBot.onUnreact 핸들러로 반응 이벤트 처리하기

인용을 통한 대화

토론에서는 종종 다른 사람이 말한 내용을 참조해야 할 때가 있습니다. 새로운 기능은 더 응집력 있는 대화 스레드를 만들어 줍니다.

// 봇의 게시물에서 다른 메시지 인용하기
await session.publish(
  text`이 흥미로운 관점에 대한 답변입니다...`,
  { quoteTarget: originalMessage }
);

// 사용자가 봇의 메시지를 인용할 때 처리하기
bot.onQuote = async (session, quoteMessage) => {
  await session.publish(
    text`${quoteMessage.actor}님, 제 생각을 공유해 주셔서 감사합니다!`,
    { visibility: "direct" }
  );
};

인용 기능을 통해 봇은 다음과 같은 작업을 수행할 수 있습니다.

시각적 개선

소통은 시각적인 요소도 중요하기 때문에 봇의 표현 방식을 개선했습니다.

  • 웹 인터페이스에서 이미지 첨부파일이 제대로 표시됩니다
  • 봇의 콘텐츠가 더 보기 좋아지고 풍부한 경험을 제공합니다

내부 개선: 향상된 액티비티 전파

연합우주에서 액티비티가 전파되는 방식도 개선했습니다.

  • 답글, 공유, 업데이트, 삭제의 더 정확한 전파
  • 원본 메시지 작성자에게 액티비티가 제대로 전송됩니다

이러한 개선 사항은 다양한 연합우주 플랫폼에서 봇의 상호작용이 일관되고 안정적으로 이루어지도록 보장합니다.

BotKit 0.2.0으로 첫 걸음 떼기

이러한 새로운 기능을 경험해 보고 싶으신가요? BotKit 0.2.0은 JSR에서 받을 수 있으며 간단한 명령어로 설치할 수 있습니다.

deno add jsr:@fedify/botkit@0.2.0

BotKit은 Temporal API(JavaScript에서 아직 시범적인 기능)를 사용하므로 deno.json에서 이를 활성화해야 합니다.

{
  "imports": {
    "@fedify/botkit": "jsr:@fedify/botkit@0.2.0"
  },
  "unstable": ["temporal"]
}

이 간단한 단계를 통해 최신 기능으로 연합우주 봇을 만들거나 업그레이드할 준비가 완료되었습니다.

앞으로의 전망

BotKit 0.2.0은 연합우주 봇 개발을 접근하기 쉽고, 강력하며, 즐겁게 만들기 위한 우리의 지속적인 노력을 보여줍니다. 이러한 새로운 기능들이 여러분의 봇이 연합우주 커뮤니티에서 더 매력적이고 상호작용이 풍부한 구성원이 되는 데 도움이 될 것이라고 믿습니다.

전체 문서와 더 많은 예제는 저희 문서 사이트에서 확인하실 수 있습니다.

피드백, 기능 요청, 코드 기여를 통해 이번 릴리스에 도움을 주신 모든 분들께 감사드립니다. BotKit 커뮤니티는 계속 성장하고 있으며, 여러분이 만들어낼 작품들을 기대합니다!


BotKit은 ActivityPub 서버 애플리케이션을 만들기 위한 하위 레벨 프레임워크인 Fedify의 지원을 받습니다.

fedify.dev

Fedify

Fedify is a TypeScript library for building federated server apps powered by ActivityPub and other standards, so-called fediverse.

@hongminhee@hackers.pub

소프트웨어 엔지니어를 위한 연합우주 서비스 Hackers' Pub을 알고 계신가요? 저희가 특별히 중요시하는 것은 다른 플랫폼과는 조금 다른 행동 강령입니다.

저희는 현실 세계의 불평등이 온라인 공간에도 그대로 반영된다는 사실을 인식하고 있습니다. 그래서 “모든 사람을 동등하게 대우”한다는 표면적인 중립성이 아닌, 구조적 불평등에 적극적으로 대응하는 자세를 분명히 하고 있습니다. 이러한 접근의 일환으로, 차별적 발언과 차별에 대항하는 발언을 구분합니다. 이를 통해 “차별은 안 된다”는 명목 하에 차별 비판까지 동일시하는 “양비론”의 함정을 피할 수 있다고 생각합니다.

기술 커뮤니티에서 자주 볼 수 있는 문제로는 특정 기술 선택에 대한 비판이나 기술 수준에 따른 계층화가 있습니다. “이것도 모르냐?”는 태도는 학습을 방해할 뿐입니다. 저희는 초보자와 경험자 모두 동등하게 존중받는 환경 조성을 중요시합니다.

또한, 연합우주의 핵심 가치로 프라이버시가 있지만, Hackers' Pub에서는 특히 익명성의 권리를 강조합니다. 타인의 신원을 특정하려는 행위나 익명이라는 이유로 차별하는 것을 금지함으로써, 안심하고 참여할 수 있는 공간을 지향합니다.

이러한 행동 강령 자체도 완벽하지 않으며, 커뮤니티와 함께 발전해 나가는 것이라고 생각합니다. 모든 구성원이 개선안을 제안할 수 있는 체계를 마련함으로써, 더 나은 환경을 함께 만들어 나가고자 합니다.

자세한 내용은 Hackers' Pub 행동 강령을 참조해 주세요. 연합우주에서 더 건강한 기술 커뮤니티를 함께 키워나가지 않으실래요?

hackers.pub

Hackers' Pub Code of Conduct

@hongminhee@hackers.pub

소프트웨어 엔지니어를 위한 연합우주 서비스 Hackers' Pub을 알고 계신가요? 저희가 특별히 중요시하는 것은 다른 플랫폼과는 조금 다른 행동 강령입니다.

저희는 현실 세계의 불평등이 온라인 공간에도 그대로 반영된다는 사실을 인식하고 있습니다. 그래서 “모든 사람을 동등하게 대우”한다는 표면적인 중립성이 아닌, 구조적 불평등에 적극적으로 대응하는 자세를 분명히 하고 있습니다. 이러한 접근의 일환으로, 차별적 발언과 차별에 대항하는 발언을 구분합니다. 이를 통해 “차별은 안 된다”는 명목 하에 차별 비판까지 동일시하는 “양비론”의 함정을 피할 수 있다고 생각합니다.

기술 커뮤니티에서 자주 볼 수 있는 문제로는 특정 기술 선택에 대한 비판이나 기술 수준에 따른 계층화가 있습니다. “이것도 모르냐?”는 태도는 학습을 방해할 뿐입니다. 저희는 초보자와 경험자 모두 동등하게 존중받는 환경 조성을 중요시합니다.

또한, 연합우주의 핵심 가치로 프라이버시가 있지만, Hackers' Pub에서는 특히 익명성의 권리를 강조합니다. 타인의 신원을 특정하려는 행위나 익명이라는 이유로 차별하는 것을 금지함으로써, 안심하고 참여할 수 있는 공간을 지향합니다.

이러한 행동 강령 자체도 완벽하지 않으며, 커뮤니티와 함께 발전해 나가는 것이라고 생각합니다. 모든 구성원이 개선안을 제안할 수 있는 체계를 마련함으로써, 더 나은 환경을 함께 만들어 나가고자 합니다.

자세한 내용은 Hackers' Pub 행동 강령을 참조해 주세요. 연합우주에서 더 건강한 기술 커뮤니티를 함께 키워나가지 않으실래요?

hackers.pub

Hackers' Pub Code of Conduct

@hongminhee@hackers.pub

소프트웨어 엔지니어를 위한 연합우주 서비스 Hackers' Pub을 알고 계신가요? 저희가 특별히 중요시하는 것은 다른 플랫폼과는 조금 다른 행동 강령입니다.

저희는 현실 세계의 불평등이 온라인 공간에도 그대로 반영된다는 사실을 인식하고 있습니다. 그래서 “모든 사람을 동등하게 대우”한다는 표면적인 중립성이 아닌, 구조적 불평등에 적극적으로 대응하는 자세를 분명히 하고 있습니다. 이러한 접근의 일환으로, 차별적 발언과 차별에 대항하는 발언을 구분합니다. 이를 통해 “차별은 안 된다”는 명목 하에 차별 비판까지 동일시하는 “양비론”의 함정을 피할 수 있다고 생각합니다.

기술 커뮤니티에서 자주 볼 수 있는 문제로는 특정 기술 선택에 대한 비판이나 기술 수준에 따른 계층화가 있습니다. “이것도 모르냐?”는 태도는 학습을 방해할 뿐입니다. 저희는 초보자와 경험자 모두 동등하게 존중받는 환경 조성을 중요시합니다.

또한, 연합우주의 핵심 가치로 프라이버시가 있지만, Hackers' Pub에서는 특히 익명성의 권리를 강조합니다. 타인의 신원을 특정하려는 행위나 익명이라는 이유로 차별하는 것을 금지함으로써, 안심하고 참여할 수 있는 공간을 지향합니다.

이러한 행동 강령 자체도 완벽하지 않으며, 커뮤니티와 함께 발전해 나가는 것이라고 생각합니다. 모든 구성원이 개선안을 제안할 수 있는 체계를 마련함으로써, 더 나은 환경을 함께 만들어 나가고자 합니다.

자세한 내용은 Hackers' Pub 행동 강령을 참조해 주세요. 연합우주에서 더 건강한 기술 커뮤니티를 함께 키워나가지 않으실래요?

hackers.pub

Hackers' Pub Code of Conduct

@hongminhee@hackers.pub

소프트웨어 엔지니어를 위한 연합우주 서비스 Hackers' Pub을 알고 계신가요? 저희가 특별히 중요시하는 것은 다른 플랫폼과는 조금 다른 행동 강령입니다.

저희는 현실 세계의 불평등이 온라인 공간에도 그대로 반영된다는 사실을 인식하고 있습니다. 그래서 “모든 사람을 동등하게 대우”한다는 표면적인 중립성이 아닌, 구조적 불평등에 적극적으로 대응하는 자세를 분명히 하고 있습니다. 이러한 접근의 일환으로, 차별적 발언과 차별에 대항하는 발언을 구분합니다. 이를 통해 “차별은 안 된다”는 명목 하에 차별 비판까지 동일시하는 “양비론”의 함정을 피할 수 있다고 생각합니다.

기술 커뮤니티에서 자주 볼 수 있는 문제로는 특정 기술 선택에 대한 비판이나 기술 수준에 따른 계층화가 있습니다. “이것도 모르냐?”는 태도는 학습을 방해할 뿐입니다. 저희는 초보자와 경험자 모두 동등하게 존중받는 환경 조성을 중요시합니다.

또한, 연합우주의 핵심 가치로 프라이버시가 있지만, Hackers' Pub에서는 특히 익명성의 권리를 강조합니다. 타인의 신원을 특정하려는 행위나 익명이라는 이유로 차별하는 것을 금지함으로써, 안심하고 참여할 수 있는 공간을 지향합니다.

이러한 행동 강령 자체도 완벽하지 않으며, 커뮤니티와 함께 발전해 나가는 것이라고 생각합니다. 모든 구성원이 개선안을 제안할 수 있는 체계를 마련함으로써, 더 나은 환경을 함께 만들어 나가고자 합니다.

자세한 내용은 Hackers' Pub 행동 강령을 참조해 주세요. 연합우주에서 더 건강한 기술 커뮤니티를 함께 키워나가지 않으실래요?

hackers.pub

Hackers' Pub Code of Conduct

@hongminhee@hackers.pub

소프트웨어 엔지니어를 위한 연합우주 서비스 Hackers' Pub을 알고 계신가요? 저희가 특별히 중요시하는 것은 다른 플랫폼과는 조금 다른 행동 강령입니다.

저희는 현실 세계의 불평등이 온라인 공간에도 그대로 반영된다는 사실을 인식하고 있습니다. 그래서 “모든 사람을 동등하게 대우”한다는 표면적인 중립성이 아닌, 구조적 불평등에 적극적으로 대응하는 자세를 분명히 하고 있습니다. 이러한 접근의 일환으로, 차별적 발언과 차별에 대항하는 발언을 구분합니다. 이를 통해 “차별은 안 된다”는 명목 하에 차별 비판까지 동일시하는 “양비론”의 함정을 피할 수 있다고 생각합니다.

기술 커뮤니티에서 자주 볼 수 있는 문제로는 특정 기술 선택에 대한 비판이나 기술 수준에 따른 계층화가 있습니다. “이것도 모르냐?”는 태도는 학습을 방해할 뿐입니다. 저희는 초보자와 경험자 모두 동등하게 존중받는 환경 조성을 중요시합니다.

또한, 연합우주의 핵심 가치로 프라이버시가 있지만, Hackers' Pub에서는 특히 익명성의 권리를 강조합니다. 타인의 신원을 특정하려는 행위나 익명이라는 이유로 차별하는 것을 금지함으로써, 안심하고 참여할 수 있는 공간을 지향합니다.

이러한 행동 강령 자체도 완벽하지 않으며, 커뮤니티와 함께 발전해 나가는 것이라고 생각합니다. 모든 구성원이 개선안을 제안할 수 있는 체계를 마련함으로써, 더 나은 환경을 함께 만들어 나가고자 합니다.

자세한 내용은 Hackers' Pub 행동 강령을 참조해 주세요. 연합우주에서 더 건강한 기술 커뮤니티를 함께 키워나가지 않으실래요?

hackers.pub

Hackers' Pub Code of Conduct

@hongminhee@hackers.pub

소프트웨어 엔지니어를 위한 연합우주 서비스 Hackers' Pub을 알고 계신가요? 저희가 특별히 중요시하는 것은 다른 플랫폼과는 조금 다른 행동 강령입니다.

저희는 현실 세계의 불평등이 온라인 공간에도 그대로 반영된다는 사실을 인식하고 있습니다. 그래서 “모든 사람을 동등하게 대우”한다는 표면적인 중립성이 아닌, 구조적 불평등에 적극적으로 대응하는 자세를 분명히 하고 있습니다. 이러한 접근의 일환으로, 차별적 발언과 차별에 대항하는 발언을 구분합니다. 이를 통해 “차별은 안 된다”는 명목 하에 차별 비판까지 동일시하는 “양비론”의 함정을 피할 수 있다고 생각합니다.

기술 커뮤니티에서 자주 볼 수 있는 문제로는 특정 기술 선택에 대한 비판이나 기술 수준에 따른 계층화가 있습니다. “이것도 모르냐?”는 태도는 학습을 방해할 뿐입니다. 저희는 초보자와 경험자 모두 동등하게 존중받는 환경 조성을 중요시합니다.

또한, 연합우주의 핵심 가치로 프라이버시가 있지만, Hackers' Pub에서는 특히 익명성의 권리를 강조합니다. 타인의 신원을 특정하려는 행위나 익명이라는 이유로 차별하는 것을 금지함으로써, 안심하고 참여할 수 있는 공간을 지향합니다.

이러한 행동 강령 자체도 완벽하지 않으며, 커뮤니티와 함께 발전해 나가는 것이라고 생각합니다. 모든 구성원이 개선안을 제안할 수 있는 체계를 마련함으로써, 더 나은 환경을 함께 만들어 나가고자 합니다.

자세한 내용은 Hackers' Pub 행동 강령을 참조해 주세요. 연합우주에서 더 건강한 기술 커뮤니티를 함께 키워나가지 않으실래요?

hackers.pub

Hackers' Pub Code of Conduct

@hongminhee@hackers.pub

소프트웨어 엔지니어를 위한 연합우주 서비스 Hackers' Pub을 알고 계신가요? 저희가 특별히 중요시하는 것은 다른 플랫폼과는 조금 다른 행동 강령입니다.

저희는 현실 세계의 불평등이 온라인 공간에도 그대로 반영된다는 사실을 인식하고 있습니다. 그래서 “모든 사람을 동등하게 대우”한다는 표면적인 중립성이 아닌, 구조적 불평등에 적극적으로 대응하는 자세를 분명히 하고 있습니다. 이러한 접근의 일환으로, 차별적 발언과 차별에 대항하는 발언을 구분합니다. 이를 통해 “차별은 안 된다”는 명목 하에 차별 비판까지 동일시하는 “양비론”의 함정을 피할 수 있다고 생각합니다.

기술 커뮤니티에서 자주 볼 수 있는 문제로는 특정 기술 선택에 대한 비판이나 기술 수준에 따른 계층화가 있습니다. “이것도 모르냐?”는 태도는 학습을 방해할 뿐입니다. 저희는 초보자와 경험자 모두 동등하게 존중받는 환경 조성을 중요시합니다.

또한, 연합우주의 핵심 가치로 프라이버시가 있지만, Hackers' Pub에서는 특히 익명성의 권리를 강조합니다. 타인의 신원을 특정하려는 행위나 익명이라는 이유로 차별하는 것을 금지함으로써, 안심하고 참여할 수 있는 공간을 지향합니다.

이러한 행동 강령 자체도 완벽하지 않으며, 커뮤니티와 함께 발전해 나가는 것이라고 생각합니다. 모든 구성원이 개선안을 제안할 수 있는 체계를 마련함으로써, 더 나은 환경을 함께 만들어 나가고자 합니다.

자세한 내용은 Hackers' Pub 행동 강령을 참조해 주세요. 연합우주에서 더 건강한 기술 커뮤니티를 함께 키워나가지 않으실래요?

hackers.pub

Hackers' Pub Code of Conduct

@hongminhee@hackers.pub

소프트웨어 엔지니어를 위한 연합우주 서비스 Hackers' Pub을 알고 계신가요? 저희가 특별히 중요시하는 것은 다른 플랫폼과는 조금 다른 행동 강령입니다.

저희는 현실 세계의 불평등이 온라인 공간에도 그대로 반영된다는 사실을 인식하고 있습니다. 그래서 “모든 사람을 동등하게 대우”한다는 표면적인 중립성이 아닌, 구조적 불평등에 적극적으로 대응하는 자세를 분명히 하고 있습니다. 이러한 접근의 일환으로, 차별적 발언과 차별에 대항하는 발언을 구분합니다. 이를 통해 “차별은 안 된다”는 명목 하에 차별 비판까지 동일시하는 “양비론”의 함정을 피할 수 있다고 생각합니다.

기술 커뮤니티에서 자주 볼 수 있는 문제로는 특정 기술 선택에 대한 비판이나 기술 수준에 따른 계층화가 있습니다. “이것도 모르냐?”는 태도는 학습을 방해할 뿐입니다. 저희는 초보자와 경험자 모두 동등하게 존중받는 환경 조성을 중요시합니다.

또한, 연합우주의 핵심 가치로 프라이버시가 있지만, Hackers' Pub에서는 특히 익명성의 권리를 강조합니다. 타인의 신원을 특정하려는 행위나 익명이라는 이유로 차별하는 것을 금지함으로써, 안심하고 참여할 수 있는 공간을 지향합니다.

이러한 행동 강령 자체도 완벽하지 않으며, 커뮤니티와 함께 발전해 나가는 것이라고 생각합니다. 모든 구성원이 개선안을 제안할 수 있는 체계를 마련함으로써, 더 나은 환경을 함께 만들어 나가고자 합니다.

자세한 내용은 Hackers' Pub 행동 강령을 참조해 주세요. 연합우주에서 더 건강한 기술 커뮤니티를 함께 키워나가지 않으실래요?

hackers.pub

Hackers' Pub Code of Conduct

@botkit@hollo.social · Reply to BotKit by Fedify :botkit:

()를 위한 봇을 만들고 싶으신가요? by Fedify를 사용하면 몇 줄의 코드만으로 독립형 봇을 구축할 수 있습니다! 일반적인 Mastodon 또는 Misskey 봇과 달리, BotKit은 플랫폼 제약 없이 완전한 ActivityPub 서버를 만들 수 있게 도와줍니다.

BotKit으로 할 수 있는 것:

  • 멘션, 팔로우 및 메시지에 응답하는 봇 만들기
  • 형식화된 텍스트, 멘션 및 미디어가 포함된 풍부한 콘텐츠 생성
  • 예약된 게시물 발행 및 대화 자동 관리
  • Deno Deploy, Docker 또는 자체 호스팅 서버에 쉽게 배포

문서는 https://botkit.fedify.dev/에서 확인하시고 지금 바로 연합우주 봇을 만들어 보세요!

botkit.fedify.dev

BotKit by Fedify

A framework for creating your ActivityPub bots

@botkit@hollo.social · Reply to BotKit by Fedify :botkit:

()를 위한 봇을 만들고 싶으신가요? by Fedify를 사용하면 몇 줄의 코드만으로 독립형 봇을 구축할 수 있습니다! 일반적인 Mastodon 또는 Misskey 봇과 달리, BotKit은 플랫폼 제약 없이 완전한 ActivityPub 서버를 만들 수 있게 도와줍니다.

BotKit으로 할 수 있는 것:

  • 멘션, 팔로우 및 메시지에 응답하는 봇 만들기
  • 형식화된 텍스트, 멘션 및 미디어가 포함된 풍부한 콘텐츠 생성
  • 예약된 게시물 발행 및 대화 자동 관리
  • Deno Deploy, Docker 또는 자체 호스팅 서버에 쉽게 배포

문서는 https://botkit.fedify.dev/에서 확인하시고 지금 바로 연합우주 봇을 만들어 보세요!

botkit.fedify.dev

BotKit by Fedify

A framework for creating your ActivityPub bots

@botkit@hollo.social · Reply to BotKit by Fedify :botkit:

()를 위한 봇을 만들고 싶으신가요? by Fedify를 사용하면 몇 줄의 코드만으로 독립형 봇을 구축할 수 있습니다! 일반적인 Mastodon 또는 Misskey 봇과 달리, BotKit은 플랫폼 제약 없이 완전한 ActivityPub 서버를 만들 수 있게 도와줍니다.

BotKit으로 할 수 있는 것:

  • 멘션, 팔로우 및 메시지에 응답하는 봇 만들기
  • 형식화된 텍스트, 멘션 및 미디어가 포함된 풍부한 콘텐츠 생성
  • 예약된 게시물 발행 및 대화 자동 관리
  • Deno Deploy, Docker 또는 자체 호스팅 서버에 쉽게 배포

문서는 https://botkit.fedify.dev/에서 확인하시고 지금 바로 연합우주 봇을 만들어 보세요!

botkit.fedify.dev

BotKit by Fedify

A framework for creating your ActivityPub bots

@hongminhee@hackers.pub

최근 X(구 Twitter)를 떠나는 사람들이 늘면서 Bluesky에 대한 관심이 뜨겁습니다. Bluesky는 깔끔한 인터페이스와 과거 Twitter와 유사한 사용자 경험을 제공하며, 신뢰할 수 있는 이탈(credible exit)이라는 매력적인 개념을 내세워 X의 유력한 대안으로 떠오르고 있습니다. 하지만 Bluesky와 그 기반 프로토콜인 AT Protocol을 연합우주(fediverse)의 대안으로 보기에는 근본적인 차이가 존재합니다. 이 글에서는 Christine Lemmer-Webber 씨(@cwebber)의 날카로운 분석(〈Bluesky는 실제로 얼마나 탈중앙화 되어 있나〉 및 〈답장: 답장: Bluesky와 탈중앙화〉)을 바탕으로, Bryan Newbold 씨(@bnewbold)의 반론(〈Bluesky와 탈중앙화에 대한 답변〉)을 충분히 고려하면서 Bluesky가 어째서 X의 대안은 될 수 있어도 연합우주의 대안은 될 수 없는지 이야기를 풀어볼까 합니다.

메시지 전달 對 공유 힙: 근본적인 설계 차이

Bluesky와 연합우주의 가장 큰 차이점 중 하나는 설계입니다. 연합우주는 이메일이나 XMPP와 유사한 메시지 전달(message passing) 방식을 채택하고 있습니다. 이는 특정 수신자에게 메시지를 직접 전달하는 방식으로, 효율성이 높습니다. 예를 들어, 수많은 서버 중 단 몇 곳의 사용자만 특정 메시지에 관심을 있다면 해당 서버에만 메시지를 전달하면 됩니다. 비유하자면, 철수가 영희에게 편지를 보내려면 직접 영희의 집으로 편지를 보내고, 영희가 회신하고 싶으면 직접 철수에게 회신하는 것과 같은 방식입니다.

반면, Bluesky는 공유 힙(shared heap) 방식을 사용합니다. 이는 메시지를 특정 수신자에게 직접 보내는 대신, 모든 메시지를 중앙의 “릴레이”라는 곳에 저장하고, 관심 있는 사용자가 릴레이에서 자신에게 필요한 정보를 필터링하는 방식입니다. 이는 마치 모든 편지가 하나의 거대한 우체국(릴레이)에 쌓이고, 각자가 이 우체국에 방문하여 자신에게 관련된 편지를 직접 찾아야 하는 것과 같습니다. 이런 방식에서는 메시지가 직접 전달되지 않기 때문에, 답글이 어떤 메시지에 대한 것인지 파악하려면 모든 가능한 메시지를 알고 있어야 합니다.

이 설계는 데이터와 색인을 분리하여 유연성을 제공한다는 주장도 있지만, 필연적으로 대규모 중앙 집권화된 릴레이에 의존하게 되어 탈중앙화의 이상과는 거리가 멀어진다는 한계가 있습니다.

결국 Bluesky가 공유 힙 방식을 채택하고 중앙 집권화된 릴레이에 의존하게 되는 데에는 운영 비용이라는 현실적인 이유가 크게 작용합니다. Christine Lemmer-Webber 씨의 분석에 따르면, Bluesky에서 전체 네트워크 기록을 저장하는 릴레이를 운영하는 데에는 상당한 스토리지를 요구하며, 이는 빠르게 증가하고 있습니다. 2024년 7월에는 약 1TB의 저장 공간이 필요했지만, 불과 4개월 후인 11월에는 약 5TB로 증가했습니다. 상업용 호스팅 서비스 기준으로 이는 연간 수만 달러(약 $55,000)에 달하는 비용이 발생할 수 있습니다.

반면, 연합우주에서는 개인이나 소규모 단체가 Raspberry Pi와 같은 저렴한 장비로도 GoToSocial과 같은 소프트웨어를 실행하여 독립적인 노드를 운영할 수 있습니다. 물론 대규모 연합우주 인스턴스는 더 많은 비용이 들겠지만, Bluesky의 전체 릴레이 운영 비용과는 비교하기 어려울 정도로 저렴합니다. 이처럼 운영 비용의 현격한 차이는 Bluesky가 분산된 구조를 채택하기 어렵게 만들고, 결국 중앙 집권화된 릴레이에 의존하게 만드는 주요 원인이라고 볼 수 있습니다.

전역 뷰에 대한 집착과 중앙 집권화의 심화

Bluesky는 댓글 누락과 같은 문제를 피하기 위해 네트워크 전체의 일관된 전역 뷰를 유지하는 데 집중하는 것으로 보입니다. 이러한 목표는 사용자 경험 측면에서 긍정적일 수 있지만, 필연적으로 중앙 집권화를 야기합니다. 대표적인 예가 차단 목록의 전체 공개입니다. 네트워크 전체의 일관성을 유지하기 위해 누가 누구를 차단했는지 모든 앱뷰가 알아야 하므로, 차단 정보가 공개되는 것입니다.

이는 개인 정보 보호 측면에서 심각한 우려를 낳을 수 있습니다. 단순히 누군가의 게시물을 보고 차단된 사람을 추측하는 것과, 네트워크에 “J. K. Rowling[1]을 차단한 모든 사람”을 직접 질의할 수 있는 것 사이에는 큰 차이가 있습니다. 실제로 ActivityPub 개발 과정에서는 이런 문제를 고려하여 서버 간에 차단 활동을 전달하지 않도록 명시적으로 설계했습니다. 이는 차단한 사람이 차단당한 사람의 보복을 받을 위험을 줄이기 위함입니다.

반면 연합우주에서는 각 서버가 독립적으로 차단 정책을 시행하며, 사용자에게 더 많은 자율성을 제공합니다.

AT Protocol과 개방형 표준으로서의 ActivityPub

연합우주의 핵심 프로토콜인 ActivityPub은 W3C의 채택 권고안으로, 개방형 표준입니다. 이는 누구나 자유롭게 구현하고 사용할 수 있으며, 다양한 소프트웨어 간의 상호 운용성을 보장합니다. 현재 페디버스 커뮤니티는 FEP를 중심으로 활발하게 프로토콜을 개선하고 발전시켜 나가고 있습니다. 반면, Bluesky의 AT Protocol은 아직 특정 사기업에 의해 주도되고 있으며, 개방형 표준으로서의 지위는 아직 확립되지 않았습니다. 이는 페디버스가 가진 확장성과 지속 가능성 측면에서 중요한 차이점이라고 할 수 있습니다.

DM의 중앙화

Bluesky는 콘텐츠 주소 지정이나 이동 가능한 아이덴티티와 같은 탈중앙화 요소를 도입했지만, DM은 완전히 중앙화되어 있습니다. 사용자가 어떤 PDS를 사용하든, 어떤 릴레이를 사용하든 상관없이 모든 DM은 Bluesky 회사를 통해 전송됩니다.

이는 Bluesky가 아직 기능적으로 완전한 Twitter 대체품이 되기 위해 속도를 우선시했다는 증거입니다. Bluesky는 이 DM 시스템이 장기적인 솔루션이 아니라고 밝혔지만, 대부분의 사용자들은 이 사실을 인지하지 못하고 있으며 DM도 AT Protocol의 다른 기능처럼 작동한다고 가정합니다.

이러한 중앙화된 DM 구현은 “신뢰할 수 있는 이탈”이라는 Bluesky의 핵심 가치와도 모순됩니다. 만약 Bluesky社가 적대적인 인수나 정책 변경을 겪게 된다면, 사용자들의 개인 대화는 완전히 회사의 통제 하에 남게 됩니다.

이동 가능한 아이덴티티와 DID: Bluesky 방식의 한계

Bluesky는 이동 가능한 아이덴티티(portable identity)를 핵심적인 장점 중 하나로 내세우며, 이를 위해 DIDs, 즉 분산 식별자를 활용합니다. 이는 사용자가 자신의 계정과 데이터를 다른 플랫폼으로 쉽게 이동할 수 있도록 하는 중요한 기능입니다. 하지만 Christine Lemmer-Webber는 AT Protocol이 채택한 did:webdid:plc 방식이 여전히 DNS와 Bluesky社가 관리하는 중앙 집권화된 PLC 레지스트리에 의존하고 있어 완전한 사용자 통제하의 독립적인 아이덴티티를 제공하는지 의문을 제기합니다.

더 놀라운 점은 Bluesky社가 초기에 모든 계정에 대해 동일한 rotationKeys를 사용했다는 사실입니다. 이는 클라우드 HSM 제품이 키별로 비용을 청구해서 각 사용자에게 고유한 키를 제공하는 것이 금전적으로 비용이 많이 들었기 때문이라고 합니다. 이러한 접근 방식은 DIDs 시스템을 구축하는 근본적인 목표와 모순되는 것으로 보입니다.

중요한 점은 DIDs 기술 자체가 탈중앙화된 아이덴티티를 위한 잠재력을 가지고 있음에도, Bluesky와 AT Protocol이 채택한 특정 방식이 중앙 집권화된 요소에 의존한다는 것입니다. 블록체인 기반의 DIDs와 같은 진정으로 탈중앙화된 방식도 존재하지만, AT Protocol은 비교적 구현이 쉬운 did:webdid:plc를 선택했습니다. 따라서 사용자가 Bluesky 생태계를 벗어나 자신의 아이덴티티를 완전히 독립적으로 관리하고자 할 때 제약이 발생할 수 있습니다.

또한 현재 시스템에서는 Bluesky社가 사용자의 키를 대신 관리하고 있어, 사용자가 현재는 Bluesky社를 신뢰하더라도 미래에 신뢰하지 않게 된 경우에도 여전히 회사에 의존해야 합니다. Bluesky社가 사용자를 대신하여 이동을 수행하도록 신뢰해야 하며, 심지어 Bluesky社가 사용자에게 향후 신원 정보를 제어할 권한을 위임하더라도 Bluesky社는 항상 해당 사용자의 키를 통제할 것입니다.

한편, 연합우주에서는 이미 노마딕 아이덴티티(nomadic identity)라는 개념을 통해 이동 가능한 아이덴티티에 대한 논의와 연구가 활발하게 진행되어 왔습니다. 이는 단순히 계정을 이전하는 것을 넘어, 사용자의 데이터와 관계, 심지어 평판까지도 자유롭게 이동할 수 있도록 하는 더 포괄적인 개념입니다. 《We Distribute》에 실린 기사 〈오, Zot! ActivityPub에 노마딕 아이덴티티가 도입된다〉에 소개된 Zot 프로토콜과 같은 기술은 이미 연합우주 안에서 이러한 노마딕 아이덴티티를 구현하기 위한 메커니즘을 제공하고 있습니다. 또한, FEP-ef61와 같은 제안을 통해 ActivityPub 자체를 개선하여 더 나은 이동 가능한 아이덴티티 기능을 추가하려는 노력도 진행 중입니다.

그래서, 결론은?

결론적으로, Bluesky는 사용자 친화적인 인터페이스와 신뢰할 수 있는 이탈 기능을 통해 X의 훌륭한 대안이 될 수 있습니다. Bluesky는 콘텐츠 주소 지정 방식을 통해 노드가 다운되더라도 콘텐츠가 살아남을 수 있게 하는 등 연합우주가 아직 충분히 활용하지 못하는 몇 가지 강점도 가지고 있습니다.

하지만 중앙 집권화된 설계, 전역 뷰에 대한 집착으로 인한 부작용, 개방형 표준으로서의 한계, DM의 중앙화, 그리고 이동 가능한 아이덴티티 구현의 제한점 등 여러 측면에서 연합우주의 대안으로 보기는 어렵습니다. 연합우주는 메시지 전달 방식의 분산된 아키텍처, 낮은 참여 장벽, 개방형 표준 기반의 활발한 커뮤니티 개발, 그리고 사용자에게 더 많은 자율성과 통제권을 제공하는 철학을 바탕으로 구축된, 근본적으로 다른 종류의 탈중앙화 소셜 네트워크입니다.

또한, Bluesky社가 벤처 캐피털 자금을 확보함에 따라 “조직은 미래의 적이다”라는 그들의 자체 인식에도 불구하고, 투자자 수익과 플랫폼 성장이라는 상업적 압력이 진정한 탈중앙화 추구보다 우선시될 위험이 있습니다. 특히 유료 계정과 광고가 도입되면서 이러한 우려는 더욱 커질 수 있습니다.

따라서 Bluesky는 X를 대체할 수 있을지 모르지만, 연합우주가 제공하는 탈중앙화된 가치와 경험을 대체하기는 어려울 것이라고 생각합니다. 두 시스템은 근본적으로 다른 목표와 설계 철학을 가지고 있으며, 이상적으로는 서로를 보완하는 방향으로 발전해 나갈 수 있을 것입니다.


  1. 판타지 소설 시리즈 《해리 포터》의 작가. ↩︎

@hongminhee@hollo.social
@hongminhee@hollo.social
@hongminhee@hollo.social

Fedify는 새로운 후원 파트너를 찾고 있습니다!

:fedify: Fedify란?

Fedify는 기반 연합형 서버 프레임워크로, 개발자들이 분산형 소셜 네트워크인 ()에 애플리케이션을 쉽게 통합할 수 있도록 돕습니다. 복잡한 ActivityPub 프로토콜 구현을 단순화하여 개발 시간을 크게 단축시킵니다. MIT 라이선스 하에 제공되는 오픈 소스 프로젝트입니다.

💼 Fedify를 활용하는 프로젝트들

다양한 프로젝트들이 이미 Fedify를 활용하고 있습니다:

  • Ghost: 수백만 사용자를 보유한 전문적인 오픈 소스(MIT 라이선스) 퍼블리싱 플랫폼으로, Fedify의 주요 후원사이자 파트너입니다.
  • Hollo: 개인 사용자를 위한 경량 마이크로블로그 (오픈 소스, AGPL-3.0)
  • Hackers' Pub: 소프트웨어 엔지니어를 위한 연합우주 블로그 플랫폼 (오픈 소스, AGPL-3.0)
  • Encyclia: ORCID 학술 기록을 ActivityPub을 통해 제공하는 브리지 서비스

🚀 Fedify가 제공하는 가치

  • 개발 시간 80% 단축: ActivityPub의 복잡한 구현 대신 검증된 프레임워크 활용
  • 즉각적인 연합우주 호환성: Mastodon, Misskey, Pleroma, Pixelfed, PeerTube 등 다양한 연합우주 서비스와 즉시 호환
  • 전문 기술 지원: ActivityPub 및 연합 프로토콜 전문가의 직접 지원
  • 맞춤형 개발: 귀사의 특정 요구사항에 맞는 맞춤형 기능 개발

🤝 가능한 협력 모델

  • 맞춤형 컨설팅 및 통합 지원: 귀사 플랫폼에 통합을 위한 전문적 지원
  • 맞춤형 기능 개발 의뢰: 귀사에 필요한 특정 기능의 개발 및 구현
  • 장기적인 기술 파트너십: 지속적인 개발 및 유지보수를 위한 장기 협력 관계

🌟 Fedify와 협력했을 때의 이점

  • 기술적 이점: 자체 구현 대비 시간과 리소스 절약
  • 브랜드 이미지: 오픈 소스 생태계 지원을 통한 기업 이미지 강화
  • 분산형 소셜 네트워크 진입: 연합우주 생태계에 쉽게 참여
  • 경쟁 우위: 소셜 기능을 통한 제품 경쟁력 강화

📩 관심이 있으신가요?

ActivityPub 구현을 고려 중이시거나, Fedify 프로젝트와 협력하고 싶으시다면 연락 주세요:

귀사의 요구사항과 목표에 맞는 맞춤형 협력 방안을 함께 모색하겠습니다.

github.com

GitHub - fedify-dev/fedify: ActivityPub server framework in TypeScript

ActivityPub server framework in TypeScript. Contribute to fedify-dev/fedify development by creating an account on GitHub.

Fedify는 새로운 후원 파트너를 찾고 있습니다!

:fedify: Fedify란?

Fedify는 기반 연합형 서버 프레임워크로, 개발자들이 분산형 소셜 네트워크인 ()에 애플리케이션을 쉽게 통합할 수 있도록 돕습니다. 복잡한 ActivityPub 프로토콜 구현을 단순화하여 개발 시간을 크게 단축시킵니다. MIT 라이선스 하에 제공되는 오픈 소스 프로젝트입니다.

💼 Fedify를 활용하는 프로젝트들

다양한 프로젝트들이 이미 Fedify를 활용하고 있습니다:

  • Ghost: 수백만 사용자를 보유한 전문적인 오픈 소스(MIT 라이선스) 퍼블리싱 플랫폼으로, Fedify의 주요 후원사이자 파트너입니다.
  • Hollo: 개인 사용자를 위한 경량 마이크로블로그 (오픈 소스, AGPL-3.0)
  • Hackers' Pub: 소프트웨어 엔지니어를 위한 연합우주 블로그 플랫폼 (오픈 소스, AGPL-3.0)
  • Encyclia: ORCID 학술 기록을 ActivityPub을 통해 제공하는 브리지 서비스

🚀 Fedify가 제공하는 가치

  • 개발 시간 80% 단축: ActivityPub의 복잡한 구현 대신 검증된 프레임워크 활용
  • 즉각적인 연합우주 호환성: Mastodon, Misskey, Pleroma, Pixelfed, PeerTube 등 다양한 연합우주 서비스와 즉시 호환
  • 전문 기술 지원: ActivityPub 및 연합 프로토콜 전문가의 직접 지원
  • 맞춤형 개발: 귀사의 특정 요구사항에 맞는 맞춤형 기능 개발

🤝 가능한 협력 모델

  • 맞춤형 컨설팅 및 통합 지원: 귀사 플랫폼에 통합을 위한 전문적 지원
  • 맞춤형 기능 개발 의뢰: 귀사에 필요한 특정 기능의 개발 및 구현
  • 장기적인 기술 파트너십: 지속적인 개발 및 유지보수를 위한 장기 협력 관계

🌟 Fedify와 협력했을 때의 이점

  • 기술적 이점: 자체 구현 대비 시간과 리소스 절약
  • 브랜드 이미지: 오픈 소스 생태계 지원을 통한 기업 이미지 강화
  • 분산형 소셜 네트워크 진입: 연합우주 생태계에 쉽게 참여
  • 경쟁 우위: 소셜 기능을 통한 제품 경쟁력 강화

📩 관심이 있으신가요?

ActivityPub 구현을 고려 중이시거나, Fedify 프로젝트와 협력하고 싶으시다면 연락 주세요:

귀사의 요구사항과 목표에 맞는 맞춤형 협력 방안을 함께 모색하겠습니다.

github.com

GitHub - fedify-dev/fedify: ActivityPub server framework in TypeScript

ActivityPub server framework in TypeScript. Contribute to fedify-dev/fedify development by creating an account on GitHub.

Fedify는 새로운 후원 파트너를 찾고 있습니다!

:fedify: Fedify란?

Fedify는 기반 연합형 서버 프레임워크로, 개발자들이 분산형 소셜 네트워크인 ()에 애플리케이션을 쉽게 통합할 수 있도록 돕습니다. 복잡한 ActivityPub 프로토콜 구현을 단순화하여 개발 시간을 크게 단축시킵니다. MIT 라이선스 하에 제공되는 오픈 소스 프로젝트입니다.

💼 Fedify를 활용하는 프로젝트들

다양한 프로젝트들이 이미 Fedify를 활용하고 있습니다:

  • Ghost: 수백만 사용자를 보유한 전문적인 오픈 소스(MIT 라이선스) 퍼블리싱 플랫폼으로, Fedify의 주요 후원사이자 파트너입니다.
  • Hollo: 개인 사용자를 위한 경량 마이크로블로그 (오픈 소스, AGPL-3.0)
  • Hackers' Pub: 소프트웨어 엔지니어를 위한 연합우주 블로그 플랫폼 (오픈 소스, AGPL-3.0)
  • Encyclia: ORCID 학술 기록을 ActivityPub을 통해 제공하는 브리지 서비스

🚀 Fedify가 제공하는 가치

  • 개발 시간 80% 단축: ActivityPub의 복잡한 구현 대신 검증된 프레임워크 활용
  • 즉각적인 연합우주 호환성: Mastodon, Misskey, Pleroma, Pixelfed, PeerTube 등 다양한 연합우주 서비스와 즉시 호환
  • 전문 기술 지원: ActivityPub 및 연합 프로토콜 전문가의 직접 지원
  • 맞춤형 개발: 귀사의 특정 요구사항에 맞는 맞춤형 기능 개발

🤝 가능한 협력 모델

  • 맞춤형 컨설팅 및 통합 지원: 귀사 플랫폼에 통합을 위한 전문적 지원
  • 맞춤형 기능 개발 의뢰: 귀사에 필요한 특정 기능의 개발 및 구현
  • 장기적인 기술 파트너십: 지속적인 개발 및 유지보수를 위한 장기 협력 관계

🌟 Fedify와 협력했을 때의 이점

  • 기술적 이점: 자체 구현 대비 시간과 리소스 절약
  • 브랜드 이미지: 오픈 소스 생태계 지원을 통한 기업 이미지 강화
  • 분산형 소셜 네트워크 진입: 연합우주 생태계에 쉽게 참여
  • 경쟁 우위: 소셜 기능을 통한 제품 경쟁력 강화

📩 관심이 있으신가요?

ActivityPub 구현을 고려 중이시거나, Fedify 프로젝트와 협력하고 싶으시다면 연락 주세요:

귀사의 요구사항과 목표에 맞는 맞춤형 협력 방안을 함께 모색하겠습니다.

github.com

GitHub - fedify-dev/fedify: ActivityPub server framework in TypeScript

ActivityPub server framework in TypeScript. Contribute to fedify-dev/fedify development by creating an account on GitHub.

Fedify는 새로운 후원 파트너를 찾고 있습니다!

:fedify: Fedify란?

Fedify는 기반 연합형 서버 프레임워크로, 개발자들이 분산형 소셜 네트워크인 ()에 애플리케이션을 쉽게 통합할 수 있도록 돕습니다. 복잡한 ActivityPub 프로토콜 구현을 단순화하여 개발 시간을 크게 단축시킵니다. MIT 라이선스 하에 제공되는 오픈 소스 프로젝트입니다.

💼 Fedify를 활용하는 프로젝트들

다양한 프로젝트들이 이미 Fedify를 활용하고 있습니다:

  • Ghost: 수백만 사용자를 보유한 전문적인 오픈 소스(MIT 라이선스) 퍼블리싱 플랫폼으로, Fedify의 주요 후원사이자 파트너입니다.
  • Hollo: 개인 사용자를 위한 경량 마이크로블로그 (오픈 소스, AGPL-3.0)
  • Hackers' Pub: 소프트웨어 엔지니어를 위한 연합우주 블로그 플랫폼 (오픈 소스, AGPL-3.0)
  • Encyclia: ORCID 학술 기록을 ActivityPub을 통해 제공하는 브리지 서비스

🚀 Fedify가 제공하는 가치

  • 개발 시간 80% 단축: ActivityPub의 복잡한 구현 대신 검증된 프레임워크 활용
  • 즉각적인 연합우주 호환성: Mastodon, Misskey, Pleroma, Pixelfed, PeerTube 등 다양한 연합우주 서비스와 즉시 호환
  • 전문 기술 지원: ActivityPub 및 연합 프로토콜 전문가의 직접 지원
  • 맞춤형 개발: 귀사의 특정 요구사항에 맞는 맞춤형 기능 개발

🤝 가능한 협력 모델

  • 맞춤형 컨설팅 및 통합 지원: 귀사 플랫폼에 통합을 위한 전문적 지원
  • 맞춤형 기능 개발 의뢰: 귀사에 필요한 특정 기능의 개발 및 구현
  • 장기적인 기술 파트너십: 지속적인 개발 및 유지보수를 위한 장기 협력 관계

🌟 Fedify와 협력했을 때의 이점

  • 기술적 이점: 자체 구현 대비 시간과 리소스 절약
  • 브랜드 이미지: 오픈 소스 생태계 지원을 통한 기업 이미지 강화
  • 분산형 소셜 네트워크 진입: 연합우주 생태계에 쉽게 참여
  • 경쟁 우위: 소셜 기능을 통한 제품 경쟁력 강화

📩 관심이 있으신가요?

ActivityPub 구현을 고려 중이시거나, Fedify 프로젝트와 협력하고 싶으시다면 연락 주세요:

귀사의 요구사항과 목표에 맞는 맞춤형 협력 방안을 함께 모색하겠습니다.

github.com

GitHub - fedify-dev/fedify: ActivityPub server framework in TypeScript

ActivityPub server framework in TypeScript. Contribute to fedify-dev/fedify development by creating an account on GitHub.

Fedify는 새로운 후원 파트너를 찾고 있습니다!

:fedify: Fedify란?

Fedify는 기반 연합형 서버 프레임워크로, 개발자들이 분산형 소셜 네트워크인 ()에 애플리케이션을 쉽게 통합할 수 있도록 돕습니다. 복잡한 ActivityPub 프로토콜 구현을 단순화하여 개발 시간을 크게 단축시킵니다. MIT 라이선스 하에 제공되는 오픈 소스 프로젝트입니다.

💼 Fedify를 활용하는 프로젝트들

다양한 프로젝트들이 이미 Fedify를 활용하고 있습니다:

  • Ghost: 수백만 사용자를 보유한 전문적인 오픈 소스(MIT 라이선스) 퍼블리싱 플랫폼으로, Fedify의 주요 후원사이자 파트너입니다.
  • Hollo: 개인 사용자를 위한 경량 마이크로블로그 (오픈 소스, AGPL-3.0)
  • Hackers' Pub: 소프트웨어 엔지니어를 위한 연합우주 블로그 플랫폼 (오픈 소스, AGPL-3.0)
  • Encyclia: ORCID 학술 기록을 ActivityPub을 통해 제공하는 브리지 서비스

🚀 Fedify가 제공하는 가치

  • 개발 시간 80% 단축: ActivityPub의 복잡한 구현 대신 검증된 프레임워크 활용
  • 즉각적인 연합우주 호환성: Mastodon, Misskey, Pleroma, Pixelfed, PeerTube 등 다양한 연합우주 서비스와 즉시 호환
  • 전문 기술 지원: ActivityPub 및 연합 프로토콜 전문가의 직접 지원
  • 맞춤형 개발: 귀사의 특정 요구사항에 맞는 맞춤형 기능 개발

🤝 가능한 협력 모델

  • 맞춤형 컨설팅 및 통합 지원: 귀사 플랫폼에 통합을 위한 전문적 지원
  • 맞춤형 기능 개발 의뢰: 귀사에 필요한 특정 기능의 개발 및 구현
  • 장기적인 기술 파트너십: 지속적인 개발 및 유지보수를 위한 장기 협력 관계

🌟 Fedify와 협력했을 때의 이점

  • 기술적 이점: 자체 구현 대비 시간과 리소스 절약
  • 브랜드 이미지: 오픈 소스 생태계 지원을 통한 기업 이미지 강화
  • 분산형 소셜 네트워크 진입: 연합우주 생태계에 쉽게 참여
  • 경쟁 우위: 소셜 기능을 통한 제품 경쟁력 강화

📩 관심이 있으신가요?

ActivityPub 구현을 고려 중이시거나, Fedify 프로젝트와 협력하고 싶으시다면 연락 주세요:

귀사의 요구사항과 목표에 맞는 맞춤형 협력 방안을 함께 모색하겠습니다.

github.com

GitHub - fedify-dev/fedify: ActivityPub server framework in TypeScript

ActivityPub server framework in TypeScript. Contribute to fedify-dev/fedify development by creating an account on GitHub.

Fedify는 새로운 후원 파트너를 찾고 있습니다!

:fedify: Fedify란?

Fedify는 기반 연합형 서버 프레임워크로, 개발자들이 분산형 소셜 네트워크인 ()에 애플리케이션을 쉽게 통합할 수 있도록 돕습니다. 복잡한 ActivityPub 프로토콜 구현을 단순화하여 개발 시간을 크게 단축시킵니다. MIT 라이선스 하에 제공되는 오픈 소스 프로젝트입니다.

💼 Fedify를 활용하는 프로젝트들

다양한 프로젝트들이 이미 Fedify를 활용하고 있습니다:

  • Ghost: 수백만 사용자를 보유한 전문적인 오픈 소스(MIT 라이선스) 퍼블리싱 플랫폼으로, Fedify의 주요 후원사이자 파트너입니다.
  • Hollo: 개인 사용자를 위한 경량 마이크로블로그 (오픈 소스, AGPL-3.0)
  • Hackers' Pub: 소프트웨어 엔지니어를 위한 연합우주 블로그 플랫폼 (오픈 소스, AGPL-3.0)
  • Encyclia: ORCID 학술 기록을 ActivityPub을 통해 제공하는 브리지 서비스

🚀 Fedify가 제공하는 가치

  • 개발 시간 80% 단축: ActivityPub의 복잡한 구현 대신 검증된 프레임워크 활용
  • 즉각적인 연합우주 호환성: Mastodon, Misskey, Pleroma, Pixelfed, PeerTube 등 다양한 연합우주 서비스와 즉시 호환
  • 전문 기술 지원: ActivityPub 및 연합 프로토콜 전문가의 직접 지원
  • 맞춤형 개발: 귀사의 특정 요구사항에 맞는 맞춤형 기능 개발

🤝 가능한 협력 모델

  • 맞춤형 컨설팅 및 통합 지원: 귀사 플랫폼에 통합을 위한 전문적 지원
  • 맞춤형 기능 개발 의뢰: 귀사에 필요한 특정 기능의 개발 및 구현
  • 장기적인 기술 파트너십: 지속적인 개발 및 유지보수를 위한 장기 협력 관계

🌟 Fedify와 협력했을 때의 이점

  • 기술적 이점: 자체 구현 대비 시간과 리소스 절약
  • 브랜드 이미지: 오픈 소스 생태계 지원을 통한 기업 이미지 강화
  • 분산형 소셜 네트워크 진입: 연합우주 생태계에 쉽게 참여
  • 경쟁 우위: 소셜 기능을 통한 제품 경쟁력 강화

📩 관심이 있으신가요?

ActivityPub 구현을 고려 중이시거나, Fedify 프로젝트와 협력하고 싶으시다면 연락 주세요:

귀사의 요구사항과 목표에 맞는 맞춤형 협력 방안을 함께 모색하겠습니다.

github.com

GitHub - fedify-dev/fedify: ActivityPub server framework in TypeScript

ActivityPub server framework in TypeScript. Contribute to fedify-dev/fedify development by creating an account on GitHub.

Fedify는 새로운 후원 파트너를 찾고 있습니다!

:fedify: Fedify란?

Fedify는 기반 연합형 서버 프레임워크로, 개발자들이 분산형 소셜 네트워크인 ()에 애플리케이션을 쉽게 통합할 수 있도록 돕습니다. 복잡한 ActivityPub 프로토콜 구현을 단순화하여 개발 시간을 크게 단축시킵니다. MIT 라이선스 하에 제공되는 오픈 소스 프로젝트입니다.

💼 Fedify를 활용하는 프로젝트들

다양한 프로젝트들이 이미 Fedify를 활용하고 있습니다:

  • Ghost: 수백만 사용자를 보유한 전문적인 오픈 소스(MIT 라이선스) 퍼블리싱 플랫폼으로, Fedify의 주요 후원사이자 파트너입니다.
  • Hollo: 개인 사용자를 위한 경량 마이크로블로그 (오픈 소스, AGPL-3.0)
  • Hackers' Pub: 소프트웨어 엔지니어를 위한 연합우주 블로그 플랫폼 (오픈 소스, AGPL-3.0)
  • Encyclia: ORCID 학술 기록을 ActivityPub을 통해 제공하는 브리지 서비스

🚀 Fedify가 제공하는 가치

  • 개발 시간 80% 단축: ActivityPub의 복잡한 구현 대신 검증된 프레임워크 활용
  • 즉각적인 연합우주 호환성: Mastodon, Misskey, Pleroma, Pixelfed, PeerTube 등 다양한 연합우주 서비스와 즉시 호환
  • 전문 기술 지원: ActivityPub 및 연합 프로토콜 전문가의 직접 지원
  • 맞춤형 개발: 귀사의 특정 요구사항에 맞는 맞춤형 기능 개발

🤝 가능한 협력 모델

  • 맞춤형 컨설팅 및 통합 지원: 귀사 플랫폼에 통합을 위한 전문적 지원
  • 맞춤형 기능 개발 의뢰: 귀사에 필요한 특정 기능의 개발 및 구현
  • 장기적인 기술 파트너십: 지속적인 개발 및 유지보수를 위한 장기 협력 관계

🌟 Fedify와 협력했을 때의 이점

  • 기술적 이점: 자체 구현 대비 시간과 리소스 절약
  • 브랜드 이미지: 오픈 소스 생태계 지원을 통한 기업 이미지 강화
  • 분산형 소셜 네트워크 진입: 연합우주 생태계에 쉽게 참여
  • 경쟁 우위: 소셜 기능을 통한 제품 경쟁력 강화

📩 관심이 있으신가요?

ActivityPub 구현을 고려 중이시거나, Fedify 프로젝트와 협력하고 싶으시다면 연락 주세요:

귀사의 요구사항과 목표에 맞는 맞춤형 협력 방안을 함께 모색하겠습니다.

github.com

GitHub - fedify-dev/fedify: ActivityPub server framework in TypeScript

ActivityPub server framework in TypeScript. Contribute to fedify-dev/fedify development by creating an account on GitHub.

Fedify는 새로운 후원 파트너를 찾고 있습니다!

:fedify: Fedify란?

Fedify는 기반 연합형 서버 프레임워크로, 개발자들이 분산형 소셜 네트워크인 ()에 애플리케이션을 쉽게 통합할 수 있도록 돕습니다. 복잡한 ActivityPub 프로토콜 구현을 단순화하여 개발 시간을 크게 단축시킵니다. MIT 라이선스 하에 제공되는 오픈 소스 프로젝트입니다.

💼 Fedify를 활용하는 프로젝트들

다양한 프로젝트들이 이미 Fedify를 활용하고 있습니다:

  • Ghost: 수백만 사용자를 보유한 전문적인 오픈 소스(MIT 라이선스) 퍼블리싱 플랫폼으로, Fedify의 주요 후원사이자 파트너입니다.
  • Hollo: 개인 사용자를 위한 경량 마이크로블로그 (오픈 소스, AGPL-3.0)
  • Hackers' Pub: 소프트웨어 엔지니어를 위한 연합우주 블로그 플랫폼 (오픈 소스, AGPL-3.0)
  • Encyclia: ORCID 학술 기록을 ActivityPub을 통해 제공하는 브리지 서비스

🚀 Fedify가 제공하는 가치

  • 개발 시간 80% 단축: ActivityPub의 복잡한 구현 대신 검증된 프레임워크 활용
  • 즉각적인 연합우주 호환성: Mastodon, Misskey, Pleroma, Pixelfed, PeerTube 등 다양한 연합우주 서비스와 즉시 호환
  • 전문 기술 지원: ActivityPub 및 연합 프로토콜 전문가의 직접 지원
  • 맞춤형 개발: 귀사의 특정 요구사항에 맞는 맞춤형 기능 개발

🤝 가능한 협력 모델

  • 맞춤형 컨설팅 및 통합 지원: 귀사 플랫폼에 통합을 위한 전문적 지원
  • 맞춤형 기능 개발 의뢰: 귀사에 필요한 특정 기능의 개발 및 구현
  • 장기적인 기술 파트너십: 지속적인 개발 및 유지보수를 위한 장기 협력 관계

🌟 Fedify와 협력했을 때의 이점

  • 기술적 이점: 자체 구현 대비 시간과 리소스 절약
  • 브랜드 이미지: 오픈 소스 생태계 지원을 통한 기업 이미지 강화
  • 분산형 소셜 네트워크 진입: 연합우주 생태계에 쉽게 참여
  • 경쟁 우위: 소셜 기능을 통한 제품 경쟁력 강화

📩 관심이 있으신가요?

ActivityPub 구현을 고려 중이시거나, Fedify 프로젝트와 협력하고 싶으시다면 연락 주세요:

귀사의 요구사항과 목표에 맞는 맞춤형 협력 방안을 함께 모색하겠습니다.

github.com

GitHub - fedify-dev/fedify: ActivityPub server framework in TypeScript

ActivityPub server framework in TypeScript. Contribute to fedify-dev/fedify development by creating an account on GitHub.

Fedify는 새로운 후원 파트너를 찾고 있습니다!

:fedify: Fedify란?

Fedify는 기반 연합형 서버 프레임워크로, 개발자들이 분산형 소셜 네트워크인 ()에 애플리케이션을 쉽게 통합할 수 있도록 돕습니다. 복잡한 ActivityPub 프로토콜 구현을 단순화하여 개발 시간을 크게 단축시킵니다. MIT 라이선스 하에 제공되는 오픈 소스 프로젝트입니다.

💼 Fedify를 활용하는 프로젝트들

다양한 프로젝트들이 이미 Fedify를 활용하고 있습니다:

  • Ghost: 수백만 사용자를 보유한 전문적인 오픈 소스(MIT 라이선스) 퍼블리싱 플랫폼으로, Fedify의 주요 후원사이자 파트너입니다.
  • Hollo: 개인 사용자를 위한 경량 마이크로블로그 (오픈 소스, AGPL-3.0)
  • Hackers' Pub: 소프트웨어 엔지니어를 위한 연합우주 블로그 플랫폼 (오픈 소스, AGPL-3.0)
  • Encyclia: ORCID 학술 기록을 ActivityPub을 통해 제공하는 브리지 서비스

🚀 Fedify가 제공하는 가치

  • 개발 시간 80% 단축: ActivityPub의 복잡한 구현 대신 검증된 프레임워크 활용
  • 즉각적인 연합우주 호환성: Mastodon, Misskey, Pleroma, Pixelfed, PeerTube 등 다양한 연합우주 서비스와 즉시 호환
  • 전문 기술 지원: ActivityPub 및 연합 프로토콜 전문가의 직접 지원
  • 맞춤형 개발: 귀사의 특정 요구사항에 맞는 맞춤형 기능 개발

🤝 가능한 협력 모델

  • 맞춤형 컨설팅 및 통합 지원: 귀사 플랫폼에 통합을 위한 전문적 지원
  • 맞춤형 기능 개발 의뢰: 귀사에 필요한 특정 기능의 개발 및 구현
  • 장기적인 기술 파트너십: 지속적인 개발 및 유지보수를 위한 장기 협력 관계

🌟 Fedify와 협력했을 때의 이점

  • 기술적 이점: 자체 구현 대비 시간과 리소스 절약
  • 브랜드 이미지: 오픈 소스 생태계 지원을 통한 기업 이미지 강화
  • 분산형 소셜 네트워크 진입: 연합우주 생태계에 쉽게 참여
  • 경쟁 우위: 소셜 기능을 통한 제품 경쟁력 강화

📩 관심이 있으신가요?

ActivityPub 구현을 고려 중이시거나, Fedify 프로젝트와 협력하고 싶으시다면 연락 주세요:

귀사의 요구사항과 목표에 맞는 맞춤형 협력 방안을 함께 모색하겠습니다.

github.com

GitHub - fedify-dev/fedify: ActivityPub server framework in TypeScript

ActivityPub server framework in TypeScript. Contribute to fedify-dev/fedify development by creating an account on GitHub.

Fedify는 새로운 후원 파트너를 찾고 있습니다!

:fedify: Fedify란?

Fedify는 기반 연합형 서버 프레임워크로, 개발자들이 분산형 소셜 네트워크인 ()에 애플리케이션을 쉽게 통합할 수 있도록 돕습니다. 복잡한 ActivityPub 프로토콜 구현을 단순화하여 개발 시간을 크게 단축시킵니다. MIT 라이선스 하에 제공되는 오픈 소스 프로젝트입니다.

💼 Fedify를 활용하는 프로젝트들

다양한 프로젝트들이 이미 Fedify를 활용하고 있습니다:

  • Ghost: 수백만 사용자를 보유한 전문적인 오픈 소스(MIT 라이선스) 퍼블리싱 플랫폼으로, Fedify의 주요 후원사이자 파트너입니다.
  • Hollo: 개인 사용자를 위한 경량 마이크로블로그 (오픈 소스, AGPL-3.0)
  • Hackers' Pub: 소프트웨어 엔지니어를 위한 연합우주 블로그 플랫폼 (오픈 소스, AGPL-3.0)
  • Encyclia: ORCID 학술 기록을 ActivityPub을 통해 제공하는 브리지 서비스

🚀 Fedify가 제공하는 가치

  • 개발 시간 80% 단축: ActivityPub의 복잡한 구현 대신 검증된 프레임워크 활용
  • 즉각적인 연합우주 호환성: Mastodon, Misskey, Pleroma, Pixelfed, PeerTube 등 다양한 연합우주 서비스와 즉시 호환
  • 전문 기술 지원: ActivityPub 및 연합 프로토콜 전문가의 직접 지원
  • 맞춤형 개발: 귀사의 특정 요구사항에 맞는 맞춤형 기능 개발

🤝 가능한 협력 모델

  • 맞춤형 컨설팅 및 통합 지원: 귀사 플랫폼에 통합을 위한 전문적 지원
  • 맞춤형 기능 개발 의뢰: 귀사에 필요한 특정 기능의 개발 및 구현
  • 장기적인 기술 파트너십: 지속적인 개발 및 유지보수를 위한 장기 협력 관계

🌟 Fedify와 협력했을 때의 이점

  • 기술적 이점: 자체 구현 대비 시간과 리소스 절약
  • 브랜드 이미지: 오픈 소스 생태계 지원을 통한 기업 이미지 강화
  • 분산형 소셜 네트워크 진입: 연합우주 생태계에 쉽게 참여
  • 경쟁 우위: 소셜 기능을 통한 제품 경쟁력 강화

📩 관심이 있으신가요?

ActivityPub 구현을 고려 중이시거나, Fedify 프로젝트와 협력하고 싶으시다면 연락 주세요:

귀사의 요구사항과 목표에 맞는 맞춤형 협력 방안을 함께 모색하겠습니다.

github.com

GitHub - fedify-dev/fedify: ActivityPub server framework in TypeScript

ActivityPub server framework in TypeScript. Contribute to fedify-dev/fedify development by creating an account on GitHub.

Fedify는 새로운 후원 파트너를 찾고 있습니다!

:fedify: Fedify란?

Fedify는 기반 연합형 서버 프레임워크로, 개발자들이 분산형 소셜 네트워크인 ()에 애플리케이션을 쉽게 통합할 수 있도록 돕습니다. 복잡한 ActivityPub 프로토콜 구현을 단순화하여 개발 시간을 크게 단축시킵니다. MIT 라이선스 하에 제공되는 오픈 소스 프로젝트입니다.

💼 Fedify를 활용하는 프로젝트들

다양한 프로젝트들이 이미 Fedify를 활용하고 있습니다:

  • Ghost: 수백만 사용자를 보유한 전문적인 오픈 소스(MIT 라이선스) 퍼블리싱 플랫폼으로, Fedify의 주요 후원사이자 파트너입니다.
  • Hollo: 개인 사용자를 위한 경량 마이크로블로그 (오픈 소스, AGPL-3.0)
  • Hackers' Pub: 소프트웨어 엔지니어를 위한 연합우주 블로그 플랫폼 (오픈 소스, AGPL-3.0)
  • Encyclia: ORCID 학술 기록을 ActivityPub을 통해 제공하는 브리지 서비스

🚀 Fedify가 제공하는 가치

  • 개발 시간 80% 단축: ActivityPub의 복잡한 구현 대신 검증된 프레임워크 활용
  • 즉각적인 연합우주 호환성: Mastodon, Misskey, Pleroma, Pixelfed, PeerTube 등 다양한 연합우주 서비스와 즉시 호환
  • 전문 기술 지원: ActivityPub 및 연합 프로토콜 전문가의 직접 지원
  • 맞춤형 개발: 귀사의 특정 요구사항에 맞는 맞춤형 기능 개발

🤝 가능한 협력 모델

  • 맞춤형 컨설팅 및 통합 지원: 귀사 플랫폼에 통합을 위한 전문적 지원
  • 맞춤형 기능 개발 의뢰: 귀사에 필요한 특정 기능의 개발 및 구현
  • 장기적인 기술 파트너십: 지속적인 개발 및 유지보수를 위한 장기 협력 관계

🌟 Fedify와 협력했을 때의 이점

  • 기술적 이점: 자체 구현 대비 시간과 리소스 절약
  • 브랜드 이미지: 오픈 소스 생태계 지원을 통한 기업 이미지 강화
  • 분산형 소셜 네트워크 진입: 연합우주 생태계에 쉽게 참여
  • 경쟁 우위: 소셜 기능을 통한 제품 경쟁력 강화

📩 관심이 있으신가요?

ActivityPub 구현을 고려 중이시거나, Fedify 프로젝트와 협력하고 싶으시다면 연락 주세요:

귀사의 요구사항과 목표에 맞는 맞춤형 협력 방안을 함께 모색하겠습니다.

github.com

GitHub - fedify-dev/fedify: ActivityPub server framework in TypeScript

ActivityPub server framework in TypeScript. Contribute to fedify-dev/fedify development by creating an account on GitHub.

Fedify는 새로운 후원 파트너를 찾고 있습니다!

:fedify: Fedify란?

Fedify는 기반 연합형 서버 프레임워크로, 개발자들이 분산형 소셜 네트워크인 ()에 애플리케이션을 쉽게 통합할 수 있도록 돕습니다. 복잡한 ActivityPub 프로토콜 구현을 단순화하여 개발 시간을 크게 단축시킵니다. MIT 라이선스 하에 제공되는 오픈 소스 프로젝트입니다.

💼 Fedify를 활용하는 프로젝트들

다양한 프로젝트들이 이미 Fedify를 활용하고 있습니다:

  • Ghost: 수백만 사용자를 보유한 전문적인 오픈 소스(MIT 라이선스) 퍼블리싱 플랫폼으로, Fedify의 주요 후원사이자 파트너입니다.
  • Hollo: 개인 사용자를 위한 경량 마이크로블로그 (오픈 소스, AGPL-3.0)
  • Hackers' Pub: 소프트웨어 엔지니어를 위한 연합우주 블로그 플랫폼 (오픈 소스, AGPL-3.0)
  • Encyclia: ORCID 학술 기록을 ActivityPub을 통해 제공하는 브리지 서비스

🚀 Fedify가 제공하는 가치

  • 개발 시간 80% 단축: ActivityPub의 복잡한 구현 대신 검증된 프레임워크 활용
  • 즉각적인 연합우주 호환성: Mastodon, Misskey, Pleroma, Pixelfed, PeerTube 등 다양한 연합우주 서비스와 즉시 호환
  • 전문 기술 지원: ActivityPub 및 연합 프로토콜 전문가의 직접 지원
  • 맞춤형 개발: 귀사의 특정 요구사항에 맞는 맞춤형 기능 개발

🤝 가능한 협력 모델

  • 맞춤형 컨설팅 및 통합 지원: 귀사 플랫폼에 통합을 위한 전문적 지원
  • 맞춤형 기능 개발 의뢰: 귀사에 필요한 특정 기능의 개발 및 구현
  • 장기적인 기술 파트너십: 지속적인 개발 및 유지보수를 위한 장기 협력 관계

🌟 Fedify와 협력했을 때의 이점

  • 기술적 이점: 자체 구현 대비 시간과 리소스 절약
  • 브랜드 이미지: 오픈 소스 생태계 지원을 통한 기업 이미지 강화
  • 분산형 소셜 네트워크 진입: 연합우주 생태계에 쉽게 참여
  • 경쟁 우위: 소셜 기능을 통한 제품 경쟁력 강화

📩 관심이 있으신가요?

ActivityPub 구현을 고려 중이시거나, Fedify 프로젝트와 협력하고 싶으시다면 연락 주세요:

귀사의 요구사항과 목표에 맞는 맞춤형 협력 방안을 함께 모색하겠습니다.

github.com

GitHub - fedify-dev/fedify: ActivityPub server framework in TypeScript

ActivityPub server framework in TypeScript. Contribute to fedify-dev/fedify development by creating an account on GitHub.

Fedify는 새로운 후원 파트너를 찾고 있습니다!

:fedify: Fedify란?

Fedify는 기반 연합형 서버 프레임워크로, 개발자들이 분산형 소셜 네트워크인 ()에 애플리케이션을 쉽게 통합할 수 있도록 돕습니다. 복잡한 ActivityPub 프로토콜 구현을 단순화하여 개발 시간을 크게 단축시킵니다. MIT 라이선스 하에 제공되는 오픈 소스 프로젝트입니다.

💼 Fedify를 활용하는 프로젝트들

다양한 프로젝트들이 이미 Fedify를 활용하고 있습니다:

  • Ghost: 수백만 사용자를 보유한 전문적인 오픈 소스(MIT 라이선스) 퍼블리싱 플랫폼으로, Fedify의 주요 후원사이자 파트너입니다.
  • Hollo: 개인 사용자를 위한 경량 마이크로블로그 (오픈 소스, AGPL-3.0)
  • Hackers' Pub: 소프트웨어 엔지니어를 위한 연합우주 블로그 플랫폼 (오픈 소스, AGPL-3.0)
  • Encyclia: ORCID 학술 기록을 ActivityPub을 통해 제공하는 브리지 서비스

🚀 Fedify가 제공하는 가치

  • 개발 시간 80% 단축: ActivityPub의 복잡한 구현 대신 검증된 프레임워크 활용
  • 즉각적인 연합우주 호환성: Mastodon, Misskey, Pleroma, Pixelfed, PeerTube 등 다양한 연합우주 서비스와 즉시 호환
  • 전문 기술 지원: ActivityPub 및 연합 프로토콜 전문가의 직접 지원
  • 맞춤형 개발: 귀사의 특정 요구사항에 맞는 맞춤형 기능 개발

🤝 가능한 협력 모델

  • 맞춤형 컨설팅 및 통합 지원: 귀사 플랫폼에 통합을 위한 전문적 지원
  • 맞춤형 기능 개발 의뢰: 귀사에 필요한 특정 기능의 개발 및 구현
  • 장기적인 기술 파트너십: 지속적인 개발 및 유지보수를 위한 장기 협력 관계

🌟 Fedify와 협력했을 때의 이점

  • 기술적 이점: 자체 구현 대비 시간과 리소스 절약
  • 브랜드 이미지: 오픈 소스 생태계 지원을 통한 기업 이미지 강화
  • 분산형 소셜 네트워크 진입: 연합우주 생태계에 쉽게 참여
  • 경쟁 우위: 소셜 기능을 통한 제품 경쟁력 강화

📩 관심이 있으신가요?

ActivityPub 구현을 고려 중이시거나, Fedify 프로젝트와 협력하고 싶으시다면 연락 주세요:

귀사의 요구사항과 목표에 맞는 맞춤형 협력 방안을 함께 모색하겠습니다.

github.com

GitHub - fedify-dev/fedify: ActivityPub server framework in TypeScript

ActivityPub server framework in TypeScript. Contribute to fedify-dev/fedify development by creating an account on GitHub.

자매 프로젝트들을 소개해 드리고자 합니다. 애플리케이션 개발을 더 쉽게 만들어주는 관련 도구들입니다:

Fedify :fedify:

Fedify(@fedify)는 ActivityPub와 다른 () 표준을 기반으로 연합 서버 애플리케이션을 구축하기 위한 라이브러리입니다. Activity Vocabulary를 위한 타입 안전한 객체, WebFinger 클라이언트·서버, HTTP Signatures 등를 제공하여 반복적인 코드를 줄이고 애플리케이션 로직에 집중할 수 있게 해줍니다.

Hollo :hollo:

Hollo(@hollo)는 Fedify로 구동되는 1인 사용자용 마이크로블로깅 서버입니다. 1인 사용자를 위해 설계되었지만, ActivityPub를 통해 완전히 연합되어 연합우주 전체의 사용자들과 상호작용할 수 있습니다. Hollo는 Mastodon 호환 API를 구현하여 자체 웹 인터페이스 없이도 대부분의 Mastodon 클라이언트와 호환됩니다.

Hollo는 또한 정식 출시 전에 최신 Fedify 기능을 테스트하는 실험장으로도 활용되고 있습니다.

BotKit :botkit:

BotKit(@botkit)은 저희의 가장 새로운 구성원으로, ActivityPub 봇을 만들기 위해 특별히 설계된 프레임워크입니다. 전통적인 Mastodon 봇과 달리, BotKit은 플랫폼별 제한(글자 수 제한 등)에 구애받지 않는 독립적인 ActivityPub 서버를 만듭니다.

BotKit의 API는 의도적으로 단순하게 설계되어 단일 TypeScript 파일로 완전한 봇을 만들 수 있습니다!


세 프로젝트 모두 @fedify-dev GitHub 조직에서 오픈 소스로 공개되어 있습니다. 각기 다른 목적을 가지고 있지만, ActivityPub 개발을 더 접근하기 쉽게 만들고 연합우주 생태계를 확장한다는 공통된 목표를 공유합니다.

이러한 프로젝트를 사용해보거나 개발에 기여하는 데 관심이 있으시다면, 다음을 확인해보세요:

botkit.fedify.dev

BotKit by Fedify

A framework for creating your ActivityPub bots

자매 프로젝트들을 소개해 드리고자 합니다. 애플리케이션 개발을 더 쉽게 만들어주는 관련 도구들입니다:

Fedify :fedify:

Fedify(@fedify)는 ActivityPub와 다른 () 표준을 기반으로 연합 서버 애플리케이션을 구축하기 위한 라이브러리입니다. Activity Vocabulary를 위한 타입 안전한 객체, WebFinger 클라이언트·서버, HTTP Signatures 등를 제공하여 반복적인 코드를 줄이고 애플리케이션 로직에 집중할 수 있게 해줍니다.

Hollo :hollo:

Hollo(@hollo)는 Fedify로 구동되는 1인 사용자용 마이크로블로깅 서버입니다. 1인 사용자를 위해 설계되었지만, ActivityPub를 통해 완전히 연합되어 연합우주 전체의 사용자들과 상호작용할 수 있습니다. Hollo는 Mastodon 호환 API를 구현하여 자체 웹 인터페이스 없이도 대부분의 Mastodon 클라이언트와 호환됩니다.

Hollo는 또한 정식 출시 전에 최신 Fedify 기능을 테스트하는 실험장으로도 활용되고 있습니다.

BotKit :botkit:

BotKit(@botkit)은 저희의 가장 새로운 구성원으로, ActivityPub 봇을 만들기 위해 특별히 설계된 프레임워크입니다. 전통적인 Mastodon 봇과 달리, BotKit은 플랫폼별 제한(글자 수 제한 등)에 구애받지 않는 독립적인 ActivityPub 서버를 만듭니다.

BotKit의 API는 의도적으로 단순하게 설계되어 단일 TypeScript 파일로 완전한 봇을 만들 수 있습니다!


세 프로젝트 모두 @fedify-dev GitHub 조직에서 오픈 소스로 공개되어 있습니다. 각기 다른 목적을 가지고 있지만, ActivityPub 개발을 더 접근하기 쉽게 만들고 연합우주 생태계를 확장한다는 공통된 목표를 공유합니다.

이러한 프로젝트를 사용해보거나 개발에 기여하는 데 관심이 있으시다면, 다음을 확인해보세요:

botkit.fedify.dev

BotKit by Fedify

A framework for creating your ActivityPub bots

자매 프로젝트들을 소개해 드리고자 합니다. 애플리케이션 개발을 더 쉽게 만들어주는 관련 도구들입니다:

Fedify :fedify:

Fedify(@fedify)는 ActivityPub와 다른 () 표준을 기반으로 연합 서버 애플리케이션을 구축하기 위한 라이브러리입니다. Activity Vocabulary를 위한 타입 안전한 객체, WebFinger 클라이언트·서버, HTTP Signatures 등를 제공하여 반복적인 코드를 줄이고 애플리케이션 로직에 집중할 수 있게 해줍니다.

Hollo :hollo:

Hollo(@hollo)는 Fedify로 구동되는 1인 사용자용 마이크로블로깅 서버입니다. 1인 사용자를 위해 설계되었지만, ActivityPub를 통해 완전히 연합되어 연합우주 전체의 사용자들과 상호작용할 수 있습니다. Hollo는 Mastodon 호환 API를 구현하여 자체 웹 인터페이스 없이도 대부분의 Mastodon 클라이언트와 호환됩니다.

Hollo는 또한 정식 출시 전에 최신 Fedify 기능을 테스트하는 실험장으로도 활용되고 있습니다.

BotKit :botkit:

BotKit(@botkit)은 저희의 가장 새로운 구성원으로, ActivityPub 봇을 만들기 위해 특별히 설계된 프레임워크입니다. 전통적인 Mastodon 봇과 달리, BotKit은 플랫폼별 제한(글자 수 제한 등)에 구애받지 않는 독립적인 ActivityPub 서버를 만듭니다.

BotKit의 API는 의도적으로 단순하게 설계되어 단일 TypeScript 파일로 완전한 봇을 만들 수 있습니다!


세 프로젝트 모두 @fedify-dev GitHub 조직에서 오픈 소스로 공개되어 있습니다. 각기 다른 목적을 가지고 있지만, ActivityPub 개발을 더 접근하기 쉽게 만들고 연합우주 생태계를 확장한다는 공통된 목표를 공유합니다.

이러한 프로젝트를 사용해보거나 개발에 기여하는 데 관심이 있으시다면, 다음을 확인해보세요:

botkit.fedify.dev

BotKit by Fedify

A framework for creating your ActivityPub bots

@hongminhee@hollo.social
@hongminhee@hollo.social
@hongminhee@hollo.social
@hongminhee@hollo.social
@hongminhee@hollo.social

제가 開發(개발)하고 있는 프로젝트 Hackers' Pub의 베타 테스터를 모십니다!

이 프로젝트는 (fediverse)() velog 같은 것으로, 소프트웨어 開發者(개발자)() 基盤(기반)의 SNS () 블로그 플랫폼입니다. AGPL-3.0 라이선스로 소스 코드가 公開(공개)되어 있을 뿐 아니라, GitHub에서 프로젝트를 公開的(공개적)으로 進行(진행)하고 있습니다.

職業(직업)으로든 趣味(취미)로든 소프트웨어를 開發(개발)하시는 분들, 聯合宇宙(연합우주)를 좋아하시는 분들, 새로운 플랫폼을 써 보고 싶으신 분들은 부디 參與(참여)해 주시기 바랍니다! 關心(관심) 있으신 분들은 ()글이나 DM으로 이메일 住所(주소)를 보내주시면 됩니다.

github.com

GitHub - dahlia/hackerspub: ActivityPub-enabled social network for hackers

ActivityPub-enabled social network for hackers. Contribute to dahlia/hackerspub development by creating an account on GitHub.

@hongminhee@hollo.social

제가 開發(개발)하고 있는 프로젝트 Hackers' Pub의 베타 테스터를 모십니다!

이 프로젝트는 (fediverse)() velog 같은 것으로, 소프트웨어 開發者(개발자)() 基盤(기반)의 SNS () 블로그 플랫폼입니다. AGPL-3.0 라이선스로 소스 코드가 公開(공개)되어 있을 뿐 아니라, GitHub에서 프로젝트를 公開的(공개적)으로 進行(진행)하고 있습니다.

職業(직업)으로든 趣味(취미)로든 소프트웨어를 開發(개발)하시는 분들, 聯合宇宙(연합우주)를 좋아하시는 분들, 새로운 플랫폼을 써 보고 싶으신 분들은 부디 參與(참여)해 주시기 바랍니다! 關心(관심) 있으신 분들은 ()글이나 DM으로 이메일 住所(주소)를 보내주시면 됩니다.

github.com

GitHub - dahlia/hackerspub: ActivityPub-enabled social network for hackers

ActivityPub-enabled social network for hackers. Contribute to dahlia/hackerspub development by creating an account on GitHub.

@hongminhee@hollo.social

제가 開發(개발)하고 있는 프로젝트 Hackers' Pub의 베타 테스터를 모십니다!

이 프로젝트는 (fediverse)() velog 같은 것으로, 소프트웨어 開發者(개발자)() 基盤(기반)의 SNS () 블로그 플랫폼입니다. AGPL-3.0 라이선스로 소스 코드가 公開(공개)되어 있을 뿐 아니라, GitHub에서 프로젝트를 公開的(공개적)으로 進行(진행)하고 있습니다.

職業(직업)으로든 趣味(취미)로든 소프트웨어를 開發(개발)하시는 분들, 聯合宇宙(연합우주)를 좋아하시는 분들, 새로운 플랫폼을 써 보고 싶으신 분들은 부디 參與(참여)해 주시기 바랍니다! 關心(관심) 있으신 분들은 ()글이나 DM으로 이메일 住所(주소)를 보내주시면 됩니다.

github.com

GitHub - dahlia/hackerspub: ActivityPub-enabled social network for hackers

ActivityPub-enabled social network for hackers. Contribute to dahlia/hackerspub development by creating an account on GitHub.

@hongminhee@hollo.social

제가 開發(개발)하고 있는 프로젝트 Hackers' Pub의 베타 테스터를 모십니다!

이 프로젝트는 (fediverse)() velog 같은 것으로, 소프트웨어 開發者(개발자)() 基盤(기반)의 SNS () 블로그 플랫폼입니다. AGPL-3.0 라이선스로 소스 코드가 公開(공개)되어 있을 뿐 아니라, GitHub에서 프로젝트를 公開的(공개적)으로 進行(진행)하고 있습니다.

職業(직업)으로든 趣味(취미)로든 소프트웨어를 開發(개발)하시는 분들, 聯合宇宙(연합우주)를 좋아하시는 분들, 새로운 플랫폼을 써 보고 싶으신 분들은 부디 參與(참여)해 주시기 바랍니다! 關心(관심) 있으신 분들은 ()글이나 DM으로 이메일 住所(주소)를 보내주시면 됩니다.

github.com

GitHub - dahlia/hackerspub: ActivityPub-enabled social network for hackers

ActivityPub-enabled social network for hackers. Contribute to dahlia/hackerspub development by creating an account on GitHub.

大部分(대부분) 具顯(구현)들이 NoteArticle內容(내용) (content) 안에서 누군가 다른 액터를 멘션할 境遇(경우) tag 屬性(속성)으로 該當(해당)하는 Mention 客體(객체)들을 包含(포함)시킵니다. 그러면 Person, Group () 액터 客體(객체)들도 略歷(약력) (summary) 안에서 누군가 다른 액터를 멘션할 境遇(경우) tag 屬性(속성)으로 該當(해당)하는 Mention 客體(객체)들을 包含(포함)해야 할까요? 或是(혹시) 이미 그렇게 動作(동작)하는 具顯(구현)이 있을까요? (Mastodon은 確認(확인)해 본 結果(결과) 包含(포함)시키지 않는 것 같습니다만.) 어떻게 보시나요?

大部分(대부분) 具顯(구현)들이 NoteArticle內容(내용) (content) 안에서 누군가 다른 액터를 멘션할 境遇(경우) tag 屬性(속성)으로 該當(해당)하는 Mention 客體(객체)들을 包含(포함)시킵니다. 그러면 Person, Group () 액터 客體(객체)들도 略歷(약력) (summary) 안에서 누군가 다른 액터를 멘션할 境遇(경우) tag 屬性(속성)으로 該當(해당)하는 Mention 客體(객체)들을 包含(포함)해야 할까요? 或是(혹시) 이미 그렇게 動作(동작)하는 具顯(구현)이 있을까요? (Mastodon은 確認(확인)해 본 結果(결과) 包含(포함)시키지 않는 것 같습니다만.) 어떻게 보시나요?

大部分(대부분) 具顯(구현)들이 NoteArticle內容(내용) (content) 안에서 누군가 다른 액터를 멘션할 境遇(경우) tag 屬性(속성)으로 該當(해당)하는 Mention 客體(객체)들을 包含(포함)시킵니다. 그러면 Person, Group () 액터 客體(객체)들도 略歷(약력) (summary) 안에서 누군가 다른 액터를 멘션할 境遇(경우) tag 屬性(속성)으로 該當(해당)하는 Mention 客體(객체)들을 包含(포함)해야 할까요? 或是(혹시) 이미 그렇게 動作(동작)하는 具顯(구현)이 있을까요? (Mastodon은 確認(확인)해 본 結果(결과) 包含(포함)시키지 않는 것 같습니다만.) 어떻게 보시나요?

@hongminhee@hollo.social

제가 開發(개발)하고 있는 프로젝트 Hackers' Pub의 베타 테스터를 모십니다!

이 프로젝트는 (fediverse)() velog 같은 것으로, 소프트웨어 開發者(개발자)() 基盤(기반)의 SNS () 블로그 플랫폼입니다. AGPL-3.0 라이선스로 소스 코드가 公開(공개)되어 있을 뿐 아니라, GitHub에서 프로젝트를 公開的(공개적)으로 進行(진행)하고 있습니다.

職業(직업)으로든 趣味(취미)로든 소프트웨어를 開發(개발)하시는 분들, 聯合宇宙(연합우주)를 좋아하시는 분들, 새로운 플랫폼을 써 보고 싶으신 분들은 부디 參與(참여)해 주시기 바랍니다! 關心(관심) 있으신 분들은 ()글이나 DM으로 이메일 住所(주소)를 보내주시면 됩니다.

github.com

GitHub - dahlia/hackerspub: ActivityPub-enabled social network for hackers

ActivityPub-enabled social network for hackers. Contribute to dahlia/hackerspub development by creating an account on GitHub.

@hongminhee@hollo.social

제가 開發(개발)하고 있는 프로젝트 Hackers' Pub의 베타 테스터를 모십니다!

이 프로젝트는 (fediverse)() velog 같은 것으로, 소프트웨어 開發者(개발자)() 基盤(기반)의 SNS () 블로그 플랫폼입니다. AGPL-3.0 라이선스로 소스 코드가 公開(공개)되어 있을 뿐 아니라, GitHub에서 프로젝트를 公開的(공개적)으로 進行(진행)하고 있습니다.

職業(직업)으로든 趣味(취미)로든 소프트웨어를 開發(개발)하시는 분들, 聯合宇宙(연합우주)를 좋아하시는 분들, 새로운 플랫폼을 써 보고 싶으신 분들은 부디 參與(참여)해 주시기 바랍니다! 關心(관심) 있으신 분들은 ()글이나 DM으로 이메일 住所(주소)를 보내주시면 됩니다.

github.com

GitHub - dahlia/hackerspub: ActivityPub-enabled social network for hackers

ActivityPub-enabled social network for hackers. Contribute to dahlia/hackerspub development by creating an account on GitHub.

@hongminhee@hollo.social

제가 開發(개발)하고 있는 프로젝트 Hackers' Pub의 베타 테스터를 모십니다!

이 프로젝트는 (fediverse)() velog 같은 것으로, 소프트웨어 開發者(개발자)() 基盤(기반)의 SNS () 블로그 플랫폼입니다. AGPL-3.0 라이선스로 소스 코드가 公開(공개)되어 있을 뿐 아니라, GitHub에서 프로젝트를 公開的(공개적)으로 進行(진행)하고 있습니다.

職業(직업)으로든 趣味(취미)로든 소프트웨어를 開發(개발)하시는 분들, 聯合宇宙(연합우주)를 좋아하시는 분들, 새로운 플랫폼을 써 보고 싶으신 분들은 부디 參與(참여)해 주시기 바랍니다! 關心(관심) 있으신 분들은 ()글이나 DM으로 이메일 住所(주소)를 보내주시면 됩니다.

github.com

GitHub - dahlia/hackerspub: ActivityPub-enabled social network for hackers

ActivityPub-enabled social network for hackers. Contribute to dahlia/hackerspub development by creating an account on GitHub.

@hongminhee@hollo.social

제가 開發(개발)하고 있는 프로젝트 Hackers' Pub의 베타 테스터를 모십니다!

이 프로젝트는 (fediverse)() velog 같은 것으로, 소프트웨어 開發者(개발자)() 基盤(기반)의 SNS () 블로그 플랫폼입니다. AGPL-3.0 라이선스로 소스 코드가 公開(공개)되어 있을 뿐 아니라, GitHub에서 프로젝트를 公開的(공개적)으로 進行(진행)하고 있습니다.

職業(직업)으로든 趣味(취미)로든 소프트웨어를 開發(개발)하시는 분들, 聯合宇宙(연합우주)를 좋아하시는 분들, 새로운 플랫폼을 써 보고 싶으신 분들은 부디 參與(참여)해 주시기 바랍니다! 關心(관심) 있으신 분들은 ()글이나 DM으로 이메일 住所(주소)를 보내주시면 됩니다.

github.com

GitHub - dahlia/hackerspub: ActivityPub-enabled social network for hackers

ActivityPub-enabled social network for hackers. Contribute to dahlia/hackerspub development by creating an account on GitHub.

@hongminhee@hollo.social

제가 開發(개발)하고 있는 프로젝트 Hackers' Pub의 베타 테스터를 모십니다!

이 프로젝트는 (fediverse)() velog 같은 것으로, 소프트웨어 開發者(개발자)() 基盤(기반)의 SNS () 블로그 플랫폼입니다. AGPL-3.0 라이선스로 소스 코드가 公開(공개)되어 있을 뿐 아니라, GitHub에서 프로젝트를 公開的(공개적)으로 進行(진행)하고 있습니다.

職業(직업)으로든 趣味(취미)로든 소프트웨어를 開發(개발)하시는 분들, 聯合宇宙(연합우주)를 좋아하시는 분들, 새로운 플랫폼을 써 보고 싶으신 분들은 부디 參與(참여)해 주시기 바랍니다! 關心(관심) 있으신 분들은 ()글이나 DM으로 이메일 住所(주소)를 보내주시면 됩니다.

github.com

GitHub - dahlia/hackerspub: ActivityPub-enabled social network for hackers

ActivityPub-enabled social network for hackers. Contribute to dahlia/hackerspub development by creating an account on GitHub.

@hongminhee@hollo.social

제가 開發(개발)하고 있는 프로젝트 Hackers' Pub의 베타 테스터를 모십니다!

이 프로젝트는 (fediverse)() velog 같은 것으로, 소프트웨어 開發者(개발자)() 基盤(기반)의 SNS () 블로그 플랫폼입니다. AGPL-3.0 라이선스로 소스 코드가 公開(공개)되어 있을 뿐 아니라, GitHub에서 프로젝트를 公開的(공개적)으로 進行(진행)하고 있습니다.

職業(직업)으로든 趣味(취미)로든 소프트웨어를 開發(개발)하시는 분들, 聯合宇宙(연합우주)를 좋아하시는 분들, 새로운 플랫폼을 써 보고 싶으신 분들은 부디 參與(참여)해 주시기 바랍니다! 關心(관심) 있으신 분들은 ()글이나 DM으로 이메일 住所(주소)를 보내주시면 됩니다.

github.com

GitHub - dahlia/hackerspub: ActivityPub-enabled social network for hackers

ActivityPub-enabled social network for hackers. Contribute to dahlia/hackerspub development by creating an account on GitHub.

@hongminhee@hollo.social

제가 開發(개발)하고 있는 프로젝트 Hackers' Pub의 베타 테스터를 모십니다!

이 프로젝트는 (fediverse)() velog 같은 것으로, 소프트웨어 開發者(개발자)() 基盤(기반)의 SNS () 블로그 플랫폼입니다. AGPL-3.0 라이선스로 소스 코드가 公開(공개)되어 있을 뿐 아니라, GitHub에서 프로젝트를 公開的(공개적)으로 進行(진행)하고 있습니다.

職業(직업)으로든 趣味(취미)로든 소프트웨어를 開發(개발)하시는 분들, 聯合宇宙(연합우주)를 좋아하시는 분들, 새로운 플랫폼을 써 보고 싶으신 분들은 부디 參與(참여)해 주시기 바랍니다! 關心(관심) 있으신 분들은 ()글이나 DM으로 이메일 住所(주소)를 보내주시면 됩니다.

github.com

GitHub - dahlia/hackerspub: ActivityPub-enabled social network for hackers

ActivityPub-enabled social network for hackers. Contribute to dahlia/hackerspub development by creating an account on GitHub.

@hongminhee@hollo.social

제가 開發(개발)하고 있는 프로젝트 Hackers' Pub의 베타 테스터를 모십니다!

이 프로젝트는 (fediverse)() velog 같은 것으로, 소프트웨어 開發者(개발자)() 基盤(기반)의 SNS () 블로그 플랫폼입니다. AGPL-3.0 라이선스로 소스 코드가 公開(공개)되어 있을 뿐 아니라, GitHub에서 프로젝트를 公開的(공개적)으로 進行(진행)하고 있습니다.

職業(직업)으로든 趣味(취미)로든 소프트웨어를 開發(개발)하시는 분들, 聯合宇宙(연합우주)를 좋아하시는 분들, 새로운 플랫폼을 써 보고 싶으신 분들은 부디 參與(참여)해 주시기 바랍니다! 關心(관심) 있으신 분들은 ()글이나 DM으로 이메일 住所(주소)를 보내주시면 됩니다.

github.com

GitHub - dahlia/hackerspub: ActivityPub-enabled social network for hackers

ActivityPub-enabled social network for hackers. Contribute to dahlia/hackerspub development by creating an account on GitHub.

@hongminhee@hollo.social

제가 開發(개발)하고 있는 프로젝트 Hackers' Pub의 베타 테스터를 모십니다!

이 프로젝트는 (fediverse)() velog 같은 것으로, 소프트웨어 開發者(개발자)() 基盤(기반)의 SNS () 블로그 플랫폼입니다. AGPL-3.0 라이선스로 소스 코드가 公開(공개)되어 있을 뿐 아니라, GitHub에서 프로젝트를 公開的(공개적)으로 進行(진행)하고 있습니다.

職業(직업)으로든 趣味(취미)로든 소프트웨어를 開發(개발)하시는 분들, 聯合宇宙(연합우주)를 좋아하시는 분들, 새로운 플랫폼을 써 보고 싶으신 분들은 부디 參與(참여)해 주시기 바랍니다! 關心(관심) 있으신 분들은 ()글이나 DM으로 이메일 住所(주소)를 보내주시면 됩니다.

github.com

GitHub - dahlia/hackerspub: ActivityPub-enabled social network for hackers

ActivityPub-enabled social network for hackers. Contribute to dahlia/hackerspub development by creating an account on GitHub.

@hongminhee@hollo.social

제가 開發(개발)하고 있는 프로젝트 Hackers' Pub의 베타 테스터를 모십니다!

이 프로젝트는 (fediverse)() velog 같은 것으로, 소프트웨어 開發者(개발자)() 基盤(기반)의 SNS () 블로그 플랫폼입니다. AGPL-3.0 라이선스로 소스 코드가 公開(공개)되어 있을 뿐 아니라, GitHub에서 프로젝트를 公開的(공개적)으로 進行(진행)하고 있습니다.

職業(직업)으로든 趣味(취미)로든 소프트웨어를 開發(개발)하시는 분들, 聯合宇宙(연합우주)를 좋아하시는 분들, 새로운 플랫폼을 써 보고 싶으신 분들은 부디 參與(참여)해 주시기 바랍니다! 關心(관심) 있으신 분들은 ()글이나 DM으로 이메일 住所(주소)를 보내주시면 됩니다.

github.com

GitHub - dahlia/hackerspub: ActivityPub-enabled social network for hackers

ActivityPub-enabled social network for hackers. Contribute to dahlia/hackerspub development by creating an account on GitHub.

@hongminhee@hollo.social

제가 開發(개발)하고 있는 프로젝트 Hackers' Pub의 베타 테스터를 모십니다!

이 프로젝트는 (fediverse)() velog 같은 것으로, 소프트웨어 開發者(개발자)() 基盤(기반)의 SNS () 블로그 플랫폼입니다. AGPL-3.0 라이선스로 소스 코드가 公開(공개)되어 있을 뿐 아니라, GitHub에서 프로젝트를 公開的(공개적)으로 進行(진행)하고 있습니다.

職業(직업)으로든 趣味(취미)로든 소프트웨어를 開發(개발)하시는 분들, 聯合宇宙(연합우주)를 좋아하시는 분들, 새로운 플랫폼을 써 보고 싶으신 분들은 부디 參與(참여)해 주시기 바랍니다! 關心(관심) 있으신 분들은 ()글이나 DM으로 이메일 住所(주소)를 보내주시면 됩니다.

github.com

GitHub - dahlia/hackerspub: ActivityPub-enabled social network for hackers

ActivityPub-enabled social network for hackers. Contribute to dahlia/hackerspub development by creating an account on GitHub.

@hongminhee@hollo.social

제가 開發(개발)하고 있는 프로젝트 Hackers' Pub의 베타 테스터를 모십니다!

이 프로젝트는 (fediverse)() velog 같은 것으로, 소프트웨어 開發者(개발자)() 基盤(기반)의 SNS () 블로그 플랫폼입니다. AGPL-3.0 라이선스로 소스 코드가 公開(공개)되어 있을 뿐 아니라, GitHub에서 프로젝트를 公開的(공개적)으로 進行(진행)하고 있습니다.

職業(직업)으로든 趣味(취미)로든 소프트웨어를 開發(개발)하시는 분들, 聯合宇宙(연합우주)를 좋아하시는 분들, 새로운 플랫폼을 써 보고 싶으신 분들은 부디 參與(참여)해 주시기 바랍니다! 關心(관심) 있으신 분들은 ()글이나 DM으로 이메일 住所(주소)를 보내주시면 됩니다.

github.com

GitHub - dahlia/hackerspub: ActivityPub-enabled social network for hackers

ActivityPub-enabled social network for hackers. Contribute to dahlia/hackerspub development by creating an account on GitHub.

Fedify는 새로운 후원 파트너를 찾고 있습니다!

:fedify: Fedify란?

Fedify는 기반 연합형 서버 프레임워크로, 개발자들이 분산형 소셜 네트워크인 ()에 애플리케이션을 쉽게 통합할 수 있도록 돕습니다. 복잡한 ActivityPub 프로토콜 구현을 단순화하여 개발 시간을 크게 단축시킵니다. MIT 라이선스 하에 제공되는 오픈 소스 프로젝트입니다.

💼 Fedify를 활용하는 프로젝트들

다양한 프로젝트들이 이미 Fedify를 활용하고 있습니다:

  • Ghost: 수백만 사용자를 보유한 전문적인 오픈 소스(MIT 라이선스) 퍼블리싱 플랫폼으로, Fedify의 주요 후원사이자 파트너입니다.
  • Hollo: 개인 사용자를 위한 경량 마이크로블로그 (오픈 소스, AGPL-3.0)
  • Hackers' Pub: 소프트웨어 엔지니어를 위한 연합우주 블로그 플랫폼 (오픈 소스, AGPL-3.0)
  • Encyclia: ORCID 학술 기록을 ActivityPub을 통해 제공하는 브리지 서비스

🚀 Fedify가 제공하는 가치

  • 개발 시간 80% 단축: ActivityPub의 복잡한 구현 대신 검증된 프레임워크 활용
  • 즉각적인 연합우주 호환성: Mastodon, Misskey, Pleroma, Pixelfed, PeerTube 등 다양한 연합우주 서비스와 즉시 호환
  • 전문 기술 지원: ActivityPub 및 연합 프로토콜 전문가의 직접 지원
  • 맞춤형 개발: 귀사의 특정 요구사항에 맞는 맞춤형 기능 개발

🤝 가능한 협력 모델

  • 맞춤형 컨설팅 및 통합 지원: 귀사 플랫폼에 통합을 위한 전문적 지원
  • 맞춤형 기능 개발 의뢰: 귀사에 필요한 특정 기능의 개발 및 구현
  • 장기적인 기술 파트너십: 지속적인 개발 및 유지보수를 위한 장기 협력 관계

🌟 Fedify와 협력했을 때의 이점

  • 기술적 이점: 자체 구현 대비 시간과 리소스 절약
  • 브랜드 이미지: 오픈 소스 생태계 지원을 통한 기업 이미지 강화
  • 분산형 소셜 네트워크 진입: 연합우주 생태계에 쉽게 참여
  • 경쟁 우위: 소셜 기능을 통한 제품 경쟁력 강화

📩 관심이 있으신가요?

ActivityPub 구현을 고려 중이시거나, Fedify 프로젝트와 협력하고 싶으시다면 연락 주세요:

귀사의 요구사항과 목표에 맞는 맞춤형 협력 방안을 함께 모색하겠습니다.

github.com

GitHub - fedify-dev/fedify: ActivityPub server framework in TypeScript

ActivityPub server framework in TypeScript. Contribute to fedify-dev/fedify development by creating an account on GitHub.

@botkit@hollo.social · Reply to BotKit by Fedify :botkit:

()를 위한 봇을 만들고 싶으신가요? by Fedify를 사용하면 몇 줄의 코드만으로 독립형 봇을 구축할 수 있습니다! 일반적인 Mastodon 또는 Misskey 봇과 달리, BotKit은 플랫폼 제약 없이 완전한 ActivityPub 서버를 만들 수 있게 도와줍니다.

BotKit으로 할 수 있는 것:

  • 멘션, 팔로우 및 메시지에 응답하는 봇 만들기
  • 형식화된 텍스트, 멘션 및 미디어가 포함된 풍부한 콘텐츠 생성
  • 예약된 게시물 발행 및 대화 자동 관리
  • Deno Deploy, Docker 또는 자체 호스팅 서버에 쉽게 배포

문서는 https://botkit.fedify.dev/에서 확인하시고 지금 바로 연합우주 봇을 만들어 보세요!

botkit.fedify.dev

BotKit by Fedify

A framework for creating your ActivityPub bots

@botkit@hollo.social · Reply to BotKit by Fedify :botkit:

()를 위한 봇을 만들고 싶으신가요? by Fedify를 사용하면 몇 줄의 코드만으로 독립형 봇을 구축할 수 있습니다! 일반적인 Mastodon 또는 Misskey 봇과 달리, BotKit은 플랫폼 제약 없이 완전한 ActivityPub 서버를 만들 수 있게 도와줍니다.

BotKit으로 할 수 있는 것:

  • 멘션, 팔로우 및 메시지에 응답하는 봇 만들기
  • 형식화된 텍스트, 멘션 및 미디어가 포함된 풍부한 콘텐츠 생성
  • 예약된 게시물 발행 및 대화 자동 관리
  • Deno Deploy, Docker 또는 자체 호스팅 서버에 쉽게 배포

문서는 https://botkit.fedify.dev/에서 확인하시고 지금 바로 연합우주 봇을 만들어 보세요!

botkit.fedify.dev

BotKit by Fedify

A framework for creating your ActivityPub bots

@botkit@hollo.social · Reply to BotKit by Fedify :botkit:

()를 위한 봇을 만들고 싶으신가요? by Fedify를 사용하면 몇 줄의 코드만으로 독립형 봇을 구축할 수 있습니다! 일반적인 Mastodon 또는 Misskey 봇과 달리, BotKit은 플랫폼 제약 없이 완전한 ActivityPub 서버를 만들 수 있게 도와줍니다.

BotKit으로 할 수 있는 것:

  • 멘션, 팔로우 및 메시지에 응답하는 봇 만들기
  • 형식화된 텍스트, 멘션 및 미디어가 포함된 풍부한 콘텐츠 생성
  • 예약된 게시물 발행 및 대화 자동 관리
  • Deno Deploy, Docker 또는 자체 호스팅 서버에 쉽게 배포

문서는 https://botkit.fedify.dev/에서 확인하시고 지금 바로 연합우주 봇을 만들어 보세요!

botkit.fedify.dev

BotKit by Fedify

A framework for creating your ActivityPub bots

Fedify는 새로운 후원 파트너를 찾고 있습니다!

:fedify: Fedify란?

Fedify는 기반 연합형 서버 프레임워크로, 개발자들이 분산형 소셜 네트워크인 ()에 애플리케이션을 쉽게 통합할 수 있도록 돕습니다. 복잡한 ActivityPub 프로토콜 구현을 단순화하여 개발 시간을 크게 단축시킵니다. MIT 라이선스 하에 제공되는 오픈 소스 프로젝트입니다.

💼 Fedify를 활용하는 프로젝트들

다양한 프로젝트들이 이미 Fedify를 활용하고 있습니다:

  • Ghost: 수백만 사용자를 보유한 전문적인 오픈 소스(MIT 라이선스) 퍼블리싱 플랫폼으로, Fedify의 주요 후원사이자 파트너입니다.
  • Hollo: 개인 사용자를 위한 경량 마이크로블로그 (오픈 소스, AGPL-3.0)
  • Hackers' Pub: 소프트웨어 엔지니어를 위한 연합우주 블로그 플랫폼 (오픈 소스, AGPL-3.0)
  • Encyclia: ORCID 학술 기록을 ActivityPub을 통해 제공하는 브리지 서비스

🚀 Fedify가 제공하는 가치

  • 개발 시간 80% 단축: ActivityPub의 복잡한 구현 대신 검증된 프레임워크 활용
  • 즉각적인 연합우주 호환성: Mastodon, Misskey, Pleroma, Pixelfed, PeerTube 등 다양한 연합우주 서비스와 즉시 호환
  • 전문 기술 지원: ActivityPub 및 연합 프로토콜 전문가의 직접 지원
  • 맞춤형 개발: 귀사의 특정 요구사항에 맞는 맞춤형 기능 개발

🤝 가능한 협력 모델

  • 맞춤형 컨설팅 및 통합 지원: 귀사 플랫폼에 통합을 위한 전문적 지원
  • 맞춤형 기능 개발 의뢰: 귀사에 필요한 특정 기능의 개발 및 구현
  • 장기적인 기술 파트너십: 지속적인 개발 및 유지보수를 위한 장기 협력 관계

🌟 Fedify와 협력했을 때의 이점

  • 기술적 이점: 자체 구현 대비 시간과 리소스 절약
  • 브랜드 이미지: 오픈 소스 생태계 지원을 통한 기업 이미지 강화
  • 분산형 소셜 네트워크 진입: 연합우주 생태계에 쉽게 참여
  • 경쟁 우위: 소셜 기능을 통한 제품 경쟁력 강화

📩 관심이 있으신가요?

ActivityPub 구현을 고려 중이시거나, Fedify 프로젝트와 협력하고 싶으시다면 연락 주세요:

귀사의 요구사항과 목표에 맞는 맞춤형 협력 방안을 함께 모색하겠습니다.

github.com

GitHub - fedify-dev/fedify: ActivityPub server framework in TypeScript

ActivityPub server framework in TypeScript. Contribute to fedify-dev/fedify development by creating an account on GitHub.

Fedify는 새로운 후원 파트너를 찾고 있습니다!

:fedify: Fedify란?

Fedify는 기반 연합형 서버 프레임워크로, 개발자들이 분산형 소셜 네트워크인 ()에 애플리케이션을 쉽게 통합할 수 있도록 돕습니다. 복잡한 ActivityPub 프로토콜 구현을 단순화하여 개발 시간을 크게 단축시킵니다. MIT 라이선스 하에 제공되는 오픈 소스 프로젝트입니다.

💼 Fedify를 활용하는 프로젝트들

다양한 프로젝트들이 이미 Fedify를 활용하고 있습니다:

  • Ghost: 수백만 사용자를 보유한 전문적인 오픈 소스(MIT 라이선스) 퍼블리싱 플랫폼으로, Fedify의 주요 후원사이자 파트너입니다.
  • Hollo: 개인 사용자를 위한 경량 마이크로블로그 (오픈 소스, AGPL-3.0)
  • Hackers' Pub: 소프트웨어 엔지니어를 위한 연합우주 블로그 플랫폼 (오픈 소스, AGPL-3.0)
  • Encyclia: ORCID 학술 기록을 ActivityPub을 통해 제공하는 브리지 서비스

🚀 Fedify가 제공하는 가치

  • 개발 시간 80% 단축: ActivityPub의 복잡한 구현 대신 검증된 프레임워크 활용
  • 즉각적인 연합우주 호환성: Mastodon, Misskey, Pleroma, Pixelfed, PeerTube 등 다양한 연합우주 서비스와 즉시 호환
  • 전문 기술 지원: ActivityPub 및 연합 프로토콜 전문가의 직접 지원
  • 맞춤형 개발: 귀사의 특정 요구사항에 맞는 맞춤형 기능 개발

🤝 가능한 협력 모델

  • 맞춤형 컨설팅 및 통합 지원: 귀사 플랫폼에 통합을 위한 전문적 지원
  • 맞춤형 기능 개발 의뢰: 귀사에 필요한 특정 기능의 개발 및 구현
  • 장기적인 기술 파트너십: 지속적인 개발 및 유지보수를 위한 장기 협력 관계

🌟 Fedify와 협력했을 때의 이점

  • 기술적 이점: 자체 구현 대비 시간과 리소스 절약
  • 브랜드 이미지: 오픈 소스 생태계 지원을 통한 기업 이미지 강화
  • 분산형 소셜 네트워크 진입: 연합우주 생태계에 쉽게 참여
  • 경쟁 우위: 소셜 기능을 통한 제품 경쟁력 강화

📩 관심이 있으신가요?

ActivityPub 구현을 고려 중이시거나, Fedify 프로젝트와 협력하고 싶으시다면 연락 주세요:

귀사의 요구사항과 목표에 맞는 맞춤형 협력 방안을 함께 모색하겠습니다.

github.com

GitHub - fedify-dev/fedify: ActivityPub server framework in TypeScript

ActivityPub server framework in TypeScript. Contribute to fedify-dev/fedify development by creating an account on GitHub.

Fedify는 새로운 후원 파트너를 찾고 있습니다!

:fedify: Fedify란?

Fedify는 기반 연합형 서버 프레임워크로, 개발자들이 분산형 소셜 네트워크인 ()에 애플리케이션을 쉽게 통합할 수 있도록 돕습니다. 복잡한 ActivityPub 프로토콜 구현을 단순화하여 개발 시간을 크게 단축시킵니다. MIT 라이선스 하에 제공되는 오픈 소스 프로젝트입니다.

💼 Fedify를 활용하는 프로젝트들

다양한 프로젝트들이 이미 Fedify를 활용하고 있습니다:

  • Ghost: 수백만 사용자를 보유한 전문적인 오픈 소스(MIT 라이선스) 퍼블리싱 플랫폼으로, Fedify의 주요 후원사이자 파트너입니다.
  • Hollo: 개인 사용자를 위한 경량 마이크로블로그 (오픈 소스, AGPL-3.0)
  • Hackers' Pub: 소프트웨어 엔지니어를 위한 연합우주 블로그 플랫폼 (오픈 소스, AGPL-3.0)
  • Encyclia: ORCID 학술 기록을 ActivityPub을 통해 제공하는 브리지 서비스

🚀 Fedify가 제공하는 가치

  • 개발 시간 80% 단축: ActivityPub의 복잡한 구현 대신 검증된 프레임워크 활용
  • 즉각적인 연합우주 호환성: Mastodon, Misskey, Pleroma, Pixelfed, PeerTube 등 다양한 연합우주 서비스와 즉시 호환
  • 전문 기술 지원: ActivityPub 및 연합 프로토콜 전문가의 직접 지원
  • 맞춤형 개발: 귀사의 특정 요구사항에 맞는 맞춤형 기능 개발

🤝 가능한 협력 모델

  • 맞춤형 컨설팅 및 통합 지원: 귀사 플랫폼에 통합을 위한 전문적 지원
  • 맞춤형 기능 개발 의뢰: 귀사에 필요한 특정 기능의 개발 및 구현
  • 장기적인 기술 파트너십: 지속적인 개발 및 유지보수를 위한 장기 협력 관계

🌟 Fedify와 협력했을 때의 이점

  • 기술적 이점: 자체 구현 대비 시간과 리소스 절약
  • 브랜드 이미지: 오픈 소스 생태계 지원을 통한 기업 이미지 강화
  • 분산형 소셜 네트워크 진입: 연합우주 생태계에 쉽게 참여
  • 경쟁 우위: 소셜 기능을 통한 제품 경쟁력 강화

📩 관심이 있으신가요?

ActivityPub 구현을 고려 중이시거나, Fedify 프로젝트와 협력하고 싶으시다면 연락 주세요:

귀사의 요구사항과 목표에 맞는 맞춤형 협력 방안을 함께 모색하겠습니다.

github.com

GitHub - fedify-dev/fedify: ActivityPub server framework in TypeScript

ActivityPub server framework in TypeScript. Contribute to fedify-dev/fedify development by creating an account on GitHub.

자매 프로젝트들을 소개해 드리고자 합니다. 애플리케이션 개발을 더 쉽게 만들어주는 관련 도구들입니다:

Fedify :fedify:

Fedify(@fedify)는 ActivityPub와 다른 () 표준을 기반으로 연합 서버 애플리케이션을 구축하기 위한 라이브러리입니다. Activity Vocabulary를 위한 타입 안전한 객체, WebFinger 클라이언트·서버, HTTP Signatures 등를 제공하여 반복적인 코드를 줄이고 애플리케이션 로직에 집중할 수 있게 해줍니다.

Hollo :hollo:

Hollo(@hollo)는 Fedify로 구동되는 1인 사용자용 마이크로블로깅 서버입니다. 1인 사용자를 위해 설계되었지만, ActivityPub를 통해 완전히 연합되어 연합우주 전체의 사용자들과 상호작용할 수 있습니다. Hollo는 Mastodon 호환 API를 구현하여 자체 웹 인터페이스 없이도 대부분의 Mastodon 클라이언트와 호환됩니다.

Hollo는 또한 정식 출시 전에 최신 Fedify 기능을 테스트하는 실험장으로도 활용되고 있습니다.

BotKit :botkit:

BotKit(@botkit)은 저희의 가장 새로운 구성원으로, ActivityPub 봇을 만들기 위해 특별히 설계된 프레임워크입니다. 전통적인 Mastodon 봇과 달리, BotKit은 플랫폼별 제한(글자 수 제한 등)에 구애받지 않는 독립적인 ActivityPub 서버를 만듭니다.

BotKit의 API는 의도적으로 단순하게 설계되어 단일 TypeScript 파일로 완전한 봇을 만들 수 있습니다!


세 프로젝트 모두 @fedify-dev GitHub 조직에서 오픈 소스로 공개되어 있습니다. 각기 다른 목적을 가지고 있지만, ActivityPub 개발을 더 접근하기 쉽게 만들고 연합우주 생태계를 확장한다는 공통된 목표를 공유합니다.

이러한 프로젝트를 사용해보거나 개발에 기여하는 데 관심이 있으시다면, 다음을 확인해보세요:

botkit.fedify.dev

BotKit by Fedify

A framework for creating your ActivityPub bots

자매 프로젝트들을 소개해 드리고자 합니다. 애플리케이션 개발을 더 쉽게 만들어주는 관련 도구들입니다:

Fedify :fedify:

Fedify(@fedify)는 ActivityPub와 다른 () 표준을 기반으로 연합 서버 애플리케이션을 구축하기 위한 라이브러리입니다. Activity Vocabulary를 위한 타입 안전한 객체, WebFinger 클라이언트·서버, HTTP Signatures 등를 제공하여 반복적인 코드를 줄이고 애플리케이션 로직에 집중할 수 있게 해줍니다.

Hollo :hollo:

Hollo(@hollo)는 Fedify로 구동되는 1인 사용자용 마이크로블로깅 서버입니다. 1인 사용자를 위해 설계되었지만, ActivityPub를 통해 완전히 연합되어 연합우주 전체의 사용자들과 상호작용할 수 있습니다. Hollo는 Mastodon 호환 API를 구현하여 자체 웹 인터페이스 없이도 대부분의 Mastodon 클라이언트와 호환됩니다.

Hollo는 또한 정식 출시 전에 최신 Fedify 기능을 테스트하는 실험장으로도 활용되고 있습니다.

BotKit :botkit:

BotKit(@botkit)은 저희의 가장 새로운 구성원으로, ActivityPub 봇을 만들기 위해 특별히 설계된 프레임워크입니다. 전통적인 Mastodon 봇과 달리, BotKit은 플랫폼별 제한(글자 수 제한 등)에 구애받지 않는 독립적인 ActivityPub 서버를 만듭니다.

BotKit의 API는 의도적으로 단순하게 설계되어 단일 TypeScript 파일로 완전한 봇을 만들 수 있습니다!


세 프로젝트 모두 @fedify-dev GitHub 조직에서 오픈 소스로 공개되어 있습니다. 각기 다른 목적을 가지고 있지만, ActivityPub 개발을 더 접근하기 쉽게 만들고 연합우주 생태계를 확장한다는 공통된 목표를 공유합니다.

이러한 프로젝트를 사용해보거나 개발에 기여하는 데 관심이 있으시다면, 다음을 확인해보세요:

botkit.fedify.dev

BotKit by Fedify

A framework for creating your ActivityPub bots

자매 프로젝트들을 소개해 드리고자 합니다. 애플리케이션 개발을 더 쉽게 만들어주는 관련 도구들입니다:

Fedify :fedify:

Fedify(@fedify)는 ActivityPub와 다른 () 표준을 기반으로 연합 서버 애플리케이션을 구축하기 위한 라이브러리입니다. Activity Vocabulary를 위한 타입 안전한 객체, WebFinger 클라이언트·서버, HTTP Signatures 등를 제공하여 반복적인 코드를 줄이고 애플리케이션 로직에 집중할 수 있게 해줍니다.

Hollo :hollo:

Hollo(@hollo)는 Fedify로 구동되는 1인 사용자용 마이크로블로깅 서버입니다. 1인 사용자를 위해 설계되었지만, ActivityPub를 통해 완전히 연합되어 연합우주 전체의 사용자들과 상호작용할 수 있습니다. Hollo는 Mastodon 호환 API를 구현하여 자체 웹 인터페이스 없이도 대부분의 Mastodon 클라이언트와 호환됩니다.

Hollo는 또한 정식 출시 전에 최신 Fedify 기능을 테스트하는 실험장으로도 활용되고 있습니다.

BotKit :botkit:

BotKit(@botkit)은 저희의 가장 새로운 구성원으로, ActivityPub 봇을 만들기 위해 특별히 설계된 프레임워크입니다. 전통적인 Mastodon 봇과 달리, BotKit은 플랫폼별 제한(글자 수 제한 등)에 구애받지 않는 독립적인 ActivityPub 서버를 만듭니다.

BotKit의 API는 의도적으로 단순하게 설계되어 단일 TypeScript 파일로 완전한 봇을 만들 수 있습니다!


세 프로젝트 모두 @fedify-dev GitHub 조직에서 오픈 소스로 공개되어 있습니다. 각기 다른 목적을 가지고 있지만, ActivityPub 개발을 더 접근하기 쉽게 만들고 연합우주 생태계를 확장한다는 공통된 목표를 공유합니다.

이러한 프로젝트를 사용해보거나 개발에 기여하는 데 관심이 있으시다면, 다음을 확인해보세요:

botkit.fedify.dev

BotKit by Fedify

A framework for creating your ActivityPub bots

자매 프로젝트들을 소개해 드리고자 합니다. 애플리케이션 개발을 더 쉽게 만들어주는 관련 도구들입니다:

Fedify :fedify:

Fedify(@fedify)는 ActivityPub와 다른 () 표준을 기반으로 연합 서버 애플리케이션을 구축하기 위한 라이브러리입니다. Activity Vocabulary를 위한 타입 안전한 객체, WebFinger 클라이언트·서버, HTTP Signatures 등를 제공하여 반복적인 코드를 줄이고 애플리케이션 로직에 집중할 수 있게 해줍니다.

Hollo :hollo:

Hollo(@hollo)는 Fedify로 구동되는 1인 사용자용 마이크로블로깅 서버입니다. 1인 사용자를 위해 설계되었지만, ActivityPub를 통해 완전히 연합되어 연합우주 전체의 사용자들과 상호작용할 수 있습니다. Hollo는 Mastodon 호환 API를 구현하여 자체 웹 인터페이스 없이도 대부분의 Mastodon 클라이언트와 호환됩니다.

Hollo는 또한 정식 출시 전에 최신 Fedify 기능을 테스트하는 실험장으로도 활용되고 있습니다.

BotKit :botkit:

BotKit(@botkit)은 저희의 가장 새로운 구성원으로, ActivityPub 봇을 만들기 위해 특별히 설계된 프레임워크입니다. 전통적인 Mastodon 봇과 달리, BotKit은 플랫폼별 제한(글자 수 제한 등)에 구애받지 않는 독립적인 ActivityPub 서버를 만듭니다.

BotKit의 API는 의도적으로 단순하게 설계되어 단일 TypeScript 파일로 완전한 봇을 만들 수 있습니다!


세 프로젝트 모두 @fedify-dev GitHub 조직에서 오픈 소스로 공개되어 있습니다. 각기 다른 목적을 가지고 있지만, ActivityPub 개발을 더 접근하기 쉽게 만들고 연합우주 생태계를 확장한다는 공통된 목표를 공유합니다.

이러한 프로젝트를 사용해보거나 개발에 기여하는 데 관심이 있으시다면, 다음을 확인해보세요:

botkit.fedify.dev

BotKit by Fedify

A framework for creating your ActivityPub bots

자매 프로젝트들을 소개해 드리고자 합니다. 애플리케이션 개발을 더 쉽게 만들어주는 관련 도구들입니다:

Fedify :fedify:

Fedify(@fedify)는 ActivityPub와 다른 () 표준을 기반으로 연합 서버 애플리케이션을 구축하기 위한 라이브러리입니다. Activity Vocabulary를 위한 타입 안전한 객체, WebFinger 클라이언트·서버, HTTP Signatures 등를 제공하여 반복적인 코드를 줄이고 애플리케이션 로직에 집중할 수 있게 해줍니다.

Hollo :hollo:

Hollo(@hollo)는 Fedify로 구동되는 1인 사용자용 마이크로블로깅 서버입니다. 1인 사용자를 위해 설계되었지만, ActivityPub를 통해 완전히 연합되어 연합우주 전체의 사용자들과 상호작용할 수 있습니다. Hollo는 Mastodon 호환 API를 구현하여 자체 웹 인터페이스 없이도 대부분의 Mastodon 클라이언트와 호환됩니다.

Hollo는 또한 정식 출시 전에 최신 Fedify 기능을 테스트하는 실험장으로도 활용되고 있습니다.

BotKit :botkit:

BotKit(@botkit)은 저희의 가장 새로운 구성원으로, ActivityPub 봇을 만들기 위해 특별히 설계된 프레임워크입니다. 전통적인 Mastodon 봇과 달리, BotKit은 플랫폼별 제한(글자 수 제한 등)에 구애받지 않는 독립적인 ActivityPub 서버를 만듭니다.

BotKit의 API는 의도적으로 단순하게 설계되어 단일 TypeScript 파일로 완전한 봇을 만들 수 있습니다!


세 프로젝트 모두 @fedify-dev GitHub 조직에서 오픈 소스로 공개되어 있습니다. 각기 다른 목적을 가지고 있지만, ActivityPub 개발을 더 접근하기 쉽게 만들고 연합우주 생태계를 확장한다는 공통된 목표를 공유합니다.

이러한 프로젝트를 사용해보거나 개발에 기여하는 데 관심이 있으시다면, 다음을 확인해보세요:

botkit.fedify.dev

BotKit by Fedify

A framework for creating your ActivityPub bots

📢 여러분만의 서버를 Fedify로 만들어보세요!

Fedify 프로토콜 구현을 도와주는 프레임워크입니다. 복잡한 연합 프로토콜을 쉽게 구현하고 싶으신가요? Fedify가 도와드립니다!

✨ 주요 기능

🔧 CLI 도구

🚀 런타임 지원

📚 배우기 쉽습니다

오픈소스 라이선스로 누구나 자유롭게 사용할 수 있습니다!

discord.com

Join the Fedify/Hollo Discord Server!

Check out the Fedify/Hollo community on Discord - hang out with 81 other members and enjoy free voice and text chat.

📢 여러분만의 서버를 Fedify로 만들어보세요!

Fedify 프로토콜 구현을 도와주는 프레임워크입니다. 복잡한 연합 프로토콜을 쉽게 구현하고 싶으신가요? Fedify가 도와드립니다!

✨ 주요 기능

🔧 CLI 도구

🚀 런타임 지원

📚 배우기 쉽습니다

오픈소스 라이선스로 누구나 자유롭게 사용할 수 있습니다!

discord.com

Join the Fedify/Hollo Discord Server!

Check out the Fedify/Hollo community on Discord - hang out with 81 other members and enjoy free voice and text chat.

📢 여러분만의 서버를 Fedify로 만들어보세요!

Fedify 프로토콜 구현을 도와주는 프레임워크입니다. 복잡한 연합 프로토콜을 쉽게 구현하고 싶으신가요? Fedify가 도와드립니다!

✨ 주요 기능

🔧 CLI 도구

🚀 런타임 지원

📚 배우기 쉽습니다

오픈소스 라이선스로 누구나 자유롭게 사용할 수 있습니다!

discord.com

Join the Fedify/Hollo Discord Server!

Check out the Fedify/Hollo community on Discord - hang out with 81 other members and enjoy free voice and text chat.

📢 여러분만의 서버를 Fedify로 만들어보세요!

Fedify 프로토콜 구현을 도와주는 프레임워크입니다. 복잡한 연합 프로토콜을 쉽게 구현하고 싶으신가요? Fedify가 도와드립니다!

✨ 주요 기능

🔧 CLI 도구

🚀 런타임 지원

📚 배우기 쉽습니다

오픈소스 라이선스로 누구나 자유롭게 사용할 수 있습니다!

discord.com

Join the Fedify/Hollo Discord Server!

Check out the Fedify/Hollo community on Discord - hang out with 81 other members and enjoy free voice and text chat.

@hollo@hollo.social · Reply to Hollo :hollo:

안녕하세요! :hollo:

Hollo의 새로운 계획에 대해 여러분의 의견을 듣고자 합니다.

지금까지 Hollo는 셀프 호스팅을 기본 원칙으로 삼아왔습니다. 이는 앞으로도 변함없이 유지될 것이며, 소스 코드는 계속해서 AGPLv3 라이선스로 공개됩니다.

최근 저희는 프로젝트의 지속 가능한 발전을 위해, Open Collective(@opencollective)를 통해 일정 금액 이상을 정기적으로 후원해 주시는 분들을 위한 호스팅 서비스 제공을 검토하고 있습니다.

이는 기술적인 부분에 신경 쓰지 않고도 Hollo를 이용하고 싶으신 분들을 위한 추가 옵션이 될 것입니다. 물론 지금처럼 직접 설치하고 운영하시는 것도 계속 가능합니다.

아래 인용된 영어 게시물의 투표에 참여해 주시면 감사하겠습니다! 📊

  1. 좋은 생각입니다! 호스팅 서비스를 이용하고 싶어요.
  2. 괜찮네요! 전 셀프 호스팅을 계속하지만 응원합니다.
  3. 다른 방식으로 후원을 늘리는 게 좋겠어요.
  4. 현재처럼 순수 셀프 호스팅으로 남았으면 좋겠어요.

💭 추가 의견이나 제안이 있으시다면 댓글로 남겨주세요!

https://hollo.social/@hollo/01950344-1c55-7f43-8afc-b0a1ee8b4abf

hollo.social

#Hollo everyone! :hollo: We'd…

#Hollo everyone! :hollo: We'd like to hear your thoughts on something we've been considering. As you know, Hollo has always been focused on self-hosting—this won't change, and our source code will continue to be available under the AGPLv3 license. We're exploring ways to make the project more sustainable, and we're considering offering a hosting service for those who regularly support us with a certain amount through @opencollective@opencollective.com. This would be an additional option for those who want to use Hollo without managing the technical aspects themselves. Of course, you'll still be able to self-host just like you do now. What are your thoughts on this idea? Please vote below! 📊 💭 Have additional thoughts or suggestions? Feel free to share them in the comments! #poll #fediverse

@hollo@hollo.social

everyone! :hollo:

We'd like to hear your thoughts on something we've been considering.

As you know, Hollo has always been focused on self-hosting—this won't change, and our source code will continue to be available under the AGPLv3 license.

We're exploring ways to make the project more sustainable, and we're considering offering a hosting service for those who regularly support us with a certain amount through @opencollective.

This would be an additional option for those who want to use Hollo without managing the technical aspects themselves. Of course, you'll still be able to self-host just like you do now.

What are your thoughts on this idea? Please vote below! 📊

💭 Have additional thoughts or suggestions? Feel free to share them in the comments!

  • 1️⃣ Great idea! I'd be interested in supporting and using the hosted service.26 (45%)
  • 2️⃣ Sounds good! I'll stick to self-hosting but support the initiative.29 (50%)
  • 3️⃣ I think we should explore other ways to increase support.2 (3%)
  • 4️⃣ I prefer Hollo to remain purely self-hosted.1 (2%)
@hollo@hollo.social · Reply to Hollo :hollo:

안녕하세요! :hollo:

Hollo의 새로운 계획에 대해 여러분의 의견을 듣고자 합니다.

지금까지 Hollo는 셀프 호스팅을 기본 원칙으로 삼아왔습니다. 이는 앞으로도 변함없이 유지될 것이며, 소스 코드는 계속해서 AGPLv3 라이선스로 공개됩니다.

최근 저희는 프로젝트의 지속 가능한 발전을 위해, Open Collective(@opencollective)를 통해 일정 금액 이상을 정기적으로 후원해 주시는 분들을 위한 호스팅 서비스 제공을 검토하고 있습니다.

이는 기술적인 부분에 신경 쓰지 않고도 Hollo를 이용하고 싶으신 분들을 위한 추가 옵션이 될 것입니다. 물론 지금처럼 직접 설치하고 운영하시는 것도 계속 가능합니다.

아래 인용된 영어 게시물의 투표에 참여해 주시면 감사하겠습니다! 📊

  1. 좋은 생각입니다! 호스팅 서비스를 이용하고 싶어요.
  2. 괜찮네요! 전 셀프 호스팅을 계속하지만 응원합니다.
  3. 다른 방식으로 후원을 늘리는 게 좋겠어요.
  4. 현재처럼 순수 셀프 호스팅으로 남았으면 좋겠어요.

💭 추가 의견이나 제안이 있으시다면 댓글로 남겨주세요!

https://hollo.social/@hollo/01950344-1c55-7f43-8afc-b0a1ee8b4abf

hollo.social

#Hollo everyone! :hollo: We'd…

#Hollo everyone! :hollo: We'd like to hear your thoughts on something we've been considering. As you know, Hollo has always been focused on self-hosting—this won't change, and our source code will continue to be available under the AGPLv3 license. We're exploring ways to make the project more sustainable, and we're considering offering a hosting service for those who regularly support us with a certain amount through @opencollective@opencollective.com. This would be an additional option for those who want to use Hollo without managing the technical aspects themselves. Of course, you'll still be able to self-host just like you do now. What are your thoughts on this idea? Please vote below! 📊 💭 Have additional thoughts or suggestions? Feel free to share them in the comments! #poll #fediverse

@hollo@hollo.social

everyone! :hollo:

We'd like to hear your thoughts on something we've been considering.

As you know, Hollo has always been focused on self-hosting—this won't change, and our source code will continue to be available under the AGPLv3 license.

We're exploring ways to make the project more sustainable, and we're considering offering a hosting service for those who regularly support us with a certain amount through @opencollective.

This would be an additional option for those who want to use Hollo without managing the technical aspects themselves. Of course, you'll still be able to self-host just like you do now.

What are your thoughts on this idea? Please vote below! 📊

💭 Have additional thoughts or suggestions? Feel free to share them in the comments!

  • 1️⃣ Great idea! I'd be interested in supporting and using the hosted service.26 (45%)
  • 2️⃣ Sounds good! I'll stick to self-hosting but support the initiative.29 (50%)
  • 3️⃣ I think we should explore other ways to increase support.2 (3%)
  • 4️⃣ I prefer Hollo to remain purely self-hosted.1 (2%)
@hollo@hollo.social · Reply to Hollo :hollo:

안녕하세요! :hollo:

Hollo의 새로운 계획에 대해 여러분의 의견을 듣고자 합니다.

지금까지 Hollo는 셀프 호스팅을 기본 원칙으로 삼아왔습니다. 이는 앞으로도 변함없이 유지될 것이며, 소스 코드는 계속해서 AGPLv3 라이선스로 공개됩니다.

최근 저희는 프로젝트의 지속 가능한 발전을 위해, Open Collective(@opencollective)를 통해 일정 금액 이상을 정기적으로 후원해 주시는 분들을 위한 호스팅 서비스 제공을 검토하고 있습니다.

이는 기술적인 부분에 신경 쓰지 않고도 Hollo를 이용하고 싶으신 분들을 위한 추가 옵션이 될 것입니다. 물론 지금처럼 직접 설치하고 운영하시는 것도 계속 가능합니다.

아래 인용된 영어 게시물의 투표에 참여해 주시면 감사하겠습니다! 📊

  1. 좋은 생각입니다! 호스팅 서비스를 이용하고 싶어요.
  2. 괜찮네요! 전 셀프 호스팅을 계속하지만 응원합니다.
  3. 다른 방식으로 후원을 늘리는 게 좋겠어요.
  4. 현재처럼 순수 셀프 호스팅으로 남았으면 좋겠어요.

💭 추가 의견이나 제안이 있으시다면 댓글로 남겨주세요!

https://hollo.social/@hollo/01950344-1c55-7f43-8afc-b0a1ee8b4abf

hollo.social

#Hollo everyone! :hollo: We'd…

#Hollo everyone! :hollo: We'd like to hear your thoughts on something we've been considering. As you know, Hollo has always been focused on self-hosting—this won't change, and our source code will continue to be available under the AGPLv3 license. We're exploring ways to make the project more sustainable, and we're considering offering a hosting service for those who regularly support us with a certain amount through @opencollective@opencollective.com. This would be an additional option for those who want to use Hollo without managing the technical aspects themselves. Of course, you'll still be able to self-host just like you do now. What are your thoughts on this idea? Please vote below! 📊 💭 Have additional thoughts or suggestions? Feel free to share them in the comments! #poll #fediverse

@hollo@hollo.social

everyone! :hollo:

We'd like to hear your thoughts on something we've been considering.

As you know, Hollo has always been focused on self-hosting—this won't change, and our source code will continue to be available under the AGPLv3 license.

We're exploring ways to make the project more sustainable, and we're considering offering a hosting service for those who regularly support us with a certain amount through @opencollective.

This would be an additional option for those who want to use Hollo without managing the technical aspects themselves. Of course, you'll still be able to self-host just like you do now.

What are your thoughts on this idea? Please vote below! 📊

💭 Have additional thoughts or suggestions? Feel free to share them in the comments!

  • 1️⃣ Great idea! I'd be interested in supporting and using the hosted service.26 (45%)
  • 2️⃣ Sounds good! I'll stick to self-hosting but support the initiative.29 (50%)
  • 3️⃣ I think we should explore other ways to increase support.2 (3%)
  • 4️⃣ I prefer Hollo to remain purely self-hosted.1 (2%)
@hollo@hollo.social · Reply to Hollo :hollo:

안녕하세요! :hollo:

Hollo의 새로운 계획에 대해 여러분의 의견을 듣고자 합니다.

지금까지 Hollo는 셀프 호스팅을 기본 원칙으로 삼아왔습니다. 이는 앞으로도 변함없이 유지될 것이며, 소스 코드는 계속해서 AGPLv3 라이선스로 공개됩니다.

최근 저희는 프로젝트의 지속 가능한 발전을 위해, Open Collective(@opencollective)를 통해 일정 금액 이상을 정기적으로 후원해 주시는 분들을 위한 호스팅 서비스 제공을 검토하고 있습니다.

이는 기술적인 부분에 신경 쓰지 않고도 Hollo를 이용하고 싶으신 분들을 위한 추가 옵션이 될 것입니다. 물론 지금처럼 직접 설치하고 운영하시는 것도 계속 가능합니다.

아래 인용된 영어 게시물의 투표에 참여해 주시면 감사하겠습니다! 📊

  1. 좋은 생각입니다! 호스팅 서비스를 이용하고 싶어요.
  2. 괜찮네요! 전 셀프 호스팅을 계속하지만 응원합니다.
  3. 다른 방식으로 후원을 늘리는 게 좋겠어요.
  4. 현재처럼 순수 셀프 호스팅으로 남았으면 좋겠어요.

💭 추가 의견이나 제안이 있으시다면 댓글로 남겨주세요!

https://hollo.social/@hollo/01950344-1c55-7f43-8afc-b0a1ee8b4abf

hollo.social

#Hollo everyone! :hollo: We'd…

#Hollo everyone! :hollo: We'd like to hear your thoughts on something we've been considering. As you know, Hollo has always been focused on self-hosting—this won't change, and our source code will continue to be available under the AGPLv3 license. We're exploring ways to make the project more sustainable, and we're considering offering a hosting service for those who regularly support us with a certain amount through @opencollective@opencollective.com. This would be an additional option for those who want to use Hollo without managing the technical aspects themselves. Of course, you'll still be able to self-host just like you do now. What are your thoughts on this idea? Please vote below! 📊 💭 Have additional thoughts or suggestions? Feel free to share them in the comments! #poll #fediverse

@hollo@hollo.social

everyone! :hollo:

We'd like to hear your thoughts on something we've been considering.

As you know, Hollo has always been focused on self-hosting—this won't change, and our source code will continue to be available under the AGPLv3 license.

We're exploring ways to make the project more sustainable, and we're considering offering a hosting service for those who regularly support us with a certain amount through @opencollective.

This would be an additional option for those who want to use Hollo without managing the technical aspects themselves. Of course, you'll still be able to self-host just like you do now.

What are your thoughts on this idea? Please vote below! 📊

💭 Have additional thoughts or suggestions? Feel free to share them in the comments!

  • 1️⃣ Great idea! I'd be interested in supporting and using the hosted service.26 (45%)
  • 2️⃣ Sounds good! I'll stick to self-hosting but support the initiative.29 (50%)
  • 3️⃣ I think we should explore other ways to increase support.2 (3%)
  • 4️⃣ I prefer Hollo to remain purely self-hosted.1 (2%)
@hollo@hollo.social · Reply to Hollo :hollo:

안녕하세요! :hollo:

Hollo의 새로운 계획에 대해 여러분의 의견을 듣고자 합니다.

지금까지 Hollo는 셀프 호스팅을 기본 원칙으로 삼아왔습니다. 이는 앞으로도 변함없이 유지될 것이며, 소스 코드는 계속해서 AGPLv3 라이선스로 공개됩니다.

최근 저희는 프로젝트의 지속 가능한 발전을 위해, Open Collective(@opencollective)를 통해 일정 금액 이상을 정기적으로 후원해 주시는 분들을 위한 호스팅 서비스 제공을 검토하고 있습니다.

이는 기술적인 부분에 신경 쓰지 않고도 Hollo를 이용하고 싶으신 분들을 위한 추가 옵션이 될 것입니다. 물론 지금처럼 직접 설치하고 운영하시는 것도 계속 가능합니다.

아래 인용된 영어 게시물의 투표에 참여해 주시면 감사하겠습니다! 📊

  1. 좋은 생각입니다! 호스팅 서비스를 이용하고 싶어요.
  2. 괜찮네요! 전 셀프 호스팅을 계속하지만 응원합니다.
  3. 다른 방식으로 후원을 늘리는 게 좋겠어요.
  4. 현재처럼 순수 셀프 호스팅으로 남았으면 좋겠어요.

💭 추가 의견이나 제안이 있으시다면 댓글로 남겨주세요!

https://hollo.social/@hollo/01950344-1c55-7f43-8afc-b0a1ee8b4abf

hollo.social

#Hollo everyone! :hollo: We'd…

#Hollo everyone! :hollo: We'd like to hear your thoughts on something we've been considering. As you know, Hollo has always been focused on self-hosting—this won't change, and our source code will continue to be available under the AGPLv3 license. We're exploring ways to make the project more sustainable, and we're considering offering a hosting service for those who regularly support us with a certain amount through @opencollective@opencollective.com. This would be an additional option for those who want to use Hollo without managing the technical aspects themselves. Of course, you'll still be able to self-host just like you do now. What are your thoughts on this idea? Please vote below! 📊 💭 Have additional thoughts or suggestions? Feel free to share them in the comments! #poll #fediverse

@hollo@hollo.social

everyone! :hollo:

We'd like to hear your thoughts on something we've been considering.

As you know, Hollo has always been focused on self-hosting—this won't change, and our source code will continue to be available under the AGPLv3 license.

We're exploring ways to make the project more sustainable, and we're considering offering a hosting service for those who regularly support us with a certain amount through @opencollective.

This would be an additional option for those who want to use Hollo without managing the technical aspects themselves. Of course, you'll still be able to self-host just like you do now.

What are your thoughts on this idea? Please vote below! 📊

💭 Have additional thoughts or suggestions? Feel free to share them in the comments!

  • 1️⃣ Great idea! I'd be interested in supporting and using the hosted service.26 (45%)
  • 2️⃣ Sounds good! I'll stick to self-hosting but support the initiative.29 (50%)
  • 3️⃣ I think we should explore other ways to increase support.2 (3%)
  • 4️⃣ I prefer Hollo to remain purely self-hosted.1 (2%)
@hollo@hollo.social · Reply to Hollo :hollo:

안녕하세요! :hollo:

Hollo의 새로운 계획에 대해 여러분의 의견을 듣고자 합니다.

지금까지 Hollo는 셀프 호스팅을 기본 원칙으로 삼아왔습니다. 이는 앞으로도 변함없이 유지될 것이며, 소스 코드는 계속해서 AGPLv3 라이선스로 공개됩니다.

최근 저희는 프로젝트의 지속 가능한 발전을 위해, Open Collective(@opencollective)를 통해 일정 금액 이상을 정기적으로 후원해 주시는 분들을 위한 호스팅 서비스 제공을 검토하고 있습니다.

이는 기술적인 부분에 신경 쓰지 않고도 Hollo를 이용하고 싶으신 분들을 위한 추가 옵션이 될 것입니다. 물론 지금처럼 직접 설치하고 운영하시는 것도 계속 가능합니다.

아래 인용된 영어 게시물의 투표에 참여해 주시면 감사하겠습니다! 📊

  1. 좋은 생각입니다! 호스팅 서비스를 이용하고 싶어요.
  2. 괜찮네요! 전 셀프 호스팅을 계속하지만 응원합니다.
  3. 다른 방식으로 후원을 늘리는 게 좋겠어요.
  4. 현재처럼 순수 셀프 호스팅으로 남았으면 좋겠어요.

💭 추가 의견이나 제안이 있으시다면 댓글로 남겨주세요!

https://hollo.social/@hollo/01950344-1c55-7f43-8afc-b0a1ee8b4abf

hollo.social

#Hollo everyone! :hollo: We'd…

#Hollo everyone! :hollo: We'd like to hear your thoughts on something we've been considering. As you know, Hollo has always been focused on self-hosting—this won't change, and our source code will continue to be available under the AGPLv3 license. We're exploring ways to make the project more sustainable, and we're considering offering a hosting service for those who regularly support us with a certain amount through @opencollective@opencollective.com. This would be an additional option for those who want to use Hollo without managing the technical aspects themselves. Of course, you'll still be able to self-host just like you do now. What are your thoughts on this idea? Please vote below! 📊 💭 Have additional thoughts or suggestions? Feel free to share them in the comments! #poll #fediverse

@hollo@hollo.social

everyone! :hollo:

We'd like to hear your thoughts on something we've been considering.

As you know, Hollo has always been focused on self-hosting—this won't change, and our source code will continue to be available under the AGPLv3 license.

We're exploring ways to make the project more sustainable, and we're considering offering a hosting service for those who regularly support us with a certain amount through @opencollective.

This would be an additional option for those who want to use Hollo without managing the technical aspects themselves. Of course, you'll still be able to self-host just like you do now.

What are your thoughts on this idea? Please vote below! 📊

💭 Have additional thoughts or suggestions? Feel free to share them in the comments!

  • 1️⃣ Great idea! I'd be interested in supporting and using the hosted service.26 (45%)
  • 2️⃣ Sounds good! I'll stick to self-hosting but support the initiative.29 (50%)
  • 3️⃣ I think we should explore other ways to increase support.2 (3%)
  • 4️⃣ I prefer Hollo to remain purely self-hosted.1 (2%)
@hollo@hollo.social · Reply to Hollo :hollo:

저장소가 @dahlia/hollo에서 @fedify-dev/hollo로 이전되었습니다. 이에 따라 이미지 레지스트리도 ghcr.io/dahlia/hollo에서 ghcr.io/fedify-dev/hollo로 이전되었습니다.

기존 이미지 레지스트리는 계속 접근 가능하지만, 새로운 태그는 더 이상 추가되지 않을 예정입니다. Hollo를 사용 중이신 모든 분들은 새로운 레지스트리 주소로 업데이트해 주시기 바랍니다.

Docker 설정을 다음과 같이 변경해 주세요:

  • 기존 이미지 주소: ghcr.io/dahlia/hollo:latest
  • 새 이미지 주소: ghcr.io/fedify-dev/hollo:latest

이번 이전은 프로젝트의 더 나은 운영과 지속적인 개발을 위해 진행되었습니다. 원활한 전환에 협조해 주셔서 감사합니다. :hollo:

https://hollo.social/@fedify/0194a851-581d-779c-b777-dc39e753ef14

hollo.social

We've just moved the #Fedify p…

We've just moved the #Fedify project and related repositories to our new GitHub organization account, [@fedify-dev]! 🎉 Here's what moved: - [@dahlia/fedify](https://github.com/dahlia/fedify) → [@fedify-dev/fedify](https://github.com/fedify-dev/fedify) - [@dahlia/botkit](https://github.com/dahlia/botkit) → [@fedify-dev/botkit](https://github.com/fedify-dev/botkit) - [@dahlia/hollo](https://github.com/dahlia/hollo) → [@fedify-dev/hollo](https://github.com/fedify-dev/hollo) - [@dahlia/fedify-amqp](https://github.com/dahlia/fedify-amqp) → [@fedify-dev/amqp](https://github.com/fedify-dev/amqp) - [@dahlia/fedify-h3](https://github.com/dahlia/fedify-h3) → [@fedify-dev/h3](https://github.com/fedify-dev/h3) - [@dahlia/fedify-express](https://github.com/dahlia/fedify-express) → [@fedify-dev/express](https://github.com/fedify-dev/express) - [@dahlia/fedify-postgres](https://github.com/dahlia/fedify-postgres) → [@fedify-dev/postgres](https://github.com/fedify-dev/postgres) - [@dahlia/fedify-redis](https://github.com/dahlia/fedify-redis) → [@fedify-dev/redis](https://github.com/fedify-dev/redis) - [@dahlia/markdown-it-hashtag](https://github.com/dahlia/markdown-it-hashtag) → [@fedify-dev/markdown-it-hashtag](https://github.com/fedify-dev/markdown-it-hashtag) - [@dahlia/markdown-it-mention](https://github.com/dahlia/markdown-it-mention) → [@fedify-dev/markdown-it-mention](https://github.com/fedify-dev/markdown-it-mention) - [@dahlia/fedichatbot](https://github.com/dahlia/fedichatbot) → [@fedify-dev/fedichatbot](https://github.com/fedify-dev/fedichatbot) - [@dahlia/microblog](https://github.com/dahlia/microblog) → [@fedify-dev/microblog](https://github.com/fedify-dev/microblog) All repositories have been transferred and GitHub's automatic redirects are in place, so existing links will continue to work. Also, the project's core functionality and development process remain unchanged. Thanks to everyone who participated in our naming poll. Looking forward to Fedify's continued growth under its new organizational home! :fedify: New GitHub organization: <https://github.com/fedify-dev>. [@fedify-dev]: https://github.com/fedify-dev

We've just moved the project and related repositories to our new GitHub organization account, @fedify-dev! 🎉

Here's what moved:

All repositories have been transferred and GitHub's automatic redirects are in place, so existing links will continue to work. Also, the project's core functionality and development process remain unchanged.

Thanks to everyone who participated in our naming poll. Looking forward to Fedify's continued growth under its new organizational home!

:fedify: New GitHub organization: https://github.com/fedify-dev.

github.com

Fedify

A collection of development tools for fediverse. Fedify has 12 repositories available. Follow their code on GitHub.

@hollo@hollo.social · Reply to Hollo :hollo:

저장소가 @dahlia/hollo에서 @fedify-dev/hollo로 이전되었습니다. 이에 따라 이미지 레지스트리도 ghcr.io/dahlia/hollo에서 ghcr.io/fedify-dev/hollo로 이전되었습니다.

기존 이미지 레지스트리는 계속 접근 가능하지만, 새로운 태그는 더 이상 추가되지 않을 예정입니다. Hollo를 사용 중이신 모든 분들은 새로운 레지스트리 주소로 업데이트해 주시기 바랍니다.

Docker 설정을 다음과 같이 변경해 주세요:

  • 기존 이미지 주소: ghcr.io/dahlia/hollo:latest
  • 새 이미지 주소: ghcr.io/fedify-dev/hollo:latest

이번 이전은 프로젝트의 더 나은 운영과 지속적인 개발을 위해 진행되었습니다. 원활한 전환에 협조해 주셔서 감사합니다. :hollo:

https://hollo.social/@fedify/0194a851-581d-779c-b777-dc39e753ef14

hollo.social

We've just moved the #Fedify p…

We've just moved the #Fedify project and related repositories to our new GitHub organization account, [@fedify-dev]! 🎉 Here's what moved: - [@dahlia/fedify](https://github.com/dahlia/fedify) → [@fedify-dev/fedify](https://github.com/fedify-dev/fedify) - [@dahlia/botkit](https://github.com/dahlia/botkit) → [@fedify-dev/botkit](https://github.com/fedify-dev/botkit) - [@dahlia/hollo](https://github.com/dahlia/hollo) → [@fedify-dev/hollo](https://github.com/fedify-dev/hollo) - [@dahlia/fedify-amqp](https://github.com/dahlia/fedify-amqp) → [@fedify-dev/amqp](https://github.com/fedify-dev/amqp) - [@dahlia/fedify-h3](https://github.com/dahlia/fedify-h3) → [@fedify-dev/h3](https://github.com/fedify-dev/h3) - [@dahlia/fedify-express](https://github.com/dahlia/fedify-express) → [@fedify-dev/express](https://github.com/fedify-dev/express) - [@dahlia/fedify-postgres](https://github.com/dahlia/fedify-postgres) → [@fedify-dev/postgres](https://github.com/fedify-dev/postgres) - [@dahlia/fedify-redis](https://github.com/dahlia/fedify-redis) → [@fedify-dev/redis](https://github.com/fedify-dev/redis) - [@dahlia/markdown-it-hashtag](https://github.com/dahlia/markdown-it-hashtag) → [@fedify-dev/markdown-it-hashtag](https://github.com/fedify-dev/markdown-it-hashtag) - [@dahlia/markdown-it-mention](https://github.com/dahlia/markdown-it-mention) → [@fedify-dev/markdown-it-mention](https://github.com/fedify-dev/markdown-it-mention) - [@dahlia/fedichatbot](https://github.com/dahlia/fedichatbot) → [@fedify-dev/fedichatbot](https://github.com/fedify-dev/fedichatbot) - [@dahlia/microblog](https://github.com/dahlia/microblog) → [@fedify-dev/microblog](https://github.com/fedify-dev/microblog) All repositories have been transferred and GitHub's automatic redirects are in place, so existing links will continue to work. Also, the project's core functionality and development process remain unchanged. Thanks to everyone who participated in our naming poll. Looking forward to Fedify's continued growth under its new organizational home! :fedify: New GitHub organization: <https://github.com/fedify-dev>. [@fedify-dev]: https://github.com/fedify-dev

We've just moved the project and related repositories to our new GitHub organization account, @fedify-dev! 🎉

Here's what moved:

All repositories have been transferred and GitHub's automatic redirects are in place, so existing links will continue to work. Also, the project's core functionality and development process remain unchanged.

Thanks to everyone who participated in our naming poll. Looking forward to Fedify's continued growth under its new organizational home!

:fedify: New GitHub organization: https://github.com/fedify-dev.

github.com

Fedify

A collection of development tools for fediverse. Fedify has 12 repositories available. Follow their code on GitHub.

@hollo@hollo.social · Reply to Hollo :hollo:

저장소가 @dahlia/hollo에서 @fedify-dev/hollo로 이전되었습니다. 이에 따라 이미지 레지스트리도 ghcr.io/dahlia/hollo에서 ghcr.io/fedify-dev/hollo로 이전되었습니다.

기존 이미지 레지스트리는 계속 접근 가능하지만, 새로운 태그는 더 이상 추가되지 않을 예정입니다. Hollo를 사용 중이신 모든 분들은 새로운 레지스트리 주소로 업데이트해 주시기 바랍니다.

Docker 설정을 다음과 같이 변경해 주세요:

  • 기존 이미지 주소: ghcr.io/dahlia/hollo:latest
  • 새 이미지 주소: ghcr.io/fedify-dev/hollo:latest

이번 이전은 프로젝트의 더 나은 운영과 지속적인 개발을 위해 진행되었습니다. 원활한 전환에 협조해 주셔서 감사합니다. :hollo:

https://hollo.social/@fedify/0194a851-581d-779c-b777-dc39e753ef14

hollo.social

We've just moved the #Fedify p…

We've just moved the #Fedify project and related repositories to our new GitHub organization account, [@fedify-dev]! 🎉 Here's what moved: - [@dahlia/fedify](https://github.com/dahlia/fedify) → [@fedify-dev/fedify](https://github.com/fedify-dev/fedify) - [@dahlia/botkit](https://github.com/dahlia/botkit) → [@fedify-dev/botkit](https://github.com/fedify-dev/botkit) - [@dahlia/hollo](https://github.com/dahlia/hollo) → [@fedify-dev/hollo](https://github.com/fedify-dev/hollo) - [@dahlia/fedify-amqp](https://github.com/dahlia/fedify-amqp) → [@fedify-dev/amqp](https://github.com/fedify-dev/amqp) - [@dahlia/fedify-h3](https://github.com/dahlia/fedify-h3) → [@fedify-dev/h3](https://github.com/fedify-dev/h3) - [@dahlia/fedify-express](https://github.com/dahlia/fedify-express) → [@fedify-dev/express](https://github.com/fedify-dev/express) - [@dahlia/fedify-postgres](https://github.com/dahlia/fedify-postgres) → [@fedify-dev/postgres](https://github.com/fedify-dev/postgres) - [@dahlia/fedify-redis](https://github.com/dahlia/fedify-redis) → [@fedify-dev/redis](https://github.com/fedify-dev/redis) - [@dahlia/markdown-it-hashtag](https://github.com/dahlia/markdown-it-hashtag) → [@fedify-dev/markdown-it-hashtag](https://github.com/fedify-dev/markdown-it-hashtag) - [@dahlia/markdown-it-mention](https://github.com/dahlia/markdown-it-mention) → [@fedify-dev/markdown-it-mention](https://github.com/fedify-dev/markdown-it-mention) - [@dahlia/fedichatbot](https://github.com/dahlia/fedichatbot) → [@fedify-dev/fedichatbot](https://github.com/fedify-dev/fedichatbot) - [@dahlia/microblog](https://github.com/dahlia/microblog) → [@fedify-dev/microblog](https://github.com/fedify-dev/microblog) All repositories have been transferred and GitHub's automatic redirects are in place, so existing links will continue to work. Also, the project's core functionality and development process remain unchanged. Thanks to everyone who participated in our naming poll. Looking forward to Fedify's continued growth under its new organizational home! :fedify: New GitHub organization: <https://github.com/fedify-dev>. [@fedify-dev]: https://github.com/fedify-dev

We've just moved the project and related repositories to our new GitHub organization account, @fedify-dev! 🎉

Here's what moved:

All repositories have been transferred and GitHub's automatic redirects are in place, so existing links will continue to work. Also, the project's core functionality and development process remain unchanged.

Thanks to everyone who participated in our naming poll. Looking forward to Fedify's continued growth under its new organizational home!

:fedify: New GitHub organization: https://github.com/fedify-dev.

github.com

Fedify

A collection of development tools for fediverse. Fedify has 12 repositories available. Follow their code on GitHub.

@hollo@hollo.social · Reply to Hollo :hollo:

저장소가 @dahlia/hollo에서 @fedify-dev/hollo로 이전되었습니다. 이에 따라 이미지 레지스트리도 ghcr.io/dahlia/hollo에서 ghcr.io/fedify-dev/hollo로 이전되었습니다.

기존 이미지 레지스트리는 계속 접근 가능하지만, 새로운 태그는 더 이상 추가되지 않을 예정입니다. Hollo를 사용 중이신 모든 분들은 새로운 레지스트리 주소로 업데이트해 주시기 바랍니다.

Docker 설정을 다음과 같이 변경해 주세요:

  • 기존 이미지 주소: ghcr.io/dahlia/hollo:latest
  • 새 이미지 주소: ghcr.io/fedify-dev/hollo:latest

이번 이전은 프로젝트의 더 나은 운영과 지속적인 개발을 위해 진행되었습니다. 원활한 전환에 협조해 주셔서 감사합니다. :hollo:

https://hollo.social/@fedify/0194a851-581d-779c-b777-dc39e753ef14

hollo.social

We've just moved the #Fedify p…

We've just moved the #Fedify project and related repositories to our new GitHub organization account, [@fedify-dev]! 🎉 Here's what moved: - [@dahlia/fedify](https://github.com/dahlia/fedify) → [@fedify-dev/fedify](https://github.com/fedify-dev/fedify) - [@dahlia/botkit](https://github.com/dahlia/botkit) → [@fedify-dev/botkit](https://github.com/fedify-dev/botkit) - [@dahlia/hollo](https://github.com/dahlia/hollo) → [@fedify-dev/hollo](https://github.com/fedify-dev/hollo) - [@dahlia/fedify-amqp](https://github.com/dahlia/fedify-amqp) → [@fedify-dev/amqp](https://github.com/fedify-dev/amqp) - [@dahlia/fedify-h3](https://github.com/dahlia/fedify-h3) → [@fedify-dev/h3](https://github.com/fedify-dev/h3) - [@dahlia/fedify-express](https://github.com/dahlia/fedify-express) → [@fedify-dev/express](https://github.com/fedify-dev/express) - [@dahlia/fedify-postgres](https://github.com/dahlia/fedify-postgres) → [@fedify-dev/postgres](https://github.com/fedify-dev/postgres) - [@dahlia/fedify-redis](https://github.com/dahlia/fedify-redis) → [@fedify-dev/redis](https://github.com/fedify-dev/redis) - [@dahlia/markdown-it-hashtag](https://github.com/dahlia/markdown-it-hashtag) → [@fedify-dev/markdown-it-hashtag](https://github.com/fedify-dev/markdown-it-hashtag) - [@dahlia/markdown-it-mention](https://github.com/dahlia/markdown-it-mention) → [@fedify-dev/markdown-it-mention](https://github.com/fedify-dev/markdown-it-mention) - [@dahlia/fedichatbot](https://github.com/dahlia/fedichatbot) → [@fedify-dev/fedichatbot](https://github.com/fedify-dev/fedichatbot) - [@dahlia/microblog](https://github.com/dahlia/microblog) → [@fedify-dev/microblog](https://github.com/fedify-dev/microblog) All repositories have been transferred and GitHub's automatic redirects are in place, so existing links will continue to work. Also, the project's core functionality and development process remain unchanged. Thanks to everyone who participated in our naming poll. Looking forward to Fedify's continued growth under its new organizational home! :fedify: New GitHub organization: <https://github.com/fedify-dev>. [@fedify-dev]: https://github.com/fedify-dev

We've just moved the project and related repositories to our new GitHub organization account, @fedify-dev! 🎉

Here's what moved:

All repositories have been transferred and GitHub's automatic redirects are in place, so existing links will continue to work. Also, the project's core functionality and development process remain unchanged.

Thanks to everyone who participated in our naming poll. Looking forward to Fedify's continued growth under its new organizational home!

:fedify: New GitHub organization: https://github.com/fedify-dev.

github.com

Fedify

A collection of development tools for fediverse. Fedify has 12 repositories available. Follow their code on GitHub.

@hollo@hollo.social · Reply to Hollo :hollo:

저장소가 @dahlia/hollo에서 @fedify-dev/hollo로 이전되었습니다. 이에 따라 이미지 레지스트리도 ghcr.io/dahlia/hollo에서 ghcr.io/fedify-dev/hollo로 이전되었습니다.

기존 이미지 레지스트리는 계속 접근 가능하지만, 새로운 태그는 더 이상 추가되지 않을 예정입니다. Hollo를 사용 중이신 모든 분들은 새로운 레지스트리 주소로 업데이트해 주시기 바랍니다.

Docker 설정을 다음과 같이 변경해 주세요:

  • 기존 이미지 주소: ghcr.io/dahlia/hollo:latest
  • 새 이미지 주소: ghcr.io/fedify-dev/hollo:latest

이번 이전은 프로젝트의 더 나은 운영과 지속적인 개발을 위해 진행되었습니다. 원활한 전환에 협조해 주셔서 감사합니다. :hollo:

https://hollo.social/@fedify/0194a851-581d-779c-b777-dc39e753ef14

hollo.social

We've just moved the #Fedify p…

We've just moved the #Fedify project and related repositories to our new GitHub organization account, [@fedify-dev]! 🎉 Here's what moved: - [@dahlia/fedify](https://github.com/dahlia/fedify) → [@fedify-dev/fedify](https://github.com/fedify-dev/fedify) - [@dahlia/botkit](https://github.com/dahlia/botkit) → [@fedify-dev/botkit](https://github.com/fedify-dev/botkit) - [@dahlia/hollo](https://github.com/dahlia/hollo) → [@fedify-dev/hollo](https://github.com/fedify-dev/hollo) - [@dahlia/fedify-amqp](https://github.com/dahlia/fedify-amqp) → [@fedify-dev/amqp](https://github.com/fedify-dev/amqp) - [@dahlia/fedify-h3](https://github.com/dahlia/fedify-h3) → [@fedify-dev/h3](https://github.com/fedify-dev/h3) - [@dahlia/fedify-express](https://github.com/dahlia/fedify-express) → [@fedify-dev/express](https://github.com/fedify-dev/express) - [@dahlia/fedify-postgres](https://github.com/dahlia/fedify-postgres) → [@fedify-dev/postgres](https://github.com/fedify-dev/postgres) - [@dahlia/fedify-redis](https://github.com/dahlia/fedify-redis) → [@fedify-dev/redis](https://github.com/fedify-dev/redis) - [@dahlia/markdown-it-hashtag](https://github.com/dahlia/markdown-it-hashtag) → [@fedify-dev/markdown-it-hashtag](https://github.com/fedify-dev/markdown-it-hashtag) - [@dahlia/markdown-it-mention](https://github.com/dahlia/markdown-it-mention) → [@fedify-dev/markdown-it-mention](https://github.com/fedify-dev/markdown-it-mention) - [@dahlia/fedichatbot](https://github.com/dahlia/fedichatbot) → [@fedify-dev/fedichatbot](https://github.com/fedify-dev/fedichatbot) - [@dahlia/microblog](https://github.com/dahlia/microblog) → [@fedify-dev/microblog](https://github.com/fedify-dev/microblog) All repositories have been transferred and GitHub's automatic redirects are in place, so existing links will continue to work. Also, the project's core functionality and development process remain unchanged. Thanks to everyone who participated in our naming poll. Looking forward to Fedify's continued growth under its new organizational home! :fedify: New GitHub organization: <https://github.com/fedify-dev>. [@fedify-dev]: https://github.com/fedify-dev

We've just moved the project and related repositories to our new GitHub organization account, @fedify-dev! 🎉

Here's what moved:

All repositories have been transferred and GitHub's automatic redirects are in place, so existing links will continue to work. Also, the project's core functionality and development process remain unchanged.

Thanks to everyone who participated in our naming poll. Looking forward to Fedify's continued growth under its new organizational home!

:fedify: New GitHub organization: https://github.com/fedify-dev.

github.com

Fedify

A collection of development tools for fediverse. Fedify has 12 repositories available. Follow their code on GitHub.

@hollo@hollo.social · Reply to Hollo :hollo:

저장소가 @dahlia/hollo에서 @fedify-dev/hollo로 이전되었습니다. 이에 따라 이미지 레지스트리도 ghcr.io/dahlia/hollo에서 ghcr.io/fedify-dev/hollo로 이전되었습니다.

기존 이미지 레지스트리는 계속 접근 가능하지만, 새로운 태그는 더 이상 추가되지 않을 예정입니다. Hollo를 사용 중이신 모든 분들은 새로운 레지스트리 주소로 업데이트해 주시기 바랍니다.

Docker 설정을 다음과 같이 변경해 주세요:

  • 기존 이미지 주소: ghcr.io/dahlia/hollo:latest
  • 새 이미지 주소: ghcr.io/fedify-dev/hollo:latest

이번 이전은 프로젝트의 더 나은 운영과 지속적인 개발을 위해 진행되었습니다. 원활한 전환에 협조해 주셔서 감사합니다. :hollo:

https://hollo.social/@fedify/0194a851-581d-779c-b777-dc39e753ef14

hollo.social

We've just moved the #Fedify p…

We've just moved the #Fedify project and related repositories to our new GitHub organization account, [@fedify-dev]! 🎉 Here's what moved: - [@dahlia/fedify](https://github.com/dahlia/fedify) → [@fedify-dev/fedify](https://github.com/fedify-dev/fedify) - [@dahlia/botkit](https://github.com/dahlia/botkit) → [@fedify-dev/botkit](https://github.com/fedify-dev/botkit) - [@dahlia/hollo](https://github.com/dahlia/hollo) → [@fedify-dev/hollo](https://github.com/fedify-dev/hollo) - [@dahlia/fedify-amqp](https://github.com/dahlia/fedify-amqp) → [@fedify-dev/amqp](https://github.com/fedify-dev/amqp) - [@dahlia/fedify-h3](https://github.com/dahlia/fedify-h3) → [@fedify-dev/h3](https://github.com/fedify-dev/h3) - [@dahlia/fedify-express](https://github.com/dahlia/fedify-express) → [@fedify-dev/express](https://github.com/fedify-dev/express) - [@dahlia/fedify-postgres](https://github.com/dahlia/fedify-postgres) → [@fedify-dev/postgres](https://github.com/fedify-dev/postgres) - [@dahlia/fedify-redis](https://github.com/dahlia/fedify-redis) → [@fedify-dev/redis](https://github.com/fedify-dev/redis) - [@dahlia/markdown-it-hashtag](https://github.com/dahlia/markdown-it-hashtag) → [@fedify-dev/markdown-it-hashtag](https://github.com/fedify-dev/markdown-it-hashtag) - [@dahlia/markdown-it-mention](https://github.com/dahlia/markdown-it-mention) → [@fedify-dev/markdown-it-mention](https://github.com/fedify-dev/markdown-it-mention) - [@dahlia/fedichatbot](https://github.com/dahlia/fedichatbot) → [@fedify-dev/fedichatbot](https://github.com/fedify-dev/fedichatbot) - [@dahlia/microblog](https://github.com/dahlia/microblog) → [@fedify-dev/microblog](https://github.com/fedify-dev/microblog) All repositories have been transferred and GitHub's automatic redirects are in place, so existing links will continue to work. Also, the project's core functionality and development process remain unchanged. Thanks to everyone who participated in our naming poll. Looking forward to Fedify's continued growth under its new organizational home! :fedify: New GitHub organization: <https://github.com/fedify-dev>. [@fedify-dev]: https://github.com/fedify-dev

We've just moved the project and related repositories to our new GitHub organization account, @fedify-dev! 🎉

Here's what moved:

All repositories have been transferred and GitHub's automatic redirects are in place, so existing links will continue to work. Also, the project's core functionality and development process remain unchanged.

Thanks to everyone who participated in our naming poll. Looking forward to Fedify's continued growth under its new organizational home!

:fedify: New GitHub organization: https://github.com/fedify-dev.

github.com

Fedify

A collection of development tools for fediverse. Fedify has 12 repositories available. Follow their code on GitHub.

@hollo@hollo.social · Reply to Hollo :hollo:

저장소가 @dahlia/hollo에서 @fedify-dev/hollo로 이전되었습니다. 이에 따라 이미지 레지스트리도 ghcr.io/dahlia/hollo에서 ghcr.io/fedify-dev/hollo로 이전되었습니다.

기존 이미지 레지스트리는 계속 접근 가능하지만, 새로운 태그는 더 이상 추가되지 않을 예정입니다. Hollo를 사용 중이신 모든 분들은 새로운 레지스트리 주소로 업데이트해 주시기 바랍니다.

Docker 설정을 다음과 같이 변경해 주세요:

  • 기존 이미지 주소: ghcr.io/dahlia/hollo:latest
  • 새 이미지 주소: ghcr.io/fedify-dev/hollo:latest

이번 이전은 프로젝트의 더 나은 운영과 지속적인 개발을 위해 진행되었습니다. 원활한 전환에 협조해 주셔서 감사합니다. :hollo:

https://hollo.social/@fedify/0194a851-581d-779c-b777-dc39e753ef14

hollo.social

We've just moved the #Fedify p…

We've just moved the #Fedify project and related repositories to our new GitHub organization account, [@fedify-dev]! 🎉 Here's what moved: - [@dahlia/fedify](https://github.com/dahlia/fedify) → [@fedify-dev/fedify](https://github.com/fedify-dev/fedify) - [@dahlia/botkit](https://github.com/dahlia/botkit) → [@fedify-dev/botkit](https://github.com/fedify-dev/botkit) - [@dahlia/hollo](https://github.com/dahlia/hollo) → [@fedify-dev/hollo](https://github.com/fedify-dev/hollo) - [@dahlia/fedify-amqp](https://github.com/dahlia/fedify-amqp) → [@fedify-dev/amqp](https://github.com/fedify-dev/amqp) - [@dahlia/fedify-h3](https://github.com/dahlia/fedify-h3) → [@fedify-dev/h3](https://github.com/fedify-dev/h3) - [@dahlia/fedify-express](https://github.com/dahlia/fedify-express) → [@fedify-dev/express](https://github.com/fedify-dev/express) - [@dahlia/fedify-postgres](https://github.com/dahlia/fedify-postgres) → [@fedify-dev/postgres](https://github.com/fedify-dev/postgres) - [@dahlia/fedify-redis](https://github.com/dahlia/fedify-redis) → [@fedify-dev/redis](https://github.com/fedify-dev/redis) - [@dahlia/markdown-it-hashtag](https://github.com/dahlia/markdown-it-hashtag) → [@fedify-dev/markdown-it-hashtag](https://github.com/fedify-dev/markdown-it-hashtag) - [@dahlia/markdown-it-mention](https://github.com/dahlia/markdown-it-mention) → [@fedify-dev/markdown-it-mention](https://github.com/fedify-dev/markdown-it-mention) - [@dahlia/fedichatbot](https://github.com/dahlia/fedichatbot) → [@fedify-dev/fedichatbot](https://github.com/fedify-dev/fedichatbot) - [@dahlia/microblog](https://github.com/dahlia/microblog) → [@fedify-dev/microblog](https://github.com/fedify-dev/microblog) All repositories have been transferred and GitHub's automatic redirects are in place, so existing links will continue to work. Also, the project's core functionality and development process remain unchanged. Thanks to everyone who participated in our naming poll. Looking forward to Fedify's continued growth under its new organizational home! :fedify: New GitHub organization: <https://github.com/fedify-dev>. [@fedify-dev]: https://github.com/fedify-dev

We've just moved the project and related repositories to our new GitHub organization account, @fedify-dev! 🎉

Here's what moved:

All repositories have been transferred and GitHub's automatic redirects are in place, so existing links will continue to work. Also, the project's core functionality and development process remain unchanged.

Thanks to everyone who participated in our naming poll. Looking forward to Fedify's continued growth under its new organizational home!

:fedify: New GitHub organization: https://github.com/fedify-dev.

github.com

Fedify

A collection of development tools for fediverse. Fedify has 12 repositories available. Follow their code on GitHub.

@hollo@hollo.social · Reply to Hollo :hollo:

저장소가 @dahlia/hollo에서 @fedify-dev/hollo로 이전되었습니다. 이에 따라 이미지 레지스트리도 ghcr.io/dahlia/hollo에서 ghcr.io/fedify-dev/hollo로 이전되었습니다.

기존 이미지 레지스트리는 계속 접근 가능하지만, 새로운 태그는 더 이상 추가되지 않을 예정입니다. Hollo를 사용 중이신 모든 분들은 새로운 레지스트리 주소로 업데이트해 주시기 바랍니다.

Docker 설정을 다음과 같이 변경해 주세요:

  • 기존 이미지 주소: ghcr.io/dahlia/hollo:latest
  • 새 이미지 주소: ghcr.io/fedify-dev/hollo:latest

이번 이전은 프로젝트의 더 나은 운영과 지속적인 개발을 위해 진행되었습니다. 원활한 전환에 협조해 주셔서 감사합니다. :hollo:

https://hollo.social/@fedify/0194a851-581d-779c-b777-dc39e753ef14

hollo.social

We've just moved the #Fedify p…

We've just moved the #Fedify project and related repositories to our new GitHub organization account, [@fedify-dev]! 🎉 Here's what moved: - [@dahlia/fedify](https://github.com/dahlia/fedify) → [@fedify-dev/fedify](https://github.com/fedify-dev/fedify) - [@dahlia/botkit](https://github.com/dahlia/botkit) → [@fedify-dev/botkit](https://github.com/fedify-dev/botkit) - [@dahlia/hollo](https://github.com/dahlia/hollo) → [@fedify-dev/hollo](https://github.com/fedify-dev/hollo) - [@dahlia/fedify-amqp](https://github.com/dahlia/fedify-amqp) → [@fedify-dev/amqp](https://github.com/fedify-dev/amqp) - [@dahlia/fedify-h3](https://github.com/dahlia/fedify-h3) → [@fedify-dev/h3](https://github.com/fedify-dev/h3) - [@dahlia/fedify-express](https://github.com/dahlia/fedify-express) → [@fedify-dev/express](https://github.com/fedify-dev/express) - [@dahlia/fedify-postgres](https://github.com/dahlia/fedify-postgres) → [@fedify-dev/postgres](https://github.com/fedify-dev/postgres) - [@dahlia/fedify-redis](https://github.com/dahlia/fedify-redis) → [@fedify-dev/redis](https://github.com/fedify-dev/redis) - [@dahlia/markdown-it-hashtag](https://github.com/dahlia/markdown-it-hashtag) → [@fedify-dev/markdown-it-hashtag](https://github.com/fedify-dev/markdown-it-hashtag) - [@dahlia/markdown-it-mention](https://github.com/dahlia/markdown-it-mention) → [@fedify-dev/markdown-it-mention](https://github.com/fedify-dev/markdown-it-mention) - [@dahlia/fedichatbot](https://github.com/dahlia/fedichatbot) → [@fedify-dev/fedichatbot](https://github.com/fedify-dev/fedichatbot) - [@dahlia/microblog](https://github.com/dahlia/microblog) → [@fedify-dev/microblog](https://github.com/fedify-dev/microblog) All repositories have been transferred and GitHub's automatic redirects are in place, so existing links will continue to work. Also, the project's core functionality and development process remain unchanged. Thanks to everyone who participated in our naming poll. Looking forward to Fedify's continued growth under its new organizational home! :fedify: New GitHub organization: <https://github.com/fedify-dev>. [@fedify-dev]: https://github.com/fedify-dev

We've just moved the project and related repositories to our new GitHub organization account, @fedify-dev! 🎉

Here's what moved:

All repositories have been transferred and GitHub's automatic redirects are in place, so existing links will continue to work. Also, the project's core functionality and development process remain unchanged.

Thanks to everyone who participated in our naming poll. Looking forward to Fedify's continued growth under its new organizational home!

:fedify: New GitHub organization: https://github.com/fedify-dev.

github.com

Fedify

A collection of development tools for fediverse. Fedify has 12 repositories available. Follow their code on GitHub.

@hongminhee@fosstodon.org · Reply to 洪 民憙 (Hong Minhee)

安寧하세요, 저는 서울에 살고 있는 30代 後半 오픈 소스 소프트웨어 엔지니어이며, 自由·오픈 소스 소프트웨어와 聯合宇宙의 熱烈한 支持者입니다.

저는 TypeScript用 ActivityPub 서버 프레임워크인 @fedify 프로젝트와 싱글 유저用 聯合宇宙 마이크로블로그인 @hollo 프로젝트의 製作者이기도 합니다.

저는 東아시아 언어(이른바 )와 유니코드에도 關心이 많습니다. Mastodon에서는 國漢文混用體를 쓰고 있어요! 제게 韓國語나 英語, 日本語로 말을 걸어주세요. (아니면, 漢文으로도!)

프레임워크는 () 개발에 중요한 기능들을 기본으로 내장하고 있습니다: