https://github.com/mundanecodes/rails-starter
Production-ready Rails 8.1 template with UUID v7, RSpec, Sidekiq, Docker, and modern tooling
https://github.com/mundanecodes/rails-starter
docker postgresql production-ready rails rails8 rspec ruby sidekiq starter-template template uuid
Last synced: 3 months ago
JSON representation
Production-ready Rails 8.1 template with UUID v7, RSpec, Sidekiq, Docker, and modern tooling
- Host: GitHub
- URL: https://github.com/mundanecodes/rails-starter
- Owner: mundanecodes
- License: mit
- Created: 2025-10-06T21:11:02.000Z (9 months ago)
- Default Branch: main
- Last Pushed: 2025-10-06T21:26:00.000Z (9 months ago)
- Last Synced: 2025-10-06T23:22:36.827Z (9 months ago)
- Topics: docker, postgresql, production-ready, rails, rails8, rspec, ruby, sidekiq, starter-template, template, uuid
- Language: Ruby
- Size: 12.7 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Rails Starter Template
[](https://www.ruby-lang.org)
[](https://rubyonrails.org)
[](LICENSE)
[](https://hacktoberfest.com)
A production-ready Rails 8.1 application template with modern tooling, UUID v7 primary keys, comprehensive testing setup, and Docker support.
## Table of Contents
- [Features](#features)
- [Usage](#usage)
- [Environment Variables](#environment-variables)
- [UUID v7 Primary Keys](#uuid-v7-primary-keys)
- [SimpleState](#simplestate)
- [Testing](#testing)
- [Sidekiq Web UI](#sidekiq-web-ui)
- [Development URLs](#development-urls)
- [Robot Blocking](#robot-blocking)
- [CI/CD](#cicd)
- [Customization](#customization)
- [Tech Stack Summary](#tech-stack-summary)
- [License](#license)
## Features
### Core Stack
- **Rails 8.1.0.beta1** - Latest edge version
- **PostgreSQL** with UUID v7 primary keys (time-ordered, sortable)
- **Redis** for caching and job queue
- **Memcached** with Dalli for distributed caching
- **Puma** web server (2 workers, 5 threads)
### Background Jobs
- **Sidekiq** for background job processing
- Authenticated web UI at `/wera` with HTTP Basic Auth
### Testing
- **RSpec** testing framework
- **FactoryBot** for test data
- **Shoulda Matchers** for Rails-specific assertions
- **WebMock** for HTTP request stubbing
- **DatabaseCleaner** with transaction strategy
- Performance optimizations (GC management, eager loading)
### HTTP & Storage
- **HTTPX** - modern HTTP/2 client
- **Active Storage** with AWS S3 support
- Multi-environment storage configuration (local/test/S3)
### Development
- **dotenv-rails** for environment variables
- **Ngrok** tunnel support for webhooks
- **.localhost** domain support (no /etc/hosts editing needed)
- Port 3007 by default (avoids common conflicts)
### Security & SEO
- Robot blocking middleware (SEO and AI crawlers)
- Comprehensive robots.txt
- Constant-time authentication comparison (prevents timing attacks on password checks)
- No default credentials (environment-based)
### DevOps
- **Docker** and **docker-compose** ready
- **GitHub Actions** CI/CD pipeline
- Health check endpoint silencing
- **Kamal** deployment configuration
- **Brakeman** security scanning
- **RuboCop** and **StandardRb** code linting
### Configuration
- **UTC timezone** (standard for Rails applications)
- PostgreSQL connection pooling and statement timeouts
- Request specs only (no controller/view specs)
- No helper file generation
- Clean, organized Gemfile
## Usage
### Create a new application
```bash
rails new myapp -d postgresql -m https://raw.githubusercontent.com/mundanecodes/rails-starter/main/template.rb
```
The template will:
1. Install and configure all gems
2. Set up RSpec with all testing tools
3. Configure PostgreSQL with UUID v7 support
4. Set up Sidekiq with authenticated web UI
5. Configure Docker and docker-compose
6. Create GitHub Actions workflow
7. Set up robot blocking
8. Generate `.env.example` with all required variables
9. Create initial git commit
### Post-installation steps
1. **Configure environment variables:**
```bash
cp .env.example .env
# Edit .env with your values
```
2. **Set up database:**
```bash
bin/rails db:create db:migrate
```
3. **Start the server:**
```bash
bin/rails server -p 3007
```
4. **Access your app:**
- Main app: `http://myapp.localhost:3007`
- Sidekiq UI: `http://myapp.localhost:3007/wera`
### Using Docker
```bash
docker-compose up
```
Services included:
- Web (Rails app on port 3007)
- PostgreSQL 16
- Redis 7
- Memcached 1.6
- Sidekiq worker
## Environment Variables
Required variables (see `.env.example`):
```bash
# Database
DATABASE_URL=postgres://postgres:postgres@localhost:5432/myapp_development
# Redis & Sidekiq
REDIS_URL=redis://localhost:6379/0
SIDEKIQ_USERNAME=your_username
SIDEKIQ_PASSWORD=your_secure_password
# Memcached
MEMCACHED_SERVERS=localhost:11211
# AWS S3 (production)
AWS_ACCESS_KEY_ID=your_access_key
AWS_SECRET_ACCESS_KEY=your_secret_key
AWS_REGION=us-east-1
AWS_BUCKET=your-bucket-name
# Server
PORT=3007
```
## UUID v7 Primary Keys
All models automatically use UUID v7 as primary keys:
```ruby
# No configuration needed - it's automatic!
class User < ApplicationRecord
# id will be UUID v7
end
# In migrations
create_table :users do |t|
# id is automatically UUID v7
t.string :email
t.timestamps
end
```
UUID v7 benefits:
- Time-ordered (sortable like auto-incrementing IDs)
- Globally unique
- Better for distributed systems
- Database index-friendly
## SimpleState
A lightweight state machine module included with this template. Perfect for modeling workflows like user onboarding, order processing
```ruby
class Employee < ApplicationRecord
include SimpleState
state_column :status
enum status: {
created: "created",
invited: "invited",
enrolled: "enrolled",
suspended: "suspended",
terminated: "terminated"
}
# Basic transition
transition :invite, from: :created, to: :invited, timestamp: :invited_at
# Transition with guard
transition :enroll, from: :invited, to: :enrolled, timestamp: true,
guard: :valid_invitation?
# Transition with callback
transition :suspend, from: [:enrolled], to: :suspended do
NotificationMailer.suspension_notice(self).deliver_later
end
# Multiple source states
transition :reactivate, from: [:suspended, :terminated], to: :enrolled
private
def valid_invitation?
invited_at.present? && invited_at > 30.days.ago
end
end
```
**Usage:**
```ruby
employee = Employee.create!(status: :created)
employee.invite # => transitions to :invited, sets invited_at
employee.enroll # => transitions to :enrolled if guard passes
# Check if transition is allowed
employee.can_transition?(:suspend) # => true
# Error handling
begin
employee.invite # raises SimpleState::TransitionError if invalid
rescue SimpleState::TransitionError => e
# Handle invalid transition
end
```
**Features:**
- **Guards**: Prevent transitions unless conditions are met
- **Timestamps**: Auto-update columns on transition (e.g., `invited_at`)
- **Callbacks**: Execute code after successful transitions
- **Events**: Publishes `ActiveSupport::Notifications` for all transitions
- **Validation**: Ensures states exist in your enum at class load time
**Events published:**
Events follow the pattern: `{model_name}.{transition_name}.{outcome}`
For example, the `invite` transition on `Employee` publishes:
- `employee.invite.success` - Transition succeeded
- `employee.invite.failed` - Update failed (validation, etc.)
- `employee.invite.invalid` - Transition not allowed or guard failed
Subscribe to events for logging, metrics, or side effects:
```ruby
ActiveSupport::Notifications.subscribe(/employee\..*\.success/) do |name, start, finish, id, payload|
Rails.logger.info "Employee #{payload[:record_id]} transitioned to #{payload[:to_state]}"
end
```
## Testing
Run the full test suite:
```bash
bundle exec rspec
```
Testing features:
- Request specs generated by default
- FactoryBot syntax methods included
- WebMock prevents external HTTP calls
- Transaction-based database cleaning (fast)
- GC disabled during tests for 20-30% speed improvement
## Sidekiq Web UI
Access at `/wera` with HTTP Basic Authentication.
Set credentials via environment variables:
```bash
SIDEKIQ_USERNAME=admin
SIDEKIQ_PASSWORD=secure_password_here
```
Authentication uses constant-time comparison to prevent timing attacks.
## Development URLs
The template configures support for:
- `http://myapp.localhost:3007` (no /etc/hosts editing needed)
- Ngrok tunnels: `https://abc123.ngrok-free.app`
- Standard localhost: `http://localhost:3007`
### Starting an Ngrok tunnel
To expose your local server for webhook testing:
```bash
ngrok http 3007
```
This creates a public URL like `https://abc123.ngrok-free.app` that forwards to your local port 3007.
## Robot Blocking
All robots are blocked by default via:
1. `public/robots.txt` - Blocks all user agents including GPTBot, CCBot, etc.
2. Middleware - Adds `X-Robots-Tag` headers to all responses
3. Multiple layers ensure comprehensive blocking
Remove or modify in production if you want SEO indexing.
## CI/CD
GitHub Actions workflow includes:
- RSpec test suite
- Brakeman security scanning
- RuboCop and StandardRb linting
- PostgreSQL and Redis services
## Customization
### Change timezone
Edit `config/application.rb`:
```ruby
config.time_zone = "Your/Timezone"
```
### Change port
Edit `.env`:
```bash
PORT=3000
```
And `docker-compose.yml`:
```yaml
ports:
- "3000:3000"
```
### Disable robot blocking
Remove from `config/application.rb`:
```ruby
config.middleware.use BlockRobots
```
## Tech Stack Summary
| Category | Technology |
|----------|-----------|
| Framework | Rails 8.1.0.beta1 |
| Database | PostgreSQL 16 + UUID v7 |
| Cache | Redis 7 + Memcached 1.6 + Dalli |
| Background Jobs | Sidekiq |
| Testing | RSpec + FactoryBot + Shoulda + WebMock |
| HTTP Client | HTTPX |
| Storage | Active Storage + AWS S3 |
| Web Server | Puma (2 workers, 5 threads) |
| Containerization | Docker + docker-compose |
| CI/CD | GitHub Actions |
| Deployment | Kamal |
| Security | Brakeman |
| Linting | RuboCop + StandardRb |
## License
MIT
## Credits
Built by [mundanecodes](https://github.com/mundanecodes) for rapid Rails application development.