DEV Community

Nadim Chowdhury
Nadim Chowdhury

Posted on

Building Confessly: The Anonymous Confession Platform That Actually Listens

Look, I'll be honest with you. I spent way too many nights doom-scrolling through random confession pages, and one thought kept bugging me: what if these people could get actual support instead of just reactions? That's how Confessly was bornβ€”a place where you can spill your thoughts anonymously and get genuine, thoughtful AI-powered guidance back.

This isn't just another confession board. It's what happens when you mix the raw honesty of anonymous platforms with the empathy of modern AI. And yeah, I'm building it completely open-source because why gatekeep?

What Makes Confessly Different?

The concept is simple but powerful:

  • Anonymous by default β€” No accounts, no tracking, just pure honesty
  • AI Advisor β€” Every confession gets a supportive, non-judgmental response from GPT
  • Community-driven β€” Trending confessions, reactions, and shared experiences
  • Moderation tools β€” Because we all know the internet needs guardrails

Think Whisper meets ChatGPT, but actually useful.

The Tech Stack (And Why I Chose It)

Let me walk you through what's under the hood:

Frontend:

  • Next.js 14 (App Router) β€” Server components, edge runtime, the whole nine yards
  • React 18 β€” Because duh
  • TypeScript β€” Sanity is underrated
  • Tailwind CSS β€” Fast styling without the CSS headaches
  • Framer Motion β€” Smooth animations that don't feel overdone
  • Zustand β€” State management that doesn't make me cry

Backend & Services:

  • Next.js API Routes β€” Keeping it simple with serverless functions
  • Firebase Firestore β€” Real-time database for confessions and reactions
  • Firebase Auth β€” For the admin dashboard
  • OpenAI GPT-4 β€” The brain behind our AI advisor
  • Vercel β€” Deployment that just works

Dev Tools:

  • ESLint + Prettier β€” Because consistency matters
  • Husky β€” Git hooks for pre-commit checks

Architecture Deep Dive

Here's how everything connects:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Client Layer                      β”‚
β”‚  (Next.js 14 App Router + React Components)          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                   β”‚
                   β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                 API Routes Layer                     β”‚
β”‚  /api/confessions/* | /api/ai/* | /api/moderation/* β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                   β”‚
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β–Ό                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Firebase   β”‚      β”‚   OpenAI API     β”‚
β”‚   Firestore  β”‚      β”‚   GPT-4 Turbo    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Enter fullscreen mode Exit fullscreen mode

Data Flow:

  1. User posts anonymous confession
  2. Firebase stores confession with metadata
  3. AI Advisor endpoint receives confession
  4. GPT-4 generates empathetic response
  5. Response stored and displayed to user
  6. Real-time updates via Firebase listeners

File Structure That Makes Sense

This took me a few iterations to get right. Here's the final structure:

confessly/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ app/
β”‚   β”‚   β”œβ”€β”€ (main)/
β”‚   β”‚   β”‚   β”œβ”€β”€ page.tsx                 # Home - confession feed
β”‚   β”‚   β”‚   β”œβ”€β”€ trending/
β”‚   β”‚   β”‚   β”‚   └── page.tsx             # Trending confessions
β”‚   β”‚   β”‚   β”œβ”€β”€ confession/
β”‚   β”‚   β”‚   β”‚   └── [id]/
β”‚   β”‚   β”‚   β”‚       └── page.tsx         # Single confession view
β”‚   β”‚   β”‚   └── layout.tsx               # Main layout wrapper
β”‚   β”‚   β”œβ”€β”€ admin/
β”‚   β”‚   β”‚   β”œβ”€β”€ page.tsx                 # Admin dashboard
β”‚   β”‚   β”‚   β”œβ”€β”€ moderation/
β”‚   β”‚   β”‚   β”‚   └── page.tsx             # Moderation queue
β”‚   β”‚   β”‚   └── layout.tsx               # Admin layout
β”‚   β”‚   β”œβ”€β”€ api/
β”‚   β”‚   β”‚   β”œβ”€β”€ confessions/
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ route.ts             # POST new confession
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ [id]/
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ route.ts         # GET single confession
β”‚   β”‚   β”‚   β”‚   β”‚   └── react/
β”‚   β”‚   β”‚   β”‚   β”‚       └── route.ts     # POST reaction
β”‚   β”‚   β”‚   β”‚   └── trending/
β”‚   β”‚   β”‚   β”‚       └── route.ts         # GET trending
β”‚   β”‚   β”‚   β”œβ”€β”€ ai/
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ advisor/
β”‚   β”‚   β”‚   β”‚   β”‚   └── route.ts         # POST get AI response
β”‚   β”‚   β”‚   β”‚   └── therapist/
β”‚   β”‚   β”‚   β”‚       └── route.ts         # POST therapist mode
β”‚   β”‚   β”‚   └── moderation/
β”‚   β”‚   β”‚       β”œβ”€β”€ flag/
β”‚   β”‚   β”‚       β”‚   └── route.ts         # POST flag confession
β”‚   β”‚   β”‚       └── review/
β”‚   β”‚   β”‚           └── route.ts         # POST review decision
β”‚   β”‚   β”œβ”€β”€ layout.tsx                   # Root layout
β”‚   β”‚   └── globals.css                  # Global styles
β”‚   β”œβ”€β”€ components/
β”‚   β”‚   β”œβ”€β”€ confession/
β”‚   β”‚   β”‚   β”œβ”€β”€ ConfessionCard.tsx       # Single confession display
β”‚   β”‚   β”‚   β”œβ”€β”€ ConfessionFeed.tsx       # Feed container
β”‚   β”‚   β”‚   β”œβ”€β”€ ConfessionForm.tsx       # New confession form
β”‚   β”‚   β”‚   └── AIResponse.tsx           # AI response display
β”‚   β”‚   β”œβ”€β”€ ui/
β”‚   β”‚   β”‚   β”œβ”€β”€ Button.tsx               # Reusable button
β”‚   β”‚   β”‚   β”œβ”€β”€ Card.tsx                 # Card component
β”‚   β”‚   β”‚   β”œβ”€β”€ Modal.tsx                # Modal wrapper
β”‚   β”‚   β”‚   β”œβ”€β”€ Input.tsx                # Form inputs
β”‚   β”‚   β”‚   └── Badge.tsx                # Status badges
β”‚   β”‚   β”œβ”€β”€ layout/
β”‚   β”‚   β”‚   β”œβ”€β”€ Header.tsx               # Site header
β”‚   β”‚   β”‚   β”œβ”€β”€ Footer.tsx               # Site footer
β”‚   β”‚   β”‚   └── Sidebar.tsx              # Admin sidebar
β”‚   β”‚   └── admin/
β”‚   β”‚       β”œβ”€β”€ ModerationQueue.tsx      # Moderation interface
β”‚   β”‚       └── StatsCard.tsx            # Dashboard stats
β”‚   β”œβ”€β”€ lib/
β”‚   β”‚   β”œβ”€β”€ firebase/
β”‚   β”‚   β”‚   β”œβ”€β”€ config.ts                # Firebase initialization
β”‚   β”‚   β”‚   β”œβ”€β”€ firestore.ts             # Firestore helpers
β”‚   β”‚   β”‚   └── auth.ts                  # Auth helpers
β”‚   β”‚   β”œβ”€β”€ openai/
β”‚   β”‚   β”‚   β”œβ”€β”€ client.ts                # OpenAI client setup
β”‚   β”‚   β”‚   └── prompts.ts               # AI prompt templates
β”‚   β”‚   β”œβ”€β”€ utils/
β”‚   β”‚   β”‚   β”œβ”€β”€ formatDate.ts            # Date formatting
β”‚   β”‚   β”‚   β”œβ”€β”€ sanitize.ts              # Content sanitization
β”‚   β”‚   β”‚   └── analytics.ts             # Analytics helpers
β”‚   β”‚   └── constants.ts                 # App constants
β”‚   β”œβ”€β”€ store/
β”‚   β”‚   β”œβ”€β”€ confessionStore.ts           # Confession state
β”‚   β”‚   └── uiStore.ts                   # UI state
β”‚   β”œβ”€β”€ types/
β”‚   β”‚   β”œβ”€β”€ confession.ts                # Confession types
β”‚   β”‚   β”œβ”€β”€ user.ts                      # User types
β”‚   β”‚   └── api.ts                       # API response types
β”‚   └── hooks/
β”‚       β”œβ”€β”€ useConfessions.ts            # Confession data hook
β”‚       β”œβ”€β”€ useAIResponse.ts             # AI interaction hook
β”‚       └── useInfiniteScroll.ts         # Infinite scroll hook
β”œβ”€β”€ public/
β”‚   β”œβ”€β”€ images/
β”‚   └── favicon.ico
β”œβ”€β”€ .env.local                           # Environment variables
β”œβ”€β”€ .eslintrc.json                       # ESLint config
β”œβ”€β”€ .prettierrc                          # Prettier config
β”œβ”€β”€ next.config.js                       # Next.js config
β”œβ”€β”€ tailwind.config.ts                   # Tailwind config
β”œβ”€β”€ tsconfig.json                        # TypeScript config
└── package.json                         # Dependencies
Enter fullscreen mode Exit fullscreen mode

Database Schema (Firestore)

Keep it simple, stupid. Here's what the data looks like:

Collections:

// confessions collection
{
  id: string,
  content: string,
  category: 'relationship' | 'work' | 'mental-health' | 'other',
  aiResponse: string | null,
  reactions: {
    heart: number,
    hug: number,
    support: number
  },
  flags: number,
  status: 'active' | 'flagged' | 'removed',
  createdAt: timestamp,
  trending_score: number,  // calculated based on time + reactions
  anonymous_id: string     // hashed IP for rate limiting
}

// reactions collection (subcollection under each confession)
{
  id: string,
  confessionId: string,
  type: 'heart' | 'hug' | 'support',
  createdAt: timestamp,
  anonymous_id: string
}

// moderation collection
{
  id: string,
  confessionId: string,
  reason: string,
  status: 'pending' | 'approved' | 'removed',
  reviewedAt: timestamp | null,
  reviewerId: string | null
}
Enter fullscreen mode Exit fullscreen mode

The UI/UX Philosophy

I wanted Confessly to feel like a safe space, not another cold tech product. Here's the vibe:

Design Principles:

  • Minimalist β€” Remove everything that doesn't serve the user
  • Soft colors β€” Purples and blues that feel calming, not aggressive
  • Generous whitespace β€” Let the content breathe
  • Smooth animations β€” Transitions that feel natural, not jarring
  • Mobile-first β€” Because most people confess at 2 AM on their phones

Key UI Components:

Confession Card:

  • Soft gradient background
  • No profile pictures (obviously)
  • Emoji reactions instead of likes
  • "Get AI Support" button prominently displayed
  • Flag option tucked in the corner

AI Response Section:

  • Distinct visual treatment (lighter card, different border)
  • Warm, conversational tone in the design
  • "This is AI-generated" disclaimer (transparency matters)
  • Option to regenerate response

Feed Layout:

  • Infinite scroll with skeleton loaders
  • Filter chips at the top (category, trending, recent)
  • Floating action button for new confession
  • Smooth card entrance animations

Core Features Breakdown

1. Anonymous Confession Posting

// Simplified version of the submission flow
const submitConfession = async (content: string, category: string) => {
  // Generate anonymous ID (hashed IP + session)
  const anonymousId = await generateAnonymousId();

  // Check rate limit (max 3 per hour per anonymous ID)
  await checkRateLimit(anonymousId);

  // Sanitize content
  const sanitized = sanitizeContent(content);

  // Create confession
  const confession = await db.collection('confessions').add({
    content: sanitized,
    category,
    anonymous_id: anonymousId,
    status: 'active',
    reactions: { heart: 0, hug: 0, support: 0 },
    flags: 0,
    createdAt: serverTimestamp(),
    aiResponse: null
  });

  // Trigger AI response generation
  generateAIResponse(confession.id);

  return confession.id;
};
Enter fullscreen mode Exit fullscreen mode

2. AI Advisor Mode

The magic sauce. Here's how the AI responds:

// AI prompt engineering
const generateAdvicePrompt = (confession: string) => {
  return `You are a compassionate AI advisor for an anonymous confession platform. 

A user has shared: "${confession}"

Provide a supportive, non-judgmental response that:
- Validates their feelings
- Offers perspective or gentle advice
- Suggests actionable steps if appropriate
- Encourages professional help for serious issues
- Uses warm, conversational language
- Keeps it under 150 words

Remember: This is anonymous, so focus on the emotion and situation, not identity.`;
};
Enter fullscreen mode Exit fullscreen mode

The AI is prompted to be empathetic, concise, and helpfulβ€”not preachy or robotic.

3. Trending Algorithm

Simple but effective:

const calculateTrendingScore = (confession) => {
  const age = Date.now() - confession.createdAt.toMillis();
  const ageHours = age / (1000 * 60 * 60);

  const reactionCount = 
    confession.reactions.heart * 1 +
    confession.reactions.hug * 1.5 +
    confession.reactions.support * 2;

  // Decay score over time (gravity)
  const gravity = 1.8;
  return reactionCount / Math.pow(ageHours + 2, gravity);
};
Enter fullscreen mode Exit fullscreen mode

New confessions with lots of reactions rise fast. Old ones fade gracefully.

4. Moderation Dashboard

Admins get a clean interface to review flagged content:

  • Queue of flagged confessions
  • Context about why it was flagged
  • One-click approve/remove actions
  • Stats dashboard (total confessions, active users, flags)

Viral Features That Hook Users

1. AI Therapist Mode
Toggle between quick advice and deeper, therapy-style conversations. Costs more tokens but provides richer responses.

2. Trending Confessions Leaderboard
Shows the most-reacted confessions of the day/week. Gamification without being toxic.

3. Category-Based Exploration
Filter by relationship, work, mental health, or general confessions.

4. Reaction System
Instead of generic likes: ❀️ (Heart), πŸ€— (Hug), πŸ’ͺ (Support)

5. Anonymous Sharing
Generate shareable links to specific confessions (with AI responses included).

Environment Setup

Create a .env.local file:

# Firebase
NEXT_PUBLIC_FIREBASE_API_KEY=your_api_key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your_domain
NEXT_PUBLIC_FIREBASE_PROJECT_ID=your_project_id
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your_bucket
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your_sender_id
NEXT_PUBLIC_FIREBASE_APP_ID=your_app_id

# OpenAI
OPENAI_API_KEY=your_openai_key

# App
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_MAX_CONFESSIONS_PER_HOUR=3
Enter fullscreen mode Exit fullscreen mode

Getting Started

# Clone and install
git clone https://github.com/yourusername/confessly
cd confessly
npm install

# Set up environment
cp .env.example .env.local
# Fill in your API keys

# Run development server
npm run dev

# Build for production
npm run build
npm start
Enter fullscreen mode Exit fullscreen mode

Deployment Strategy

Vercel is the obvious choice here:

  1. Connect your GitHub repo
  2. Add environment variables in Vercel dashboard
  3. Deploy
  4. Done

Firebase handles:

  • Database scaling automatically
  • Real-time updates without extra config
  • Security rules to prevent abuse

Cost estimates (for moderate traffic):

  • Vercel: Free tier handles ~100K requests/month
  • Firebase: ~$25/month with generous free tier
  • OpenAI: ~$50/month (depends on usage)

Security & Privacy Considerations

This is crucial for a confession app:

Firestore Rules:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /confessions/{confession} {
      // Anyone can read active confessions
      allow read: if resource.data.status == 'active';
      // Anyone can create (with rate limiting in code)
      allow create: if request.auth == null;
      // Only admins can update/delete
      allow update, delete: if request.auth.token.admin == true;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Additional Measures:

  • Content sanitization on both client and server
  • Rate limiting per anonymous ID
  • IP hashing (never store raw IPs)
  • Profanity filter with manual review for edge cases
  • Clear terms of service and privacy policy

Performance Optimizations

Client Side:

  • Image lazy loading with Next.js Image component
  • Infinite scroll with intersection observer
  • Optimistic UI updates for reactions
  • Debounced search and filters

Server Side:

  • API route caching with proper headers
  • Firestore indexes for common queries
  • Edge functions for low latency
  • OpenAI streaming responses for faster perceived performance

Future Roadmap

What's next for Confessly:

  • [ ] PWA support for mobile app feel
  • [ ] Voice confession option (transcribed to text)
  • [ ] Follow-up conversations with AI
  • [ ] Community support threads
  • [ ] Multilingual support
  • [ ] Dark mode (always dark mode)
  • [ ] Export your confessions (therapy journal)

Lessons Learned

Building Confessly taught me a few things:

  1. Keep it simple β€” My first version had way too many features. Users just want to confess and get support.

  2. AI prompts matter β€” I spent more time on prompt engineering than I expected. The difference between robotic and empathetic AI responses is all in the prompt.

  3. Moderation is hard β€” You can't automate everything. Human review is necessary for edge cases.

  4. Performance obsession pays off β€” Users bounce if your app feels slow. Optimize early.

  5. Privacy builds trust β€” Being genuinely anonymous (not "we promise not to look" anonymous) is the whole point.

Why Open Source?

I'm open-sourcing Confessly because I think we need more compassionate tech in the world. If someone builds something better using this code, that's a win. If someone learns from my mistakes, even better.

The repo will be on GitHub with full documentation, deployment guides, and contribution guidelines.

Final Thoughts

Confessly isn't just a side project for meβ€”it's an experiment in building technology that actually helps people. We're all carrying something, and sometimes the best first step is just getting it out there, even if anonymously.

If you build this or something inspired by it, I'd love to see what you create. Tag me, send a DM, whatever. Let's make the internet a slightly less terrible place.


That's a wrap 🎁

Now go touch some code πŸ‘¨β€πŸ’»

Catch me here β†’ LinkedIn | GitHub | YouTube

Top comments (0)