source: docs/P4-Prototype/PrototypeImplementation.md@ 1549dae

main
Last change on this file since 1549dae 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: 8.9 KB
Line 
1# Prototype Implementation
2
3EduBerza's P4 prototype is a Go command-line program (in [`server/`](../../server/)). It works
4against the `project` schema in PostgreSQL. It implements all seven use cases from
5[UseCaseModel](../P3-UseCaseModel/UseCaseModel.md); the course asks for at least three. Every
6database access is real SQL that was executed and tested. A second program, the market bot in
7[`bots/`](../../bots/), simulates a live market so prices move while the prototype runs.
8
9## Implemented use-cases
10
11- [UseCase0001Implementation](UseCase0001Implementation.md) — Register new account
12- [UseCase0002Implementation](UseCase0002Implementation.md) — Log in
13- [UseCase0003Implementation](UseCase0003Implementation.md) — Deposit virtual funds
14- [UseCase0004Implementation](UseCase0004Implementation.md) — Place market BUY order
15- [UseCase0005Implementation](UseCase0005Implementation.md) — Place market SELL order
16- [UseCase0006Implementation](UseCase0006Implementation.md) — View portfolio and transaction history
17- [UseCase0007Implementation](UseCase0007Implementation.md) — Manage watchlist
18
19Each page follows its P3 use case step by step. It adds the exact SQL the Go code runs in that
20step and a screenshot of the step from a real run against the database. Screenshots are in
21[`screenshots/`](screenshots/).
22
23- How to build, configure, run and test the prototype: [BuildInstructions](BuildInstructions.md)
24- AI usage for this phase: [PrototypeImplementationAIUsage](PrototypeImplementationAIUsage.md)
25
26## Technology and architecture
27
28- **Language:** Go (module `bp_project`, `go 1.25` in [`go.mod`](../../go.mod)). The only
29 third-party library is the PostgreSQL driver `github.com/lib/pq`.
30- **Database:** PostgreSQL. Every table, view and function is in the `project` schema. The DDL
31 is [`schema_creation.sql`](../../server/db/schema_creation.sql) and the sample data is
32 [`data_load.sql`](../../server/db/data_load.sql). Both scripts are compiled into the binary
33 and run by `./eduberza -init`.
34- **Interface:** plain text menus on standard input and output. There are no web server,
35 frameworks, images or styles.
36- **Structure:** one source file per area of the application.
37
38| File | Responsibility | Use cases |
39|------|----------------|-----------|
40| [`server/main.go`](../../server/main.go) | Flags `-init` / `-load-data`, then starts the menu loop | — |
41| [`server/cli.go`](../../server/cli.go) | The two menus (before and after login), input reading | all |
42| [`server/db/db.go`](../../server/db/db.go) | Connection from `.env` / environment variables, embedded SQL scripts | — |
43| [`server/auth.go`](../../server/auth.go) | Register, log in (SHA-256 password hash) | UC0001, UC0002 |
44| [`server/account.go`](../../server/account.go) | Balance, deposit, transaction history | UC0003, UC0006 |
45| [`server/market.go`](../../server/market.go) | Market list, choosing a market or a holding by number, latest price | UC0004, UC0005 |
46| [`server/trade.go`](../../server/trade.go) | Market buy and sell orders, each in one transaction | UC0004, UC0005 |
47| [`server/portfolio.go`](../../server/portfolio.go) | Portfolio with current value and unrealised P/L | UC0006 |
48| [`server/watchlist.go`](../../server/watchlist.go) | List, add and remove watchlist items | UC0007 |
49| [`bots/main.go`](../../bots/main.go) | Market bot: random-walk price ticks into `market_trades`, 1-minute candles | — |
50
51## No identifiers to remember
52
53The user never has to type or remember an id, a code or a symbol:
54
55- Every menu is numbered, and the user answers with the number of an option.
56- **Buying:** all active markets are listed with their latest price, numbered `1…n`. The user
57 enters the market's number at `Market #:` (`ChooseMarket` in `market.go`).
58- **Selling:** only the cryptos the user actually holds are listed, each with the quantity held
59 and the quantity still free to sell. The user enters the holding's number at `Holding #:`
60 (`ChooseHolding`). A user who holds nothing free to sell gets
61 `you hold no crypto that is free to sell` and is never asked to choose.
62- **Watchlist:** *Add* lists the cryptos that are not on the watchlist yet. *Remove* lists the
63 ones that are on it. Both are numbered, and the user enters the number.
64- A number outside the list is refused with `Invalid choice, enter a number from 1 to N.` and
65 nothing is changed.
66
67The only things the user types are their own data: username, e-mail, full name, password, the
68amount to deposit, the quantity to buy or sell, and the date range of the two P6 reports.
69
70## What the prototype demonstrates about the database design
71
72- **The current price is never stored as a column.** It is always the price of the most recent
73 row in `market_trades`, read through the `v_latest_prices` view. The user's own fills and the
74 bot's simulated trades go into the same table, so there is only one definition of "the
75 price".
76- **Money movements are transactional.** A buy touches five tables (`orders`, `users`,
77 `holdings`, `transactions`, `market_trades`) inside one transaction. If the balance check
78 fails, the whole transaction is rolled back: after a rejected purchase there is no order row,
79 no ledger entry and no holding. The failure-path tests in
80 [BuildInstructions](BuildInstructions.md) check this.
81- **Constraints do real work.** `UNIQUE (user_id, crypto_id)` on `holdings` is what makes the
82 `INSERT … ON CONFLICT DO UPDATE` upsert possible, so the database recomputes the
83 weighted-average entry price in one statement, instead of the application reading, changing
84 and writing the row. `CHECK (reserved_quantity >= 0 AND reserved_quantity <= quantity)` does
85 the same for the sell path: the database itself makes an inconsistent reservation
86 impossible, and it does not rely only on `trade.go` being careful.
87- **Selling reserves before it removes.** A sell order locks the holding row with
88 `SELECT … FOR UPDATE`, reserves the quantity being sold, then settles by removing it (see
89 [UseCase0005Implementation](UseCase0005Implementation.md)). Two sell orders for more than the
90 free quantity, placed at the same moment from two separate processes, are serialised by the
91 row lock. Exactly one of them succeeds. This was tested with two concurrent processes in
92 session 3 (see [PrototypeImplementationAIUsage](PrototypeImplementationAIUsage.md)).
93
94## Known limitations
95
96These were left out on purpose for a first prototype. They belong to the later phases:
97
98- Only `market` orders execute. The schema accepts `limit` (`orders.type`), but there is no
99 matching logic for it.
100- Passwords are hashed with SHA-256 and no salt. That shows the password itself is never
101 stored, but it is not good enough for real use. A proper password hash belongs in P9
102 (security).
103- Money is `float64` in Go, while the database columns are `numeric`. For that reason, all
104 arithmetic that must be exact (the weighted average) is done in SQL. Real use would need a
105 decimal type on the Go side too.
106- The prototype sets no connection pool and no explicit isolation level. Both are P8 topics.
107- A reservation only exists inside one transaction, because the prototype only has market
108 orders, and they settle immediately. A real limit-order matcher would leave
109 `holdings.reserved_quantity` set and `orders.status = 'open'` between two separate commits.
110 It would also need a way to cancel an order and release the reservation. Neither is
111 implemented, because nothing in the prototype creates an order that stays open.
112
113## History of changes
114
115The code started as my own Go backend: HTTP handlers, a draft schema, and a `db.go` that
116recreated the tables on every start. It changed as follows. The AI's share of each change is
117logged in [PrototypeImplementationAIUsage](PrototypeImplementationAIUsage.md).
118
119| Date | Change | Origin |
120|------|--------|--------|
121| 2026-04-21 | My HTTP backend rewritten as the CLI prototype covering UC0001–UC0007. The schema errors in my draft were corrected. The market bot was added. | My code and decisions (CLI instead of web, drop the frontend, keep a simulator); rewrite by AI (session 1) |
122| 2026-08-06/07 | Three bugs fixed: path resolution of `.env` and the SQL scripts, an endless loop at end of input, and an error check in the wrong order on the sell path. The holding update became one `INSERT … ON CONFLICT DO UPDATE`. | I asked for a code review; fixes by AI (session 2) |
123| 2026-09-16 | `holdings.reserved_quantity` added. The sell path now reserves, then settles. Orders go from `open` to `executed`. | The edge case was mine; implementation by AI (session 3) |
124| 2026-09-24 | Every choice is picked from a numbered list: markets by number, a sell lists only the user's holdings, the watchlist lists the cryptos. All screenshots were retaken, one per step. | I asked for a check against the P4 rules; implementation by AI (session 4) |
125
126**Service:** Claude Code (Anthropic), Claude subscription. Session 1 used Claude Opus 4.7 (1M
127context), session 2 Claude Opus 5 (1M context), session 3 Claude Sonnet 5, and session 4
128Claude Opus 5.5 (1M context).
Note: See TracBrowser for help on using the repository browser.