Gate schedule digest behind feature flag, add Week tab upload button #213
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "212-digest-flag"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Gates the schedule digest feature (Claude Vision OCR) behind a
schedule_digestfeature flag (default OFF) and adds an "Upload Schedule" button to the Week tab so crew leads can upload and digest a schedule photo directly from the weekly planning view.Changes
lib/tasks/feature_flags.rake-- addedschedule_digestflag (default: false, references #204/#212)app/views/uploads/show.html.erb-- wrapped digest-trigger div infeature_enabled?(:schedule_digest)check; wiredauto-digestStimulus controller for auto-submit flow; usesweek_startURL param when presentapp/controllers/uploads_controller.rb-- added feature flag guard at top ofdigestandconfirm_digestactions (redirect with "Feature not available." flash when OFF); modifiedcreateto redirect to show page withauto_digest=1whenweek_startparam is present and flag is ONapp/views/weeks/index.html.erb-- added "Upload Schedule" button (gated behind flag + lead+ role check) with file input that submits touploads#createwith the current week's start dateapp/javascript/controllers/auto_digest_controller.js-- new Stimulus controller that auto-submits the digest form when?auto_digest=1is in the URL (used by Week tab upload flow)app/assets/stylesheets/application.css-- added.week-upload-form,.week-upload-btn,.week-upload-iconstyles matching existing button patternsspec/requests/uploads_spec.rb-- added tests for flag-gated digest/confirm_digest actions, show page button visibility, and create redirect behavior with week_start paramspec/requests/weeks_spec.rb-- added tests for Upload Schedule button visibility when flag is ON/OFF and week start date inclusionTest Plan
bundle exec rspec spec/requests/uploads_spec.rb spec/requests/weeks_spec.rb-- 47 examples, 0 failureswork_queue_items_spec.rbunrelated to this PR)schedule_digestflag at/platform/feature_flagsand verify button appears/disappears on Week tab and upload show pagesReview Checklist
Related Notes
None.
Related
Closes #212
PR #213 Review
DOMAIN REVIEW
Stack: Rails 8.1 / Hotwire / Stimulus / importmap / plain CSS / RSpec
Feature flag registration -- Clean.
schedule_digestflag registered infeature_flags.rakewithenabled: false(default OFF), description references parent tickets. Follows the existing pattern exactly.Controller gating -- Well implemented. Both
digestandconfirm_digestactions have early-return guards that redirect with a flash alert when the flag is OFF. Thecreateaction correctly checks the flag before redirecting to the auto-digest flow, and falls through to the default redirect when the flag is OFF.View gating --
uploads/show.html.erbwraps the digest-trigger div infeature_enabled?(:schedule_digest).weeks/index.html.erbwraps the upload button in the same check plus a role gate.Stimulus controllers --
auto_digest_controller.jsis minimal and correct: reads URL param, auto-submits ifauto_digest=1. Both controllers are auto-registered viaeagerLoadControllersFromandpin_all_fromin importmap -- no manual registration needed.CSS -- New styles use design tokens (
--spacing-md,--spacing-sm) consistently. No magic numbers. Follows existing component comment-block convention.BLOCKERS
None.
NITS
Dead role check in weeks view (line 26): The upload button checks
current_user_has_role?(:lead), butWeeksControlleralready hasrequire_role :admin, :super_admin-- leads cannot reach this page at all. The:leadcheck is dead code. Not harmful, but misleading to future readers who might think leads can see the Week tab.week_startparam passed through URL unvalidated increateredirect: InUploadsController#create(line 17),params[:week_start]is passed directly into the redirect URL as a query param. It is validated later inparse_week_startwhen thedigestaction runs, so there is no injection risk -- but a malformedweek_startvalue will survive the round-trip before being caught. Very minor.digest_weekfallback chain in show view (line 13): The expressionparams[:week_start].presence || (@upload.week_start || Date.current.beginning_of_week(:monday)).iso8601mixes param trust with model data. This is fine because the value only goes into a date input'svalueattribute (not executed), but worth noting the precedence: URL param wins over persisted model data.SOP COMPLIANCE
TEST COVERAGE
Tests are thorough:
uploads_spec.rbcovers: flag-ON redirect withauto_digestparam, flag-OFF fallback to index, show page button visibility (ON/OFF), digest action flag gate, confirm_digest action flag gateweeks_spec.rbcovers: Upload Schedule button visibility (ON/OFF), week start date inclusion in formAll new behavior paths have corresponding specs. Happy paths and flag-off guard paths are both tested.
PROCESS OBSERVATIONS
work_queue_items_spec.rbis documented and unrelatedVERDICT: APPROVED
PR #213 Review
DOMAIN REVIEW
Stack: Rails 7 (ERB views, Stimulus JS, importmap, RSpec request specs)
Feature flag pattern -- clean. The
schedule_digestflag follows the established pattern: rake-registered with default OFF, controller guards viafeature_enabled?, view gating, cache-busted toggles. Consistent with the existingpending_completionandstripeflags.Controller changes (uploads_controller.rb):
digestandconfirm_digestget identical guard-then-redirect blocks at the top of each action. This is the right approach -- checking the flag beforeUpload.findavoids an unnecessary DB hit when the flag is off.createredirect logic is sound: whenweek_startis present AND the flag is ON, redirect to the show page withauto_digest=1; otherwise fall through to the existing redirect. The flag check on thecreatepath prevents the auto-digest redirect when the flag is off, which is correct.View changes (uploads/show.html.erb):
digest_weeklocal variable is well-constructed: URL param takes precedence, then the upload's storedweek_start, then the current Monday. Good fallback chain.auto-digestStimulus controller is wired to the form viadata: { controller: "auto-digest" }. This will auto-submit the digest form when?auto_digest=1is in the URL.Week tab upload button (weeks/index.html.erb):
!keycloak_configured? || current_user_has_role?(:lead) || current_user_has_role?(:admin) || current_user_has_role?(:super_admin). This is consistent with theUploadsControllerclass-levelrequire_role :lead, :admin, :super_admin. The!keycloak_configured?fallback for dev mode matches the app's convention.week_startinput passes@start_date.iso8601-- this ensures the correct week context flows through the upload-to-digest pipeline.uploadStimulus controller (data-action="change->upload#submit"), which callsthis.element.requestSubmit(). This reuses the existing controller correctly.Stimulus controller (auto_digest_controller.js):
connect(), auto-submits ifauto_digest=1is present.eagerLoadControllersFrom+pin_all_frommeans no manual registration needed.requestSubmit()(vs.submit()) triggers form validation and Turbo properly. Good choice.CSS:
.week-upload-form,.week-upload-btn,.week-upload-icon) use existing design tokens (--spacing-md,--spacing-sm). No magic numbers for spacing. The1.25remicon size and1remfont size are reasonable and consistent with the codebase.BLOCKERS
None.
NITS
Verbose role check in weeks/index.html.erb -- The inline role check
(!keycloak_configured? || current_user_has_role?(:lead) || current_user_has_role?(:admin) || current_user_has_role?(:super_admin))duplicates the roles already declared inUploadsController.require_role. If a role is added/removed from the controller, the view check could drift. Consider extracting to a helper likecan_upload?or checkingvisible_tabs.include?(:uploads). Non-blocking since both are correct today.digest_weekvariable in show.html.erb -- Theparams[:week_start].presenceusage means user-supplied query params flow directly into the date input'svalueattribute. The value is used inside an<input type="date" value="...">which is safe from XSS (the browser's date picker will reject malformed values, and ERB's<%= %>escapes HTML by default). However, if a non-date string is passed, it will show as the input value rather than falling through to the computed default. Not a security issue, but slightly inconsistent UX --parse_week_startin the controller handles this gracefully, but the view does not.Auto-digest fires on browser back/forward -- The
auto_digest_controllerchecks?auto_digest=1inconnect(). If a user navigates away from the digest confirmation and hits the browser back button, Turbo's cache restoration will re-runconnect()and re-submit the form. This could cause a duplicate API call. A mitigation would be to remove the URL param after submission (e.g.,window.history.replaceStateinconnect()after triggering submit). Low risk since the digest action is idempotent (it just re-calls the Vision API), but worth noting.Test coverage for auto-digest Stimulus controller -- The JS controller itself has no unit test. The integration is covered by the request specs (redirect behavior), but the auto-submit-on-connect behavior is not tested. This is typical for Stimulus controllers in Rails apps without a JS test harness, so noting as a nit rather than a blocker.
SOP COMPLIANCE
week_startparamPROCESS OBSERVATIONS
with_feature_disabled/FeatureFlag.enabletest helpers are used correctly and consistently.work_queue_items_spec.rbis noted in the Test Plan and is unrelated -- no regression introduced.VERDICT: APPROVED