A modern, production-ready idea sharing platform where users can anonymously post ideas, upvote submissions, and engage with creative content. Built with Next.js 15, Fastify 4, Drizzle ORM, and PostgreSQL (Neon).
- Features
- Architecture
- Tech Stack
- Prerequisites
- Getting Started
- Docker Deployment
- Kubernetes Deployment
- API Documentation
- Project Structure
- Development
- Environment Variables
- Design Decisions
- Trade-offs
- Future Enhancements
- ๐จ Stunning UI: Premium gradient design with smooth animations
- ๐ฑ Fully Responsive: Optimized for mobile, tablet, and desktop
- โก Real-time Updates: Automatic polling for new ideas and votes
- ๐ Anonymous Posting: No registration or login required
- ๐ One-Click Upvoting: Instant feedback with animated interactions
- ๐ Rich Visual Effects: Gradient backgrounds, 3D effects, and decorative elements
- โฟ Accessible: ARIA labels and keyboard navigation support
- Landing Page: Professional marketing page with hero section, features, and CTAs
- Idea Board: Full-featured CRUD application for managing ideas
- Character Limits: 100 characters for titles, 500 for descriptions
- Upvote System: Community-driven content ranking
- Empty States: Helpful UI when no content exists
- Error Handling: Graceful error states and user feedback
- Loading States: Skeleton screens and spinners
- ๐ High Performance: Fastify backend with optimized queries
- ๐ Security: Rate limiting, CORS, Helmet, input validation with Zod
- ๐๏ธ Database: PostgreSQL (Neon) with SSL, Drizzle ORM
- ๐ Health Checks: Comprehensive monitoring endpoints
- ๐ณ Containerized: Multi-stage Docker builds for production
- โธ๏ธ Kubernetes Ready: Complete K8s manifests with HPA
- ๐ Auto-scaling: Horizontal Pod Autoscaler configuration
- ๐ Type Safety: End-to-end TypeScript coverage
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Client Browser โ
โ http://localhost:3000 โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โ HTTP/REST
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Frontend Service โ
โ (Next.js 15) โ
โ - Server-side rendering โ
โ - React 19 components โ
โ - Tailwind CSS styling โ
โ - API client with fetch โ
โ Port: 3000 โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โ REST API
โ http://localhost:3001/api
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Backend Service โ
โ (Fastify 4) โ
โ - RESTful API endpoints โ
โ - Request validation (Zod) โ
โ - Rate limiting & CORS โ
โ - Drizzle ORM queries โ
โ Port: 3001 โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โ PostgreSQL Protocol
โ SSL Connection
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ PostgreSQL Database โ
โ (Neon Cloud) โ
โ - Managed PostgreSQL โ
โ - Automatic backups โ
โ - SSL encryption โ
โ - Connection pooling โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- User Action โ Frontend captures user input
- API Request โ Frontend sends HTTP request to backend
- Validation โ Backend validates with Zod schemas
- Database Query โ Drizzle ORM executes SQL via postgres-js
- Response โ Backend returns JSON response
- UI Update โ Frontend updates React state and re-renders
| Technology | Version | Purpose |
|---|---|---|
| Next.js | 15.5.4 | React framework with SSR |
| React | 19.0.0 | UI library |
| TypeScript | 5.x | Type safety |
| Tailwind CSS | 3.4.1 | Utility-first CSS |
| SWR/Polling | Custom | Data fetching |
| Technology | Version | Purpose |
|---|---|---|
| Fastify | 4.24.3 | High-performance web framework |
| TypeScript | 5.x | Type safety |
| Drizzle ORM | 0.29.0 | Type-safe SQL ORM |
| postgres-js | 3.4.3 | PostgreSQL client |
| Zod | 3.22.4 | Runtime validation |
| @fastify/cors | 9.0.1 | CORS middleware |
| @fastify/helmet | 11.1.1 | Security headers |
| @fastify/rate-limit | 9.1.0 | Rate limiting |
| Technology | Purpose |
|---|---|
| PostgreSQL | Relational database |
| Neon | Serverless Postgres hosting |
| Drizzle Kit | Schema migrations |
| Technology | Purpose |
|---|---|
| Docker | Containerization |
| Docker Compose | Multi-container orchestration |
| Kubernetes | Container orchestration |
| NGINX | Ingress controller (optional) |
- Node.js: 18.x or higher
- npm: 9.x or higher
- Docker: 20.x or higher (for containerization)
- Docker Compose: 2.x or higher
- Kubernetes: 1.24+ (optional, for K8s deployment)
- kubectl: Latest (optional, for K8s deployment)
- PostgreSQL Database: Neon account or local PostgreSQL
git clone <repository-url>
cd assignment- Create a free account at Neon
- Create a new project
- Copy the connection string (it should look like):
postgresql://user:password@host/database?sslmode=require
Create or update backend/.env:
# Server Configuration
PORT=3001
HOST=0.0.0.0
NODE_ENV=development
# Database Configuration (Neon)
DATABASE_URL=postgresql://user:password@host/database?sslmode=require&channel_binding=require
# Rate Limiting
RATE_LIMIT_MAX=100
RATE_LIMIT_WINDOW=60000
# CORS
CORS_ORIGIN=http://localhost:3000
# Logging
LOG_LEVEL=infoCreate frontend/.env.local:
NEXT_PUBLIC_API_URL=http://localhost:3001cd backend
npm installcd frontend
npm installcd backend
# Generate migration files
npm run db:generate
# Run migrations
npm run db:migrate
# Seed initial data (optional)
npm run db:seedTerminal 1 (Backend):
cd backend
npm run devTerminal 2 (Frontend):
cd frontend
npm run dev# From project root
docker-compose up --build- Landing Page: http://localhost:3000
- Idea Board: http://localhost:3000/app
- Backend API: http://localhost:3001/api/health
- API Docs: See API Documentation below
# Build and start all services
docker-compose up --build
# Run in detached mode
docker-compose up -d
# View logs
docker-compose logs -f
# Stop services
docker-compose down
# Stop and remove volumes
docker-compose down -vThe docker-compose.yml defines:
- Backend: Fastify API server on port 3001
- Frontend: Next.js web server on port 3000
- Network: Custom bridge network
ideaboard_network - Health Checks: Automated health monitoring
- Dependencies: Frontend waits for backend to be healthy
# Build backend image
docker build -t ideaboard-backend:latest ./backend
# Build frontend image
docker build -t ideaboard-frontend:latest ./frontend
# Run backend
docker run -p 3001:3001 --env-file backend/.env ideaboard-backend:latest
# Run frontend
docker run -p 3000:3000 -e NEXT_PUBLIC_API_URL=http://localhost:3001 ideaboard-frontend:latestComplete Kubernetes manifests are provided in the k8s/ directory.
# Apply all manifests
kubectl apply -f k8s/namespace.yaml
kubectl apply -f k8s/configmap.yaml
kubectl apply -f k8s/secret.yaml
kubectl apply -f k8s/backend-deployment.yaml
kubectl apply -f k8s/backend-service.yaml
kubectl apply -f k8s/frontend-deployment.yaml
kubectl apply -f k8s/frontend-service.yaml
kubectl apply -f k8s/hpa-backend.yaml
kubectl apply -f k8s/hpa-frontend.yaml
# Verify deployment
kubectl get all -n ideaboard
# Access application
kubectl port-forward -n ideaboard svc/frontend 3000:80- Namespace Isolation: All resources in
ideaboardnamespace - High Availability: 2 replicas minimum per service
- Auto-scaling: HPA scales 2-10 pods based on CPU/Memory
- Health Checks: Liveness and readiness probes
- Resource Limits: Defined CPU and memory constraints
- Secrets Management: Secure database credentials
- Load Balancing: Service-based traffic distribution
- Ingress Support: NGINX ingress for external access
See k8s/README.md for detailed deployment instructions.
http://localhost:3001/api
GET /api/healthResponse:
{
"status": "ok",
"timestamp": "2025-10-01T12:00:00.000Z",
"uptime": 123.45,
"database": "connected"
}GET /api/ideas?limit=50&offset=0&sortBy=upvotes&order=descQuery Parameters:
limit(optional): Number of results (default: 50)offset(optional): Pagination offset (default: 0)sortBy(optional): Sort field -createdAtorupvotes(default:createdAt)order(optional): Sort order -ascordesc(default:desc)
Response:
{
"ideas": [
{
"id": "abc123",
"title": "Build a time machine",
"description": "Using quantum entanglement and a DeLorean",
"upvotes": 42,
"createdAt": "2025-10-01T12:00:00.000Z",
"updatedAt": "2025-10-01T12:30:00.000Z"
}
],
"total": 1,
"limit": 50,
"offset": 0
}GET /api/ideas/:idResponse:
{
"id": "abc123",
"title": "Build a time machine",
"description": "Using quantum entanglement and a DeLorean",
"upvotes": 42,
"createdAt": "2025-10-01T12:00:00.000Z",
"updatedAt": "2025-10-01T12:30:00.000Z"
}POST /api/ideas
Content-Type: application/json
{
"title": "Build a time machine",
"description": "Using quantum entanglement and a DeLorean"
}Validation:
title: Required, string, 1-100 charactersdescription: Required, string, 1-500 characters
Response:
{
"id": "abc123",
"title": "Build a time machine",
"description": "Using quantum entanglement and a DeLorean",
"upvotes": 0,
"createdAt": "2025-10-01T12:00:00.000Z",
"updatedAt": "2025-10-01T12:00:00.000Z"
}PATCH /api/ideas/:id/upvoteResponse:
{
"id": "abc123",
"title": "Build a time machine",
"description": "Using quantum entanglement and a DeLorean",
"upvotes": 43,
"createdAt": "2025-10-01T12:00:00.000Z",
"updatedAt": "2025-10-01T12:30:00.000Z"
}DELETE /api/ideas/:idResponse:
{
"message": "Idea deleted successfully"
}All endpoints return consistent error responses:
{
"statusCode": 400,
"error": "Bad Request",
"message": "Validation error: Title must be between 1 and 100 characters"
}Common Status Codes:
200 OK: Success201 Created: Resource created400 Bad Request: Invalid input404 Not Found: Resource not found429 Too Many Requests: Rate limit exceeded500 Internal Server Error: Server error
assignment/
โโโ backend/ # Backend API service
โ โโโ src/
โ โ โโโ config/ # Configuration management
โ โ โ โโโ index.ts # Environment config
โ โ โโโ db/ # Database layer
โ โ โ โโโ index.ts # DB connection
โ โ โ โโโ migrate.ts # Migration runner
โ โ โ โโโ schema.ts # Drizzle schema
โ โ โ โโโ seed.ts # Seed data
โ โ โโโ routes/ # API routes
โ โ โ โโโ health.ts # Health check endpoint
โ โ โ โโโ ideas.ts # Ideas CRUD endpoints
โ โ โโโ types/ # TypeScript types
โ โ โ โโโ api.ts # API types
โ โ โโโ utils/ # Utility functions
โ โ โ โโโ helpers.ts # Helper functions
โ โ โโโ server.ts # Main server file
โ โโโ .dockerignore # Docker ignore rules
โ โโโ .env # Environment variables
โ โโโ Dockerfile # Multi-stage Docker build
โ โโโ drizzle.config.ts # Drizzle ORM config
โ โโโ package.json # Dependencies
โ โโโ tsconfig.json # TypeScript config
โโโ frontend/ # Frontend web application
โ โโโ app/ # Next.js app directory
โ โ โโโ app/ # Idea Board application
โ โ โ โโโ components/ # App-specific components
โ โ โ โ โโโ IdeaCard.tsx # Idea display card
โ โ โ โ โโโ IdeaForm.tsx # Idea submission form
โ โ โ โโโ page.tsx # Idea Board main page
โ โ โโโ components/ # Shared components
โ โ โ โโโ EmptyState.tsx # Empty state UI
โ โ โ โโโ ErrorBoundary.tsx # Error handling
โ โ โ โโโ Header.tsx # Header component
โ โ โ โโโ LoadingSpinner.tsx # Loading states
โ โ โโโ config/ # Frontend config
โ โ โ โโโ index.ts # API URL config
โ โ โโโ hooks/ # React hooks
โ โ โ โโโ useIdeas.ts # Ideas data hook
โ โ โโโ lib/ # Libraries
โ โ โ โโโ api.ts # API client
โ โ โโโ types/ # TypeScript types
โ โ โ โโโ api.ts # API types
โ โ โโโ utils/ # Utility functions
โ โ โ โโโ helpers.ts # Helper functions
โ โ โโโ globals.css # Global styles
โ โ โโโ layout.tsx # Root layout
โ โ โโโ page.tsx # Landing page
โ โโโ public/ # Static assets
โ โโโ .dockerignore # Docker ignore rules
โ โโโ .env.local.example # Example env file
โ โโโ .gitignore # Git ignore rules
โ โโโ Dockerfile # Multi-stage Docker build
โ โโโ next.config.ts # Next.js config
โ โโโ package.json # Dependencies
โ โโโ postcss.config.mjs # PostCSS config
โ โโโ tsconfig.json # TypeScript config
โโโ k8s/ # Kubernetes manifests
โ โโโ namespace.yaml # Namespace definition
โ โโโ configmap.yaml # Configuration
โ โโโ secret.yaml # Secrets
โ โโโ backend-deployment.yaml # Backend deployment
โ โโโ backend-service.yaml # Backend service
โ โโโ frontend-deployment.yaml # Frontend deployment
โ โโโ frontend-service.yaml # Frontend service
โ โโโ hpa-backend.yaml # Backend autoscaler
โ โโโ hpa-frontend.yaml # Frontend autoscaler
โ โโโ ingress.yaml # Ingress rules
โ โโโ README.md # K8s documentation
โโโ docker-compose.yml # Docker Compose config
โโโ README.md # This file
npm run dev # Start development server with hot reload
npm run build # Compile TypeScript to JavaScript
npm start # Run compiled code
npm run db:generate # Generate migration files
npm run db:migrate # Run database migrations
npm run db:seed # Seed database with sample data
npm run db:studio # Open Drizzle Studio (GUI)npm run dev # Start development server
npm run build # Build for production
npm start # Start production server
npm run lint # Run ESLint- TypeScript: Strict mode enabled
- ESLint: Configured for Next.js and React
- Prettier: (Add if needed)
- File Naming: kebab-case for files, PascalCase for components
Currently, no automated tests are implemented. Future additions:
- Backend: Jest + Supertest for API testing
- Frontend: Vitest + React Testing Library
- E2E: Playwright or Cypress
| Variable | Description | Default | Required |
|---|---|---|---|
PORT |
Server port | 3001 |
No |
HOST |
Server host | 0.0.0.0 |
No |
NODE_ENV |
Environment | development |
No |
DATABASE_URL |
PostgreSQL connection string | - | Yes |
RATE_LIMIT_MAX |
Max requests per window | 100 |
No |
RATE_LIMIT_WINDOW |
Rate limit window (ms) | 60000 |
No |
CORS_ORIGIN |
Allowed CORS origin | * |
No |
LOG_LEVEL |
Logging level | info |
No |
| Variable | Description | Default | Required |
|---|---|---|---|
NEXT_PUBLIC_API_URL |
Backend API URL | http://localhost:3001 |
No |
- Why: Drizzle provides better TypeScript inference, smaller bundle size, and direct SQL control
- Trade-off: Less mature ecosystem, fewer GUI tools
- Why: ~2x faster, built-in TypeScript support, schema validation, modern async/await
- Trade-off: Smaller community, fewer middleware options
- Why: Server components, improved performance, better SEO, modern React patterns
- Trade-off: Learning curve for developers familiar with Pages Router
- Why: Auto-scaling, automatic backups, generous free tier, SSL by default
- Trade-off: Vendor lock-in, cold start latency
- Why: Simpler implementation, no persistent connections, easier to scale
- Trade-off: Higher latency, more network requests (mitigated with smart intervals)
- Why: Reduces friction, faster user adoption, simpler architecture
- Trade-off: Potential for abuse (mitigated with rate limiting)
- Why: Smaller image size, faster deployments, production-optimized
- Trade-off: Longer build times
- Why: Type safety, better DX, fewer runtime errors, excellent tooling
- Trade-off: Initial setup complexity, build step required
Decision: Polling with smart intervals (5s active, 30s inactive)
- โ Simple to implement and debug
- โ Works with any HTTP infrastructure
- โ Easier horizontal scaling
- โ Higher latency than WebSockets
- โ More bandwidth usage
Alternative: WebSockets would provide real-time updates but add complexity in load balancing and connection management.
Decision: Anonymous posting without authentication
- โ Zero friction for users
- โ No password management
- โ Privacy-friendly
- โ Potential for spam/abuse
- โ No user tracking
Mitigation: Rate limiting (100 requests/minute), input validation, character limits
Decision: REST API over GraphQL
- โ Simpler to implement
- โ Better caching with HTTP
- โ Easier to monitor and debug
- โ Over-fetching data
- โ Multiple round trips
Alternative: GraphQL would allow precise data fetching but requires additional tooling and learning curve.
Decision: No automated testing initially
- โ Faster initial development
- โ Focus on core features
- โ Technical debt
- โ Harder to refactor safely
Future: Add comprehensive test suite before scaling team or features.
- Add automated testing (Jest, React Testing Library, Playwright)
- Implement WebSocket support for real-time updates
- Add search and filtering for ideas
- Implement pagination with infinite scroll
- Add analytics and monitoring (Sentry, LogRocket)
- Improve error messages and user feedback
- User authentication (optional, for profiles)
- Comment system for ideas
- Categories and tags for ideas
- Image upload support
- Rich text editor for descriptions
- Email notifications (trending ideas)
- Admin dashboard for moderation
- AI-powered idea suggestions
- Collaborative editing
- Integration with third-party services (Slack, Discord)
- Mobile apps (React Native)
- Advanced analytics dashboard
- Multi-language support (i18n)
- Dark mode toggle (currently auto)
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License.
Created as a full-stack developer assessment project.
Backend on Render + Frontend on Vercel
-
Prerequisites:
- GitHub account with your repository pushed
- Render account (free tier available)
- Vercel account (free tier available)
-
Deploy Backend to Render:
# Push your code to GitHub first git add . git commit -m "Prepare for deployment" git push origin master
- Go to Render Dashboard
- Click "New +" โ "Blueprint"
- Connect your repository
- Render will detect
render.yamland configure automatically - Add required environment variables:
DATABASE_URL: PostgreSQL connection stringCORS_ORIGIN: Your Vercel frontend URL (or*temporarily)
-
Deploy Frontend to Vercel:
- Go to Vercel Dashboard
- Click "Add New..." โ "Project"
- Import your GitHub repository
- Set Root Directory to
frontend - Add environment variable:
NEXT_PUBLIC_API_URL: Your Render backend URL +/api
- Click "Deploy"
-
Update CORS:
- Go back to Render
- Update
CORS_ORIGINwith your Vercel URL - Service will automatically redeploy
๐ For detailed deployment instructions, see DEPLOYMENT.md
- Backend deployed on Render with PostgreSQL
- Frontend deployed on Vercel
- Environment variables configured correctly
- CORS settings updated with frontend URL
- Health check endpoint working
- Database migrations run successfully
- Test creating and upvoting ideas
Check Backend Health:
curl https://your-backend.onrender.com/api/healthExpected Response:
{
"status": "healthy",
"timestamp": "2024-...",
"uptime": 123.456,
"database": "connected"
}Render (Free):
- Services spin down after 15 minutes of inactivity
- First request may take 30-60 seconds after spin-down
- 750 hours/month limit
Vercel (Free):
- 100 GB bandwidth/month
- 6000 build minutes/month
- Perfect for this application size
- Next.js Documentation
- Fastify Documentation
- Drizzle ORM Documentation
- Neon Database
- Tailwind CSS
- Render Documentation
- Vercel Documentation
Built with โค๏ธ using TypeScript, Next.js, Fastify, and PostgreSQL