A secure, cloud-based notepad web application built with Next.js, TypeScript, and Firebase. Users can create, share, and optionally password-protect notes without requiring login.
- No Login Required - Create and share notes instantly
- Password Protection - Optionally secure notes with bcrypt-hashed passwords
- Unique Short Codes - Each note gets a unique, shareable short URL
- Custom Short Codes - Create custom memorable URLs for your notes
- Secure by Default - Security rules enabled in Firestore
- Rate Limited - Built-in protection against abuse
- Analytics Ready - Optional GA4 tracking
- Mobile Friendly - Responsive design works on all devices
- Production Ready - Optimized for deployment on Vercel
- Frontend: Next.js 15 (App Router), TypeScript, TailwindCSS
- Backend: Firebase Firestore, Firebase Admin SDK
- Validation: Zod
- Security: bcryptjs, Rate Limiting (Upstash)
- Deployment: Vercel
- Node.js 18+ and pnpm (or corepack enable)
- Firebase Firestore for database and realtime cross-device sync.
- Firebase Admin SDK for secure, bypassed database access on the server.
- Optional Upstash Redis for production rate limiting.
git clone <repository-url>
cd kloud-notespnpm install- Create a Firebase Project at Firebase Console.
- Add a Web App and get the configuration.
- Go to Firestore Database and create a database.
- Copy the contents of
firestore.rulesand paste them into the Rules tab of your Firestore Database (or deploy via Firebase CLI). - Go to Project Settings > Service Accounts and generate a new private key.
- Update
.env.localwith your Firebase client configuration and Admin SDK credentials.
Create a .env.local file in the root directory:
cp .env.example .env.localEdit .env.local with your values:
# Firebase client configuration
NEXT_PUBLIC_FIREBASE_API_KEY=
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=
NEXT_PUBLIC_FIREBASE_PROJECT_ID=
NEXT_PUBLIC_FIREBASE_APP_ID=
# Firebase Admin SDK
FIREBASE_PROJECT_ID=
FIREBASE_CLIENT_EMAIL=
FIREBASE_PRIVATE_KEY=
# Application URL
NEXT_PUBLIC_APP_URL=http://localhost:3000
# Optional: Google Analytics 4
NEXT_PUBLIC_GA_MEASUREMENT_ID=
# Optional: Upstash Redis (for production rate limiting)
UPSTASH_REDIS_REST_URL=
UPSTASH_REDIS_REST_TOKEN=pnpm devOpen http://localhost:3000 to see the application.
kloud-notes/
├── src/
│ ├── app/
│ │ ├── [code]/ # Dynamic route for viewing notes
│ │ │ └── page.tsx
│ │ ├── api/
│ │ │ ├── notes/ # Create note endpoint
│ │ │ │ ├── route.ts
│ │ │ │ └── [code]/ # Fetch note endpoint
│ │ │ │ └── route.ts
│ │ │ └── verify/ # Password verification endpoint
│ │ │ └── route.ts
│ │ ├── layout.tsx
│ │ ├── page.tsx # Home page (create note)
│ │ └── globals.css
│ ├── components/
│ │ ├── NoteEditorClient.tsx # Unified note creation/editing form
│ │ ├── PasswordDialog.tsx
│ │ └── Spinner.tsx
│ ├── lib/
│ │ ├── firebase-client.ts # Firebase client initialization
│ │ ├── firebase-admin.ts # Firebase Admin SDK initialization
│ │ ├── validation.ts # Zod schemas
│ │ ├── security.ts # Password hashing/verification
│ │ ├── utils.ts # Utility functions
│ │ ├── constants.ts # App configuration
│ │ └── ratelimit.ts # Rate limiting
│ └── types/
│ └── note.ts # TypeScript interfaces
├── .env.example
├── .env.local # Your local environment variables (not committed)
└── README.md
Create a new note.
Request Body:
{
"content": "Your note content",
"password": "optional-password",
"customCode": "optional-custom-code"
}Response:
{
"shortCode": "abc123",
"url": "https://your-domain.com/abc123"
}Fetch a note by short code. Returns content only if not password-protected.
Verify password for a password-protected note.
Request Body:
{
"shortCode": "abc123",
"password": "user-password"
}- Firestore Security Rules: Database-level security policies
- Password Hashing: Bcrypt with 10 rounds
- Rate Limiting: Protects against brute-force attacks
- Input Validation: Zod schemas validate all inputs
- XSS Prevention: Input sanitization
- No Exposed Secrets: Firebase Admin SDK keys never sent to client
- Constant-Time Comparison: Password verification resistant to timing attacks
git add .
git commit -m "Initial commit"
git push origin main-
Go to Vercel
-
Import your repository
-
Add environment variables:
- All Firebase Client and Admin variables
NEXT_PUBLIC_APP_URL(set to your Vercel URL)- Optional:
NEXT_PUBLIC_GA_MEASUREMENT_ID(for Google Analytics 4) - Optional:
UPSTASH_REDIS_REST_URLandUPSTASH_REDIS_REST_TOKEN
-
Deploy!
After deployment, update NEXT_PUBLIC_APP_URL in Vercel settings to your production URL.
Check:
src/lib/firebase-admin.tssrc/lib/firebase-client.tssrc/lib/security.ts:
export const RATE_LIMIT = {
CREATE_NOTE: { requests: 5, window: '1m' },
VERIFY_PASSWORD: { requests: 10, window: '1m' },
FETCH_NOTE: { requests: 30, window: '1m' },
};Set NEXT_PUBLIC_GA_MEASUREMENT_ID to enable GA4 tracking. For the production Kloud Notes property, use:
NEXT_PUBLIC_GA_MEASUREMENT_ID=G-54ETKKVKPVexport const NOTE = {
MAX_SIZE_BYTES: 10 * 1024, // 10 KB
MAX_SIZE_CHARS: 10000,
};export const SHORT_CODE = {
MIN_LENGTH: 6,
MAX_LENGTH: 8,
CUSTOM_MAX_LENGTH: 50,
};For production-grade rate limiting across multiple instances:
- Create account at Upstash
- Create a new Redis database
- Copy REST URL and token to environment variables
- The app will automatically use Redis when configured
pnpm buildpnpm startpnpm lint- Run pnpm build and pnpm lint.
- Test with a real Firebase project using the current rules.
- Enter custom codes and ensure duplicates are blocked gracefully (HTTP 409).
- Edit notes from multiple tabs to verify realtime sync and concurrency.
- Confirm Vercel env vars are set, especially FIREBASE_PRIVATE_KEY.
- Decide whether Upstash is required for production-grade rate limiting
- Note expiration (auto-delete after X days)
- Rich text editor
- File attachments
- Custom themes
- API key authentication
- Never commit
.env.local- It contains sensitive keys - Rotate keys regularly - Especially if compromised
- Monitor rate limits - Adjust based on your traffic
- Set up Firebase Auth - For future user-specific features
- Enable database backups - In Firebase console
- Verify Firebase URL and keys are correct
- Check if Firestore security rules are deployed
- Ensure Firebase Admin SDK credentials are correct
- If using Upstash, verify Redis credentials
- Check console for rate limit errors
- In-memory fallback is used when Redis is not configured
- Clear
.nextfolder:rm -rf .next - Reinstall dependencies:
rm -rf node_modules && pnpm install - Check TypeScript errors:
pnpm build
Contributions are welcome! Please feel free to submit a Pull Request.
This project is open source and available under the MIT License.
For issues and questions, please open an issue on GitHub.
Built with ❤️ using Next.js, TypeScript, and Firebase