source: docs/P4-Prototype/UseCase0007Implementation.md

main
Last change on this file was ef1c1c7, checked in by Stefan <trsunovstefan@…>, 5 days ago

Wiki docs, phase 6 and phase 7 added

  • Property mode set to 100644
File size: 6.5 KB
Line 
1# Use-case 0007 Implementation - Manage watchlist
2
3**Initiating actor:** Trader
4
5**Other actors:** —
6
7A logged-in Trader keeps a list of crypto assets they want to monitor, with the last
8price of each. The first time the watchlist is opened the system creates a default
9watchlist named "Favorites" for the Trader. From a sub-menu the Trader can list the
10watchlist, add a crypto or remove one. The Trader never types a symbol: for adding, the
11system lists, numbered, only the cryptos that are not on the watchlist yet, and for
12removing, only the cryptos that are on it; the Trader picks one by its number. Adding
13a crypto that is already on the list is a no-op (idempotent), and a number that is not
14in the list is refused without touching the database.
15
16Original use-case description (P3): [UseCase0007](../P3-UseCaseModel/UseCase0007.md).
17Implementation: [`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
22All 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
24Go code; only the Go source indentation is removed.
25
26The run shown is user `alice` on the seed data, whose watchlist contains BTC, ETH and
27SOL. She lists it, adds ADA, tries to remove a number that is not in the list, removes
28SOL and lists the result.
29
30## Scenario
31
321. **Trader** chooses `[8] Manage watchlist` in the authenticated menu (types `8`).
332. **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):
35
36 ```sql
37 SELECT id FROM watchlists WHERE user_id = $1 ORDER BY created_at LIMIT 1
38 ```
39
40 Only if this returns no row, it creates the default watchlist and uses its id:
41
42 ```sql
43 INSERT INTO watchlists (user_id, name) VALUES ($1, 'Favorites') RETURNING id
44 ```
45
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.
483. **System** shows the sub-menu `-- Watchlist --` with `[1] List items`,
49 `[2] Add crypto`, `[3] Remove crypto` and `[0] Back`.
50
51 ![UC0007 steps 1-3: Trader opens the watchlist, system shows the sub-menu](screenshots/uc0007_1_3_menu.png)
52
53### List items
54
554. **Trader** chooses `[1] List items`.
565. **System** lists the cryptos on the watchlist with their last price against USD
57 (`listWatchlist`; `$1` = watchlist id):
58
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 ```
68
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.
72
73 ![UC0007 List items](screenshots/uc0007_list.png)
74
75### Add a crypto
76
776. **Trader** chooses `[2] Add crypto`.
787. **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 ![UC0007 Add: system lists the cryptos not yet on the watchlist](screenshots/uc0007_add_1_list.png)
95
968. **Trader** picks the crypto by its number in the list: `1` (ADA).
979. **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 ![UC0007 Add: Trader picks #1 (ADA), system adds it](screenshots/uc0007_add_2_added.png)
111
112### Remove a crypto
113
11410. **Trader** chooses `[3] Remove crypto`.
11511. **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 ![UC0007 Remove: system lists the watchlist's cryptos](screenshots/uc0007_remove_1_list.png)
131
13212. **Trader** picks the crypto by its number in the list: `4` (SOL).
13313. **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 ![UC0007 Remove: Trader picks #4 (SOL), system removes it](screenshots/uc0007_remove_2_removed.png)
143
144#### Alternate flow 12a — number not in the list
145
146Before removing SOL, alice first chose `[3] Remove crypto` and, at step 12, entered `5`
147while 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
149is shown again; she then chose `[3]` once more, which returned the scenario to step 11.
150The same check applies to the number entered at step 8.
151
152![UC0007 Remove: a number that is not in the list is refused](screenshots/uc0007_remove_invalid.png)
153
154### Verification — list after the changes
155
156Choosing `[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`:
158ADA was added and SOL removed. `[0] Back` returns to the authenticated menu.
159
160![UC0007 List items after the changes](screenshots/uc0007_list_after.png)
Note: See TracBrowser for help on using the repository browser.