Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
  •  
  •  
  •  
28 changes: 28 additions & 0 deletions .brakeman.ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"ignored_warnings": [
{
"warning_type": "Mass Assignment",
"warning_code": 105,
"fingerprint": "413a4f9962b57fb22b657af4609707dbd5a70c5a2a4e3aa212f3c678c84f45e8",
"check_name": "PermitAttributes",
"message": "Potentially dangerous key allowed for mass assignment",
"file": "app/controllers/admin/users_controller.rb",
"line": 103,
"link": "https://brakemanscanner.org/docs/warning_types/mass_assignment/",
"code": "params.permit(:full_name, :email_address, :avatar, :avatar_url, :role, :password, :password_confirmation)",
"render_path": null,
"location": {
"type": "method",
"class": "Admin::UsersController",
"method": "user_params"
},
"user_input": ":role",
"confidence": "Medium",
"cwe_id": [
915
],
"note": "role is enum-whitelisted in Admin::UserForm and only reachable behind Admin::BaseController#require_admin (Users::Policy); password is handled by has_secure_password. No privilege escalation is possible."
}
],
"obsolete": []
}
53 changes: 53 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# See https://docs.docker.com/engine/reference/builder/#dockerignore-file for more about ignoring files.

# Ignore git directory.
/.git/
/.gitignore

# Ignore bundler config.
/.bundle

# Ignore all environment files.
/.env*

# Ignore all default key files.
/config/master.key
/config/credentials/*.key

# Ignore all logfiles and tempfiles.
/log/*
/tmp/*
!/log/.keep
!/tmp/.keep

# Ignore pidfiles, but keep the directory.
/tmp/pids/*
!/tmp/pids/.keep

# Ignore storage (uploaded files in development and any SQLite databases).
/storage/*
!/storage/.keep
/tmp/storage/*
!/tmp/storage/.keep

# Ignore assets.
/node_modules/
/app/assets/builds/*
!/app/assets/builds/.keep
/public/assets
# Vite build output is produced inside the Docker build (node stage), never copied from the host.
/public/vite*

# Ignore CI service files.
/.github

# Ignore Kamal files.
/config/deploy*.yml
/.kamal

# Ignore development files
/.devcontainer

# Ignore Docker-related files
/.dockerignore
/Dockerfile*
41 changes: 41 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# ------------------------------------------------------------------------------
# Environment template. Copy to .env and fill in the actual values.
# cp .env.example .env
# Never commit the .env file itself — it is gitignored.
#
# In development/test the rails app loads this file via dotenv-rails.
# In production the same variables are provided by the deploy orchestrator
# (Kamal env/secrets) — there is no .env file inside the container.
#
# Deployment variables (DOCKER_IMAGE, APP_SERVER_HOST, REGISTRY_USERNAME) are
# read by config/deploy.yml (ERB) when running `bin/kamal`. Source this file
# before invoking kamal: source .env && bin/kamal deploy
# ------------------------------------------------------------------------------

# Host used to build absolute URLs (mailers, reset links, host authorization).
APP_HOST=localhost
APP_PROTOCOL=http
# APP_PORT=3000

# Mailer sender used by ApplicationMailer.
MAIL_FROM=no-reply@localhost

# SMTP transport (optional). Password reset emails are only delivered when
# SMTP_HOST is set; otherwise delivery is disabled.
SMTP_HOST=
SMTP_PORT=587
SMTP_USER=
SMTP_PASSWORD=
SMTP_AUTH=plain
SMTP_STARTTLS_AUTO=true

# Seeds (development/test only — seeds are skipped in production unless
# SEED_ALLOW_IN_PRODUCTION=true and real credentials are provided).
SEED_ADMIN_EMAIL=admin@iam.local
SEED_ADMIN_PASSWORD=Password123!
SEED_ALLOW_IN_PRODUCTION=false

# Kamal deployment (used when running bin/kamal from the deploy host).
DOCKER_IMAGE=your-user/mini_rails8_iam_with_inertia_js
APP_SERVER_HOST=192.168.0.1
REGISTRY_USERNAME=your-user
9 changes: 9 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# See https://git-scm.com/docs/gitattributes for more about git attribute files.

# Mark the database schema as having been generated.
db/schema.rb linguist-generated

# Mark any vendored files as having been vendored.
vendor/* linguist-vendored
config/credentials/*.yml.enc diff=rails_credentials
config/credentials.yml.enc diff=rails_credentials
49 changes: 49 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
#
# Temporary files generated by your text editor or operating system
# belong in git's global ignore instead:
# `$XDG_CONFIG_HOME/git/ignore` or `~/.config/git/ignore`

# Ignore bundler config.
/.bundle

# Ignore all environment files.
/.env*
!.env.example

# Ignore all logfiles and tempfiles.
/log/*
/tmp/*
!/log/.keep
!/tmp/.keep

# Ignore pidfiles, but keep the directory.
/tmp/pids/*
!/tmp/pids/
!/tmp/pids/.keep

# Ignore storage (uploaded files in development and any SQLite databases).
/storage/*
!/storage/.keep
/tmp/storage/*
!/tmp/storage/
!/tmp/storage/.keep

/public/assets

# Ignore master key for decrypting credentials and more.
/config/master.key

# Vite Ruby
/public/vite*
node_modules
# Vite uses dotenv and suggests to ignore local-only env files. See
# https://vitejs.dev/guide/env-and-mode.html#env-files
*.local

# Ignore Kamal files.
/.kamal

# SimpleCov coverage reports.
/.resultset.json

8 changes: 8 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
*.md
*.yml
*.yaml
*.erb
Gemfile
Gemfile.lock
Rakefile
public/**
6 changes: 6 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"printWidth": 100,
"semi": false,
"singleQuote": true,
"trailingComma": "all"
}
8 changes: 8 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Omakase Ruby styling for Rails
inherit_gem: { rubocop-rails-omakase: rubocop.yml }

# Overwrite or add rules to create your own house style
#
# # Use `[a, [b, c]]` not `[ a, [ b, c ] ]`
# Layout/SpaceInsideArrayLiteralBrackets:
# Enabled: false
1 change: 1 addition & 0 deletions .ruby-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ruby-4.0.6
90 changes: 90 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# syntax=docker/dockerfile:1
# check=error=true

# This Dockerfile is designed for production, not development. Use with Kamal or build'n'run by hand:
# docker build -t mini_rails8_iam_with_inertia_js .
# docker run -d -p 80:80 -e RAILS_MASTER_KEY=<value from config/master.key> --name mini_rails8_iam_with_inertia_js mini_rails8_iam_with_inertia_js

# For a containerized dev environment, see Dev Containers: https://guides.rubyonrails.org/getting_started_with_devcontainer.html

# Make sure RUBY_VERSION matches the Ruby version in .ruby-version
ARG RUBY_VERSION=4.0.6
FROM docker.io/library/ruby:$RUBY_VERSION-slim AS base

# Rails app lives here
WORKDIR /rails

# Install base packages
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y curl libjemalloc2 libvips sqlite3 && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives

# Set production environment
ENV RAILS_ENV="production" \
BUNDLE_DEPLOYMENT="1" \
BUNDLE_PATH="/usr/local/bundle" \
BUNDLE_WITHOUT="development"

# Throw-away stage that compiles the Vite/React frontend with just Node.
# Segregated from the Ruby build so gem, bundler and Node caches never
# invalidate each other, and the final image keeps no Node tooling.
FROM node:22-slim AS build-assets

# Rails app lives here (mirrors the base stage layout)
WORKDIR /rails

# Locked npm packages first: the largest, most stable layer to cache
COPY package.json package-lock.json ./
RUN npm ci

# Application source (vite.config.ts, config/vite.json, app/frontend)
COPY . .

# Compile entrypoints to public/vite (see config/vite.json and package.json)
RUN npm run build

# Throw-away build stage to reduce size of final image
FROM base AS build

# Install packages needed to build gems
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential git libyaml-dev pkg-config && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives

# Install application gems
COPY vendor/* ./vendor/
COPY Gemfile Gemfile.lock ./
RUN bundle install && \
rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
bundle exec bootsnap precompile --gemfile

# Copy application code (the built frontend stays in build-assets)
COPY . .

# Bring in the frontend compiled by the Node stage
COPY --from=build-assets /rails/public/vite /rails/public/vite

RUN SECRET_KEY_BASE_DUMMY=1 VITE_RUBY_SKIP_ASSETS_PRECOMPILE_EXTENSION=true APP_HOST=example.com MAIL_FROM=deploy@example.com ./bin/rails assets:precompile

# Precompile bootsnap code for faster boot times
RUN bundle exec bootsnap precompile app/ lib/

# Final stage for app image
FROM base

# Copy built artifacts: gems, application
COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"
COPY --from=build /rails /rails

# Run and own only the runtime files as a non-root user for security
RUN groupadd --system --gid 1000 rails && \
useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash && \
chown -R rails:rails db log storage tmp
USER 1000:1000

# Entrypoint prepares the database.
ENTRYPOINT ["/rails/bin/docker-entrypoint"]

# Start server via Thruster by default, this can be overwritten at runtime
EXPOSE 80
CMD ["./bin/thrust", "./bin/rails", "server"]
79 changes: 79 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
source "https://rubygems.org"

# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
gem "rails", "~> 8.0.5", ">= 8.0.5.1"
gem "propshaft"
# Use sqlite3 as the database for Active Record
gem "sqlite3", ">= 2.1"
# Use the Puma web server [https://github.com/puma/puma]
gem "puma", ">= 5.0"
# Build JSON APIs with ease [https://github.com/rails/jbuilder]
gem "jbuilder"

# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
gem "bcrypt", "~> 3.1.7"

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem "tzinfo-data", platforms: %i[ windows jruby ]

# Use the database-backed adapters for Rails.cache, Active Job, and Action Cable
gem "solid_cache"
gem "solid_queue"
gem "solid_cable"

# Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", require: false

# Pin RDoc to Ruby's default gem. irb depends on rdoc, and if Bundler installs a
# newer copy alongside the default one, both get loaded and Ruby warns about
# redefined constants ("already initialized constant RDoc::..."). Pinned to the
# exact default version so Bundler uses it directly and only one copy exists.
gem "rdoc", "7.0.4", require: false

# Deploy this application anywhere as a Docker container [https://kamal-deploy.org]
gem "kamal", require: false

# Add HTTP asset caching/compression and X-Sendfile acceleration to Puma [https://github.com/basecamp/thruster/]
gem "thruster", require: false

# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
# gem "image_processing", "~> 1.2"

group :development, :test do
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
gem "debug", platforms: %i[ mri windows ], require: "debug/prelude"

# Load environment variables from .env / .env.local (see .env.example).
gem "dotenv-rails"

# Static analysis for security vulnerabilities [https://brakemanscanner.org/]
gem "brakeman", require: false

# Omakase Ruby styling [https://github.com/rails/rubocop-rails-omakase/]
gem "rubocop-rails-omakase", require: false
end

group :development do
# Use console on exceptions pages [https://github.com/rails/web-console]
gem "web-console"
end

group :test do
# Use system testing [https://guides.rubyonrails.org/testing.html#system-testing]
gem "capybara"
gem "selenium-webdriver"
end

gem "inertia_rails", "~> 3.22"

gem "vite_rails", "~> 3.11"

# Spreadsheet parsing (Phase 5: user imports)
gem "roo", "~> 3.0"

# Pagination (Phase 3: query objects)
gem "pagy", "~> 9.0"

gem "roo-xls", "~> 2.0"

gem "simplecov", "~> 1.2", group: :test
Loading