Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
110 commits
Select commit Hold shift + click to select a range
fac5b73
Upgraded Ruby to 4.0.0
newstler Jan 7, 2026
b87cc5d
Merge pull request #90 from newstler/feature/upgrade_ruby
newstler Jan 7, 2026
e3d02de
Remove devise, add magick links, configure script, and CLAUDE.md
newstler Jan 9, 2026
84a0a1a
Removed dotenv and added litestream
newstler Jan 9, 2026
b5ffb9d
Update documentation
newstler Jan 9, 2026
574cfe9
Add RubyLLM, fix Avo
newstler Jan 10, 2026
6d13c0b
Replaced Avo with Madmin
newstler Jan 13, 2026
6f9caa1
Style chats
newstler Jan 13, 2026
3d05f0a
Implementing dark mode
newstler Jan 13, 2026
f25d7e7
WIP: Fixing the design
newstler Jan 13, 2026
8ced812
Fixed most of the UI
newstler Jan 14, 2026
bb2c39a
Fixed most of the UI
newstler Jan 14, 2026
b4bdaf2
Fixed most of the UI
newstler Jan 15, 2026
6b8fa64
Fixed most of the UI
newstler Jan 15, 2026
b73a606
Add CapedBot favicon and web app icons
newstler Jan 15, 2026
3b11698
Seems fixed most of the UI
newstler Jan 15, 2026
b38b9c9
Feature: Added Claude Configuration.
newstler Jan 16, 2026
7933fc1
Feature: Added Claude Configuration.
newstler Jan 16, 2026
50103be
Feature: Added AGENTS.md.
newstler Jan 16, 2026
ee92887
Added TDD principles into AGENTS.md
newstler Jan 16, 2026
4a69edc
Added TDD principles into testing rule
newstler Jan 16, 2026
9f5a650
Added TDD principles into testing skill
newstler Jan 16, 2026
f51b2cd
Added more skills and agents
newstler Jan 16, 2026
c9b1570
Refactor
newstler Jan 16, 2026
27077ab
Style New Chat window
newstler Jan 16, 2026
7da67c8
Fix start chat UI
newstler Jan 16, 2026
62cbb41
Style New Chat window
newstler Jan 16, 2026
89ac79b
Converted all colors to OKLCH
newstler Jan 16, 2026
aa7b09c
Migrate Tailwind config from v3 to v4 CSS-first approach
newstler Jan 16, 2026
0b09c9a
Filter models by configured provider credentials
newstler Jan 16, 2026
b0e5273
Improve layout consistency and admin auth styling
newstler Jan 16, 2026
49abfd2
Fixed UI and added sorting on cost
newstler Jan 22, 2026
c80fab6
Add DDoS/malicious request protection and attachment display
newstler Jan 22, 2026
dc644f8
Refactor: Extract concerns, simplify dashboard, fix tests
newstler Jan 26, 2026
2f7f1b6
Consolidate CSS into single Tailwind entry point
newstler Jan 26, 2026
a9f855e
Fix favicon generation to preserve transparency
newstler Jan 26, 2026
c227ac6
Refactor CSS to use native nesting syntax
newstler Jan 26, 2026
a20a581
Add MCP server with Streamable HTTP transport
newstler Jan 27, 2026
e9312c2
Switched from ULID to UUIDv7
newstler Jan 27, 2026
7a0169d
Use concise id: hash syntax for UUIDv7 primary keys
newstler Jan 27, 2026
c5e57b6
Fix duplicate counter cache callbacks and remove circular FK
newstler Jan 27, 2026
d0ef656
Simplify deploy config to use Rails credentials
newstler Jan 28, 2026
138a935
Rubocop
newstler Jan 28, 2026
1b2d4e6
Move all user-facing text to Rails i18n
newstler Jan 28, 2026
485d62d
Add pre-commit hook to run bin/ci before commits
newstler Jan 28, 2026
57cd8c1
Improve configure script with port config, db:seed, and fixes
newstler Jan 29, 2026
ea9ba72
Refactor setup flow: bin/setup calls bin/configure
newstler Jan 30, 2026
57b5469
Fix duplicate db:seed and add template update tip
newstler Jan 30, 2026
67ba5e6
Unify color system in bin/configure
newstler Jan 30, 2026
13ad81b
Fix: Exclude generators from autoload in production
newstler Jan 30, 2026
aaca4f8
Add multitenancy with team-scoped routes
newstler Jan 30, 2026
b8c2b1d
Move MCP API keys from users to teams
newstler Jan 30, 2026
5c2fca5
Add Open Graph image system with per-page meta tag support
newstler Feb 5, 2026
934f541
Add Stripe billing integration for team subscriptions
newstler Feb 5, 2026
993f006
f
newstler Feb 5, 2026
e34006e
Move service API keys from credentials to database-backed admin settings
newstler Feb 7, 2026
45d8708
Multitenancy.
newstler Feb 7, 2026
c22e789
Add subscription cancellation, resume, and resubscription lifecycle
newstler Feb 7, 2026
45e5ac5
Add performance optimizations, provider credentials, and public chats…
newstler Feb 8, 2026
3ba6343
Fix critical security issues and handle provider config errors
newstler Feb 8, 2026
68ad5b4
bundle update
newstler Feb 8, 2026
5837c7b
Move mail from setting from configure script to UI
newstler Feb 8, 2026
74e67ff
Styled madmin
newstler Feb 8, 2026
3d47567
Styled show pages
newstler Feb 8, 2026
29c7637
Consolidate migrations into single initial schema during bin/configure
newstler Feb 8, 2026
5b2476f
Add Nullitics analytics with MaxMind GeoLite2 geolocation
newstler Feb 8, 2026
979473e
Fix configure script: two-step analytics flow and frozen string bug
newstler Feb 8, 2026
1a39baf
Update README: AI-Native Rails Template with featured AI capabilities
newstler Feb 8, 2026
ec71325
Add Nullitics analytics to README tech stack
newstler Feb 8, 2026
36a98cb
Remove single-tenant mode, always multi-tenant
newstler Feb 8, 2026
e938e08
Fix Brakeman SQL injection warnings in Madmin controllers
newstler Feb 8, 2026
399f0bc
Use bin/brakeman in CI so warnings fail the build
newstler Feb 8, 2026
c277589
Merge pull request #91 from newstler/feature/multitenancy
newstler Feb 8, 2026
6b1f0cc
Add multilingual content with auto-translation and Russian locale (#92)
newstler Feb 16, 2026
b8208d3
Fix bin/setup LoadError for ActiveSupport (#93)
newstler Mar 30, 2026
f266c51
fix(setup): install gems before running configure (#95)
newstler Mar 30, 2026
dd91ba9
fix(configure): remove ActiveSupport dependency from credentials setu…
newstler Mar 30, 2026
2ee9e9e
Merge template: replace Avo with Madmin, add teams/billing/MCP/multil…
newstler Apr 1, 2026
7609ded
refactor(auth): remove Devise, use session-based GitHub OAuth directly
newstler Apr 1, 2026
8339bb4
fix(deploy): improve credential reading and build reliability (#97)
newstler Apr 1, 2026
dad7263
Merge template: improve deploy reliability, fix all tests
newstler Apr 6, 2026
f820df2
chore(deps): update all gems, fix ActiveSupport::Configurable depreca…
newstler Apr 6, 2026
ef0fdf2
docs: add design spec for 37signals refactor + RubyLLM migration
newstler Apr 6, 2026
db8ddf6
docs: add implementation plan for 37signals refactor + RubyLLM migration
newstler Apr 6, 2026
70a2cfe
refactor: move LocationNormalizer + TimezoneResolver to User::Geocoda…
newstler Apr 6, 2026
4a19e66
refactor: move SvgSanitizer to Post::SvgSanitizable concern
newstler Apr 6, 2026
9577c3d
refactor: move MetadataFetcher to Post::MetadataFetchable concern
newstler Apr 6, 2026
1cb3c6c
refactor: move ImageProcessor to Post::ImageVariantable concern
newstler Apr 6, 2026
097de32
refactor: move SuccessStoryImageGenerator to Post::OgImageGeneratable…
newstler Apr 6, 2026
bc41904
refactor: move GithubDataFetcher to User::GithubSyncable concern
newstler Apr 6, 2026
92abb86
feat: add purpose column to chats for system AI tracking
newstler Apr 6, 2026
c7d4df3
refactor: move summary generation to Post::AiSummarizable, use RubyLLM
newstler Apr 6, 2026
3401cb3
refactor: move testimonial generation to Testimonial::AiGeneratable, …
newstler Apr 6, 2026
cab6644
refactor: move testimonial validation to Testimonial::AiValidatable, …
newstler Apr 6, 2026
23aa960
chore: remove ruby-openai and anthropic gems, RubyLLM handles all AI
newstler Apr 6, 2026
1070e61
docs: rewrite AGENTS.md to reflect post-refactor architecture
newstler Apr 6, 2026
0e5ab0a
fix: clean up extra blank lines in post.rb, fix stale job name in README
newstler Apr 6, 2026
dfe9c25
refactor: extract UsersController map_data and og_image to nested res…
newstler Apr 6, 2026
541b6d1
refactor: extract Tags, Sessions, and Teams::Settings custom actions …
newstler Apr 6, 2026
05d1ad6
refactor: extract PostsController custom actions to nested resource c…
newstler Apr 6, 2026
3ea4085
refactor: extract UserSettingsController to nested REST resource cont…
newstler Apr 6, 2026
f26667e
test: remove 98 useless tests that just verify Rails framework behavior
newstler Apr 6, 2026
31f59af
test: add User trust, profile visibility, SVG/metadata/AI concern tests
newstler Apr 6, 2026
785325a
fix: guard post_path_for against nil category to prevent homepage crash
newstler Apr 7, 2026
4bc86e1
refactor(madmin): expand admin panel with full resource CRUD and impr…
newstler Apr 7, 2026
84dda00
refactor(madmin): update dashboard cards with projects, testimonials,…
newstler Apr 8, 2026
1799185
fix(routes): cross-domain auth broken by wildcard route matching /aut…
newstler Apr 8, 2026
94f1ae6
refactor(settings): move credentials and AI models from code to Madmi…
newstler Apr 8, 2026
5b0a0bd
fix(urls): allow dots in URL paths and prevent bio overflow
newstler Apr 9, 2026
89c9c88
fix(ui): use break-words instead of break-all for user bio text
newstler Apr 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .claude/agents/rails-backend.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,5 +113,5 @@ Before completing any task:
```bash
bundle exec rubocop -A # Fix lint issues
rails test # Run tests
bundle exec brakeman -q # Security check
bin/brakeman --no-pager # Security check
```
2 changes: 1 addition & 1 deletion .claude/commands/commit-push-pr.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Before committing, ensure code quality:
```bash
bundle exec rubocop -A
rails test
bundle exec brakeman -q --no-pager
bin/brakeman --no-pager
```

If any quality gate fails, fix the issues before proceeding.
Expand Down
2 changes: 1 addition & 1 deletion .claude/commands/review-code.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ git diff --cached # If already staged
```bash
bundle exec rubocop -A
rails test
bundle exec brakeman -q --no-pager
bin/brakeman --no-pager
```

## 4. Common Issues
Expand Down
2 changes: 1 addition & 1 deletion .claude/commands/run-tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ Action: Method doesn't exist, check model implementation.
If all tests pass:
```bash
bundle exec rubocop -A
bundle exec brakeman -q
bin/brakeman --no-pager
```

If tests fail:
Expand Down
168 changes: 168 additions & 0 deletions .claude/rules/i18n.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# i18n Standards

## Philosophy

**No hardcoded user-facing text.** All strings shown to users must use Rails i18n.

## Key Conventions

### Lazy Lookup in Views

Use the shorthand `.key` notation in views - Rails automatically infers the full path:

```erb
<%# In app/views/sessions/new.html.erb %>
<%= t(".heading") %> <%# Looks up en.sessions.new.heading %>
<%= t(".email_label") %>
```

### Lazy Lookup in Mailers

Same pattern works in mailers:

```ruby
# In app/mailers/user_mailer.rb, method magic_link
mail(to: user.email, subject: t(".subject")) # en.user_mailer.magic_link.subject
```

### Controllers Use Full Paths

Controllers should use explicit paths for clarity:

```ruby
redirect_to path, notice: t("controllers.sessions.create.notice")
redirect_to path, alert: t("controllers.application.authenticate_user")
```

### Interpolation

Use `%{variable}` for dynamic values:

```yaml
# config/locales/en/controllers.yml
en:
controllers:
sessions:
verify:
notice: "Welcome back, %{name}!"
```

```ruby
t("controllers.sessions.verify.notice", name: user.name)
```

## File Structure

```
config/locales/
├── en.yml # Common terms (app_name, common.*)
└── en/
├── controllers.yml # Flash messages and controller strings
├── mailers.yml # Email subjects and content
└── views/
├── sessions.yml # User login views
├── home.yml # Dashboard
├── chats.yml # Chat views
├── models.yml # AI models views
├── messages.yml # Message form
├── shared.yml # Sidebar, flash, shared partials
└── admins/
└── sessions.yml # Admin login views
```

## What to Translate

| Always Translate | Don't Translate |
|-----------------|-----------------|
| Headings and titles | HTML attributes (class, id, data-*) |
| Button labels | Code paths and URLs |
| Form labels and placeholders | Technical identifiers |
| Error and success messages | Database values |
| Help text and descriptions | CSS values |
| Navigation labels | File names in code blocks |

## Quality Checks

Run before committing:

```bash
bundle exec i18n-tasks health # Full health check (in CI)
bundle exec i18n-tasks missing # Find missing translations
bundle exec i18n-tasks unused # Find unused translations
```

## Adding New Translations

1. **Add the key to the appropriate locale file** following the file structure
2. **Use lazy lookup** (`.key`) in views and mailers where possible
3. **Use full paths** in controllers for clarity
4. **Run `i18n-tasks health`** to verify no missing or unused keys

## Examples

### View with Lazy Lookup

```erb
<%# app/views/users/show.html.erb %>
<h1><%= t(".heading") %></h1>
<p><%= t(".description", name: @user.name) %></p>
```

```yaml
# config/locales/en/views/users.yml
en:
users:
show:
heading: "User Profile"
description: "Welcome, %{name}!"
```

### Controller Flash Message

```ruby
# app/controllers/users_controller.rb
def create
@user = User.create!(user_params)
redirect_to @user, notice: t("controllers.users.create.notice")
end
```

```yaml
# config/locales/en/controllers.yml
en:
controllers:
users:
create:
notice: "User created successfully"
```

### Form Labels

```erb
<%= form.label :email, t(".email_label") %>
<%= form.text_field :email, placeholder: t(".email_placeholder") %>
```

## Common Patterns

### Pluralization

```yaml
en:
messages:
count:
one: "1 message"
other: "%{count} messages"
```

```ruby
t("messages.count", count: @messages.size)
```

### Defaults

When a key might not exist, provide a default:

```erb
<%= t(".title", default: "Default Title") %>
```
149 changes: 149 additions & 0 deletions .claude/rules/madmin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
---
description: Madmin admin panel conventions
globs: ["app/madmin/**/*.rb", "app/controllers/madmin/**/*.rb"]
---

# Madmin Standards

## Overview

Madmin is the admin panel at `/madmin`. All admin CRUD operations go through Madmin resources.

## Creating Resources

```bash
rails generate madmin:resource ModelName
```

This creates `app/madmin/resources/model_name_resource.rb`

## Resource Configuration

```ruby
# app/madmin/resources/user_resource.rb
class UserResource < Madmin::Resource
# Attributes displayed in admin
attribute :id, form: false
attribute :email
attribute :name
attribute :created_at, form: false
attribute :updated_at, form: false

# Customize index columns
def self.index_attributes
[:id, :email, :name, :created_at]
end

# Customize form fields
def self.form_attributes
[:email, :name]
end

# Customize show page
def self.show_attributes
[:id, :email, :name, :created_at, :updated_at]
end

# Scopes for filtering
def self.scopes
[
Madmin::Scope.new(:all),
Madmin::Scope.new(:recent, ->(resources) { resources.where("created_at > ?", 1.week.ago) })
]
end
end
```

## Custom Fields

Create custom fields in `app/madmin/fields/`:

```ruby
# app/madmin/fields/json_field.rb
class JsonField < Madmin::Field
def to_s
JSON.pretty_generate(value) if value.present?
end
end
```

Usage:
```ruby
attribute :metadata, field: "JsonField"
```

## Custom Actions

Add member actions to resources:

```ruby
class AdminResource < Madmin::Resource
member_action :send_magic_link, method: :post do
admin = Admin.find(params[:id])
AdminMailer.magic_link(admin).deliver_later
redirect_to madmin_admin_path(admin), notice: "Magic link sent!"
end
end
```

## Authentication

```ruby
# app/controllers/madmin/application_controller.rb
class Madmin::ApplicationController < Madmin::BaseController
before_action :authenticate_admin!

private

def authenticate_admin!
redirect_to main_app.new_admins_session_path unless current_admin
end

def current_admin
@current_admin ||= Admin.find_by(id: session[:admin_id]) if session[:admin_id]
end
helper_method :current_admin
end
```

## Customizing Views

Generate views to customize:

```bash
rails generate madmin:views
rails generate madmin:views users # For specific resource
```

Views go in `app/views/madmin/`

## Sortable Columns (STRICT)

**Every column in a Madmin index table MUST be sortable.** No exceptions.

- Add the column name to `self.sortable_columns` in the resource
- Use `<%= sortable :column_name, "Label" %>` in the `<th>` (never plain `<th>Text</th>`)
- For computed columns (counts, sums), add custom sort logic in the controller's `scoped_resources`

```ruby
# Resource
def self.sortable_columns
super + %w[owner_name members_count chats_count total_cost]
end

# Controller - custom sort for computed columns
when "chats_count"
resources.left_joins(:chats).group("teams.id")
.reorder(Arel.sql("COUNT(chats.id) #{sort_direction}"))
when "total_cost"
resources.left_joins(:chats).group("teams.id")
.reorder(Arel.sql("COALESCE(SUM(chats.total_cost), 0) #{sort_direction}"))
```

## Interface Separation

**IMPORTANT:** Keep admin and user interfaces completely separate:
- User interface: `/session/new`, `/home`, etc.
- Admin interface: `/admins/session/new` (login), `/madmin` (panel)
- **No links between user and admin interfaces**
- Admin login is separate (different URLs, different styling)
Loading