Serein
Rust로 만든 가볍고 성능 좋은 Discord 전용 네이티브 클라이언트
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기LurkStack — a real, deployable, multi-user text-only social feed (Next.js 15, Better Auth, Drizzle, Neon Postgres, Playwright)
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
A real, deployable, multi-user text-only social feed — built for the MarkTrack
Agentic Engineer Intern assessment.
Guests can read everything. Any signed-in user can post, comment, react, and
edit or delete any post, regardless of who wrote it. That last rule is
deliberate and unusual; it is implemented exactly as specified, with no
ownership check anywhere in the codebase.
Every value lives in .env.local (gitignored). .env.example ships with empty
placeholders only — no real secret is ever committed.
Monitoring is additive. With no Telegram or Puter configuration the app behaves
identicaREADME 전문 보기 ↗A real, deployable, multi-user text-only social feed — built for the MarkTrack Agentic Engineer Intern assessment.
Guests can read everything. Any signed-in user can post, comment, react, and edit or delete any post, regardless of who wrote it. That last rule is deliberate and unusual; it is implemented exactly as specified, with no ownership check anywhere in the codebase.
| Concern | Choice |
|---|---|
| Framework | Next.js 15 (App Router), React 19 |
| Language | TypeScript, strict |
| Styling | Tailwind CSS v4, shadcn/ui-style primitives (Radix), Lucide |
| Auth | Better Auth 1.7 (email + password, Drizzle adapter) |
| Database | PostgreSQL (Neon) via Drizzle ORM + pg |
| Tests | Playwright (21 end-to-end tests) |
| Deploy | Netlify |
npm install
cp .env.example .env.local # then fill in the values below
npm run db:migrate # create the schema
npm run db:seed # 8 users, 40 posts, 39 comments, 140 likes
npm run dev # http://localhost:3000
Every value lives in .env.local (gitignored). .env.example ships with empty
placeholders only — no real secret is ever committed.
| Variable | Required | Purpose |
|---|---|---|
DATABASE_URL | yes | PostgreSQL / Neon connection string |
BETTER_AUTH_SECRET | yes | Session signing secret |
BETTER_AUTH_URL | yes | Public base URL the auth handler trusts |
NEXT_PUBLIC_APP_URL | yes | Public base URL for the browser auth client |
TELEGRAM_BOT_TOKEN | no | Alert delivery; app works without it |
TELEGRAM_CHAT_ID | no | Alert destination |
PUTER_AUTH_TOKEN | no | Optional AI summary of an incident |
CRON_SECRET | no | Bearer token for /api/cron/health |
AUTH_RATE_LIMIT_WINDOW | no | Credential throttle window, seconds (default 300) |
AUTH_RATE_LIMIT_MAX | no | Credential throttle attempts (default 60) |
Monitoring is additive. With no Telegram or Puter configuration the app behaves identically — alerts are simply not sent.
Created by npm run db:seed, password Password123! for both:
| Name | |
|---|---|
| Aisha Rahman | [email protected] |
| Yusuf Khan | [email protected] |
These are documented here and in the seed output only. The public login page
is a plain login form and never displays demo credentials, development hints, or
a "demo accounts" block. (tests/auth.spec.ts asserts this.)
Six further seeded users, 40 posts, 39 comments and 140 likes make the feed look like something people actually use.
Two rules, both enforced server-side from the Better Auth session. The client is never trusted for identity.
1. Any authenticated user can mutate any post.
editPost and deletePost in lib/actions/posts.ts resolve the current user,
verify a session exists, and then act. There is no authorId === user.id
comparison anywhere in the repository — by design. The Edit and Delete menu
items are likewise never hidden based on ownership.
2. Guests can read, never write.
/, /u/[id], posts, comments and counts are all publicly readable. Every
mutation returns UNAUTHENTICATED for a guest and is recorded as a blocked
authorization event. In the UI, a guest action opens an authentication gate
dialog that links to /login and /signup with a next parameter, rather than
failing silently.
| Route | Access | Notes |
|---|---|---|
/ | public | Server-rendered feed, newest first |
/u/[id] | public | Public profile + that user's posts |
/login | public | Email + password |
/signup | public | Name, email, password |
/api/auth/[...all] | public | Better Auth handler |
/api/health | public | Machine-readable health, no secrets |
/api/cron/health | CRON_SECRET | Scheduled health probe |
The UI is honest about the network, not optimistic to a fault:
online/offline events plus request outcome.lib/monitor/ records structured audit events to the audit_event table:
signup · login success/failure · logout · create/edit/delete post · comment · like/unlike · blocked unauthenticated mutations · auth/session anomalies · unexpected server errors · database errors.
Design rules, all of which are load-bearing:
lib/monitor/rules.ts assigns severity from the event
itself. AI never decides what happened; it may only summarise.allowed, never a violation. Guest mutation is
blocked and is a genuine authorization event.repeatCount; alerts render it as Repeated events: N.void record(...). Every send is wrapped and
failure-isolated; the request path never awaits Telegram or Puter.requestId./api/health returns real checks (database round-trip, required config) with
503 when unhealthy. /api/cron/health is a lightweight scheduled path guarded
by CRON_SECRET.
npx playwright test # 21 tests, ~1.2 min
Covers signup, login, logout, session persistence, guest feed, guest auth gate,
guest server-side rejection, create/edit/delete post, cross-user edit,
cross-user delete, comments, likes, duplicate-like prevention, profiles,
not-found, seeded data, and /api/health.
The two cross-user tests are permanent: they are the clearest expression of the specification, and deleting them would hide a regression.
npm run typecheck, npx next lint and npx next build are all clean.
Better Auth's limiter is enabled and real. It was tuned after a genuine bug:
the default global limit throttled /get-session as well as the credential
endpoints, so a signed-in user who made enough page loads began silently seeing
the guest UI. Credential endpoints keep a tight per-IP throttle; read-only
session checks get a much higher ceiling.
| Command | Purpose |
|---|---|
npm run dev | Development server |
npm run build | Production build |
npm run start | Serve the production build |
npm run typecheck | tsc --noEmit |
npm run lint | ESLint |
npm test | Playwright |
npm run db:generate | Generate a Drizzle migration |
npm run db:migrate | Apply migrations |
npm run db:seed | Reset and seed realistic data |
DATABASE_URL, BETTER_AUTH_SECRET, BETTER_AUTH_URL and
NEXT_PUBLIC_APP_URL (BETTER_AUTH_URL and NEXT_PUBLIC_APP_URL must be the
deployed HTTPS origin).CRON_SECRET variables.npm run db:migrate && npm run db:seed against the deployed database./api/health returns {"status":"ok"}.Intentionally not built: messaging, follows, notifications, admin, payments, file or image uploads, AI chat, and unrelated settings. Posts are text-only.