尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 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])
}