A full-stack Reddit-like community discussion platform with AI-powered moderation.
Live at ripplet.me
Fork (remix) this project on Replit — no setup required, just click the link and it spins up in your own Replit workspace with a single click. New to Replit? Sign up with this referral link to get started.
- Browse & discover all communities from the Forums page with live search by name or description
- Sorted by activity — forums are ranked by combined member and post count; the General community is always pinned first
- Join / leave any community — your personal feed on the Home page shows only forums you have joined
- Member and post counts update in real time — counts reflect the latest state immediately after joining, leaving, or deleting a post across all pages (home feed, forums list, forum detail panel)
- Slug-based URLs — communities have clean, human-readable URLs like
/forums/general-discussion
- Create posts with a title, optional body (Markdown supported), and an image or video attachment
- Image & video uploads — attach media directly when creating a post
- Vote-free but reaction-rich — express yourself with emoji reactions on any post or comment
- Share a direct link to any post via the share button
- Nested threads — reply to any comment up to 5 levels deep
- Emoji reactions on comments as well as posts
- Real-time feel — comment counts update immediately after submitting
- Profile pages at
/user/:username— view any member's avatar, role badge, bio, join date, and their full post history - Public & private profiles — toggle your profile between public (visible to everyone) and private (visible only to yourself and admins) from the Edit Profile dialog
- Edit profile — update your display name, bio, and privacy setting from one place
- Replit Auth — one-click sign-in with your Replit account; no separate password needed
- Persistent sessions — sessions last 7 days based on database TTL; OIDC token refresh is best-effort and never logs you out silently if a refresh fails
- Hidden posts and shadow-banned users are masked automatically so the community feed stays clean
USER → MODERATOR → ADMIN → SUPER_ADMIN
- AI Moderation per forum — enable Claude AI to automatically moderate posts against custom instructions and a negative-prompt blocklist
- AI-authored posts — let the AI generate its own discussion posts on a configurable schedule (daily / twice-weekly / monthly)
- Model selection per forum — Claude Haiku (fast), Sonnet (balanced), or Opus (most capable)
- Hide / unhide any post or comment to remove it from public view without deleting it
| Section | What you can do |
|---|---|
| Dashboard | Site-wide stats — total users, forums, posts, comments |
| Users | Search users, change roles (USER → SUPER_ADMIN), shadow-ban / unban |
| Forums | Search forums by name or description (live filter with result count); view member and post counts; dissolve a forum by moving all its posts to another forum or purging them entirely; delete empty forums |
| Config | Site-wide settings stored in the database |
| Integrations | Configure Google reCAPTCHA keys |
| Audit Log | Full history of every moderation and admin action with actor, target, and timestamp |
- A maximum of 100 forums can exist at any one time. Attempting to create more is blocked at the API level.
- Google reCAPTCHA v2/v3 — protect post and comment forms from spam bots; disable any time by clearing the keys
| Layer | Technology |
|---|---|
| Frontend | React + Vite + TypeScript + Tailwind CSS + shadcn/ui |
| Backend | Express (Node.js) + TypeScript |
| Database | PostgreSQL via Drizzle ORM |
| Auth | Replit Auth (OIDC + PKCE) |
| AI | Anthropic Claude (via Replit AI Integrations) |
| Monorepo | pnpm workspaces |
| API Spec | OpenAPI 3.0 + Orval (codegen) |
ripplet.me/
├── artifacts/
│ ├── api-server/ # Express REST API
│ └── ripplet/ # React frontend
├── lib/
│ ├── api-client-react/ # Generated React Query hooks (from OpenAPI)
│ ├── api-spec/ # OpenAPI spec + Orval config
│ ├── api-zod/ # Generated Zod validators (from OpenAPI)
│ ├── db/ # Drizzle ORM schema + migrations
│ └── integrations-anthropic-ai/ # Anthropic AI client
└── LICENSE
| Route | Description |
|---|---|
/ |
Home feed — recent posts across all joined communities |
/forums |
Browse and search all communities |
/forums/:slug |
Community page with posts and member info |
/forums/:slug/settings |
Forum settings & AI moderation config (moderators+) |
/ripple/create |
Create a new post (text, image, or video) |
/ripple/:postId |
Post detail with threaded comments and reactions |
/user/:username |
Public user profile — avatar, role, bio, join date, posts |
/about |
About page |
/terms |
Terms of service |
/privacy |
Privacy policy |
/admin |
Admin dashboard (admins only) |
/admin/users |
User management — roles, shadow bans |
/admin/forums |
Forum management — dissolve, delete |
/admin/config |
Site-wide config editor |
/admin/integrations |
reCAPTCHA key management |
/admin/audit |
Moderation audit log |
/admin/reports |
Reported content review |
- Node.js 18+
- pnpm 8+
- PostgreSQL database
These must be set as environment secrets before the server can start. None of them are optional.
| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
✅ | PostgreSQL connection string (e.g. postgres://user:pass@host:5432/db) |
SESSION_SECRET |
✅ | Long random string used to sign session cookies — generate with openssl rand -hex 32 |
REPL_ID |
✅ | Replit application ID — available automatically when running on Replit; required for OpenID Connect authentication |
AI_INTEGRATIONS_ANTHROPIC_BASE_URL |
✅ | Base URL for the Anthropic API proxy — provided by Replit AI Integrations |
AI_INTEGRATIONS_ANTHROPIC_API_KEY |
✅ | API key for the Anthropic proxy — provided by Replit AI Integrations |
PORT |
— | API server port (default: 8080) |
CORS_ORIGINS |
— | Comma-separated list of extra allowed CORS origins (e.g. https://ripplet.me,https://www.ripplet.me). Required when the app is served from a custom domain. |
SUPER_ADMIN_EMAIL |
— | Email address of the user who should be automatically granted the SUPER_ADMIN role on login. If unset, no one is auto-elevated — you can still grant roles manually via the database. |
VITE_GA_MEASUREMENT_ID |
— | Google Analytics 4 Measurement ID (e.g. G-XXXXXXXXXX). Baked into the frontend at build time. Page-view tracking is silently disabled if unset. |
Note:
REPL_ID,AI_INTEGRATIONS_ANTHROPIC_BASE_URL, andAI_INTEGRATIONS_ANTHROPIC_API_KEYare injected automatically when the project is run inside Replit. If you are self-hosting, you will need to supply a realREPL_IDand connect to the upstream Anthropic API directly (update the base URL and key accordingly).
Set the SUPER_ADMIN_EMAIL environment variable to the email address of the account that should have full super admin access. On every login, if the authenticated user's email matches this value, they are automatically promoted to SUPER_ADMIN.
SUPER_ADMIN_EMAIL=you@example.com
If you remix this project on Replit, set this in the Secrets panel (environment: Shared) before your first login. If the variable is not set, no one is auto-elevated — the SUPER_ADMIN role can still be granted directly in the database if needed.
GA4 tracking is configured via the VITE_GA_MEASUREMENT_ID environment variable. The value is embedded into the frontend HTML at build time, so a rebuild and redeploy is required when the Measurement ID changes.
| Variable | Where to find it | Effect if missing |
|---|---|---|
VITE_GA_MEASUREMENT_ID |
Google Analytics → Admin → Data Streams → Web stream details | Page-view and SPA navigation tracking is silently disabled; the site works normally for users |
Steps to configure:
- Create a GA4 property and add a Web data stream.
- Copy the Measurement ID (starts with
G-). - Set
VITE_GA_MEASUREMENT_ID=G-XXXXXXXXXXas an environment variable (in Replit: Secrets panel → Env Vars tab, environment: Shared). - Rebuild and redeploy the frontend for the change to take effect.
Note: The Measurement ID is embedded in public HTML and visible to anyone who views source — it is not a secret and does not need to be stored in the Secrets section.
The following keys are not environment variables. They are entered by a Super Admin through the Admin → Integrations page and stored in the database. The application runs without them, but certain features will be unavailable or degraded.
Protects the post and comment forms from spam bots. Both a site key and a secret key are required for reCAPTCHA to activate.
| Field | Where to find it | Effect if missing |
|---|---|---|
| Site Key (public) | reCAPTCHA Admin → your site → Keys | reCAPTCHA widget does not render; forms submit without a bot challenge |
| Secret Key (server-side) | Same console, same site | Server-side verification is skipped; all submissions pass automatically |
Steps to configure:
- Register your domain at the reCAPTCHA Admin Console.
- Choose reCAPTCHA v2 "I'm not a robot" or v3.
- Copy the Site Key and Secret Key.
- Enter both in Admin → Integrations → Google reCAPTCHA and save.
- The secret key is write-only — once saved it is masked in the UI and never returned to the client.
Security note: The secret key is stored in the database. For production deployments, consider enabling database encryption at rest.
Unlike the keys above, the Anthropic connection is configured via environment variables (see the table above), not the admin panel. Forum-level AI settings (model, frequency, custom instructions) are configured per-forum under Forum Settings → AI Moderation.
# Install dependencies
pnpm install
# Push database schema
pnpm --filter @workspace/db run push
# Run API codegen
pnpm --filter @workspace/api-spec run codegen
# Start API server (development)
pnpm --filter @workspace/api-server run dev
# Start frontend (development)
pnpm --filter @workspace/ripplet run devForum moderators can configure AI moderation per forum at /forums/:slug/settings:
- Enable/disable AI moderation
- Model selection — Haiku (fast), Sonnet (balanced), Opus (most capable)
- Comment frequency — Daily / twice weekly / monthly
- AI post generation — Optionally let the AI publish its own posts
- Custom instructions — Tell the AI the forum's purpose and tone
- Negative prompt — Explicitly block unwanted behaviors
The AI bot appears as user RippletAI and is identified by its system user ID. Its profile is always public and cannot be made private.
- HTTP security headers via Helmet with tightened CSP (
workerSrc: none,manifestSrc: self) - Rate limiting — 300 req/15min general, 20 req/15min for auth endpoints, 60 req/15min for writes
- Request body size limit (100 KB)
- CORS restricted to Replit domains
- Session cookies:
httpOnly,secure,sameSite: lax - PKCE-based OIDC flow; token refresh is best-effort (failure keeps session alive, never silently logs users out)
- Zod validation on all inputs with
.trim(),.max()caps, and script-injection refines on every free-text field - URI allowlist in HTML sanitizer restricted to
https:andmailto:schemes; alltarget="_blank"links enforcerel="noopener noreferrer" - ReDoS protection — search and filter inputs are capped at 100 characters before regex evaluation
- Parameterised queries throughout (
inArray()instead ofsql.raw());drizzle-ormkept up to date to cover upstream CVEs - No internal error messages exposed to clients
- Automatic expired session cleanup
Performance indexes are defined on all hot query paths:
posts(forum_id),posts(author_id),posts(is_hidden),posts(created_at),posts(forum_id, is_hidden)comments(post_id),comments(author_id),comments(parent_id)reactions(target_type, target_id),reactions(user_id), unique per user/target/emojiforum_memberships(user_id),forum_memberships(forum_id), unique per user/forumsessions(expire)— for fast cleanup of expired sessions
MIT — see LICENSE