尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证Open-source alternative to YC-controller HN
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗Open-source alternative to YC-controlled HN, featuring curated tech news, discussions, and community-driven content.
Refetch was born from a simple yet powerful idea: create a modern, open-source alternative to Hacker News that combines the best of community-driven curation with intelligent AI-powered content discovery. Free from YC-control, open and transparent, doesn't favor anyone.
j/k to move, o to open, u to upvote, s to save, ? for every shortcutWhile Hacker News has been the go-to platform for tech discussions for years, we believe there's room for innovation. Refetch brings:
DESIGN.md.posts, comments, votes, daily_topics and topics, plus channels and channel_members for channels, profiles, user_follows and user_blocks for people, and conversations, conversation_members, messages and message_reactions for messages. The web app reads and writes them on the server with an API key, exactly as before (same tables, columns, counters and rate limits; posts gain an optional channel column).httpOnly cookie, so pages render signed-in on the first byte. The API key never creates sessions./avatars/photo: uploaded photo, OAuth picture, Gravatar, then initials).functions/.refetch/
├── src/
│ ├── routes/ # File-based routes (TanStack Router)
│ │ ├── _app/ # Feeds, channels, threads, submit (app shell)
│ │ ├── _auth/ # Sign in / sign up
│ │ ├── auth/callback.ts # "Continue with Appwrite" OAuth callback
│ │ └── api/og/ # Social images (/api/og/thread/:id)
│ ├── api/ # Server functions (RPC) called by the UI
│ ├── server/ # Server-only Appwrite code (*.server.ts)
│ ├── components/
│ │ ├── ui/ # Design system primitives
│ │ └── … # Feature components (feed, channels, thread, insights, layout, command center)
│ ├── lib/ # Shared types, queries, utilities
│ └── styles/app.css # Design tokens (Tailwind v4 @theme)
├── functions/ # Appwrite Functions
│ ├── scout/ # Content discovery automation
│ ├── enhancement/ # AI content analysis
│ ├── algorithm/ # Ranking algorithm
│ ├── topic-stats/ # Topic ranking (scheduled)
│ └── channels/ # Pulls each channel's sources (scheduled)
├── scripts/appwrite-setup.mjs # Creates/updates tables, indexes and function shells
├── scripts/channels.json # Channel catalog: names, colors, keywords and sources
├── scripts/channel-icons/ # Channel icons (PNG), uploaded to Storage by appwrite:setup
├── extensions/ # Browser extension
├── public/ # Static assets
└── DESIGN.md # Design system guide
Clone the repository
git clone https://github.com/refetch-io/refetch.git
cd refetch
Install dependencies
pnpm install
Set up environment variables
cp env.example .env
Fill it in using Environment variables as a checklist.
Run the development server
pnpm dev
Open your browser at http://localhost:3000
| Script | What it does |
|---|---|
pnpm dev | Start the dev server on port 3000 |
pnpm build | Run appwrite:setup, then build the app (used by Appwrite Sites) |
pnpm build:app | Build the app only |
pnpm preview | Serve the production build locally |
pnpm typecheck | Type-check the project |
pnpm test | Run the unit tests (Vitest) |
pnpm format | Format with Prettier (Tailwind classes sorted) |
pnpm appwrite:setup | Create or update the database, tables, indexes and function shells |
Where to set them
.env locally, or the site's environment variables. Everything is read on the server — nothing is exposed to the browser except the Appwrite endpoint and project ID (needed for favicons).NEXT_PUBLIC_APPWRITE_ENDPOINT, NEXT_PUBLIC_APPWRITE_PROJECT_ID and NEXT_PUBLIC_BASE_URL names are still honored, so existing deployments keep working.Table IDs use the legacy name *_COLLECTION_ID but refer to Appwrite Tables table IDs.
| Variable | Description |
|---|---|
APPWRITE_ENDPOINT | REST API base (e.g. https://fra.cloud.appwrite.io/v1). |
APPWRITE_PROJECT_ID | Project ID. |
APPWRITE_API_KEY | Server API key with table/row access. Sign-in runs in the browser, so it doesn't need session scopes. |
SESSION_SECRET | Optional. Signs the session cookie; derived from the API key when unset (rotating the key then signs everyone out). |
| Variable | Description |
|---|---|
APPWRITE_DATABASE_ID | Tables DB database ID. |
APPWRITE_POSTS_COLLECTION_ID | posts table. |
APPWRITE_COMMENTS_COLLECTION_ID | comments table. |
APPWRITE_VOTES_COLLECTION_ID | votes table. |
APPWRITE_KEYS_COLLECTION_ID | keys table (personal API keys; secrets encrypted). |
APPWRITE_DAILY_TOPICS_COLLECTION_ID | daily_topics table (topic stats). Defaults to daily_topics. |
APPWRITE_TOPICS_COLLECTION_ID | topics table (topic stats). |
APPWRITE_CHANNELS_COLLECTION_ID | channels table. Defaults to channels. |
APPWRITE_CHANNEL_MEMBERS_COLLECTION_ID | channel_members table (who joined what). Defaults to channel_members. |
APPWRITE_CHANNEL_ICONS_BUCKET_ID | Public Storage bucket for channel icons (PNG). Defaults to channel-icons. |
APPWRITE_PROFILES_COLLECTION_ID | profiles table (name, bio, website, who can message you). Defaults to profiles. |
APPWRITE_FOLLOWS_COLLECTION_ID | user_follows table. Defaults to user_follows. |
APPWRITE_BLOCKS_COLLECTION_ID | user_blocks table. Defaults to user_blocks. |
APPWRITE_CONVERSATIONS_COLLECTION_ID | conversations table (direct and group). Defaults to conversations. |
APPWRITE_CONVERSATION_MEMBERS_COLLECTION_ID | conversation_members table (read state, unread counts, mute). Defaults to conversation_members. |
APPWRITE_MESSAGES_COLLECTION_ID | messages table. Defaults to . |
| Variable | Description |
|---|---|
SITE_URL | Canonical public origin for SEO metadata, social cards, the sitemap and links in emails (default https://refetch.io). |
MODERATOR_USER_IDS | Optional. Comma-separated user IDs who can review reports, besides accounts with the moderator or admin label. |
APPWRITE_ANALYTICS_PROPERTY_ID | Optional. Appwrite Analytics property. Pageviews and custom events are sent from production hosts only; the server reads it back for “refetchers online” and the visitors chart (needs analytics.read on the API key). |
| Variable | Description |
|---|---|
OPENAI_API_KEY | Scout and Enhancement. |
OPENAI_MODEL | OpenAI chat model for Scout and Enhancement; set as a global project variable (optional; default gpt-4o-mini). |
Actor identity, LLM batching, scraping delays, and per-run limits are constants in functions/scout/index.js (not environment variables).
| Variable | Description |
|---|---|
SCOUT_TARGET_WEBSITES | Comma-separated site roots to crawl (can be very long). |
YOUTUBE_API_KEY | Optional. YouTube Data API v3 key; Scout uses it to fetch subscriber counts for the channels in functions/scout/youtube-channels.json, which feed ranking. |
Bootstrap (scripts/appwrite-setup.mjs): npm run build runs this first; it uses the same Appwrite connection and data IDs to create or update the database, tables, indexes, and function shells (not deployments or function env).
| Part | Groups |
|---|---|
| Web app | 1, 2, 3 |
| Scout | 1, 2, 4, 5 |
| Enhancement | 1, 2, 4 |
| Algorithm | 1, 2 (posts only) |
| Topic stats | 1, 2 (incl. daily_topics + topics) |
| Channels | 1, 2 (posts + channels) |
rows.read, rows.write, tables.read for the feeds, votes and comments, plus analytics.read for “refetchers online” and the visitors chart. Sign-in happens in the browser, so no session scopes are needed./auth/callback.refetch.io, localhost) so OAuth redirects are accepted.pnpm appwrite:setup also creates the profile, follow, block and messaging tables. Profiles are written when people sign in (the server key doesn't need users.read); people who haven't signed in since are shown from their posts and comments. Messages refresh by polling (every few seconds in an open conversation).pnpm appwrite:setup adds the posts.channel column, creates channels and channel_members, seeds the catalog from scripts/channels.json (member counts are kept), uploads each icon from scripts/channel-icons to the public channel-icons bucket and creates the scheduled Channels function. Deploy functions/channels to start the content flowing. Until the setup runs, the app serves the bundled catalog and matches stories by topic, but joining is unavailable.pnpm appwrite:setup creates the notifications table. Emails go out through Appwrite Messaging: add an email provider (SMTP, Resend, Mailgun…) in Messaging → Providers and give the API key the messages.write scope. Until then the bell works and emails are skipped.moderator (or admin) label to an account in Auth → Users, or list its ID in MODERATOR_USER_IDS. Labels are read when someone signs in, so sign out and back in after adding one. The queue lives at .| Setting | Value |
|---|---|
| Framework | TanStack Start |
| Install command | pnpm install (or npm install) |
| Build command | npm run build |
| Output directory | ./dist |
Add the environment variables above to the site. npm run build runs appwrite:setup first; use build:app instead if you don't want the build to touch your Appwrite schema.
Refetch's UI follows a small, Apple-inspired design system: semantic color tokens (light + dark), Poppins titles over the SF Pro type scale, inset grouped lists, frosted materials and spring-based motion — all on the original Refetch purple. Read DESIGN.md for guidelines. A live component catalog runs at /design in every environment; it is unlisted and not indexed.
Refetch was initially 100% vibe-coded, but we're excited to welcome contributions from humans too!
We believe in the power of community-driven development and welcome all types of contributions:
git checkout -b feature/amazing-feature
pnpm typecheck && pnpm test && pnpm build:app; CI runs the same checks on every pull request)Refetch uses several Appwrite serverless functions for automated content processing:
Automatically discovers high-quality tech content from 20+ sources including TechCrunch, The Verge, Ars Technica, and more.
AI-powered content analysis that generates metadata, quality scores and summaries.
Sophisticated ranking algorithm that considers time decay, quality metrics, and community engagement.
Scheduled job that aggregates post data into daily_topics and topics tables (see Environment variables). Until it runs, the web app computes “Trending today” live from the last 24 hours of posts.
Runs every two hours (at :15). For each channel in channels, it reads the official feeds first (blogs, release notes, GitHub releases), falls back to community feeds (mostly DEV tags) when those have nothing new, and posts at most one fresh story per channel as Scout, tagged with that channel. Enhancement then scores and summarizes it like any other story. Stories also reach channels when their AI topics match a channel's keywords. To add a channel, add it to scripts/channels.json, drop a square PNG icon (256×256, full bleed; the app rounds the corners) at scripts/channel-icons/<id>.png and run pnpm appwrite:setup. You can also upload an icon to the channel-icons bucket in the Console and put its file ID in the channel's icon column.
This project is licensed under the MIT License - see the LICENSE file for details.
messagesAPPWRITE_MESSAGE_REACTIONS_COLLECTION_ID | message_reactions table. Defaults to message_reactions. |
APPWRITE_NOTIFICATIONS_COLLECTION_ID | notifications table (the bell). Defaults to notifications. |
APPWRITE_SAVES_COLLECTION_ID | saves table (saved stories). Defaults to saves. |
APPWRITE_REPORTS_COLLECTION_ID | reports table (the moderation queue). Defaults to reports. |
/moderation