Changeset ef1c1c7 for docs/P4-Prototype/UseCase0007Implementation.md
- Timestamp:
- 09/24/26 17:43:19 (6 days ago)
- Branches:
- main
- Children:
- 0cee8ec
- Parents:
- a531b45
- File:
-
- 1 edited
-
docs/P4-Prototype/UseCase0007Implementation.md (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
docs/P4-Prototype/UseCase0007Implementation.md
ra531b45 ref1c1c7 1 # Use-case 0007 Implementation — Watchlist1 # Use-case 0007 Implementation - Manage watchlist 2 2 3 **Initiating actor:** Trader . **Source file:** `server/watchlist.go`.3 **Initiating actor:** Trader 4 4 5 ## Scenario (implemented) 5 **Other actors:** — 6 6 7 1. **User** chooses `[8] Manage watchlist`. 8 2. **System** ensures a default watchlist exists: 7 A logged-in Trader keeps a list of crypto assets they want to monitor, with the last 8 price of each. The first time the watchlist is opened the system creates a default 9 watchlist named "Favorites" for the Trader. From a sub-menu the Trader can list the 10 watchlist, add a crypto or remove one. The Trader never types a symbol: for adding, the 11 system lists, numbered, only the cryptos that are not on the watchlist yet, and for 12 removing, only the cryptos that are on it; the Trader picks one by its number. Adding 13 a crypto that is already on the list is a no-op (idempotent), and a number that is not 14 in the list is refused without touching the database. 15 16 Original use-case description (P3): [UseCase0007](../P3-UseCaseModel/UseCase0007.md). 17 Implementation: [`server/watchlist.go`](../../server/watchlist.go), functions 18 `ManageWatchlist`, `ensureDefaultWatchlist`, `listWatchlist`, `addToWatchlist` and 19 `removeFromWatchlist`, with `pickNumber` from 20 [`server/market.go`](../../server/market.go). 21 22 All statements run on the `project` schema (the connection sets 23 `search_path=project,public` in `server/db/db.go`). The SQL below is copied from the 24 Go code; only the Go source indentation is removed. 25 26 The run shown is user `alice` on the seed data, whose watchlist contains BTC, ETH and 27 SOL. She lists it, adds ADA, tries to remove a number that is not in the list, removes 28 SOL and lists the result. 29 30 ## Scenario 31 32 1. **Trader** chooses `[8] Manage watchlist` in the authenticated menu (types `8`). 33 2. **System** makes sure the Trader has a watchlist and takes the id of the oldest one 34 (`ensureDefaultWatchlist`; `$1` = the logged-in user's id): 9 35 10 36 ```sql 11 SELECT id FROM watchlists WHERE user_id = $1 ORDER BY created_at LIMIT 1; 12 -- else 13 INSERT INTO watchlists (user_id, name) VALUES ($1, 'Favorites') RETURNING id; 37 SELECT id FROM watchlists WHERE user_id = $1 ORDER BY created_at LIMIT 1 14 38 ``` 15 39 16 3. **System** offers the submenu: List, Add, Remove, Back. 40 Only if this returns no row, it creates the default watchlist and uses its id: 17 41 18 ### List 42 ```sql 43 INSERT INTO watchlists (user_id, name) VALUES ($1, 'Favorites') RETURNING id 44 ``` 19 45 20 ```sql 21 SELECT c.symbol, c.name, COALESCE(lp.price, 0) 22 FROM watchlist_items wi 23 JOIN crypto c ON c.id = wi.crypto_id 24 LEFT JOIN markets m ON m.crypto_id = c.id AND m.quote_currency = 'USD' 25 LEFT JOIN v_latest_prices lp ON lp.market_id = m.id 26 WHERE wi.watchlist_id = $1 27 ORDER BY c.symbol; 28 ``` 46 (alice already has the seed watchlist "Favorites", so only the `SELECT` runs.) The 47 watchlist id is kept in Go and used as `$1` in all statements below. 48 3. **System** shows the sub-menu `-- Watchlist --` with `[1] List items`, 49 `[2] Add crypto`, `[3] Remove crypto` and `[0] Back`. 29 50 30 51  31 52 32 ### Add53 ### List items 33 54 34 ```sql 35 SELECT id FROM crypto WHERE upper(symbol) = upper($1); 55 4. **Trader** chooses `[1] List items`. 56 5. **System** lists the cryptos on the watchlist with their last price against USD 57 (`listWatchlist`; `$1` = watchlist id): 36 58 37 INSERT INTO watchlist_items (watchlist_id, crypto_id) 38 VALUES ($watchlist_id, $crypto_id) 39 ON CONFLICT (watchlist_id, crypto_id) DO NOTHING; 40 ``` 59 ```sql 60 SELECT c.symbol, c.name, COALESCE(lp.price, 0) 61 FROM watchlist_items wi 62 JOIN crypto c ON c.id = wi.crypto_id 63 LEFT JOIN markets m ON m.crypto_id = c.id AND m.quote_currency = 'USD' 64 LEFT JOIN v_latest_prices lp ON lp.market_id = m.id 65 WHERE wi.watchlist_id = $1 66 ORDER BY c.symbol 67 ``` 41 68 42 Re-adding the same symbol is a no-op thanks to the unique constraint + `ON CONFLICT`. 69 For alice it prints `BTC Bitcoin 67140.000000`, `ETH Ethereum 3520.000000` and 70 `SOL Solana 166.100000` (an empty watchlist prints `(watchlist is empty)`), then 71 shows the sub-menu again. 43 72 44 ### Remove 73  45 74 46 ```sql 47 DELETE FROM watchlist_items 48 WHERE watchlist_id = $1 49 AND crypto_id = (SELECT id FROM crypto WHERE upper(symbol) = upper($2)); 50 ``` 75 ### Add a crypto 76 77 6. **Trader** chooses `[2] Add crypto`. 78 7. **System** lists, numbered, the cryptos that are not on the watchlist yet 79 (`addToWatchlist`; `$1` = watchlist id): 80 81 ```sql 82 SELECT c.id, c.symbol, c.name 83 FROM crypto c 84 WHERE NOT EXISTS (SELECT 1 FROM watchlist_items wi 85 WHERE wi.watchlist_id = $1 AND wi.crypto_id = c.id) 86 ORDER BY c.symbol 87 ``` 88 89 For alice it prints `1 ADA Cardano` and `2 DOGE Dogecoin` and asks 90 `Crypto # to add:`. Go keeps each row's crypto id in memory. (If every crypto is 91 already on the watchlist, it prints `Every crypto is already on your watchlist.` 92 instead.) 93 94  95 96 8. **Trader** picks the crypto by its number in the list: `1` (ADA). 97 9. **System** adds the crypto of row 1 to the watchlist (`$1` = watchlist id, 98 `$2` = the chosen crypto's id); thanks to the unique constraint and 99 `ON CONFLICT ... DO NOTHING`, adding a crypto that is already there changes 100 nothing: 101 102 ```sql 103 INSERT INTO watchlist_items (watchlist_id, crypto_id) 104 VALUES ($1, $2) 105 ON CONFLICT (watchlist_id, crypto_id) DO NOTHING 106 ``` 107 108 It prints `Added ADA.` and shows the sub-menu again. 109 110  111 112 ### Remove a crypto 113 114 10. **Trader** chooses `[3] Remove crypto`. 115 11. **System** lists, numbered, the cryptos that are on the watchlist 116 (`removeFromWatchlist`; `$1` = watchlist id): 117 118 ```sql 119 SELECT c.id, c.symbol, c.name 120 FROM watchlist_items wi 121 JOIN crypto c ON c.id = wi.crypto_id 122 WHERE wi.watchlist_id = $1 123 ORDER BY c.symbol 124 ``` 125 126 For alice it now prints `1 ADA Cardano`, `2 BTC Bitcoin`, `3 ETH Ethereum` and 127 `4 SOL Solana` and asks `Crypto # to remove:`. Go keeps each row's crypto id in 128 memory. (If the watchlist is empty, it prints `Your watchlist is empty.` instead.) 129 130  131 132 12. **Trader** picks the crypto by its number in the list: `4` (SOL). 133 13. **System** removes the crypto of row 4 from the watchlist (`$1` = watchlist id, 134 `$2` = the chosen crypto's id): 135 136 ```sql 137 DELETE FROM watchlist_items WHERE watchlist_id = $1 AND crypto_id = $2 138 ``` 139 140 It prints `Removed SOL.` and shows the sub-menu again. 141 142  143 144 #### Alternate flow 12a — number not in the list 145 146 Before removing SOL, alice first chose `[3] Remove crypto` and, at step 12, entered `5` 147 while only numbers 1–4 were listed. `pickNumber` prints 148 `Invalid choice, enter a number from 1 to 4.`, the `DELETE` is not run and the sub-menu 149 is shown again; she then chose `[3]` once more, which returned the scenario to step 11. 150 The same check applies to the number entered at step 8. 151 152  153 154 ### Verification — list after the changes 155 156 Choosing `[1] List items` again runs the query from step 5, which now returns 157 `ADA Cardano 0.453750`, `BTC Bitcoin 67140.000000` and `ETH Ethereum 3520.000000`: 158 ADA was added and SOL removed. `[0] Back` returns to the authenticated menu. 159 160 
Note:
See TracChangeset
for help on using the changeset viewer.
