Commit Graph

2891 Commits

Author SHA1 Message Date
Claudio Ortolina 399c4e4a2a Remove empty packages from ui-framework usage rules 2026-04-13 08:29:38 +01:00
dependabot[bot] 14d318923c Update usage_rules from 1.2.5 to 1.2.6
Updates [usage_rules](https://github.com/ash-project/usage_rules) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/ash-project/usage_rules/releases)
- [Changelog](https://github.com/ash-project/usage_rules/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ash-project/usage_rules/compare/v1.2.5...v1.2.6)

---
updated-dependencies:
- dependency-name: usage_rules
  dependency-version: 1.2.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-13 08:28:48 +01:00
Claudio Ortolina 035b4e7197 Extract shared record action menu component
Closes #155
2026-04-12 23:23:11 +01:00
Claudio Ortolina 88906e10ad Add ex_slop, configure it, run it and fix issues 2026-04-12 22:07:27 +01:00
Claudio Ortolina 9370e5f64d No need to use a case 2026-04-12 22:05:09 +01:00
Claudio Ortolina 834226921e Update production infrastructure docs 2026-04-12 12:46:51 +01:00
Claudio Ortolina b95cfd6e43 Validate Docker builder image on CI 2026-04-12 12:42:42 +01:00
Claudio Ortolina ae262352c6 Add shellcheck to CI lint job 2026-04-12 12:33:02 +01:00
Claudio Ortolina 4a8af7be39 Move lint, precommit, shellcheck from mix aliases to mise scripts
Mix aliases should only compose mix tasks. Shell tool orchestration
(shellcheck, fd) belongs in mise scripts. This removes the mix cmd
escape hatch and makes the boundary clear: mix.exs for pure mix
composition, scripts/ for cross-toolchain orchestration.
2026-04-12 12:30:59 +01:00
Claudio Ortolina 65135a618d Add script/command to validate Dockerfile args versions 2026-04-12 12:10:34 +01:00
Claudio Ortolina 9c7ab5b229 Add Claude Code hooks, commands, and permissions
High priority:

- Auto-format on edit (.claude/hooks/format-elixir.sh): runs mix format
  synchronously after every Edit/Write on .ex, .exs, and .heex files.
  Ensures code is formatted before the next read or tool call.

- mix test permissions: added Bash(mix test) (bare) and Bash(mix test *)
  (with path/flags) to the allow list. Previously only Bash(mix test:*)
  was allowed, which didn't match common invocations.

- Slash commands: /precommit runs the full mix precommit pipeline and
  reports failures with fix suggestions. /oban-status queries Oban job
  state via Tidewave SQL, grouped by state and worker.

Medium priority:

- Chrome DevTools permissions: added 8 new tools (select_page,
  list_network_requests, get_network_request, list_console_messages,
  get_console_message, hover, press_key, wait_for) for debugging API
  traffic, JS hook errors, hover states, and keyboard navigation.

- Gettext extraction hook (.claude/hooks/gettext-extract.sh): runs
  mix gettext.extract --merge asynchronously after editing .heex files.
  Async because it's project-wide and doesn't need to block the next edit.

- Sobelow permission: added Bash(mix sobelow:*) to the allow list for
  independent security checks.
2026-04-12 09:54:32 +01:00
Claudio Ortolina e498dccde5 Provide sqlite3 console command
- Loads extensions
- Wraps with rlwrap for convenience
2026-04-12 07:36:07 +01:00
Claudio Ortolina ea9886a647 Update Erlang to 28.4.2 2026-04-12 07:16:14 +01:00
Claudio Ortolina 02761428c1 Format map and list query params as JSON 2026-04-11 23:57:40 +01:00
Claudio Ortolina a983698c72 Document SQLite query optimization conventions 2026-04-11 23:46:23 +01:00
Claudio Ortolina 1c8d63c4d7 Bump Docker image versions in production docs 2026-04-11 23:46:06 +01:00
Claudio Ortolina 754a71cf70 Update dependencies
igniter 0.7.8 => 0.7.9
2026-04-11 23:39:00 +01:00
Claudio Ortolina d8c84e787b Optimize ListeningStats query performance
Three independent refactors of lib/music_library/listening_stats.ex,
measured against the dev DB (104k tracks) via bench/listening_stats.exs:

| Query                           | Baseline  | After     | Speedup |
|---------------------------------|-----------|-----------|---------|
| recent_activity(tz, 100)        | 38.98 ms  | 2.87 ms   | 13.6x   |
| list_tracks(page 1, 200)        | 47.30 ms  | 4.81 ms   | 9.8x    |
| get_top_artists_by_days(7)      | 66.51 ms  | 1.02 ms   | 65x     |
| get_top_artists_by_days(30)     | 67.41 ms  | 2.84 ms   | 23.7x   |
| get_top_artists_by_days(365)    | 76.03 ms  | 25.57 ms  | 3.0x    |
| get_top_albums_by_days(7)       | 92.63 ms  | 1.61 ms   | 57.5x   |
| get_top_albums_by_days(30)      | 94.52 ms  | 3.69 ms   | 25.6x   |
| get_top_albums_by_days(365)     | 105.23 ms | 32.81 ms  | 3.2x    |
| get_top_artists(limit: 10)      | 123.96 ms | 101.68 ms | 1.22x   |
| get_top_albums(limit: 10)       | 209.64 ms | 108.23 ms | 1.94x   |

tracks_with_record_info_query/0 now uses correlated scalar subqueries
against record_releases and artist_records instead of materializing
helper subqueries on every call. The cost scales with the outer LIMIT,
not with the size of record_releases.

top_albums_base_query/0 and top_artists_base_query/0 are replaced by
aggregate_query + attach_metadata pairs. The pattern is aggregate first,
attach metadata second: GROUP BY runs against the raw track scan, then
a tiny outer SELECT attaches record_releases / artist_infos lookups for
the <= 10 result rows via correlated subqueries.

tracks_since_query/1 wraps the date-filtered inner scan with limit: -1.
SQLite cannot flatten a subquery that has a LIMIT, so it materializes
the date-bounded subset and the optimizer uses the timestamp index for
the range scan instead of the album/artist composite index. This trick
replaces SQLite's WITH ... AS MATERIALIZED (which ecto_sqlite3 doesn't
expose).

All json_extract(?, '\$.path') fragments use the canonical form rather
than the equivalent ? ->> '\$.path' shorthand. SQLite's index matcher
requires the GROUP BY expression to match the index expression
textually to use the composite index for natural ordering.

collected_releases_query/0 and wishlisted_releases_query/0 are removed
from Collection and Wishlist — they had a single internal caller that
no longer exists after the refactor.

New regression tests lock the semantics that the optimized queries
must preserve:
- count(DISTINCT scrobbled_at_uts) — 579 duplicate timestamps exist in
  the dev DB from rapid Last.fm scrobbles, so replacing with count(*)
  would silently change results
- :artist_id key in list_tracks result maps — ScrobbledTracksLive.Index
  destructures it even though the template body never references it

Closes #148
2026-04-11 23:36:32 +01:00
Claudio Ortolina d3da4e4559 Update architecture docs for embedding ownership 2026-04-11 21:48:59 +01:00
Claudio Ortolina 839566dd63 Update dependencies
igniter 0.7.7 => 0.7.8
2026-04-11 21:46:07 +01:00
Claudio Ortolina 82e4882aa9 Assert embedding enqueues in batch test 2026-04-11 21:43:00 +01:00
Claudio Ortolina ea6ecb2661 Assert embedding enqueues in artist info test 2026-04-11 21:43:00 +01:00
Claudio Ortolina 3da0865725 Drop Records embedding wrappers 2026-04-11 21:43:00 +01:00
Claudio Ortolina a608be7387 Move regenerate_artist_embeddings into Similarity 2026-04-11 21:43:00 +01:00
Claudio Ortolina 789ce04b87 Use MusicBrainz.get_all_releases in Records 2026-04-11 21:40:32 +01:00
Claudio Ortolina b7af9557c1 Add MusicBrainz.get_all_releases/1 2026-04-11 21:40:32 +01:00
Claudio Ortolina 755955df54 Update elixir to 1.20.0-rc.4 2026-04-10 23:12:51 +01:00
Claudio Ortolina 2422b6a243 Update dependencies
credo 1.7.17 => 1.7.18
2026-04-10 23:10:09 +01:00
Claudio Ortolina fcf5adde2f Add tests for QueryReporter 2026-04-10 11:10:12 +01:00
Claudio Ortolina 8826834549 Fix release status badge in grouped records on this day
The tooltip was using the group representative instead of the
actual record, causing all items in a group to show the same
badge regardless of their own selected_release_id.
2026-04-10 10:38:48 +01:00
Claudio Ortolina 90a0491924 Update architecture docs with QueryReporter 2026-04-10 10:31:21 +01:00
Claudio Ortolina 1c720c8394 Add query timing metadata to reporter output 2026-04-10 10:30:05 +01:00
Claudio Ortolina 27148c6507 Add dev query reporter and skill
Ecto telemetry reporter that captures executed SQL queries
to a log file with interpolated parameters and source
locations. Activated/deactivated at runtime via Tidewave
for LLM-driven query analysis workflows.
2026-04-10 10:27:12 +01:00
Claudio Ortolina b5686fa0f9 Allow creating a new page with chrome devtools 2026-04-10 09:14:27 +01:00
Claudio Ortolina eab5ec5ac1 Remove localhost URL from README (because port changes) 2026-04-10 07:49:42 +01:00
Claudio Ortolina 2c393db0f2 Add visual verification guidance to ui-framework skill 2026-04-10 07:45:22 +01:00
Claudio Ortolina 31ebfe41ed Allow use of Chrome Devtools for verification 2026-04-10 07:30:52 +01:00
Claudio Ortolina 3fb292ce35 Improve update-documentation skill
Add parallel analysis via subagents, skip-list for irrelevant
commits, format-matching guidance, and wider trigger description.
2026-04-09 16:27:49 +01:00
Claudio Ortolina f92a41241f Improve ui-framework skill with project conventions
Add project-specific UI checklist, component organization,
LiveView structure, toast patterns, and routing conventions
above the usage-rules managed section. Widen trigger description.
2026-04-09 16:24:35 +01:00
Claudio Ortolina 3e80de32b3 Improve update-dependencies skill
Adds context about dependency categories, major version bump
assessment, bulk vs selective update options, asset build
verification, and commit message conventions.
2026-04-09 16:18:16 +01:00
Claudio Ortolina eeb0763466 Deduplicate and consolidate project docs
Remove redundant sections from production-infrastructure.md that
duplicated architecture.md (Oban queues/plugins/cron, external API
integrations, SQLite extensions, scheduled maintenance). Absorb API
rate limits into architecture.md's integration table. Replace tool
versions table with pointer to mise.toml. Add two conventions from
project history: scoped test setup and single-path shared components.
2026-04-09 15:19:32 +01:00
Claudio Ortolina 67c01ab1fa Update architecture and infrastructure docs 2026-04-09 15:09:32 +01:00
Claudio Ortolina a8d6db69ec Update fine 0.1.5 to 0.1.6 2026-04-09 14:47:58 +01:00
Claudio Ortolina e2f376b423 Enable Fluxon private repo for dependabot 2026-04-09 10:43:04 +01:00
Claudio Ortolina 56b281c696 Ignore path-based NPM dependency in dependabot 2026-04-09 10:35:19 +01:00
Claudio Ortolina c048054956 Enable dependabot for Elixir and NPM packages 2026-04-09 10:28:47 +01:00
Claudio Ortolina c833149fa4 Use dependabot for docker image updates 2026-04-09 07:33:19 +01:00
Claudio Ortolina 431af98e72 Use precise litestream image version 2026-04-09 07:26:47 +01:00
Claudio Ortolina e34e06ee6f Add review and audit principles to conventions 2026-04-09 07:23:01 +01:00
Claudio Ortolina 6a60fe1860 Add benchmark for collection count functions 2026-04-09 07:05:06 +01:00