About PoemSite
PoemSite is a modern, full-stack poetry platform for reading, sharing, and discussing poems — with an elegant user interface, robust admin dashboard, and secure backend.
Table of Contents
Tech Stack
- Frontend: Next.js 15, React, Tailwind CSS, HTML5, CSS3
- Backend: Firebase Firestore, Firebase Auth, Node.js Express (mail server)
- Admin Panel: Next.js (separate app), Tailwind CSS
- Mail Server: Node.js, Express, Nodemailer, Firebase Admin SDK
- Deployment: Vercel (main), Firebase Hosting (admin), Render (mail server)
- Other: GitHub Actions (CI/CD), ESLint/Prettier, dotenv
- APIs: Custom API for mailing, Firebase Functions (optional)
- Open Source: GitHub
Pages & Navigation
Main User Site
- Home: Highlights, featured poems, CTAs.
- /poem: Browse/search all poems, filters, pagination.
- /poem/[slug]: Poem detail with comments, replies, admin replies, sharing.
- /about: About the admin and main poet of Poemsite community.
- /login, /register: Auth pages.
- /profile: User info.
Admin Dashboard
- Dashboard Home: Stats, activity, analytics.
- Poems: Add, edit, delete, approve poems.
- Users: List, search, manage roles, ban/delete users.
- Comments: Moderate, delete, admin reply.
- Mailing List: Export, send announcements.
- Poem Requests: View/respond to user requests.
Main Features & UX
- Read, search, and share poems with beautiful, responsive UI
- Nested comments & replies, admin replies highlighted
- Animated "Show Replies", "Share", and interactive buttons
- Role-based actions, only admins can manage poems/users
- Mailing list join, email notifications (custom API)
- Poem request & approval workflow
- Admin dashboard for moderation, analytics, management
- Live statistics, user tracking, audit logs (admin)
- Fast, secure authentication (Firebase Auth)
- All data is real-time via Firestore
- Animated page transitions and smooth modals
- Public, mobile-friendly, accessible
Key Code Explanations
Fetching a Poem
const poemQuery = query( collection(db, 'poems'), where('slug', '==', decodedSlug) ); const snapshot = await getDocs(poemQuery); if (snapshot.empty) return notFound(); const poemData = snapshot.docs[0].data(); setPoem(poemData);
Posting a Comment
await addDoc(collection(db, 'comments'), { poemSlug: decodedSlug, content: newComment.trim(), author: authorName, timestamp: Timestamp.now(), userId: user.uid, parentId: null });
On-demand Replies
const repliesQuery = query( collection(db, 'comments'), where('poemSlug', '==', decodedSlug), where('parentId', '==', parentId), orderBy('timestamp', 'asc') ); const repliesSnapshot = await getDocs(repliesQuery); const replyData = repliesSnapshot.docs.map((doc) => ({ id: doc.id, ...doc.data() }));
Role-based Actions Example
{user?.uid === comment.userId && ( <button onClick={() => handleDeleteComment(comment.id)}> Delete </button> )}
Security & Authentication
Strict Firestore rules and authentication for both user and admin flows:
match /comments/{commentId} { allow read: if true; allow create: if request.auth != null; allow update: if request.auth.uid == resource.data.userId && !(request.resource.data.keys().hasAny(['adminReply'])); allow update: if request.auth != null && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 'admin' && request.resource.data.diff(resource.data).changedKeys().hasOnly(['adminReply']); allow delete: if request.auth.uid == resource.data.userId; allow delete: if request.auth != null && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 'admin'; }
- All reads public for poems/comments; writes are restricted.
- Only authenticated users can comment/reply.
- Only comment owners/admins can delete/edit.
- Only admins can manage poems and users.
- Roles are securely managed in
users
collection.
Collections & Data Models
poems
- title: String
- author: String
- content: String
- slug: String (unique, URL-friendly)
- datePosted: Timestamp
comments
- poemSlug: String
- content: String
- author: String
- timestamp: Timestamp
- userId: String
- parentId: String/null
- adminReply: String (admin-only, optional)
users
- uid: String
- name: String
- role: "user" | "admin"
- email: String
poemRequests
- requestedBy: uid
- poemTitle: String
- reason: String
- timestamp: Timestamp
mailingList
- uid: String
- email: String
- subscribedOn: Timestamp
Admin Dashboard (separate app)
The admin dashboard is a dedicated Next.js app built for moderators and admins, deployed at admin.poems.toshankanwar.website
- Poem CRUD: Add, approve, edit, delete, feature poems
- User Management: List, search, ban, change roles
- Comment Moderation: Delete, reply as admin, audit logs
- Mailing List management: export, emails, stats
- Poem Requests: View/respond, one-click publish
- Analytics dashboard: charts, stats, live activity
- Authentication: admin role required (checked via Firestore + UI)
- Seamless connection to main Firestore DB
- Responsive, animated, professional UI (Tailwind, modals)
- Open source: GitHub Repo
Mail Server & API
A dedicated backend service (Node.js + Express + Nodemailer) powers:
- Sending welcome emails, admin approval/announcement notifications
- Mailing list subscription, opt-in/out, bulk notifications
- Fully integrated with Firestore and Firebase Admin SDK
- Endpoints:
/api/send-welcome-email
,/api/send-aproval-email
,/api/send-poem-announcement
,/api/unsubscribe
- Hosted at mail-server-poetry-website.onrender.com
- Open source: Mail Server GitHub
app.post('/api/send-welcome-email', ... ); app.post('/api/send-aproval-email', ... ); app.post('/api/send-poem-announcement', ... ); app.post('/api/unsubscribe', ... );
Deployment & Hosting
- Main Site: Deployed on Vercel with auto CI/CD from GitHub.
- Admin Dashboard: Hosted as a separate app at admin.poems.toshankanwar.website (Firebase Hosting or Vercel).
- Mail Server: Hosted on Render for scalable mail API.
- Firestore: Central data store, rules-enforced, real-time.
- GitHub: All code open source. See main repo and admin repo.
All sensitive keys are securely stored in environment files. Never commit secrets to source!