158 Commits

Author SHA1 Message Date
b0fb9726b1 Add clickable facet pills for mobile-friendly DSL filter composition
All checks were successful
Deploy / deploy (push) Successful in 1m50s
- Create reusable dsl_facets.py component with clickable pills that compose
  DSL filter expressions by appending field:value to the filter input
- Add /api/facets endpoint for dynamic facet count refresh via HTMX
- Fix select dropdown dark mode styling with color-scheme: dark in SelectStyles
- Integrate facet pills into all DSL filter screens: registry, move, and
  all action forms (tag-add, tag-end, attrs, outcome, status-correct)
- Update routes to fetch and pass facet counts, locations, and species
- Add comprehensive unit tests for component and API endpoint
- Add E2E tests for facet pill click behavior and dark mode select visibility

This enables tap-based filter composition on mobile without requiring typing.
Facet counts update dynamically as filters are applied via HTMX.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 22:51:17 +00:00
ffef49b931 Fix egg sale form: remove duplicate route, change price to euros
All checks were successful
Deploy / deploy (push) Successful in 2m50s
The egg sale form had two issues:
- Duplicate POST /actions/product-sold route in products.py was
  overwriting the eggs.py handler, causing incomplete page responses
  (no tabs, no recent sales list)
- Price input used cents while feed purchase uses euros, inconsistent UX

Changes:
- Remove duplicate handler from products.py (keep only redirect)
- Change sell form price input from cents to euros (consistent with feed)
- Parse euros in handler, convert to cents for storage
- Add TestEggSale class with 4 tests for the fixed behavior

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 07:35:02 +00:00
51e502ed10 Add Playwright e2e tests for all 8 spec acceptance scenarios
All checks were successful
Deploy / deploy (push) Successful in 1m49s
Implement browser-based e2e tests covering:
- Tests 1-5: Stats progression (cohort, feed, eggs, moves, backdating)
- Test 6: Event viewing and deletion UI
- Test 7: Harvest outcomes with yield items
- Test 8: Optimistic lock selection validation

Includes page objects for reusable form interactions and fresh_db
fixtures for tests requiring isolated database state.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 17:30:26 +00:00
feca97a796 Add Playwright e2e test infrastructure
Set up browser-based end-to-end testing using pytest-playwright:
- Add playwright-driver and pytest-playwright to nix flake
- Configure PLAYWRIGHT_BROWSERS_PATH for NixOS compatibility
- Create ServerHarness to manage live server for tests
- Add smoke tests for health endpoint and page loading
- Exclude e2e tests from pre-commit hook (require special setup)

Run e2e tests with: pytest tests/e2e/ -v -n 0

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 08:11:15 +00:00
c477d801d1 Fix datetime picker not updating ts_utc before form submission
All checks were successful
Deploy / deploy (push) Successful in 2m39s
The datetime picker used only onchange to update the hidden ts_utc field,
but onchange fires on blur, not immediately. On mobile, submitting the form
right after selecting a date would submit before onchange fired, leaving
ts_utc at "0" (defaulting to current time).

Adding oninput ensures the hidden field updates immediately as the value
changes, fixing backdating on all forms using event_datetime_field().

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 07:39:45 +00:00
a1c268c7ae Improve mobile UI: compact bottom nav and sticky action bar
All checks were successful
Deploy / deploy (push) Successful in 2m38s
- Enable daisyUI and use btm-nav component for compact bottom navigation
- Add sticky ActionBar component for form submit buttons on mobile
- Form buttons now float above the bottom nav, preventing obscuring
- Update all form templates (actions, eggs, feed, move) to use ActionBar
- Menu drawer header now shows AnimalTrack + version like desktop sidebar

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 06:22:19 +00:00
e7efcdfd28 Include static files in package build
All checks were successful
Deploy / deploy (push) Successful in 1m38s
Add package-data configuration so static files (JavaScript, CSS) are
included when the package is built and deployed. Fixes 404 errors for
datetime-picker.js in production.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 08:00:04 +00:00
880ef2b397 Fix cost/egg window to use later of first egg or first feed event
All checks were successful
Deploy / deploy (push) Successful in 1m39s
When egg data is imported but feed data starts later, cost/egg was
incorrectly using the egg window (e.g., 30 days) instead of the
period where both data types exist. Now cost/egg uses max(first_egg,
first_feed) to ensure accurate cost calculation.

Each metric now displays its own window: "4.7 eggs/day (30d) | €0.28/egg (7d)"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 20:07:15 +00:00
86dc3a13d2 Dynamic window metrics for cold start scenarios
All checks were successful
Deploy / deploy (push) Successful in 2m37s
Calculate metrics from first relevant event to now (capped at 30 days)
instead of a fixed 30-day window. This fixes inaccurate metrics for new
users who have only a few days of data.

Changes:
- Add _get_first_event_ts() and _calculate_window() helpers to stats.py
- Add window_days field to EggStats dataclass
- Update routes/eggs.py and routes/feed.py to use dynamic window
- Update templates to display "N-day avg" instead of "30-day avg"
- Use ceiling division for window_days to ensure first event is included

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 19:06:00 +00:00
4c62840cdf Fix mobile UI: slide panel padding and datetime picker clicks
- Increase event detail panel bottom padding from pb-20 to pb-28 to
  prevent delete button from being obscured by mobile nav + safe area
- Change datetime picker from hx_on_click/hx_on_change to standard
  onclick/onchange attributes (HTMX doesn't recognize hx-on-* syntax)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 17:06:32 +00:00
fe73363a4b Filter egg harvest events to only include adult female ducks
Males, juveniles, and other non-laying animals were incorrectly being
associated with egg collection events. Added life_stage='adult' and
sex='female' filters to resolve_ducks_at_location() query.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 16:56:08 +00:00
66d404efbc Fix mobile UI issues: form text visibility, slide panel overlap, notes display
All checks were successful
Deploy / deploy (push) Successful in 2m38s
- Add CSS for all form fields (input, textarea, select) in dark mode with
  -webkit-text-fill-color for iOS Safari compatibility
- Add padding-bottom to event detail panel so delete button is visible
  above bottom nav on mobile
- Display notes field in ProductCollected and ProductSold event details

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 16:38:04 +00:00
5be8da96f2 Fix 405 error after event deletion via HX-Push-Url header
All checks were successful
Deploy / deploy (push) Successful in 2m39s
When HTMX boosted forms submit via POST, the browser URL wasn't being
updated correctly. This caused window.location.reload() after event
deletion to reload the action URL (e.g., /actions/feed-given) instead
of the display URL (e.g., /feed), resulting in a 405 Method Not Allowed.

The fix adds a render_page_post() helper that returns FT components
with an HttpHeader("HX-Push-Url", push_url). This tells HTMX to update
the browser history to the correct URL after successful form submission.

Updated routes:
- /actions/feed-given -> push /feed
- /actions/feed-purchased -> push /feed
- /actions/product-collected -> push /
- /actions/product-sold -> push /
- /actions/animal-move -> push /move
- /actions/animal-cohort -> push /actions/cohort
- /actions/hatch-recorded -> push /actions/hatch
- /actions/animal-tag-add -> push /actions/tag-add
- /actions/animal-tag-end -> push /actions/tag-end
- /actions/animal-attrs -> push /actions/attrs
- /actions/animal-outcome -> push /actions/outcome
- /actions/animal-status-correct -> push /actions/status-correct

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 14:23:50 +00:00
803169816b Replace onclick navigation with proper links
Converts cancel buttons that use onclick="window.location.href='...'" to
proper A tags with href. This improves accessibility (keyboard navigation,
right-click options) and semantics while maintaining the same button styling.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 12:25:02 +00:00
7315e552e3 Extract DateTime picker to static JS file
Moves ~50 lines of inline JavaScript from event_datetime_field() to a
static file. The component now uses data attributes for element binding
and global functions (toggleDatetimePicker, updateDatetimeTs) from the
static JS file.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 12:22:41 +00:00
4e78b79745 Extract slide-over script to shared component
Creates slide_over_script() in shared_scripts.py that generates JavaScript
for slide-over panels with open/close functions. EventSlideOverScript and
SidebarScript now use this shared function, reducing duplicated JS logic.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 12:20:18 +00:00
fc4c2a8e40 Extract common diff_confirmation_panel() for selection mismatch UI
Refactors 5 nearly-identical diff_panel functions into a single reusable
component. Each specific diff_panel function now delegates to the common
function with action-specific parameters.

Reduces ~300 lines of duplicated code to ~100 lines of shared logic.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 12:17:51 +00:00
b2132a8ef5 Add accessibility attributes for screen readers
Improve accessibility by adding ARIA attributes to interactive
components:

nav.py:
- Menu button: aria_label="Open navigation menu"

sidebar.py:
- Close button: aria_label="Close menu"
- Drawer panel: role="dialog", aria_label="Navigation menu"

base.py:
- Toast container: aria_live="polite" (announces toasts)
- Event slide-over: role="dialog", aria_label="Event details"

These changes help screen readers properly announce interactive
elements and their purposes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 12:12:46 +00:00
a87b5cbac6 Preserve form field values in eggs.py on validation errors
When a validation error occurs in the harvest or sell forms, the
entered field values are now preserved and redisplayed to the user.
This prevents the frustration of having to re-enter all values after
a single field fails validation.

Template changes (eggs.py):
- Added default_* parameters to harvest_form and sell_form
- Updated LabelInput/LabelTextArea fields to use these values

Route changes (routes/eggs.py):
- Updated _render_harvest_error to accept quantity and notes
- Updated _render_sell_error to accept quantity, total_price_cents,
  buyer, and notes
- All error return calls now pass form values through

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 12:10:54 +00:00
b09d3088eb Add loading state indicators to all form submit buttons
Add hx_disabled_elt="this" to submit buttons across all forms to
disable them during form submission, preventing double-clicks and
providing visual feedback that the action is processing.

Buttons updated:
- actions.py: promote, cohort, hatch, tag-add, tag-end, attrs,
  outcome, status-correct forms and their diff_panel confirmations
- eggs.py: collect and sell forms
- feed.py: give and purchase forms
- locations.py: create and rename forms
- move.py: move form and diff_panel confirmation
- products.py: create form
- registry.py: filter apply button

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 12:07:15 +00:00
2fc98155c3 Replace LabelSelect with raw Select to fix MonsterUI value bug
MonsterUI LabelSelect has a confirmed bug where it sends the option's
label text instead of the value attribute on form submission. This was
causing 422 validation errors in forms.

- Replace all LabelSelect usages with raw Div(FormLabel, Select) pattern
- Add comments documenting the MonsterUI bug workaround
- Matches pattern already used in feed.py since commit ad1f910

Files modified: eggs.py, move.py, actions.py, products.py

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 11:24:34 +00:00
eee8552345 Allow recording zero eggs collected
All checks were successful
Deploy / deploy (push) Successful in 1m37s
Enable recording "checked coop, found 0 eggs" to distinguish from days
when the coop wasn't checked at all. Statistics remain eggs/calendar day.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 06:37:31 +00:00
d91ee362fa Fix tombstone bug in stats and add cost statistics to forms
All checks were successful
Deploy / deploy (push) Successful in 1m38s
Bug fix: Stats queries (eggs/day, feed/bird/day, etc.) were not excluding
tombstoned (deleted) events. Updated EventStore.list_events() to exclude
tombstoned events by default via LEFT JOIN, and updated direct SQL queries
in stats.py with the same tombstone exclusion.

New stats added:
- Harvest form: cost/egg (global, 30-day avg)
- Sell form: avg price/egg (30-day)
- Give feed form: cost/bird/day (global, 30-day avg)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 06:19:30 +00:00
e42eede010 Add recent events and stats to eggs, feed, and move forms
All checks were successful
Deploy / deploy (push) Successful in 2m40s
- Create recent_events.py helper for rendering event lists with humanized
  timestamps and deleted event styling (line-through + opacity)
- Query events with ORDER BY ts_utc DESC to show newest first
- Join event_tombstones to detect deleted events
- Fix move form to read animal_ids (not resolved_ids) from entity_refs
- Fix feed purchase format to use total_kg from entity_refs
- Use hx_get with #event-panel-content target for slide-over panel
- Add days-since-last stats for move and feed forms

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 21:10:09 +00:00
62cc6c07d1 Add CSRF token to event delete fetch() call
All checks were successful
Deploy / deploy (push) Successful in 2m38s
The delete event functionality uses vanilla fetch() instead of HTMX,
so it wasn't getting the x-csrf-token header that the htmx:configRequest
listener adds. This caused 403 Forbidden on event deletion.

Changes:
- Made getCsrfToken() a global window function so it can be used by
  both HTMX and vanilla fetch() calls
- Added x-csrf-token header to the deleteEvent() fetch request

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 16:09:21 +00:00
cd01daec6d Fix CSRF cookie not being set on HTML responses
All checks were successful
Deploy / deploy (push) Successful in 1m38s
FastHTML's fast_app() silently ignores the 'after' parameter - it only
supports 'before'. The afterware function was never being called, so the
CSRF cookie was never set, causing 403 Forbidden on all POST requests
in production.

Replaced the non-functional afterware with proper Starlette ASGI
middleware (CsrfCookieMiddleware) that intercepts responses and adds
the Set-Cookie header directly to HTML GET responses.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 16:01:30 +00:00
b306fa022c Make dropdowns legible. 2026-01-08 15:52:14 +00:00
1853bca745 Fix UIkit tab/switcher list markers showing as squares
All checks were successful
Deploy / deploy (push) Successful in 1m39s
Add global CSS to remove ::marker pseudo-elements from uk-tab and
uk-switcher components. Also clean up tab structure to match MonsterUI
idioms (uk-active on Li, use None instead of empty string for cls).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 12:56:25 +00:00
94701c2f7e Fix registry filter input/button width ratio
Use Grid with col-span instead of flex to give the filter input 10/12
of the width and the Apply button only 2/12.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 10:42:34 +00:00
5c12eb553c Add build version indicator to sidebar menu
Display commit date and short hash (e.g., "2026-01-08 fb59ef7") below
the ANIMALTRACK title in the sidebar. In development, reads from git
directly; in Docker, reads from BUILD_DATE/BUILD_COMMIT env vars
injected at build time from the Nix flake.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 10:36:44 +00:00
fb59ef72a8 Fix FastHTML empty value attribute omission in select options
FastHTML omits the value attribute when value="" (empty string), causing
browsers to use the option's text content as the submitted value. This
made forms send "Keep current" or "No change" text instead of empty
string, failing Pydantic enum validation.

Fixed by using "-" as a sentinel value instead of "" for "no change"
options, and updating route handlers to treat "-" as None.

Affected forms:
- Promote form (sex, repro_status)
- Update attributes form (sex, life_stage, repro_status)
- Outcome form (yield_product_code)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 09:31:11 +00:00
29fbe68c73 Add backdating support to egg harvest and sell forms
Both forms now have datetime pickers like the feed forms, allowing
users to record events at past timestamps. Each form has a unique
field_id (harvest_datetime, sell_datetime) to avoid conflicts.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 09:24:26 +00:00
4b951d428f Remove bootstrapping data. 2026-01-08 09:21:09 +00:00
1d322de67b Fix datetime picker on multi-form pages
The event_datetime_field JavaScript used querySelector to find the
ts_utc hidden input by name, which breaks when multiple forms have
ts_utc fields (like feed give and purchase forms). Now each hidden
field gets a unique ID based on the field_id parameter, and the
JavaScript uses getElementById for correct scoping.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 09:17:56 +00:00
d4a29130f6 Fix feed error response rendering with to_xml
The 422 error handlers were using str() to convert FT objects to HTML,
which produces Python repr output instead of HTML. Changed to use
to_xml() like other routes (eggs.py, products.py) do.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 09:11:08 +00:00
3f510d8d76 Add animal_id filter support for registry selection
The registry selection feature builds filters like animal_id:X|Y|Z
but the parser didn't recognize animal_id as a valid field.

- Add animal_id to VALID_FIELDS in parser.py
- Add animal_id handler in resolver.py _build_filter_clause

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 08:44:28 +00:00
abb1c87e6c Add registry selection + expandable affected animals
Registry improvements:
- Add checkbox column for selecting animals in the table
- Add selection toolbar with count display
- Add Actions dropdown (Move, Add Tag, Update Attributes, Record Outcome)
- Selection persists across infinite scroll via JavaScript
- Navigate to action page with filter=animal_id:X|Y|Z for selected animals

Event detail improvements:
- Show more animal details: sex (M/F/?), life stage, location name
- Add "Show all X animals" button when >20 animals affected
- HTMX endpoint to load full list on demand
- Separate affected_animals_list component for HTMX swaps

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 16:03:25 +00:00
ad1f91098b Fix MonsterUI Select bug, UI improvements, enable animal rename
- Replace broken MonsterUI LabelSelect with raw HTML Select elements
  (was sending label text instead of value attribute)
- Fix wrong ReproStatus options in promote form (use enum values)
- Add spacing between name and details in animal selection list
- Fix registry filter layout, add Clear button
- Use phonetic ID in animal details panel title
- Change feed price input from cents to euros
- Allow renaming already-identified animals (remove identified check)
- Fix FeedGiven 422 error (same MonsterUI Select bug)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 15:57:09 +00:00
14bf2fa4ae Fix CSRF 403, improve registry UI, add phonetic IDs
- Fix CSRF token handling for production: generate tokens with HMAC,
  set cookie via afterware, inject into HTMX requests via JS
- Improve registry page: filter at top with better proportions,
  compact horizontal pill layout for facets
- Add phonetic ID encoding (e.g., "tobi-kafu-meli") for animal display
  instead of truncated ULIDs
- Remove "subadult" life stage (migration converts to juvenile)
- Change "Death (natural)" outcome label to just "Death"
- Show sex/life stage in animal picker alongside species/location

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 15:20:26 +00:00
a4b4fe6ab8 Migrate to alo organization
All checks were successful
Deploy / deploy (push) Successful in 2m51s
Update docker image path and workflow reference to use alo org.
Fix var directory permissions in docker build.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 10:50:16 +00:00
0b51ad3dac Use shared CI/CD workflow from alo-cluster
All checks were successful
Deploy / deploy (push) Successful in 2m40s
Simplify workflow to use reusable workflow:
  uses: ppetru/alo-cluster/.gitea/workflows/deploy-nomad.yaml@master

All build/push/deploy logic is now centralized in alo-cluster.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 07:48:44 +00:00
1b6147817b Fix CI: resubmit job with new UUID to trigger deployment
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m37s
Evaluate alone doesn't create deployments. We need to resubmit
the job with a changed meta.uuid to force Nomad to deploy.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 22:33:51 +00:00
75e7323d7d Fix CI workflow: use bundled tools, add debugging
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m40s
- Use skopeo and jq directly (already in nix-runner image)
- Redirect evaluate response to /dev/null
- Echo responses for debugging
- Handle case where no deployment exists

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 22:24:36 +00:00
f07102d199 Use extraCommands instead of runAsRoot in Docker build
Some checks failed
Build and Deploy / build-and-deploy (push) Failing after 2m12s
runAsRoot requires KVM which isn't available in CI containers.
extraCommands achieves the same result without virtualization.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 21:47:34 +00:00
a2893162e6 Fix branch name.
Some checks failed
Build and Deploy / build-and-deploy (push) Failing after 41s
2026-01-03 12:34:49 +00:00
ee572a37f1 Allow manual workflow runs. 2026-01-03 12:33:17 +00:00
3ac1e1140a Log more info when rejecting connections. 2026-01-03 11:58:35 +00:00
743fe9d68d Deploy workflow. 2026-01-03 11:47:02 +00:00
06421f38bb Make docker image work. 2026-01-03 11:46:50 +00:00
f2145e4827 feat: add CIDR/netmask support for trusted proxy IPs
TRUSTED_PROXY_IPS now accepts CIDR notation (e.g., 192.168.1.0/24)
in addition to exact IP addresses. Supports both IPv4 and IPv6.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 11:46:04 +00:00