diff --git a/.gitignore b/.gitignore index 4ad4ee8..3ac60d7 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,10 @@ !/tmp/storage/ !/tmp/storage/.keep +# Ignore SQLite database files +/db/*.sqlite3 +/db/*.sqlite3-journal + /public/assets # Ignore key files for decrypting credentials and more. diff --git a/.ruby-version b/.ruby-version index 90cdbdc..1454f6e 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -ruby-4.0.1 +4.0.1 diff --git a/Dockerfile b/Dockerfile index 98795d8..4b3ec36 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,7 @@ ARG RUBY_VERSION=4.0.1 FROM docker.io/library/ruby:$RUBY_VERSION-slim AS base # Rails app lives here -WORKDIR /rails +WORKDIR /app # Install base packages RUN apt-get update -qq && \ @@ -67,10 +67,10 @@ USER 1000:1000 # Copy built artifacts: gems, application COPY --chown=rails:rails --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}" -COPY --chown=rails:rails --from=build /rails /rails +COPY --chown=rails:rails --from=build /app /app # Entrypoint prepares the database. -ENTRYPOINT ["/rails/bin/docker-entrypoint"] +ENTRYPOINT ["/app/bin/docker-entrypoint"] # Start server via Thruster by default, this can be overwritten at runtime EXPOSE 80 diff --git a/Dockerfile.dev b/Dockerfile.dev new file mode 100644 index 0000000..609fc4d --- /dev/null +++ b/Dockerfile.dev @@ -0,0 +1,35 @@ +# Development Dockerfile for Rails app using sqlite on Alpine +FROM docker.io/library/ruby:4.0.1-alpine + +ENV RAILS_ENV=development + +# Install build and runtime dependencies (no Node) +RUN apk add --no-cache \ +build-base \ + curl \ + bash \ + git \ + imagemagick \ + sqlite \ + sqlite-dev \ + yaml-dev \ + tzdata + + +# Install latest bundler +RUN gem install bundler + +WORKDIR /app + +# Copy only Gemfile (lock file will be generated at runtime) +COPY Gemfile Gemfile.lock ./ +RUN bundle install + +# Copy application code (will be mounted via volume in dev) +COPY . . + +# Expose default rails port +EXPOSE 3000 + +# Default to an interactive shell; compose overrides command to run the server. +CMD ["/bin/bash"] diff --git a/Gemfile b/Gemfile index bfabc96..52f68e1 100644 --- a/Gemfile +++ b/Gemfile @@ -18,7 +18,6 @@ gem "stimulus-rails" gem "tailwindcss-rails" # 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 ] diff --git a/Gemfile.lock b/Gemfile.lock index b3b59d8..124ca26 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -83,7 +83,7 @@ GEM bcrypt_pbkdf (1.1.2) bigdecimal (4.0.1) bindex (0.8.1) - bootsnap (1.21.1) + bootsnap (1.22.0) msgpack (~> 1.2) brakeman (8.0.2) racc @@ -124,7 +124,6 @@ GEM ffi (1.17.3-aarch64-linux-musl) ffi (1.17.3-arm-linux-gnu) ffi (1.17.3-arm-linux-musl) - ffi (1.17.3-arm64-darwin) ffi (1.17.3-x86_64-linux-gnu) ffi (1.17.3-x86_64-linux-musl) fugit (1.12.1) @@ -146,7 +145,7 @@ GEM pp (>= 0.6.0) rdoc (>= 4.0.0) reline (>= 0.4.2) - json (2.18.0) + json (2.18.1) kamal (2.10.1) activesupport (>= 7.0) base64 (~> 0.2) @@ -201,8 +200,6 @@ GEM racc (~> 1.4) nokogiri (1.19.0-arm-linux-musl) racc (~> 1.4) - nokogiri (1.19.0-arm64-darwin) - racc (~> 1.4) nokogiri (1.19.0-x86_64-linux-gnu) racc (~> 1.4) nokogiri (1.19.0-x86_64-linux-musl) @@ -293,7 +290,7 @@ GEM rspec-mocks (~> 3.13) rspec-support (~> 3.13) rspec-support (3.13.7) - rubocop (1.84.0) + rubocop (1.84.1) json (~> 2.3) language_server-protocol (~> 3.17.0.2) lint_roller (~> 1.1.0) @@ -353,7 +350,6 @@ GEM sqlite3 (2.9.0-aarch64-linux-musl) sqlite3 (2.9.0-arm-linux-gnu) sqlite3 (2.9.0-arm-linux-musl) - sqlite3 (2.9.0-arm64-darwin) sqlite3 (2.9.0-x86_64-linux-gnu) sqlite3 (2.9.0-x86_64-linux-musl) sshkit (1.25.0) @@ -372,14 +368,12 @@ GEM tailwindcss-ruby (4.1.18) tailwindcss-ruby (4.1.18-aarch64-linux-gnu) tailwindcss-ruby (4.1.18-aarch64-linux-musl) - tailwindcss-ruby (4.1.18-arm64-darwin) tailwindcss-ruby (4.1.18-x86_64-linux-gnu) tailwindcss-ruby (4.1.18-x86_64-linux-musl) thor (1.5.0) - thruster (0.1.17) - thruster (0.1.17-aarch64-linux) - thruster (0.1.17-arm64-darwin) - thruster (0.1.17-x86_64-linux) + thruster (0.1.18) + thruster (0.1.18-aarch64-linux) + thruster (0.1.18-x86_64-linux) timeout (0.6.0) tsort (0.2.0) turbo-rails (2.0.23) @@ -412,7 +406,6 @@ PLATFORMS aarch64-linux-musl arm-linux-gnu arm-linux-musl - arm64-darwin-25 x86_64-linux x86_64-linux-gnu x86_64-linux-musl @@ -465,7 +458,7 @@ CHECKSUMS bcrypt_pbkdf (1.1.2) sha256=c2414c23ce66869b3eb9f643d6a3374d8322dfb5078125c82792304c10b94cf6 bigdecimal (4.0.1) sha256=8b07d3d065a9f921c80ceaea7c9d4ae596697295b584c296fe599dd0ad01c4a7 bindex (0.8.1) sha256=7b1ecc9dc539ed8bccfc8cb4d2732046227b09d6f37582ff12e50a5047ceb17e - bootsnap (1.21.1) sha256=9373acfe732da35846623c337d3481af8ce77c7b3a927fb50e9aa92b46dbc4c4 + bootsnap (1.22.0) sha256=5820c9d42c2efef095bee6565484bdc511f1223bf950140449c9385ae775793e brakeman (8.0.2) sha256=7b02065ce8b1de93949cefd3f2ad78e8eb370e644b95c8556a32a912a782426a builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f bundler-audit (0.9.3) sha256=81c8766c71e47d0d28a0f98c7eed028539f21a6ea3cd8f685eb6f42333c9b4e9 @@ -488,7 +481,6 @@ CHECKSUMS ffi (1.17.3-aarch64-linux-musl) sha256=020b33b76775b1abacc3b7d86b287cef3251f66d747092deec592c7f5df764b2 ffi (1.17.3-arm-linux-gnu) sha256=5bd4cea83b68b5ec0037f99c57d5ce2dd5aa438f35decc5ef68a7d085c785668 ffi (1.17.3-arm-linux-musl) sha256=0d7626bb96265f9af78afa33e267d71cfef9d9a8eb8f5525344f8da6c7d76053 - ffi (1.17.3-arm64-darwin) sha256=0c690555d4cee17a7f07c04d59df39b2fba74ec440b19da1f685c6579bb0717f ffi (1.17.3-x86_64-linux-gnu) sha256=3746b01f677aae7b16dc1acb7cb3cc17b3e35bdae7676a3f568153fb0e2c887f ffi (1.17.3-x86_64-linux-musl) sha256=086b221c3a68320b7564066f46fed23449a44f7a1935f1fe5a245bd89d9aea56 fugit (1.12.1) sha256=5898f478ede9b415f0804e42b8f3fd53f814bd85eebffceebdbc34e1107aaf68 @@ -498,7 +490,7 @@ CHECKSUMS importmap-rails (2.2.3) sha256=7101be2a4dc97cf1558fb8f573a718404c5f6bcfe94f304bf1f39e444feeb16a io-console (0.8.2) sha256=d6e3ae7a7cc7574f4b8893b4fca2162e57a825b223a177b7afa236c5ef9814cc irb (1.16.0) sha256=2abe56c9ac947cdcb2f150572904ba798c1e93c890c256f8429981a7675b0806 - json (2.18.0) sha256=b10506aee4183f5cf49e0efc48073d7b75843ce3782c68dbeb763351c08fd505 + json (2.18.1) sha256=fe112755501b8d0466b5ada6cf50c8c3f41e897fa128ac5d263ec09eedc9f986 kamal (2.10.1) sha256=53b7ecb4c33dd83b1aedfc7aacd1c059f835993258a552d70d584c6ce32b6340 language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87 @@ -523,7 +515,6 @@ CHECKSUMS nokogiri (1.19.0-aarch64-linux-musl) sha256=eb70507f5e01bc23dad9b8dbec2b36ad0e61d227b42d292835020ff754fb7ba9 nokogiri (1.19.0-arm-linux-gnu) sha256=572a259026b2c8b7c161fdb6469fa2d0edd2b61cd599db4bbda93289abefbfe5 nokogiri (1.19.0-arm-linux-musl) sha256=23ed90922f1a38aed555d3de4d058e90850c731c5b756d191b3dc8055948e73c - nokogiri (1.19.0-arm64-darwin) sha256=0811dfd936d5f6dd3f6d32ef790568bf29b2b7bead9ba68866847b33c9cf5810 nokogiri (1.19.0-x86_64-linux-gnu) sha256=f482b95c713d60031d48c44ce14562f8d2ce31e3a9e8dd0ccb131e9e5a68b58c nokogiri (1.19.0-x86_64-linux-musl) sha256=1c4ca6b381622420073ce6043443af1d321e8ed93cc18b08e2666e5bd02ffae4 ostruct (0.6.3) sha256=95a2ed4a4bd1d190784e666b47b2d3f078e4a9efda2fccf18f84ddc6538ed912 @@ -557,7 +548,7 @@ CHECKSUMS rspec-mocks (3.13.7) sha256=0979034e64b1d7a838aaaddf12bf065ea4dc40ef3d4c39f01f93ae2c66c62b1c rspec-rails (8.0.2) sha256=113139a53f5d068d4f48d1c29ad5f982013ed9b0daa69d7f7b266eda5d433ace rspec-support (3.13.7) sha256=0640e5570872aafefd79867901deeeeb40b0c9875a36b983d85f54fb7381c47c - rubocop (1.84.0) sha256=88dec310153bb685a879f5a7cdb601f6287b8f0ee675d9dc63a17c7204c4190a + rubocop (1.84.1) sha256=14cc626f355141f5a2ef53c10a68d66b13bb30639b26370a76559096cc6bcc1a rubocop-ast (1.49.0) sha256=49c3676d3123a0923d333e20c6c2dbaaae2d2287b475273fddee0c61da9f71fd rubocop-performance (1.26.1) sha256=cd19b936ff196df85829d264b522fd4f98b6c89ad271fa52744a8c11b8f71834 rubocop-rails (2.34.3) sha256=10d37989024865ecda8199f311f3faca990143fbac967de943f88aca11eb9ad2 @@ -574,7 +565,6 @@ CHECKSUMS sqlite3 (2.9.0-aarch64-linux-musl) sha256=56a35cb2d70779afc2ac191baf2c2148242285ecfed72f9b021218c5c4917913 sqlite3 (2.9.0-arm-linux-gnu) sha256=a19a21504b0d7c8c825fbbf37b358ae316b6bd0d0134c619874060b2eef05435 sqlite3 (2.9.0-arm-linux-musl) sha256=fca5b26197c70e3363115d3faaea34d7b2ad9c7f5fa8d8312e31b64e7556ee07 - sqlite3 (2.9.0-arm64-darwin) sha256=a917bd9b84285766ff3300b7d79cd583f5a067594c8c1263e6441618c04a6ed3 sqlite3 (2.9.0-x86_64-linux-gnu) sha256=72fff9bd750070ba3af695511ba5f0e0a2d8a9206f84869640b3e99dfaf3d5a5 sqlite3 (2.9.0-x86_64-linux-musl) sha256=ef716ba7a66d7deb1ccc402ac3a6d7343da17fac862793b7f0be3d2917253c90 sshkit (1.25.0) sha256=c8c6543cdb60f91f1d277306d585dd11b6a064cb44eab0972827e4311ff96744 @@ -584,14 +574,12 @@ CHECKSUMS tailwindcss-ruby (4.1.18) sha256=b62fad5b00494e92987ee319dfb5c5ad272f0ed93649963d62f08d2ba0f03fa7 tailwindcss-ruby (4.1.18-aarch64-linux-gnu) sha256=e10f9560bccddbb4955fd535b3bcc8c7071a7df07404dd473a23fa791ec4e46b tailwindcss-ruby (4.1.18-aarch64-linux-musl) sha256=3c8426674718a2c98a0649c825ac0b3286ff52acd0b4052d7d19126cd74904f3 - tailwindcss-ruby (4.1.18-arm64-darwin) sha256=f940531d5a030c566d3d616004235bcd4c361abdd328f7d6c7e3a953a32e0155 tailwindcss-ruby (4.1.18-x86_64-linux-gnu) sha256=e0a2220163246fe0126c5c5bafb95bc6206e7d21fce2a2878fd9c9a359137534 tailwindcss-ruby (4.1.18-x86_64-linux-musl) sha256=d957cf545b09d2db7eb6267450cc1fc589e126524066537a0c4d5b99d701f4b2 thor (1.5.0) sha256=e3a9e55fe857e44859ce104a84675ab6e8cd59c650a49106a05f55f136425e73 - thruster (0.1.17) sha256=6f3f1de43e22f0162d81cbc363f45ee42a1b8460213856c1a899cbf0d3297235 - thruster (0.1.17-aarch64-linux) sha256=1b3a34b2814185c2aeaf835b5ecff5348cdcf8e77809f7a092d46e4b962a16ba - thruster (0.1.17-arm64-darwin) sha256=75da66fc4a0f012f9a317f6362f786a3fa953879a3fa6bed8deeaebf1c1d66ec - thruster (0.1.17-x86_64-linux) sha256=77b8f335075bd4ece7631dc84a19a710a1e6e7102cbce147b165b45851bdfcd3 + thruster (0.1.18) sha256=f025103bc7c8e6747436bb9de058c366840d2871560574ea7070a9bc8608a889 + thruster (0.1.18-aarch64-linux) sha256=16f3d49468d76a9a5de86b7bdedf535b7b80da7c16495ca8ec96cfdc256870e2 + thruster (0.1.18-x86_64-linux) sha256=0ec1ff5f12289c1ac10cf8e28ce6b5266f4e73416b34a664b79d037c7d955c40 timeout (0.6.0) sha256=6d722ad619f96ee383a0c557ec6eb8c4ecb08af3af62098a0be5057bf00de1af tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f turbo-rails (2.0.23) sha256=ee0d90733aafff056cf51ff11e803d65e43cae258cc55f6492020ec1f9f9315f @@ -608,4 +596,4 @@ CHECKSUMS zeitwerk (2.7.4) sha256=2bef90f356bdafe9a6c2bd32bcd804f83a4f9b8bc27f3600fff051eb3edcec8b BUNDLED WITH - 4.0.3 + 4.0.5 diff --git a/LOCAL-DOCKER-DEV-GUIDANCE-AGENT-CONTEXT.md b/LOCAL-DOCKER-DEV-GUIDANCE-AGENT-CONTEXT.md new file mode 100644 index 0000000..4631a76 --- /dev/null +++ b/LOCAL-DOCKER-DEV-GUIDANCE-AGENT-CONTEXT.md @@ -0,0 +1,27 @@ +# Local Development with Docker + +## Goals + +1. To have `Dockerfile.dev` and `docker-compose.dev.yml` files that enable Ruby on Rails development completely in Docker. +1. The developer should be able to run commands such as `bin/rails s` and `bin/rails c`, `bin/rspec `; ideally, we should have some containers that run in `RAILS_ENV=development` and `RAILS_ENV=test`. +1. Some of the database config and other related files were copied from another project, but we need to change this project to use sqlite +1. We shouldn't need any config to AWS, for example, but that might change in the future; for now, I don't think we need any references to AWS in the Docker files. + +## Important Details for the compose file: + +I'm not sure if sqlite needs database user, password, name, port, host, etc, or if we even need a service for it in Docker. I'm relying on the Copilot Agent for guidance on this. + +We need the following ENV variables: + +- ${RAILS_ENV} +- DOCKER_CONTAINER: true + +## Definition of Done: + +1. Successful build of the image from a Dockerfile.dev +1. Successful execution of `docker compose up` using our `docker-compose.dev.yml` +1. This Rails app is reconfigured to use SQLITE +1. A user can `docker exec -it /bin/bash` to enter: + +- A container in `development` environment and execute `bin/rails s`, `bin/rails c`. +- A container in `test` environment and execute `bin/rspec` diff --git a/config/database.yml b/config/database.yml index 302d638..05edc98 100644 --- a/config/database.yml +++ b/config/database.yml @@ -6,35 +6,65 @@ # default: &default adapter: sqlite3 + encoding: unicode + # For details on connection pooling, see Rails configuration guide + # https://guides.rubyonrails.org/configuring.html#database-pooling max_connections: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> timeout: 5000 development: <<: *default - database: storage/development.sqlite3 + database: db/development.sqlite3 + + # The specified database role being used to connect to PostgreSQL. + # To create additional roles in PostgreSQL see `$ createuser --help`. + # When left blank, PostgreSQL will use the default role. This is + # the same name as the operating system user running Rails. + #username: skillrx_beacon + + # The password associated with the PostgreSQL role (username). + #password: + + # Connect on a TCP socket. Omitted by default since the client uses a + # domain socket that doesn't need configuration. Windows does not have + # domain sockets, so uncomment these lines. + #host: localhost + + # The TCP port the server listens on. Defaults to 5432. + # If your server runs on a different port number, change accordingly. + #port: 5432 + + # Schema search path. The server defaults to $user,public + #schema_search_path: myapp,sharedapp,public + + # Minimum log levels, in increasing order: + # debug5, debug4, debug3, debug2, debug1, + # log, notice, warning, error, fatal, and panic + # Defaults to warning. + #min_messages: notice # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: <<: *default - database: storage/test.sqlite3 + database: db/test.sqlite3 -# Store production database in the storage/ directory, which by default +# Store production database in the db/ directory, which by default # is mounted as a persistent Docker volume in config/deploy.yml. production: primary: <<: *default - database: storage/production.sqlite3 + database: db/production.sqlite3 cache: <<: *default - database: storage/production_cache.sqlite3 + database: db/production_cache.sqlite3 migrations_paths: db/cache_migrate queue: <<: *default - database: storage/production_queue.sqlite3 + database: db/production_queue.sqlite3 migrations_paths: db/queue_migrate cable: <<: *default - database: storage/production_cable.sqlite3 + database: db/production_cable.sqlite3 migrations_paths: db/cable_migrate diff --git a/config/deploy.yml b/config/deploy.yml index 9d6a811..609bef9 100644 --- a/config/deploy.yml +++ b/config/deploy.yml @@ -85,7 +85,7 @@ builder: # # # Pass arguments and secrets to the Docker build process # args: - # RUBY_VERSION: ruby-4.0.1 + # RUBY_VERSION: 4.0.1 # secrets: # - GITHUB_TOKEN # - RAILS_MASTER_KEY diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 0000000..dec0dfc --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,17 @@ +services: + app: + build: + context: . + dockerfile: Dockerfile.dev + args: + RUBY_VERSION: 4.0.1 + environment: + RAILS_ENV: ${RAILS_ENV:-development} + DOCKER_CONTAINER: "true" + volumes: + - ./:/app + ports: + - "3000:3000" + tty: true + stdin_open: true + command: ["/bin/bash", "-lc", "bin/rails server -b 0.0.0.0"] diff --git a/docker-compose.development.yml b/docker-compose.development.yml deleted file mode 100644 index 0e0416c..0000000 --- a/docker-compose.development.yml +++ /dev/null @@ -1,24 +0,0 @@ -# Development overrides for Docker Compose -# -# Usage: -# docker compose -f docker-compose.yml -f docker-compose.development.yml up - -services: - web: - build: - context: . - args: - - RUBY_VERSION=4.0.1 - ports: - - "3000:3000" - environment: - - RAILS_ENV=development - volumes: - # Mount source code for live reloading - - .:/rails - - bundle:/usr/local/bundle - command: ["./bin/rails", "server", "-b", "0.0.0.0"] - -volumes: - bundle: - driver: local diff --git a/docker-compose.production.yml b/docker-compose.production.yml index 35155c0..350ca81 100644 --- a/docker-compose.production.yml +++ b/docker-compose.production.yml @@ -1,14 +1,31 @@ -# Production overrides for Docker Compose -# -# Usage: -# docker compose -f docker-compose.yml -f docker-compose.production.yml up -d - services: web: + build: + context: . + dockerfile: Dockerfile + ports: + - "${PORT:-3000}:80" environment: - - RAILS_ENV=production - - RAILS_LOG_TO_STDOUT=1 - - RAILS_SERVE_STATIC_FILES=1 + RAILS_ENV: production + RAILS_MASTER_KEY: ${RAILS_MASTER_KEY} + RAILS_LOG_TO_STDOUT: "1" + RAILS_SERVE_STATIC_FILES: "1" + SOLID_QUEUE_IN_PUMA: "1" + DOCKER_CONTAINER: "true" + volumes: + # Persist SQLite databases + - storage:/app/storage + # Persist ActiveStorage uploads + - uploads:/app/storage/uploads + # Mount content directory (medical content files) + - ${CONTENT_PATH:-./content}:/app/content:ro + restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:80/up"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s logging: driver: "json-file" options: @@ -21,3 +38,9 @@ services: memory: 512M reservations: memory: 256M + +volumes: + storage: + driver: local + uploads: + driver: local diff --git a/docker-compose.test.yml b/docker-compose.test.yml new file mode 100644 index 0000000..ac015e6 --- /dev/null +++ b/docker-compose.test.yml @@ -0,0 +1,15 @@ +services: + test: + build: + context: . + dockerfile: Dockerfile.dev + args: + RUBY_VERSION: 4.0.1 + environment: + RAILS_ENV: test + DOCKER_CONTAINER: "true" + volumes: + - ./:/app + tty: true + stdin_open: true + command: ["/bin/bash"]