Skip to content

A modern Rails 8.1 + React SaaS starter with Inertia.js, featuring passwordless authentication, Google OAuth, i18n support, Avo admin panel, and Kamal deployment

Notifications You must be signed in to change notification settings

goodmatedesign/rails_inertia_starter

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

79 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Rails SaaS Starter

A modern Rails 8.1 + React SaaS starter with authentication, admin panel, and Docker deployment.

Tech Stack

  • Backend: Rails 8.1, PostgreSQL, Puma
  • Frontend: React 19, TypeScript, Vite, Tailwind CSS 4
  • Integration: Inertia.js (seamless frontend-backend)
  • Auth: Passwordless magic link + Google OAuth
  • Admin: Avo admin panel
  • I18n: Rails i18n + i18n-js (URL-based locale switching)
  • Deployment: Kamal (Docker-based)

Quick Start

Prerequisites

  • Ruby 3.4+
  • Node.js 22+
  • PostgreSQL

Setup

# Clone and install dependencies
git clone https://github.com/goodmatedesign/rails_inertia_starter
cd rails_inertia_starter
bin/setup

Development

bin/dev  # Starts Rails + Vite

Visit http://localhost:3000

Configuration

Rails Credentials

Edit credentials with:

bin/rails credentials:edit

Add these keys:

# Google OAuth (required for Google sign-in)
google:
  client_id: your_google_client_id
  client_secret: your_google_client_secret

Google OAuth Setup

  1. Go to Google Cloud Console
  2. Create a new project or select existing
  3. Go to "Credentials" > "Create Credentials" > "OAuth client ID"
  4. Choose "Web application"
  5. Add authorized redirect URIs:
    • Development: http://localhost:3000/auth/google_oauth2/callback
    • Production: https://yourdomain.com/auth/google_oauth2/callback
  6. Copy Client ID and Client Secret to Rails credentials

Database

Development uses PostgreSQL with default settings. Configure in config/database.yml if needed.

bin/rails db:prepare  # Create and migrate
bin/rails db:reset    # Reset database

Authentication

Magic Link (Email)

Users enter email, receive a 6-digit verification code valid for 15 minutes.

Rate Limiting:

  • Email submission: 10 attempts per 3 minutes
  • Code verification: 10 attempts per 15 minutes

Google OAuth

"Continue with Google" button on sign-in page.

Account Linking

If a user signs up with email first, then uses Google (same email), accounts are automatically linked.

Admin Access

Make a user admin via Rails console:

bin/rails console
> User.find_by(email: "[email protected]").update!(admin: true)

Admin panel available at /avo (admin users only).

Deployment

Production Credentials

For production, create separate credentials:

EDITOR="code --wait" bin/rails credentials:edit --environment production

Add the same keys as development credentials.

Additionally, create config/postgres.key with your production database password.

Check .kamal/secrets for details:

RAILS_MASTER_KEY=$(cat config/credentials/production.key)
POSTGRES_PASSWORD=$(cat config/postgres.key)

Kamal Setup

  1. Update config/deploy.yml:

    • Set your server IP
    • Set your domain
    • Configure registry settings ( we use local registry by default, so you can skip this step )
  2. Deploy:

bin/kamal setup   # First deploy
bin/kamal accessory boot db # Start database
bin/kamal deploy  # Subsequent deploys

Trubleshooting

permission denied while trying to connect to the docker API

ERROR (SSHKit::Command::Failed): Exception while executing on host 12.222.123.123: docker exit status: 1
docker stdout: Nothing written
docker stderr: permission denied while trying to connect to the docker API at unix:///var/run/docker.sock

Check https://kamal-deploy.org/docs/configuration/ssh/

target failed to become healthy within configured timeout

ERROR (SSHKit::Command::Failed): Exception while executing on host 12.222.123.123: docker exit status: 1
docker stdout: Nothing written
docker stderr: Error: target failed to become healthy within configured timeout (30s)

This probably means that your server DB is not reachable from the app container. Check your config/deploy.yml and make sure that the DB configuration is correct. and you have started the DB accessory with bin/kamal accessory boot db

Internationalization (i18n)

This app supports multiple languages using Rails i18n on the backend and i18n-js on the frontend.

Supported Locales

  • English (en) - default
  • Chinese (zh)

How It Works

  • URL-based: Locale is determined by URL prefix (/en/..., /zh/...)
  • Session persistence: Locale is stored in session for non-localized routes (e.g., OAuth callbacks)
  • Shared translations: Rails YAML translations are exported to JSON for React

Adding Translations

  1. Add translations to config/locales/en.yml and config/locales/zh.yml:
# config/locales/en.yml
en:
  my_feature:
    title: "My Feature"
    description: "Feature description"
  1. Export translations to frontend:
bundle exec i18n export
  1. Use in React components:
import { useI18n } from "@/hooks/use-i18n";

export default function MyComponent() {
  const { t } = useI18n();

  return <h1>{t("my_feature.title")}</h1>;
}
  1. Use in Rails controllers/views:
flash[:notice] = t("flash.signed_in")

Adding a New Locale

  1. Add locale to config/application.rb:
config.i18n.available_locales = [:en, :zh, :es]  # Add :es
  1. Create locale file config/locales/es.yml

  2. Update app/frontend/types/index.ts:

export type Locale = "en" | "zh" | "es";
  1. Update app/frontend/components/locale-switcher.tsx:
const localeNames: Record<string, string> = {
  en: "EN",
  zh: "中文",
  es: "ES",
};
  1. Import new locale in app/frontend/lib/i18n.ts:
import es from "@/locales/es.json";

const i18n = new I18n({
  ...en,
  ...zh,
  ...es,
});
  1. Export translations:
bundle exec i18n export

Auto-Export During Development

Add to config/initializers/i18n.rb:

Rails.application.config.after_initialize do
  require "i18n-js/listen"
  I18nJS.listen
end

This auto-exports translations when locale files change.

Localized Links in React

Always include the locale in links:

import { usePage } from '@inertiajs/react'
import type { SharedProps } from '@/types'

const { locale } = usePage<SharedProps>().props

<Link href={`/${locale}/posts`}>Posts</Link>

Theming

Dark mode is supported via a custom useAppearance hook with Light/Dark/System modes. The app uses CSS variables with OKLch color space for modern color handling.

  • Theme preference is persisted in localStorage
  • System mode follows OS preference and updates automatically
  • Theme is initialized before React hydration to prevent flash

Toast notifications are provided by sonner with automatic dark mode support.

Development Tools

Process Managers

bin/dev supports multiple process managers (in order of preference):

  • overmind
  • hivemind
  • foreman

CI Pipeline

The CI suite (bin/ci) runs:

  1. RuboCop (linting)
  2. Brakeman (security analysis)
  3. bundler-audit (gem vulnerability scanning)
  4. Rails tests
  5. System tests

Testing

bin/rails test          # Run all tests
bin/rails test:system   # System tests
npm run check           # TypeScript check
bin/rubocop             # Ruby linting
bin/brakeman            # Security scan
bin/ci                  # Full CI suite

Project Structure

app/
├── controllers/        # Rails controllers
├── frontend/           # React frontend
│   ├── components/     # Shared components
│   ├── pages/          # Inertia pages
│   ├── hooks/          # React hooks
│   ├── locales/        # Exported JSON translations
│   ├── lib/            # Utilities (i18n setup, etc.)
│   └── types/          # TypeScript types
├── models/             # Rails models
├── mailers/            # Email templates
└── avo/                # Admin panel resources
config/
├── locales/            # Rails YAML translations (en.yml, zh.yml)
└── i18n.yml            # i18n-js export configuration

License

MIT

About

A modern Rails 8.1 + React SaaS starter with Inertia.js, featuring passwordless authentication, Google OAuth, i18n support, Avo admin panel, and Kamal deployment

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

  •  
  •  
  •