Finished phase005
CI / scan_ruby (push) Failing after 1m5s
CI / scan_js (push) Failing after 6s
CI / lint (push) Failing after 1m29s

This commit is contained in:
2026-09-16 15:34:50 -06:00
parent a3a65c24ed
commit 0826d267f2
38 changed files with 1596 additions and 9 deletions
+36
View File
@@ -0,0 +1,36 @@
# Phase 003 Execution
## Scope
- Built the vehicle CRUD interface.
- Made the vehicle index the root page.
- Kept vehicle removal non-destructive by deactivating vehicles.
- Added request specs for the vehicle UI flows.
## Changes
- Added `VehiclesController` with index, show, new, create, edit, update, and destroy actions.
- Added `resources :vehicles` and changed the root route to `vehicles#index`.
- Added plain ERB views for vehicle index, detail, new, edit, and the shared form.
- Added query-param filtering on the vehicle index:
- default shows active vehicles
- `status=inactive` shows inactive vehicles
- `status=all` shows all vehicles
- Implemented `destroy` as a deactivate action that sets `active` to `false`.
- Displayed maintenance schedules, fuel history, and maintenance history on `vehicles#show`.
- Ordered fuel and maintenance history newest first.
- Updated home specs for the new root behavior.
- Added vehicle request specs for successful and invalid create/update paths.
- Added licence plate normalization to uppercase before validation.
## Decisions
- Vehicles are not hard-deleted because maintenance and fuel history must be preserved.
- The UI labels the destructive route as `Deactivate` to match actual behavior.
- The vehicle show page is display-only for related schedules and histories in this phase.
- Event creation remains reserved for Phase 004.
- Maintenance schedule CRUD remains reserved for Phase 006.
- Licence plates are standardized to uppercase before validation and storage.
## Verification
- Passed: `bundle exec rspec spec/requests/vehicles_spec.rb`
- Passed: `bundle exec rspec`
- Passed for touched Phase 003 Ruby files: `bin/rubocop app/controllers/vehicles_controller.rb spec/requests/vehicles_spec.rb spec/requests/home_spec.rb spec/system/home_spec.rb`
- Full `bin/rubocop` was not clean because of pre-existing unrelated `Gemfile` single-quote offenses.
+49
View File
@@ -0,0 +1,49 @@
# Phase 004 Execution
## Scope
- Added fuel and maintenance event creation from the vehicle detail page.
- Added nested event routes and focused create controllers.
- Added odometer update behavior for fuel and maintenance entries.
- Added placeholder event attribution until Phase 005 authentication exists.
- Added request and model specs for the new behavior.
## Changes
- Added nested `fuel_entries#create` and `maintenance_entries#create` routes under vehicles.
- Added `FuelEntriesController` for creating fuel entries from a vehicle page.
- Added `MaintenanceEntriesController` for creating maintenance entries from a vehicle page.
- Added a private `unknown_user` controller helper that looks up `unknown@example.invalid`.
- Added an idempotent `Unknown User` seed in `db/seeds.rb` for temporary Phase 004 attribution.
- Updated `vehicles#show` setup to build form objects and eager-load event users.
- Added fuel and maintenance forms to `vehicles#show`.
- Added inline validation error display for both event forms.
- Added maintenance type selection from the vehicle's existing maintenance schedules.
- Disabled maintenance entry creation in the UI when a vehicle has no maintenance schedules.
- Added `Updated by` columns to fuel and maintenance history tables.
- Added fuel-entry validation rejecting odometer readings lower than the vehicle current odometer.
- Added vehicle odometer updates when saved fuel or maintenance entries have newer odometer readings.
- Added a Stimulus controller that warns when a maintenance odometer is more than 500 miles behind the current vehicle odometer.
- Added server-side flash warning and application log warning for maintenance entries more than 500 miles behind the current vehicle odometer.
- Hardened temporary `Unknown User` attribution so event creation creates the placeholder if the seed has not been run.
- Added a user-visible warning path for attribution setup failures instead of raising a server error.
## Decisions
- Phase 004 uses `Unknown User` for event attribution because Phase 005 will add actual authentication and session identity.
- `Unknown User` is seeded instead of silently created by controllers so missing setup is visible.
- Controllers also create `Unknown User` as a runtime fallback because a missing seed should not produce a 404/server error for users.
- Fuel entries below the current vehicle odometer are rejected.
- Maintenance entries below the current vehicle odometer are allowed because paperwork may be entered later.
- Maintenance entries update the vehicle odometer only when their odometer is newer.
- Maintenance entry names must match an existing maintenance schedule for the vehicle.
- Client-side maintenance odometer warnings are advisory only; server-side logging is the durable audit trail.
## Phase 005 Follow-Up
- Replace `Unknown User` attribution with the authenticated/current session user.
- Remove or stop using the temporary `Unknown User` seed once all event creation requires an identified user.
## Verification
- Passed: `bundle exec rspec spec/models/fuel_entry_spec.rb spec/requests/vehicles_spec.rb`
- Passed: `bundle exec rspec`
- Passed: `bin/rubocop app/controllers/application_controller.rb app/controllers/vehicles_controller.rb app/controllers/fuel_entries_controller.rb app/controllers/maintenance_entries_controller.rb app/models/fuel_entry.rb spec/models/fuel_entry_spec.rb spec/requests/vehicles_spec.rb db/seeds.rb`
- Passed after attribution hardening: `bundle exec rspec spec/requests/vehicles_spec.rb`
- Passed after attribution hardening: `bundle exec rspec`
- Passed after attribution hardening: `bin/rubocop app/controllers/application_controller.rb app/controllers/fuel_entries_controller.rb app/controllers/maintenance_entries_controller.rb spec/requests/vehicles_spec.rb`
+51
View File
@@ -0,0 +1,51 @@
# Phase 005 Execution
## Scope
- Added lightweight internal authentication without passwords.
- Added database-backed monthly access keys with lazy auto-rotation.
- Added random browser tokens stored in encrypted cookies and mapped to users through server-side session records.
- Required identification for all application pages except the identify flow and Rails health check.
- Replaced temporary `Unknown User` event attribution with the active identified user.
- Added request and model specs for authenticated and unauthenticated flows.
## Changes
- Added `AccessKey` model and migration.
- Added `UserSession` model and migration.
- Added `Current` for request-local user/session access.
- Added `SessionsController` with identify, create session, and logout behavior.
- Added `/identify`, `POST /identify`, and `DELETE /session` routes.
- Added `app/views/sessions/new.html.erb` for the “Identify yourself” page.
- Updated the application layout to show the identified user and a logout button on authenticated pages.
- Updated `ApplicationController` to lazily rotate access keys, load the encrypted-cookie auth token, and require identification by default.
- Updated fuel and maintenance entry creation to set `updated_by_user` from `Current.user`.
- Removed the temporary `Unknown User` seed and replaced it with initial `AccessKey.current` creation.
- Updated vehicle, home, and session request/system specs for the new authentication requirements.
## Decisions
- Access keys are stored in plaintext in the database so the server manager can retrieve the current key with `AccessKey.current.raw_key` from Rails console.
- Browser clients store only a random auth token in an encrypted cookie.
- The database stores only token digests, not raw session tokens.
- `AccessKey.rotate!` invalidates all active sessions by deleting `UserSession` records.
- Auto-rotation is lazy and runs during normal requests when enabled and expired.
- Default auto-rotation frequency is 30 days.
- Auto-rotation can be disabled and re-enabled with `AccessKey.current.disable_auto_rotation!` and `AccessKey.current.enable_auto_rotation!`.
- The rotation frequency can be changed with `AccessKey.current.update!(auto_rotation_frequency_days: days)`.
- Existing users are matched by normalized email and require an exact stored-name match.
- `/up` remains publicly accessible for health checks.
- `DELETE /session` uses the `logout_path` helper because `session_path` is already used for `POST /identify`.
## Console API
```ruby
AccessKey.current.raw_key
AccessKey.rotate!
AccessKey.current.disable_auto_rotation!
AccessKey.current.enable_auto_rotation!
AccessKey.current.auto_rotation_frequency_days
AccessKey.current.update!(auto_rotation_frequency_days: 60)
```
## Verification
- Passed: `bundle exec rspec spec/models/access_key_spec.rb spec/models/user_session_spec.rb spec/requests/sessions_spec.rb spec/requests/vehicles_spec.rb`
- Passed: `bundle exec rspec`
- Passed: `bin/rubocop app/models/access_key.rb app/models/user_session.rb app/models/current.rb app/models/user.rb app/controllers/application_controller.rb app/controllers/sessions_controller.rb app/controllers/fuel_entries_controller.rb app/controllers/maintenance_entries_controller.rb spec/models/access_key_spec.rb spec/models/user_session_spec.rb spec/requests/sessions_spec.rb spec/requests/vehicles_spec.rb spec/requests/home_spec.rb spec/system/home_spec.rb db/seeds.rb`
- Passed after lint cleanup: `bundle exec rspec`