CurrencyTransfer
Dealer booking · Variant E2 design review
Phone and WhatsApp booking with consent · Variant E, taken further

Dealer booking, Variant E2

E2 keeps Variant E’s flow and answers the review point by point. 1Every admin screen is the real admin portal, snapshotted and changed in place: the client record, the Authorised Users page, and the request form, which becomes the evidence form. 2The email is the real mailer: the authorised-user request email, rebuilt with the activation email’s icon list, button, .soft/.small note and standard footer. 3There is no dashboard checklist: Margaret confirms from the existing tray item and the existing approval page, and Stage 1’s self-serve switch is a row in Settings, Authorised Users. 4Nothing parallel: the dealer’s access is today’s admin-requested authorised user, its TradingAuthorization, tray type and approval page, plus an append-only consent history; the build appendix maps every screen to the code it changes. 5One name, Dealer booking, and one label for the dealer’s row, CurrencyTransfer dealer, on every screen, with alternatives in Variants. 6Stage 0 comes first and complete, then Stages 1 to 3, Book for client and the build appendix, with at most four notes per screen. 7The client is Margaret Ellwood, a fictional private client in Bath; the dealer is Daniel Mercer; every address is on .example.

Prepared 8 Oct 2026 from the local app (ct-web) and the live website. Screens are real pages saved with their own CSS, then edited. Numbered markers on a screen match its notes.
Where the client confirmsThe existing tray item and approval page, redesigned with Keep it on and Turn it off.
The recorded call is consentThe dealer’s evidence-backed turn-on takes effect at once. The client’s answer is a second consent point.
All stages, rebuiltStages 0 to 3 and Book for client, all in the real UI.
Decision, then buildShort notes for Paul and compliance on each screen; the detail for whoever builds it is in the appendix.

The states

One dealer, one client. The dealer can book in both On states. Every arrow writes a row to the consent history.

The dealer can book Off On awaiting the client On, confirmed client kept it on Turned off by the client Suspended by CurrencyTransfer dealer, with evidence Keep it on Stage 1: the client turns it on in Settings client: app, Settings or the email link RM change, leaver, compliance turns it back on a new dealer starts again at Off, with fresh evidence

Who does what, where

Every place a person touches dealer booking, and the real page it lives on.

WhoWhereWhat
DealerAdmin: client record stripChecks the status before every call.
DealerAdmin: Authorised Users, evidence formTurns it on after the client asks, with the link to the conversation and the contact on file it came from.
DealerAdmin: Log in to book, Create Offline TradeRecords the client’s instruction for every booking.
ClientEmail, no-login pageReads what was turned on, and can turn it off without signing in.
ClientApp: tray item, approval pageKeeps it on or turns it off: the second consent point.
ClientApp: Settings, Authorised UsersSees the dealer, turns it off or back on; from Stage 1 turns it on.
ComplianceAdmin: Authorised Users, consent historyReads every event and its evidence; samples turn-ons against recordings.
SystemMailer, tray, RM changeSends the notice and the tray item; suspends a dealer’s access when the RM changes or the dealer leaves.
1
Stage 0 · Dealer turns it on

Admin client record, before the call

What Daniel sees before he picks up: whether he can book for Margaret, in the summary strip at the top of her record.

Real page it's based on: Admin: client record /admin/users/:id Open at 1440px
  1. 1

    Status sits in the summary strip, the first thing on every client page: Off (grey), On awaiting client (blue), On confirmed (green). Placement alternatives are in Variants (a).

  2. 2

    Daniel Mercer is Margaret's relationship manager. Dealer booking always belongs to a named dealer's own authorised user, never a shared login.

  3. 3

    Nothing else moves. Authorised Users is still in the Account menu, and the strip links straight to it.

2
Stage 0 · Dealer turns it on

Authorised Users, before

The existing admin page with one change: the request button becomes Turn on dealer booking.

Real page it's based on: Admin: Authorised Users /admin/users/:id/authorized_users Open at 1440px
  1. 1

    Replaces "Request authorised user access". Today that button emails a request the client has to approve (used 9 times in 2026); E2 asks for evidence instead.

  2. 2

    The rule is on the page, in one line: only after the client asks, and only with the link to that conversation.

3
Stage 0 · Dealer turns it on

The evidence form

The request page (Request Authorised User Permissions) becomes the evidence form. Fixed dealer permissions replace its three checkboxes.

Real page it's based on: Admin: Request Authorised User Permissions /admin/users/:id/authorized_users/new Open at 1440px
Nothing filled in: the button stays disabled and says why
Real page it's based on: Admin: Request Authorised User Permissions /admin/users/:id/authorized_users/new Open at 1440px
A link that isn’t Aircall, WhatsApp or email: a warning, not a block
Real page it's based on: Admin: Request Authorised User Permissions /admin/users/:id/authorized_users/new Open at 1440px
  1. 1

    Channel is a choice, not free text: Recorded call, WhatsApp or Email. Nothing else counts as Margaret asking.

  2. 2

    Only contact details already on the account are offered. If she called from another number, Daniel calls her back on the number on file and records that call.

  3. 3

    Daniel sees exactly the words Margaret will read, so the call, the email and the app make the same promise.

  4. 4

    The side panel shows what goes into the consent history and what happens on submit. Access starts at once (decision 2).

4
Stage 0 · The notice

The email, sent the moment it’s on

The existing request email (AuthorizedTraderMailer#request_activation) becomes a notice, in the house mailer layout.

FromDaniel Mercer at CurrencyTransfer <dealing@currencytransfer.example>
ToMargaret Ellwood <margaret.ellwood@mail.example>
SubjectWe’ve turned on dealer booking for you
PreheaderYou asked on our call today. Here’s what it means and how to turn it off.
Desktop mail client (600px email, 900px window)
Real page it's based on: AuthorizedTraderMailer#request_activation /rails/mailers/authorized_trader_mailer/request_activation Open at 900px
On a phone (390px)
Real page it's based on: AuthorizedTraderMailer#request_activation /rails/mailers/authorized_trader_mailer/request_activation Open at 390px
  1. 1

    A notice, not a request: it says when and how she asked, in the dealer’s voice, from the dealer’s name.

  2. 2

    The promise as a mailer_header_with_icon list, with icons the registration-complete email already uses. No speed or savings claims.

  3. 3

    One button, into the approval page where she confirms. It replaces "Authorise User".

  4. 4

    The turn-off link sits in the .soft.small line under the button: signed, no login, valid until the setting changes rather than for a fixed 90 days.

5
Stage 0 · The notice

Turn it off, without signing in

Evolves the existing no-login unsubscribe page (notifications/change_subscription), which today renders a legacy layout cut off at the left. This uses the clean header the sign-up pages use.

From the email link: one click
Done
A link for an earlier setting
  1. 1

    One click on the page, not on arrival: mail security scanners open links by themselves, and a GET that turns things off would fire without her. Still no login and no "are you sure" questionnaire.

  2. 2

    The time on the page matches the consent history row (turned off, by client, email link).

  3. 3

    A sign-in link, never a login wall. The page tells her where to turn it back on.

  4. 4

    Old links never fail silently: a link for an earlier setting changes nothing and says so, with a phone number.

6
Stage 0 · The client confirms

The tray item

The existing authorized_trader_request item, with new words. It opens the approval page. Margaret opens the app the next morning.

Desktop, tray open
The tray, zoomed
Phone
Real page it's based on: Client app on a phone: tray /#/ Open at 390px
  1. 1

    Same type, icon and yellow action style as today. The subject fits: real tray titles clip at about 24 characters (see Variants c).

  2. 2

    Today the item disappears 7 days after the request (RecentActivities::AuthorizedTraderRequest). E2 keeps it until she answers.

  3. 3

    It also shows under Recent activity on the dashboard, with View details, as today.

7
Stage 0 · The client confirms

The approval page: keep it on, or turn it off

The existing approval page, /#/accounts/authorised/edit/:uuid, redesigned for a dealer. Today it shows Activate User, Approve and nine permission toggles.

Awaiting her answer
Real page it's based on: Client app: approval page /#/accounts/authorised/edit/:uuid Open at 1440px
Phone
Real page it's based on: Client app on a phone: approval page /#/accounts/authorised/edit/:uuid Open at 390px
  1. 1

    "CurrencyTransfer dealer" replaces "CurrencyTransfer Admin", which reads as more power than a dealer has. No Edit link.

  2. 2

    Who turned it on, when and why, in one line she can check against her memory of the call.

  3. 3

    Keep it on and Turn it off are the same size. Either one writes a consent event with her session and IP. If she ignores it, nothing changes: the dealer’s turn-on stands (decision 2).

  4. 4

    The permission toggles become a plain list of what Daniel can and can’t do. Every dealer gets the same fixed permissions; the client can’t edit them.

After Keep it on
Real page it's based on: Client app: approval page /#/accounts/authorised/edit/:uuid Open at 1440px
After Turn it off
Real page it's based on: Client app: approval page /#/accounts/authorised/edit/:uuid Open at 1440px
8
Stage 0 · The client confirms

Settings, Authorised Users

Daniel appears as an active authorised user, labelled, with his status and permissions in plain words.

Real page it's based on: Client app: Settings, Authorised Users /#/accounts/authorised Open at 1440px
  1. 1

    One label for the dealer’s row, everywhere: CurrencyTransfer dealer.

  2. 2

    On, with the date she confirmed. Turning it off shows Off on this card, not "Suspended", which stays the word for what CurrencyTransfer does.

  3. 3

    Plain-words pills instead of Approver and Admin.

9
Stage 0 · Afterwards

What staff and compliance see afterwards

The client record and the Authorised Users page after she confirms.

Authorised Users: status, consent history, authorised users
Real page it's based on: Admin: Authorised Users /admin/users/:id/authorized_users Open at 1440px
Client record: the strip after she confirms
Real page it's based on: Admin: client record /admin/users/:id Open at 1440px
  1. 1

    Status, who, since when, and that the client confirmed, at the top of the page.

  2. 2

    Consent history: append-only, one row per event. Every staff event has evidence; every client event has a session and IP.

  3. 3

    Log in to book replaces "Login as authorised user" and asks for Margaret’s instruction first (see Book for client).

  4. 4

    The authorised-users table gets a Dealer booking column, and its permissions show recipients are not editable.

10
Stage 0 · Edge cases

When things change

The relationship manager changes: the old dealer’s access is suspended automatically, and the new dealer starts again with fresh evidence.

Real page it's based on: Admin: Authorised Users /admin/users/:id/authorized_users Open at 1440px
  1. 1

    Changing the RM suspends Daniel’s authorised user in the same request and writes a "suspended" event. His sessions end.

  2. 2

    Aisha Rahman gets a new authorised user only after Margaret asks her on a recorded call. Margaret gets a new notice naming her new dealer.

  3. 3

    Leavers work the same way: deleting the admin already makes TradingAuthorization#active? false; E2 adds the event and the notice.

A business account with several contacts

"Asked from" lists every contact allowed to instruct: the account holder and the client’s own authorised users who can book trades, each with their verified phone and email. Only the account holder can keep it on or turn it off in the app, as with every authorised user today.

She calls from another number

Nothing to pick in "Asked from", so the dealer can’t turn it on. The help text says what to do: call her back on the number on file and record that call.

The turn-off link is old

The link stays valid while the setting it was sent for is current. If it was turned off already, the page says when. If the dealer or RM changed since, it says the link is for an earlier setting and changes nothing.

She never answers

The tray item stays until she does, and dealer booking stays on (decision 2). The dealer’s script asks her to look on the next call. The consent history shows the email was opened, or wasn’t.

She turns it off mid-session

The dealer’s session ends at once; a booking in progress fails with a clear message to the dealer, not the client.

Holiday cover

No shared login. Cover is the client calling the desk and the cover dealer turning on their own access with evidence, or waiting for the named dealer.

S1
Stage 1 · Self-serve, for everyone

Turn it on yourself

For clients nobody has spoken to: a self-serve row in Settings, Authorised Users, reached from a tray item and a one-off email. No dashboard checklist.

The row, Off
Real page it's based on: Client app: Settings, Authorised Users /#/accounts/authorised Open at 1440px
After Turn on: one confirmation, naming her dealer
Real page it's based on: Client app: Settings, Authorised Users /#/accounts/authorised Open at 1440px
Tray item: a new info type, not the yellow action style
FromCurrencyTransfer <dealing@currencytransfer.example>
SubjectWould you like your dealer to book for you?
SentOnce, to activated clients with no dealer booking events
One-off email
Real page it's based on: BrokerAccountMailer#activation_notification /rails/mailers/broker_account_mailer/activation_notification Open at 900px
  1. 1

    The Off row sits above the people list, in the page’s own settings-row style.

  2. 2

    Turn on asks once, names her dealer (her RM) and shows the same promise. It writes a client consent event, and the RM’s authorised user starts already confirmed.

  3. 3

    No RM yet: the row says a dealer will be assigned, and the dealing team gets a queue item. Booking can’t start until a named dealer exists.

  4. 4

    The email goes once, says nothing changes unless she turns it on, and links to this page.

S2
Stage 2 · Onboarding

One optional question at sign-up

One optional question on the existing Transfer Requirements step, not a new step.

Desktop
Real page it's based on: Sign-up wizard: Transfer Requirements /#/requirements Open at 1440px
Phone
Real page it's based on: Sign-up wizard on a phone /#/requirements Open at 390px
  1. 1

    Keeps the three-step wizard and its "Only three minutes left" promise. Next works with nothing chosen.

  2. 2

    A preference, not consent: it tells the RM what to raise on the intro call. Nothing is turned on and the Settings row stays Off.

S3
Stage 3 · Website

The website says the same thing

The live Personal Transfers page, in its own components: a paragraph under "Our specialists are on call", and a new first FAQ.

Our specialists are on call
Real page it's based on: currencytransfer.com/personal-transfers (live) https://www.currencytransfer.com/personal-transfers Open at 1440px
Help and FAQs: a new first question, open
Real page it's based on: currencytransfer.com/personal-transfers (live) https://www.currencytransfer.com/personal-transfers Open at 1440px
  1. 1

    The same promise, in its "your dealer" form, sitting next to the RM promise the page already makes.

  2. 2

    The FAQ answer says what it can’t do as plainly as what it can, and how to turn it off.

B
Book for client

Every dealer booking points at an instruction

Both real admin booking paths get the same three fields: "Login as authorised user" (the dealer books in the app) and Create Offline Trade.

Log in to book: record the instruction first
Real page it's based on: Admin: Request Authorised User Permissions /admin/users/:id/authorized_users/new Open at 1440px
In the app, as the dealer: whose account, and which instruction
Real page it's based on: Client app: Make a Transfer /#/quotes/new Open at 1440px
Create Offline Trade: the same section, required
Real page it's based on: Admin: Create Offline Trade /admin/users/:id/offline_trade Open at 1440px
  1. 1

    Log in to book asks for the instruction before the session starts: channel, link and contact on file. One instruction covers one booking.

  2. 2

    In the app the dealer always sees whose account it is and which instruction the booking will carry. End session is one click.

  3. 3

    Create Offline Trade gets the same three required fields, so no admin-booked trade is without evidence.

V
Variants

Three contested choices

Each shows the same state side by side. The recommendation is marked; pick one per choice and it is saved with your feedback.

(a) Where the dealer booking status sits in the admin client record

(b) The client’s confirm page

(c) The feature’s name and the dealer’s label

Wherec1 (recommended)c2c3 (Variant E)
Tray subjectDealer booking is onBooking through your dealer is on clipsPhone & WhatsApp dealing is on clips
Email subjectWe’ve turned on dealer booking for youWe’ve turned on booking through your dealerWe’ve turned on phone & WhatsApp dealing for you
Admin strip and buttonDealer booking: On · Turn on dealer bookingBooking through your dealer: OnPhone & WhatsApp dealing: On
Dealer’s row labelCurrencyTransfer dealerYour dealerTrading Support
WebsiteTurn on dealer booking and your dealer can book transfers for youBook through your dealerPhone & WhatsApp dealing
A
Build appendix

What changes in the code

For whoever builds it. Each screen above maps to the code it changes. Today's machinery is extended, not replaced: the admin-requested AuthorizedTrader, its TradingAuthorization, the authorized_trader_request tray type and the approval page.

1. Screens to code (Stage 0)

ScreenRouteCodeChange
1 Record strip/admin/users/:idviews/admins/users/_highlight.html.hamlFifth column: dealer booking state (see 3) as a status_badge, dealer name and dates, link to Authorised Users. Rendered on every client page that renders the strip.
2 AU page/admin/users/:id/authorized_usersAdmins::AuthorizedUsersController#index, index.html.hamlStatus line; "Turn on dealer booking" replaces "Request authorised user access"; consent history table; Dealer booking column; "Log in to book" replaces "Login as authorised user"; "Suspend access" (staff, needs a reason).
3 Evidence formGET/POST .../authorized_users/new#new, #create, new.html.haml, _formFields channel (recorded_call, whatsapp, email), evidence_url (required, soft host check), contact_used (only verified contacts on file). Fixed dealer permissions (below). On create: activated_at = now (decision 2), event turned_on, notice email and push. No create if any field is missing.
4 EmailmailerAuthorizedTraderMailer#request_activation becomes #dealer_booking_onNew template in the house layout (mailer_header_with_icon list with the registration-complete icons, mailer_button, .soft.small turn-off line). From the dealer's name; reply-to the dealer. Logs email_sent with the MailLog id.
5 Turn-off pageGET /dealer_booking/off/:token, POST samenew controller, like NotificationsController (@skip_navigation, no auth)GET shows one button (link scanners open GETs), POST turns off. Token: Rails.application.message_verifier(:dealer_booking_off) over [trading_authorization_id, latest_event_id], so it is valid while that state is current; otherwise "already off" or "earlier setting". Rate-limited.
6 TrayAPI recent activitiesRecentActivities::AuthorizedTraderRequest, AuthorizedTraderPushNotificatorQuery dealer authorisations with no client answer (not activated_at: nil), drop the 7-day window. Subject "Dealer booking is on"; message names the dealer and the call date. Same type, icon and category.
7 Approval page/#/accounts/authorised/edit/:uuidedit-authorised-user-page componentBranch on is_dealer: decision card, can-do list, history. Keep it on / Turn it off call PUT /api/v1/authorized_traders/:uuid with dealer_booking: confirm | off | on. No Edit, no toggles for dealer rows.
8 Settings list/#/accounts/authorisedauthorised-users-pageDealer label instead of "CurrencyTransfer Admin"; On/Off pill; plain-words pills. Turned-off dealer rows stay in Active with Off, not in Suspended.
API/api/v1/authorized_traderscontroller, AuthorizedTraderForms::UpdateForm, _authorized_trader.json.jbuilderAccept dealer_booking for dealer rows only (account owner only, as today). Add is_dealer, dealer_booking_state, turned_on_at, confirmed_at, history[]. Mobile apps get the same fields.
RM changePATCH /admin/users/:id/assign_assistantAdmins::UserAssistantsController#updateChanging the RM suspends the old RM's dealer authorisation in the same transaction, writes suspended (reason rm_change) and ends its sessions. Same on admin deletion (leaver).

2. Screens to code (Stages 1 to 3, Book for client)

ScreenCodeChange
S1 Settings rowauthorised-users-page, new POST /api/v1/dealer_bookingOff row with Turn on; confirmation names the RM. Creates the RM's dealer authorisation already confirmed (turned_on by client, channel settings) and sends the same notice email in the client's own wording, with the turn-off link. No RM: a queue item for the dealing team and the row says so.
S1 Traynew RecentActivities::DealerBookingOfferInfo item for activated clients with no dealer booking events, until dismissed or answered.
S1 Emailnew mailer method + one-off workerSent once to activated clients with no events, throttled (sleep 1 if index % 5 == 0), logged per client so it can't send twice.
S2 Sign-upregistration/pages/transfer-requirements-page, client dataOptional booking_preference (online, dealer) in the client's data; shown to the RM; not a consent event.
S3 WebsiteWordPress (ctw), Personal Transfers pageOne paragraph in the speak-to-experts block; one FAQ accordion item. Marketing and compliance sign-off; no product build.
Log in to bookAdmins::AuthorizedUserSessionsController#create + new instruction pageInstruction first (channel, evidence, contact, optional request text), stored as a dealer_instruction on the session; the next TradeBooking created in that session takes its id; banner in the app; End session.
Offline tradeAdmins::ManageTradesController#new/#createSame three required fields; creates the dealer_instruction and links the trade.

3. Data

TableColumnsNotes
trading_authorizationsdealer_booking boolean, client_confirmed_atMarks a dealer row (fixed permissions). One live dealer row per client and admin: partial unique index on [trading_account_id, admin_id] where active.
dealer_booking_events (new)trading_authorization_id, user_id, event, actor_type, actor_id, channel, evidence_url, contact_used, contact_verified_at, terms_accepted_at, ip, session_id, mail_log_id, reason, created_atAppend-only: no updated_at, model is readonly after create, no destroy. Events: turned_on, email_sent, confirmed, turned_off, turned_back_on, suspended. Index on trading_authorization_id and user_id.
dealer_instructions (new)user_id, admin_id, channel, evidence_url, contact_used, request_text, trade_booking_id (unique), created_atOne instruction, one booking. Indexes on user_id, admin_id.

State is derived, not stored twice: Off no live dealer row; On, awaiting client activated_at set, client_confirmed_at nil; On, confirmed both set; Turned off latest event turned_off; Suspended latest event suspended (or the admin is deleted, as TradingAuthorization#active? already checks).

4. Transitions

FromTriggerWho, whereToSide effects
OffTurn on, with evidenceDealer, evidence formOn, awaitingAuthorised user created and active; email; tray item; push.
OffTurn on (Stage 1)Client, SettingsOn, confirmedRM's authorised user created; the RM is told.
On, awaitingKeep it onClient, approval pageOn, confirmedTray item cleared.
Either OnTurn it offClient: approval page, Settings, email linkTurned offactivated_at nil, the dealer's sessions and tokens revoked, the dealer told.
Turned offTurn it back onClient, approval page or SettingsOn, confirmedSame dealer, new event.
Turned offClient asks againDealer, evidence formOn, awaitingNew email; the old turn-off link becomes an "earlier setting".
Either OnRM change, leaver, complianceSystem or staff with a reasonSuspendedSessions end. A new dealer starts again at Off with fresh evidence.

5. Every promise must be true in code before it ships

What the client readsWhat makes it true
Only when you askEvery dealer booking needs a dealer_instruction (Log in to book, Create Offline Trade). Compliance samples turn-ons and bookings against the recordings each month.
Only to recipients you already haveDealer permissions are fixed: trade: [admin], payment: [admin], beneficiary: []. Today's request asks for admin on all three. Check that payment allocation can't create a recipient inline.
Can't change your detailsOnly 3 API controllers call need_account_owner! today (authorised traders, automated settlements, forward contract settings). Audit profile, password, 2FA, bank and settlement endpoints against an authorised-user session before this sentence ships.
Stops straight awayTurn-off clears activated_at, revokes the dealer's access tokens and sessions in the same request; AuthorizedUserSessionsController already refuses inactive rows.

6. Tests and checks

7. Open questions for Paul and compliance

✓
Feedback

Your verdict

Ratings, notes and variant picks save in this browser as you go. Copy them into Claude when you’re done.