Skip to content

leejaew/ripplet.me

Repository files navigation

Ripplet

A full-stack Reddit-like community discussion platform with AI-powered moderation.

Live at ripplet.me

Run on Replit

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.

Features for Users

Communities

  • 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

Posts (Ripples)

  • 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

Comments

  • 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

User Profiles

  • 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

Moderation awareness

  • Hidden posts and shadow-banned users are masked automatically so the community feed stays clean

Features for Admins & Moderators

Role hierarchy

USERMODERATORADMINSUPER_ADMIN

Forum-level moderation (Moderators, Admins, Super Admins)

  • 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

Admin panel (/admin)

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

Forum limits

  • A maximum of 100 forums can exist at any one time. Attempting to create more is blocked at the API level.

Integrations (configured via Admin → Integrations)

  • Google reCAPTCHA v2/v3 — protect post and comment forms from spam bots; disable any time by clearing the keys

Tech Stack

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)

Project Structure

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

Pages

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

Getting Started

Prerequisites

  • Node.js 18+
  • pnpm 8+
  • PostgreSQL database

Environment Variables

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, and AI_INTEGRATIONS_ANTHROPIC_API_KEY are injected automatically when the project is run inside Replit. If you are self-hosting, you will need to supply a real REPL_ID and connect to the upstream Anthropic API directly (update the base URL and key accordingly).

Super Admin Setup

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.

Google Analytics 4

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:

  1. Create a GA4 property and add a Web data stream.
  2. Copy the Measurement ID (starts with G-).
  3. Set VITE_GA_MEASUREMENT_ID=G-XXXXXXXXXX as an environment variable (in Replit: Secrets panel → Env Vars tab, environment: Shared).
  4. 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.

Third-Party API Keys (Admin Panel)

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.

Google reCAPTCHA v2 / v3

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:

  1. Register your domain at the reCAPTCHA Admin Console.
  2. Choose reCAPTCHA v2 "I'm not a robot" or v3.
  3. Copy the Site Key and Secret Key.
  4. Enter both in Admin → Integrations → Google reCAPTCHA and save.
  5. 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.

Anthropic Claude (AI Moderation)

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 & Run

# 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 dev

AI Moderation

Forum 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.

Security

  • 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: and mailto: schemes; all target="_blank" links enforce rel="noopener noreferrer"
  • ReDoS protection — search and filter inputs are capped at 100 characters before regex evaluation
  • Parameterised queries throughout (inArray() instead of sql.raw()); drizzle-orm kept up to date to cover upstream CVEs
  • No internal error messages exposed to clients
  • Automatic expired session cleanup

Database Indexes

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/emoji
  • forum_memberships(user_id), forum_memberships(forum_id), unique per user/forum
  • sessions(expire) — for fast cleanup of expired sessions

License

MIT — see LICENSE

About

A community discussion platform where ideas create ripple effects. Features forums, threaded comments, emoji reactions, moderation tools, and an admin panel — built with React, Express, and PostgreSQL.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages