Note: This project is currently on hiatus as I focus on other priorities. This was intended to give me an alternative to Evernote. ZappyNotes serves as an open source learning resource and starting point for note-taking applications.
A modern, self-hosted note-taking application built with Rails 8. ZappyNotes provides a clean, intuitive interface for organizing your thoughts with Markdown support, auto-save, and tiered subscription plans.
- π¨ WYSIWYG Markdown Editor - Toast UI Editor with real-time formatting
- πΎ Auto-Save - Notes save automatically on blur and every 60 seconds
- πΌοΈ Image Upload - Paste or upload images directly into notes
- π Notebook Organization - Color-coded notebooks (6 colors)
- π± Responsive Design - Works on desktop and mobile
- π Email Confirmation - Verify email addresses to prevent abuse
- π‘οΈ Rate Limiting - Rack::Attack for DDoS protection
- Free Plan - 3 notebooks, 10 notes per notebook, 100MB storage
- Plus Plan ($1.99/mo) - 10 notebooks, 30 notes per notebook, 500MB storage
- Pro Plan ($4.99/mo) - Unlimited notebooks, notes, and storage
- ποΈ Motor Admin Panel - Full database management
- π€ Admin Users - Unlimited resources for administrators
- π Usage Tracking - Monitor storage and resource usage
- Framework: Ruby on Rails 8.1.1
- Ruby: 3.3.8
- Database: PostgreSQL 18
- CSS: Tailwind CSS v4
- JavaScript: Importmap, Stimulus, Turbo
- Editor: Toast UI Editor
- UI Components: Flowbite
- Payments: Stripe
- Email: ActionMailer with letter_opener (dev)
- Testing: RSpec, FactoryBot
- Monitoring: AppSignal (optional)
- Security: Rack::Attack
- Ruby 3.3.8
- Rails 8.1.1
- PostgreSQL 18
- Node.js (for JavaScript tooling)
git clone https://github.com/YOUR_USERNAME/zappynotes.git
cd zappynotesbundle installCreate a .env file:
cp .env.example .envUpdate .env with your configuration:
# Database
DATABASE_URL=postgresql://localhost/zappynotes_development
# Stripe Keys (optional - get from https://dashboard.stripe.com/apikeys)
STRIPE_PUBLISHABLE_KEY=pk_test_your_key
STRIPE_SECRET_KEY=sk_test_your_key
STRIPE_WEBHOOK_SECRET=whsec_your_secret
# Stripe Price IDs (optional - create in Stripe Dashboard)
STRIPE_PLUS_PRICE_ID=price_your_plus_id
STRIPE_PRO_PRICE_ID=price_your_pro_id
# AppSignal (optional - for monitoring)
APPSIGNAL_PUSH_API_KEY=your_key
# IP Blocking (optional)
BLOCKED_IPS=192.168.1.100,10.0.0.50rails db:create
rails db:migraterails console
> User.create!(
email_address: "admin@example.com",
password: "password123",
password_confirmation: "password123",
admin: true,
confirmed_at: Time.current
)
> exitTerminal 1 - Rails:
rails serverTerminal 2 - Tailwind CSS:
rails tailwindcss:watchVisit http://localhost:3000
# Run all tests
bundle exec rspec
# Run specific test file
bundle exec rspec spec/models/user_spec.rb
# Run with coverage
COVERAGE=true bundle exec rspecUses letter_opener gem - emails open in browser automatically.
Configure ActionMailer with your email service (SendGrid, Mailgun, etc.):
# config/environments/production.rb
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: 'smtp.sendgrid.net',
port: 587,
# ... other settings
}# Create app
heroku create your-app-name
# Add PostgreSQL
heroku addons:create heroku-postgresql:mini
# Set environment variables
heroku config:set STRIPE_PUBLISHABLE_KEY=pk_live_xxx
heroku config:set STRIPE_SECRET_KEY=sk_live_xxx
# ... set other env vars
# Deploy
git push heroku main
# Run migrations
heroku run rails db:migrate
# Create admin user
heroku run rails consoleSee deployment guides for Railway, Render, or Fly.io.
Edit config/initializers/rack_attack.rb:
# Sign-in attempts per IP
throttle('sign-in/ip', limit: 5, period: 20.seconds)
# Sign-up attempts per IP
throttle('sign-up/ip', limit: 3, period: 1.hour)
# General API requests
throttle('req/ip', limit: 300, period: 5.minutes)Add malicious IPs to .env:
BLOCKED_IPS=192.168.1.100,10.0.0.50,203.0.113.1Edit plan limits in app/models/user.rb:
def plan_limits
case plan
when :free
{ notebooks: 3, notes_per_notebook: 10, storage_mb: 100 }
when :plus
{ notebooks: 10, notes_per_notebook: 30, storage_mb: 500 }
when :pro
{ notebooks: Float::INFINITY, notes_per_notebook: Float::INFINITY, storage_mb: Float::INFINITY }
end
endContributions are welcome! This project is on hiatus but PRs will be reviewed.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Write tests for your changes
- Ensure all tests pass (
bundle exec rspec) - Run RuboCop (
bundle exec rubocop -A) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Follow Ruby Style Guide
- Write tests for new features (RSpec)
- Keep test coverage high
- Run RuboCop before committing
This project is open source and available under the MIT License.
- Built with Ruby on Rails
- UI components from Flowbite
- Editor powered by Toast UI Editor
- Monitoring by AppSignal (optional)
- Payments by Stripe
For questions or feedback, please open an issue on GitHub.
This is a learning project and personal tool. While functional, it's not actively maintained. Use at your own risk. For a polished, supported note-taking solution, consider Evernote, Notion, or Obsidian.
Star β this repo, and shoot me a βοΈ message if you find it useful!