This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Human Essentials is a Ruby on Rails inventory management system for diaper banks and essentials banks. It's a Ruby for Good project serving 200+ non-profit organizations. The app manages donations, purchases, distributions, inventory, partners, and requests for essential items.
bin/setup # First-time setup (installs gems, creates DB, seeds)
bin/start # Starts Rails server (port 3000) + Delayed Job workerbundle exec rspec # Run full test suite
bundle exec rspec spec/models/item_spec.rb # Run a single test file
bundle exec rspec spec/models/item_spec.rb:42 # Run a single test at line
bundle exec rspec spec/models/ # Run a directory of testsCI splits tests into two workflows: rspec (unit tests, excludes system/request specs) and rspec-system (system and request specs only, 6 parallel nodes). System tests use Capybara with Cuprite (headless Chrome).
bundle exec rubocop # Ruby linter (Standard-based config)
bundle exec erb_lint --lint-all # ERB template linter
bundle exec brakeman # Security scannerbundle exec rake db:migrate
bundle exec rake db:seed
bundle exec rake db:reset # Drop + create + migrate + seedNearly all data is scoped to an Organization. Most models belong_to :organization and queries should always scope by organization context. The current user's organization is the primary tenant boundary.
Four roles defined in Role: ORG_USER, ORG_ADMIN, SUPER_ADMIN, PARTNER. Roles are polymorphic and scoped to a resource (usually an Organization). Authentication is via Devise.
Inventory is not tracked via simple column updates. Instead, it uses an event sourcing pattern:
Event(STI base model) stores all inventory-affecting actions as JSONB events- Subclasses:
DonationEvent,DistributionEvent,PurchaseEvent,TransferEvent,AdjustmentEvent,AuditEvent,KitAllocateEvent,SnapshotEvent, etc. InventoryAggregatereplays events to compute current inventory state. It finds the most recentSnapshotEventand replays subsequent eventsEventTypes::Inventoryis the in-memory inventory representation built from events- When creating/updating donations, distributions, purchases, transfers, or adjustments, the corresponding service creates an Event, and
Event#validate_inventoryreplays all events to verify consistency
This means: to check inventory levels, use InventoryAggregate.inventory_for(organization_id), not direct DB queries on quantity columns.
Business logic lives in service classes (app/services/), not controllers. Pattern: {Model}{Action}Service (e.g., DistributionCreateService, DonationDestroyService). Controllers are thin and delegate to services.
- Item: Individual item types (diapers, wipes, etc.) belonging to an Organization. Maps to a
BaseItem(system-wide template) viapartner_key. - Kit: A bundle of items. Kits contain line items referencing Items.
- StorageLocation: Where inventory is physically stored. Inventory quantities are per storage location.
- Distribution: Items sent to a Partner. Donation/Purchase: Items coming in. Transfer: Items between storage locations. Adjustment: Manual inventory corrections.
- Partner: Organizations that receive distributions. Partners have their own portal (
/partners/*routes) and users. - Request: Partner requests for items, which can become Distributions.
/- Bank user dashboard and resources (distributions, donations, etc.)/partners/*- Partner-facing portal (separate namespace)/admin/*- Super admin management/reports/*- Reporting endpoints
Complex queries are extracted into app/queries/ (e.g., ItemsInQuery, LowInventoryQuery).
Bootstrap 5.2, Turbo Rails, Stimulus.js, ImportMap (no Webpack/bundler). JavaScript controllers live in app/javascript/.
Delayed Job for async processing (emails, etc.). Clockwork (clock.rb) for scheduled tasks (caching historical data, reminder emails, DB backups).
Flipper is available for feature flags, accessible at /flipper (auth required).
- RSpec with FactoryBot. Factories are in
spec/factories/. - Setting up inventory in tests: Use
TestInventory.create_inventory(organization, { storage_location_id => [[item_id, quantity], ...] })fromspec/inventory.rb. There's also asetup_storage_locationhelper inspec/support/inventory_assistant.rb. - System tests use Capybara with Cuprite driver. Failed screenshots go to
tmp/screenshots/andtmp/capybara/. - Models use
has_paper_trailfor audit trails andDiscardfor soft deletes (notdestroy). - The
Filterableconcern providesclass_filterfor scope-based filtering on index actions.
All passwords are password!. Key accounts: superadmin@example.com, org_admin1@example.com, user_1@example.com.