Serein
Rust로 만든 가볍고 성능 좋은 Discord 전용 네이티브 클라이언트
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Production-grade Liberia-focused petition platform with verification, trust scoring, and conversion-first UX.
🎉 Phase 1 Complete: Block-Based CMS System
Status: ✅ PRODUCTION READY (May 9, 2026)README 전문 보기 ↗Production-grade Liberia-focused petition platform with verification, trust scoring, and conversion-first UX.
Status: ✅ PRODUCTION READY (May 9, 2026)
apps/web - conversion-optimized web appapps/api - REST API with trust, fraud, and admin modulespackages/ui - shared UI primitivespackages/types - shared typespackages/config - shared config packagecp .env.example .envpnpm installpnpm --filter api prisma:generatepnpm --filter api prisma:migrate --name initpnpm seedpnpm devDISCOVER -> EMOTIONAL TRIGGER -> SIGN -> SHARE -> VIRAL GROWTH
Implemented with:
/api/v1/auth/*/api/v1/petitions/*/api/v1/signatures/api/v1/verification/*/api/v1/admin/*/api/v1/fraud/rules/api/v1/fraud/analytics/api/v1/fraud/jobs/anomaly-scan/api/v1/petitions/:id/updates/api/v1/petitions/:id/comments/api/v1/petitions/:id/approve / /api/v1/petitions/:id/reject (admin, JWT)/api/v1/verification/id-document (submit ID for review; legacy /verification/id remains for dev)/api/v1/verification/id-documents/:id/file (JWT: owner or admin — stream or redirect)/api/v1/admin/id-documents/* (pending queue + status updates)/api/v1/users/me/petitions/api/v1/docs (Swagger UI)mock, Cloudflare Turnstile, or hCaptcha (CAPTCHA_PROVIDER, secrets in .env)NEXT_PUBLIC_TURNSTILE_SITE_KEY for real Turnstile widget on high-risk signatures (falls back to mock token flow when unset)FraudJob queue + cron enqueue + per-minute worker (FraudScheduler)GET /metrics (root path, not under /api/v1) — vlv_fraud_risk_index, vlv_fraud_queue_depth, vlv_captcha_verifications_total, etc.GET /health (liveness), GET /health/ready (DB readiness)riskIndex exceeds FRAUD_RISK_ALERT_THRESHOLD, vlv_fraud_anomaly_alerts_total incrementsGET /api/v1/fraud/metrics (aggregate view for admin UIs)POST /api/v1/petitions/:id/updates (JWT); public GET /api/v1/petitions/:id/updates for approved petitions.GET /api/v1/petitions/:id/comments and POST /api/v1/petitions/:id/comments (optional JWT; stricter rate limit). Petition page loads updates + comments and supports posting comments.GET http://localhost:4000/api/v1/docs (after global prefix).POST /api/v1/verification/id-document; each submission creates an IDDocument in PENDING until an admin reviews it. Transport and on-disk storage (multipart file vs. JSON fileUrl, local uploads/, and public URL prefix) are defined in Phase 8 below.GET /api/v1/admin/id-documents/pending and PATCH /api/v1/admin/id-documents/:id to approve/reject; on first approval, ID_UPLOAD trust event (+30) is applied once per user.GET /api/v1/users/me/petitions powers /dashboard; web auth uses Zustand persist for session continuity.PATCH /petitions/:id/approve / reject).User.role is USER or ADMIN (JWT is validated against the database on each request). All /api/v1/admin/* routes, all /api/v1/fraud/* routes, and PATCH /api/v1/petitions/:id/approve / reject require ADMIN.pnpm seed, user +231770000001 has ADMIN (sign in via your auth flow, then open /admin in the web app). In production, assign ADMIN in the database (or a one-off script); do not rely on seed data for real moderators.POST /api/v1/verification/id-document accepts multipart/form-data (type + file, JPEG/PNG/PDF up to 5 MB) or JSON { type, fileUrl } for an already-hosted URL. Uploaded files are written under uploads/id-documents/. GET /api/v1/verification/id-documents/:id/file (JWT) streams the file to the document owner or an admin; external fileUrl values redirect only to http:/https: targets. There is no anonymous public /uploads static route. Set ID_DOCUMENT_PUBLIC_BASE_URL so stored metadata URLs stay consistent with your API origin. For stronger privacy and scale, plan private object storage (S3-compatible) and short-lived URLs—this repo defaults to local disk + optional remote fileUrl.NODE_ENV=production), OpenAPI UI is off unless ENABLE_SWAGGER=true. When Swagger is off, Helmet’s default Content-Security-Policy is enabled; when Swagger is on, CSP is relaxed for the docs UI.api_uploads at /app/apps/api/uploads so ID files survive container restarts.JWT_SECRET, database credentials, and CAPTCHA/Twilio keys; never commit real .env files.CORS_ORIGIN to your real web origins (comma-separated). Set web NEXT_PUBLIC_API_URL and server API_URL_INTERNAL (Docker/K8s service URL) to the deployed API. Terminate TLS at your reverse proxy or load balancer.ENABLE_SWAGGER=false in production unless operators need in-browser docs; prefer network restriction if you enable it. Use real CAPTCHA_PROVIDER (Turnstile or hCaptcha) with valid keys.ID_DOCUMENT_PUBLIC_BASE_URL to the public API URL; use a persistent volume for uploads/. Files are served only via GET /api/v1/verification/id-documents/:id/file (owner or admin). Plan object storage + access policies for serious deployments.User.role = ADMIN; audit via database./health, /health/ready, and /metrics as appropriate for your environment.pnpm install, pnpm dev (API + web via Turbo). Ensure Postgres is up and migrations are applied (pnpm --filter api prisma migrate deploy).pnpm lint, pnpm typecheck, pnpm test (API smoke e2e, no DB), pnpm build.pnpm seed for sample data and a seeded admin phone (+231770000001).pnpm docker:up — Postgres, API (migrations on start when RUN_MIGRATIONS_ON_START=true), and web (Next standalone).apps/api/Dockerfile, apps/web/Dockerfile; build context is the repo root.API_URL_INTERNAL on the web service (e.g. http://api:4000/api/v1) so RSC/SSR can reach the API; browsers still use NEXT_PUBLIC_API_URL (e.g. http://localhost:4000/api/v1)..github/workflows/ci.yml runs install, typecheck, lint, and build on push/PR to main/master.CORS_ORIGIN (comma-separated origins, or omit for permissive dev).A modern, database-driven content management system enabling admins to build pages visually without code.
/about, /how-it-works, /help-center without redeployingCMSPage + CMSBlock models)GET /api/cms/pages/:slug # Public: fetch page with blocks
GET /api/cms/pages/:pageId/blocks # Admin: list blocks
POST /api/cms/pages/:pageId/blocks # Admin: create block
PATCH /api/cms/blocks/:blockId # Admin: update block
DELETE /api/cms/blocks/:blockId # Admin: delete block
/about, /how-it-works, /help-centerapps/api/src/cms/
├── cms.service.ts # Business logic
├── cms.controller.ts # API endpoints
└── cms.dto.ts # Validation
apps/web/components/
├── cms-block-renderer.tsx # Render any block type
└── cms-page-block-editor.tsx # Admin visual editor (380+ lines)
apps/web/lib/
└── cms.ts # Types & utilities
apps/web/app/
├── about/page.tsx # Block-based (5 blocks)
├── how-it-works/page.tsx # Block-based (4 blocks)
├── help-center/page.tsx # Block-based (5 blocks)
└── admin/
└── admin-page-client.tsx # Editor integrated
model CMSPage {
id String @id @default(cuid())
title String
slug String @unique
blocks CMSBlock[] @relation(onDelete: Cascade)
published Boolean @default(false)
metadata String? @db.Text()
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model CMSBlock {
id String @id @default(cuid())
pageId String
page CMSPage @relation(fields: [pageId], references: [id], onDelete: Cascade)
type String # hero|text|image|grid|cta|testimonial|divider|faq|features
order Int # Position in page
props String @db.Text() # JSON-stringified properties
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([pageId, order])
@@index([pageId, order])
}