* feat(api): allow multiple active API keys per user
Previously a user could hold only one active API key; creating a new one
silently revoked the existing key, breaking any app using it. Allow
multiple named active keys instead.
- Drop the one-active-key-per-source validation; add name uniqueness
among the user's active visible keys (revoked names are reusable,
same name allowed across users).
- Rewrite Settings::ApiKeysController as a RESTful collection
(index/show/new/create/destroy); create no longer revokes existing
keys, and key lookup is scoped to the current user's active keys.
- resource :api_key -> resources :api_keys.
- Add an API keys list view with per-key revoke and an empty state;
rewrite the show page for a single key.
- Update i18n (remove single-key copy, pluralise nav label) and tests.
* refactor(api): address review on multiple API keys
- Remove unreachable destroy branches (cannot_revoke is guarded by the
.visible 404; revoke! raises rather than returning false) and document
that .visible is the demo-key revocation guard.
- Delete the orphaned created.html.erb / created.turbo_stream.erb
templates (no action renders them) and their unused locale keys.
- Extract shared partials (_scope_badges, _status_indicator, _key_meta,
_key_reveal, _usage) to de-duplicate the index and show views; unify
the active-status indicator on the standard dot.
- Carry forward the @container / @lg:flex-row / min-w-0 responsive
fixes from #2079 into the shared key-reveal partial.
* test(api): cover newly-created API key confirmation render
* refactor(api): harden demo-key guard and address review nits
- Document the demo-key revocation guard on ApiKey's `visible` scope (the
authoritative spot) and add a model test locking the invariant that
`.visible` excludes the demo monitoring key.
- _scope_badges: use an i18n lookup with a humanize fallback instead of
bypassing translation for unknown scopes.
- _key_reveal: drop the hard-coded `id` from the shared partial; the
system test now locates the key via its data-clipboard-target.
* refactor(api-keys): migrate hand-rolled badges to DS::Pill
Replace raw span elements in scope badges and status indicator
with DS::Pill to align with the design system migration convention.
* fix(loans): opening anchor now uses current balance, not original principal
When creating a loan manually, the opening anchor valuation was being
set to `initial_balance` (the original loan principal) instead of
`account.balance` (the current outstanding balance). After the sync
job ran, `account.balance` was overwritten to match the anchor,
making every manually-created loan show its original principal as
the current balance.
Fix by always using `account.balance` for the opening anchor in
`create_and_sync`, and reading `Loan#original_balance` from the
`loans.initial_balance` column directly (with a fallback to
`first_valuation_amount` for provider-synced loans that may not
have the column populated).
* fix(api-keys): strip accidental loan changes; rescue revoke! failures
The fix(loans) commit was accidentally committed into this branch.
Remove the loan-related changes from account.rb, loan.rb, and both
test files, restoring them to their pre-loan-commit state.
Also fix the destroy action: revoke! uses update! internally which
raises ActiveRecord::RecordInvalid on failure rather than returning
false. Add rescue for RecordInvalid and RecordNotDestroyed so failures
produce a flash alert instead of a 500. Re-adds the revoke_failed
locale key that was dropped from settings.api_keys.destroy.
---------
Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>