Day 2 · Exercise

FX Platform Challenge Brief

Build a polished foreign exchange platform where users explore rates, preview a conversion, exchange demo balances, and review their transactions.

Goal

Build a polished foreign exchange platform where users explore rates, preview a conversion, exchange demo balances, and review their transactions.

Requirements

  • Create a dashboard, rates workspace, currency converter, wallets, and transaction history.
  • Support BHD, USD, EUR, GBP, AED, and SAR using clearly labelled demo rates and balances.
  • Provide a complete quote, review, confirm, and receipt flow with transparent fees.
  • Save accounts, quotes, conversions, watchlists, and alerts in Supabase.
  • Add protected administration for demo rates and an audit trail.
  • Follow the design guidelines and make the platform responsive across desktop, tablet, and mobile.
  • Collaborate through reviewed Pull Requests and deploy the working app through Vercel.

The product you are building

FX means foreign exchange: converting one currency into another. Build a web platform that makes the rate, cost, and outcome of a conversion easy to understand. A user should be able to sign in, inspect rates, choose currencies, review a quote, confirm a simulated exchange, and find the saved receipt later. Work as a team of 2–3 and use a product name of your choice.

  • This is a training simulation. Use fictional users, seeded balances, and demo rates. Show a persistent ‘Demo environment’ label near the account context and ‘Simulated exchange’ on confirmation and receipts.
  • The required product is a spot conversion simulator: exchanging now at an offered rate. Actual payments, bank connections, leverage, derivatives, and real settlement are outside this challenge.
  • All features in the required sections below belong in the completed challenge. Build the main conversion flow first, then complete the supporting features. Stretch features are separate.

People and permissions

  • Customer: sign in and out, view their own balances, request quotes, confirm exchanges, and manage their own history, watchlist, and alerts.
  • Administrator: access a separate rate-management workspace, update demo reference rates, pause a currency, and inspect the rate-change audit log.
  • Use Supabase Auth for identity. Store administrator permissions in protected data. Users must not be able to assign themselves an administrator role.
  • Enforce ownership and permissions in server/database operations as well as the interface. One customer cannot read another customer’s balances, quotes, transactions, or alerts.
  • Create two customer test accounts and one administrator account for the demo. Keep credentials out of the repository and public brief.

Required screens and navigation

  • Overview: a BHD portfolio estimate, individual currency balances, favourite pairs, recent conversions, and one clear ‘Convert currency’ action. Label the total as an estimate at demo reference rates, excluding fees.
  • Rates: a searchable currency-pair list, pair detail, historical chart, watchlist control, and source/update information.
  • Convert: source and destination selectors, amount entry, balance check, quote breakdown, review step, confirmation, and receipt.
  • Wallets: each currency’s available demo balance and its related transactions. Wallet detail links directly to conversion with that currency selected.
  • Transactions: searchable and filterable history, transaction detail, receipt download, and CSV export of the current filtered results.
  • Watchlist and alerts: saved pairs, target-rate rules, triggered notifications, and controls to edit or remove alerts.
  • Profile: display name, preferred display currency, and sign-out. Store timestamps in UTC and show the display timezone clearly.
  • Admin: demo rate editor, currency availability controls, and a chronological audit log. Keep it separate from customer navigation.

Rates, charts, and watchlist

  • Support BHD, USD, EUR, GBP, AED, and SAR. Always show currency codes alongside names. Flags may supplement labels but must not replace them.
  • Use USD as the reference currency. Store one positive reference value per currency, defined as units of that currency for 1 USD; USD itself is 1. Derive every cross-pair rate from the same reference snapshot.
  • Display direction explicitly: ‘1 USD = 0.900000 EUR’. Label this as a demo reference rate. The converter separately shows the rate offered to the customer.
  • Provide pair search, favourites, and a pair-detail view with 1D, 1W, and 1M history filters. Seed enough timestamped demo observations for each range.
  • Calculate the displayed period change from the first and last available observations in that range. Label the range, units, and timestamps, and show ‘Not enough data’ when appropriate.
  • Persist each user’s watchlist. Rate refresh updates the timestamp, dependent pairs, and displayed estimates together. Show loading, retry, unavailable-pair, and empty-search states.
  • Mark the current snapshot stale after 5 minutes. Explain the stale state and disable new quotes until a successful refresh. A demo refresh may generate a new simulated snapshot, clearly identified as such.

Conversion and quote rules

A quote is a temporary offer showing exactly what the user will pay and receive. Use the following fixed exercise rules so every team can test the same behaviour. These values are fictional product rules, not market pricing.

  • The user chooses the currency they pay, the currency they receive, and the amount to exchange. Reject missing, zero, negative, non-finite, or over-precision amounts and identical source/destination currencies.
  • Allow source amounts up to 1,000,000 units for this exercise, subject to available balance. Provide a swap action that reverses currencies, clears the old quote, and calculates the new direction.
  • Derive reference rate = destination reference value / source reference value. The result is destination-currency units for 1 source-currency unit.
  • Apply a 0.50% spread: offered rate = reference rate × 0.995. Charge a separate 0.25% fee on the entered source amount. Show the reference rate, offered rate, included spread, fee, total debit, and destination credit separately.
  • Total debit = entered source amount + fee. Destination credit = entered source amount × offered rate. The fee is added to the debit, so do not also subtract it from the amount being converted.
  • Store rates using decimal arithmetic with sufficient precision for cross rates; round the offered rate to 6 decimal places before calculating the displayed and committed quote. Use half-up rounding for money: 3 decimal places for BHD and 2 for the other supported currencies. Never use formatted strings for arithmetic.
  • Create quotes on the server with an ID, owner, immutable amounts/rate/fee snapshot, created time, and expiry 60 seconds later. Editing the amount or either currency invalidates the quote and requires a new one.
  • The review screen shows ‘You pay’ including the fee, ‘You receive’, the rate direction, and an expiry countdown. Confirm stays unavailable for invalid input, insufficient funds, or an expired quote.
  • A new rate snapshot changes new quotes only. Honour an existing quote until its server-checked expiry unless its currency has been paused. Never silently replace the reviewed rate during confirmation.
  • After expiry, show ‘Quote expired’ and let the user request and review a new quote. Cancelling review does not change balances.

A calculation every team must pass

Seed a test snapshot with USD = 1 and EUR = 0.9. These are artificial exercise values. For an entered amount of USD 100.00, the reference rate is 0.900000 EUR per USD and the offered rate is 0.895500 after the spread. The fee is USD 0.25. The total debit is USD 100.25 and the credit is EUR 89.55. A wallet with USD 100.00 must fail the balance check. A wallet with USD 100.25 must pass it and finish at USD 0.00.

  • Changing the pair requires deriving the reverse rate from the reference values and applying the same spread policy. Do not take the reciprocal of the already discounted offered rate.
  • The quote, review, saved transaction, receipt, and export must agree on these amounts. Show enough rate precision for the user to reproduce the calculation.

Wallets and reliable confirmation

  • Create one wallet per supported currency for each customer. Seed an account once with BHD 1,000.000, USD 5,000.00, EUR 2,000.00, and zero in the remaining currencies. Reloading or signing in again must not add funds.
  • On confirmation, the server checks quote ownership, expiry, active currencies, and available funds again. Treat the browser’s amounts and balance display as informational.
  • Use one database transaction to debit the source wallet, credit the destination wallet, record ledger entries, save the completed exchange, and consume the quote. If any step fails, none of those changes should remain.
  • Lock or otherwise protect wallet updates from concurrent spending. Enforce one execution per quote with a unique constraint/idempotency key. Repeated clicks and network retries return the existing result rather than creating another exchange.
  • Show a progress state while confirming. If the response is lost, let the user check the result by quote/transaction reference before retrying. Failed and expired attempts must not appear as completed exchanges.
  • After success, refresh both balances and history, then show a receipt with a unique reference, date/time/timezone, pair, rate, source amount, fee, total debit, and destination credit.

History, receipts, and alerts

  • Search completed exchanges by reference or currency. Filter by date and pair, sort newest/oldest, and paginate the results. Keep quoted, expired, and failed attempts clearly separate from completed history.
  • Open a saved exchange to see its immutable receipt. Provide a print/download receipt action and CSV export that includes currency codes, fees, timestamps, and a demo label. Escape user-supplied text safely in exports.
  • Let users create an alert for a pair, a positive target reference rate, and an ‘at or above’ or ‘at or below’ condition. Explain the direction using ‘1 source currency = X destination currency’.
  • Evaluate alerts on each successful demo rate refresh. Record one in-app notification when an active alert reaches its condition, mark the alert triggered, and require re-arming before it can trigger again.
  • Show active and triggered alerts, and support editing, deleting, and re-arming. Explain that this prototype checks alerts on refresh; it does not promise background monitoring or email delivery.

Administrator workspace

  • Show each currency’s reference value, availability, and last update. Keep USD fixed at 1. Validate every editable rate as a positive finite decimal before publishing one complete snapshot.
  • Allow an administrator to pause/resume a currency. Paused currencies cannot receive new quotes or execute existing quotes, while past receipts remain readable.
  • Require a reason for rate and availability changes. Record the actor, timestamp, before/after values, and reason in an append-only audit log.
  • Show a confirmation step before publishing a new snapshot. Existing executed conversions and receipts must never change after a rate edit.

Data and implementation requirements

Use Next.js for the application, Supabase for authentication and persistent data, GitHub for team collaboration, and Vercel for deployment. Model the data before implementing the screens. A suggested structure follows; equivalent designs are acceptable if they preserve the same rules.

  • Profiles and protected roles: user ID, display name, preferred currency, and role assignment controlled by an administrator.
  • Currencies, rate snapshots, and observations: code, money precision, availability, snapshot ID, reference value, source label, observation timestamp, and publication timestamp.
  • Wallets: owner, currency, balance, and a unique owner/currency constraint. Use exact decimal or minor-unit storage for money.
  • Quotes: owner, source/destination currencies, immutable pricing fields, snapshot ID, created/expiry times, and execution state.
  • Conversions and ledger entries: unique quote reference, owner, final amounts, debit/credit wallet entries, and execution time. Ledger entries must reconcile with the wallet changes, including the source-currency fee.
  • Watchlist, alerts, and notifications: owner, pair, target/condition, state, trigger time, and read state. Audit events capture protected administrative changes.
  • Use database access policies for private data and protected server/database operations for confirmation and rate administration. Users must not directly edit balances, consumed quotes, ledger entries, or audit history.
  • Keep secrets in environment variables. Commit an example configuration with placeholders, database migrations, and an idempotent seed script. Document how to reset demo data deliberately.

Design requirements

Follow the design guidelines and make the platform responsive across desktop, tablet, and mobile.

Build order and team ownership

  1. Agree the required features, calculation rules, and data model. Split ownership into conversion/wallets, rates/alerts, and identity/history/admin, adjusting for team size.
  2. Set up authentication, database migrations, permissions, and seeded wallets/rates. Confirm that two customer accounts see different private data.
  3. Build the quote and atomic confirmation flow first. Pass the USD-to-EUR calculation and duplicate-confirmation checks before adding dashboards.
  4. Complete rates, charts, watchlists, alerts, receipts, history/export, profile, and the protected admin workspace.
  5. Use a branch per feature, have a teammate review each Pull Request, and merge working increments. Test integration after each merge.
  6. Run the acceptance checklist, deploy through Vercel, repeat the main checks on the deployed version, and prepare the demo.

Acceptance checklist

  • A signed-in user completes a conversion and can find the same receipt after refresh and sign-out/sign-in. Both wallet balances reconcile with the receipt.
  • The USD 100.00 test yields a USD 100.25 debit and EUR 89.55 credit. BHD amounts display 3 decimals. Invalid amounts, same-currency pairs, and insufficient balances produce clear errors.
  • An expired quote cannot execute even if the browser countdown is altered. Changing inputs requires review of a new quote. Updating rates does not alter an existing unexpired quote or a completed receipt.
  • Double-clicking Confirm, retrying after a lost response, and simultaneous confirmations do not create duplicate exchanges or negative balances. Simulate a failure halfway through and verify that no partial wallet changes remain.
  • User A cannot read or mutate user B’s private data. A customer cannot publish rates, assign an administrator role, or modify wallet balances directly.
  • Pausing a currency blocks quoting and confirmation. A stale snapshot blocks new quotes. Refresh errors preserve the last timestamp and show a retry state.
  • Watchlists survive refresh. An alert triggers once when its threshold is reached, then only again after re-arming. History filters and CSV export return the same results.
  • The platform follows the design guidelines and works across desktop, tablet, and mobile.
  • The live app uses the intended Supabase project, contains only demo data, and completes the same tests as the local build.

Submission and review

  • Submit the deployed URL, GitHub repository, database migrations and seed instructions, and a short README with setup steps and known limitations.
  • Include evidence of reviewed Pull Requests, your calculation/permission/concurrency checks, and a short note on how you used AI.
  • Prepare a five-minute demo: complete one exchange, demonstrate one failure case, reopen its receipt, and explain one technical decision.
  • Review weighting: working features and end-to-end flow 30%; calculation accuracy and data integrity 25%; design-guideline alignment and usability 25%; permissions and error handling 10%; collaboration and explanation 10%.

Optional stretch features

  • Arabic/English interface with right-to-left layout support and correct placement of currency codes and numbers.
  • Comparison mode that shows how different demo fee/spread settings change the final received amount without making a recommendation.
  • An AI receipt explainer that answers questions using the saved quote fields and transaction data. Keep all arithmetic and execution in deterministic code, and identify missing data rather than inventing it.
  • Scheduled background evaluation of demo rate alerts, with delivery history and explicit notification preferences.

Starter prompt

Act as a product designer and full-stack engineer. Read the attached FX Platform Challenge brief as the source of truth. Build a simulated FX platform with Next.js, Supabase Auth and database, and Vercel deployment. First return the screen map, data model, permission rules, exact quote formulas, and a small implementation plan. Follow the design guidelines and make the platform responsive across desktop, tablet, and mobile. Use only clearly labelled demo rates and balances. Start with the quote/review/atomic-confirmation/receipt flow. Preserve immutable quotes, 60-second server-checked expiry, one execution per quote, and exact decimal money calculations. Do not skip required features or replace working actions with decorative buttons. Implement and verify one stage at a time against the acceptance checklist.