This is a start app kit template analogous to Jumpstart Pro or BulletTrain, but using Svelte and Inertia.js for the frontend, with Ruby on Rails as the backend, and including a number of other useful libraries and tools.
Unlike typical app-kits, this one begins with the assumption that all apps worth building at this point will have heavy AI integration, including at the very least chat/conversation features, agentic set ups, tools, and group chat features.
- Svelte 5 - A modern JavaScript framework for building user interfaces.
- Ruby on Rails - A powerful web application framework for building server-side applications.
- Inertia.js Rails - Enables single-page applications using classic Rails routing and controllers.
- ShadcnUI - A collection of UI components for Svelte.
- Tailwind CSS - A utility-first CSS framework for building custom designs.
- Phosphor Icons - A versatile icon library for user interfaces.
- JS Routes - A library for generating JavaScript routes in Rails applications.
- Rails Authentication - Built-in authentication using the default Rails 8 authentication system.
- Vite - A fast and modern frontend bundler.
- PostgreSQL - A powerful, open-source relational database system.
- DaisyUI - A plugin for Tailwind CSS that provides a set of pre-designed components, for rapid prototyping of components not covered by ShadcnUI.
- Claude Code Ready - Clear documentation in
/docs/to enable Claude Code to perform at its best. - SolidQueue/Cable/Cache - Set up in development environment, for background jobs, real-time features, and caching.
- Obfuscated IDs - For better security and aesthetics in URLs. Copy implementation from BulletTrain.
- Testing - Full test suite setup with Playwright Component Testing for page testing, Vitest for Svelte component unit testing, Minitest for Rails model and controller testing.
- Full-featured user system - Necessary for most commercial applications, but not included in the default user setup.
- User signup and confirmation
- Personal/Organization Accounts
- Site Admin
- User Profiles
- Invitations
- Roles
- Svelte Object Synchronization - Using ActionCable and Inertia's partial reload and a custom Regitry to keep Svelte $props up to date in real-time.
- Audit Logging with audit log viewer (required in many business applications).
- AI Integration features:
- OpenRouter integration
- Prompt system
- Basic Conversation System
- Agentic Conversation System (Tools)
- Group Chat System - Multiple agents in single chat:
- Memory management (Journal - mid term, Core - long term)
- Consolidation of idle conversations (hourly job)
- Shared whiteboard for collaborative editing
- Automated Database Backups - Daily PostgreSQL backups to S3 via scheduled job
-
**Discard gem: Never delete anything important (e.g. accounts, users, etc), only discard it.
-
AI Integration features:
- Thinking Mode
-
MultiAttachment system supporting:
- Direct uploads to S3
- PDF/Document parsing
- URL fetch
- Free text
-
Organisation account settings:
- Logo
- Company Name
-
All account settings:
- Billing
-
API capability:
- API key management
- API key usage tracking
- API key rate limiting
- API key billing
- API key audit logging
- API documentation
- Internationalization (i18n)
- Click "Use this template" to create a new repository from this template.
- Clone your new repository:
git clone https://github.com/<youruser>/<your_repo> cd <your-repo>
- Install dependencies:
bundle install npm install
- Setup the database:
Check that the solid* databases have been created by checking
rails db:create:all rails db:setup db:prepare rails db:migrate:cache db:migrate:queue db:migrate:cable rails db:schema:dump:cable db:schema:dump:cache db:schema:dump:queue
db/cable_schema.rb,db/cache_schema.rb, anddb/queue_schema.rband seeing that they contain a comment at the top about auto-generation. - Either download the
config/master.keyfrom a colleague, orrails credentials:editand add the following credentials:aws: access_key_id: ... s3_bucket: ... s3_region: ... secret_access_key: ... postgres_bucket: ... # For automated database backups ai: claude: api_token: ... open_ai: api_token: ... openrouter: api_token: ... honeybadger: api_key: ...
- Start the development server:
bin/dev
- Open in browser at localhost:3100
Necessary for Claude Code to be full featured.
claude mcp add --scope=local playwright npx @executeautomation/playwright-mcp-server
claude mcp add --scope=local snap-happy npx @mariozechner/snap-happyThis template integrates Svelte with Rails using Inertia.js to manage front-end routing while keeping Rails' backend structure. It uses Vite for asset bundling, and all frontend code is located in the app/frontend directory. Place assets such as images and fonts inside the app/frontend/assets folder.
Feel free to fork this repository and submit pull requests with improvements, fixes, or additional features.
This application includes a powerful real-time synchronization system that automatically updates Svelte components when Rails models change, using ActionCable and Inertia.js partial reloads.
- Rails models broadcast minimal "marker" messages when they change
- Svelte components subscribe to these broadcasts via ActionCable
- When a broadcast is received, Inertia performs a partial reload of just the affected props
- Updates are debounced (300ms) to handle multiple rapid changes efficiently
Rails Side:
app/channels/sync_channel.rb- ActionCable channel with authorizationapp/models/concerns/broadcastable.rb- Model concern for automatic broadcastingapp/models/concerns/sync_authorizable.rb- Authorization logic for sync accessapp/channels/application_cable/connection.rb- WebSocket authentication
JavaScript/Svelte Side:
app/frontend/lib/cable.js- Core ActionCable subscription managementapp/frontend/lib/use-sync.js- Svelte hook for easy integration
1. Add to your Rails model:
class Account < ApplicationRecord
include SyncAuthorizable
include Broadcastable
# Configure what to broadcast to
broadcasts_to :all # Broadcast to admin collection (for index pages)
end
class AccountUser < ApplicationRecord
include Broadcastable
belongs_to :account
belongs_to :user
# Broadcast changes to the parent account
broadcasts_to :account
end
class User < ApplicationRecord
include Broadcastable
has_many :accounts
# Broadcast changes to all associated accounts (uses Rails reflection)
broadcasts_to :accounts
endUnderstanding broadcasts_to:
:all- Broadcasts to a collection channel (typically for admin index pages)- Association name - Broadcasts to associated records automatically:
- For
belongs_to/has_one: Broadcasts to the single associated record - For
has_many/has_and_belongs_to_many: Broadcasts to each record in the collection
- For
- Rails uses reflection to automatically detect the association type and handle it correctly
2. Use in your Svelte component:
For static subscriptions:
<script>
import { useSync } from '$lib/use-sync';
let { accounts = [] } = $props();
// Simple static subscriptions
useSync({
'Account:all': 'accounts', // Updates when any account changes
});
</script>For dynamic subscriptions (when the subscribed objects can change):
<script>
import { createDynamicSync } from '$lib/use-sync';
let { accounts = [], selected_account = null } = $props();
// Create dynamic sync handler
const updateSync = createDynamicSync();
// Update subscriptions when selected_account changes
$effect(() => {
const subs = { 'Account:all': 'accounts' };
if (selected_account) {
subs[`Account:${selected_account.id}`] = 'selected_account';
}
updateSync(subs);
});
</script>That's it! Your component will now automatically update when the data changes on the server.
Here's how all the pieces work together:
Rails Controller:
# app/controllers/dashboard_controller.rb
class DashboardController < ApplicationController
def index
render inertia: "Dashboard", props: {
current_user: current_user.as_json,
account: current_account.as_json,
notifications: current_user.notifications
}
end
endRails Models:
# app/models/notification.rb
class Notification < ApplicationRecord
include Broadcastable
belongs_to :user
# Broadcast changes to the parent user
broadcasts_to :user
end
# app/models/user.rb
class User < ApplicationRecord
include Broadcastable
has_many :accounts, through: :account_users
# Broadcast changes to all associated accounts
broadcasts_to :accounts
endSvelte Component:
<script>
import { useSync } from '$lib/use-sync';
// These prop names match what the controller sends
let { current_user, account, notifications } = $props();
// Subscribe to updates - map channels to props to reload
useSync({
[`User:${current_user.id}`]: 'current_user',
[`Account:${account.id}`]: 'account',
[`Notification:all`]: 'notifications'
});
</script>The key insight: The model just broadcasts its identity (e.g., "User:123"), and the Svelte component decides which props need reloading based on its subscriptions.
- Objects with an
accountproperty: Accessible by all users in that account - Objects without an
accountproperty: Admin-only access - Site admins can subscribe to
:allcollections for any model
Run the synchronization tests:
rails test test/channels/sync_channel_test.rb
rails test test/models/concerns/broadcastable_test.rbSee the in-app documentation for more detailed information and advanced usage.
This application includes a powerful convention for controlling how Rails models are serialized to JSON, with automatic ID obfuscation for better security and cleaner URLs.
The json_attributes concern provides a declarative way to specify which attributes and methods should be included when a model is converted to JSON (for Inertia props or API responses). It also automatically obfuscates model IDs using to_param.
- Declarative Attribute Selection - Explicitly define which attributes/methods to include
- Automatic ID Obfuscation - IDs are automatically replaced with obfuscated versions via
to_param - Boolean Key Cleaning - Methods ending with
?have the?removed in JSON (e.g.,admin?becomesadmin) - Association Support - Include associated models with their own json_attributes
- Context Propagation - Pass context (like
current_user) through nested associations
class User < ApplicationRecord
include JsonAttributes
# Specify what to include in JSON, excluding sensitive fields
json_attributes :full_name, :site_admin, except: [:password_digest]
end
class Account < ApplicationRecord
include JsonAttributes
# Include boolean methods (the ? will be stripped in JSON)
json_attributes :personal?, :team?, :active?, :is_site_admin, :name
end
class AccountUser < ApplicationRecord
include JsonAttributes
# Include associations with their json_attributes
json_attributes :role, :confirmed_at, include: { user: {}, account: {} }
endclass AccountsController < ApplicationController
def show
@account = current_user.accounts.find(params[:id])
render inertia: "accounts/show", props: {
# as_json automatically uses json_attributes configuration
account: @account.as_json,
# Pass current_user context for authorization in nested associations
members: @account.account_users.as_json(current_user: current_user)
}
end
end- Security: Sensitive attributes like
password_digestare never accidentally exposed - Clean URLs: Obfuscated IDs provide better aesthetics and security
- Consistency: All models serialize the same way throughout the application
- Performance: Only specified attributes are serialized, reducing payload size
- Maintainability: JSON structure is defined in one place (the model)
See the in-app documentation for more detailed information and advanced usage.
This project is open-source and available under the MIT License.