Ignore:
Timestamp:
09/24/26 17:43:19 (5 days ago)
Author:
Stefan <trsunovstefan@…>
Branches:
main
Children:
0cee8ec
Parents:
a531b45
Message:

Wiki docs, phase 6 and phase 7 added

File:
1 edited

Legend:

Unmodified
Added
Removed
  • docs/P4-Prototype/PrototypeImplementation.md

    ra531b45 ref1c1c7  
    1 = Prototype Implementation =
     1# Prototype Implementation
    22
    3 The prototype is a Go command-line application in
    4 [https://github.com/StefanTrsunov/bp/tree/main/server server/] that works against the `project`
    5 schema in PostgreSQL. It implements all seven use cases from
    6 [https://github.com/StefanTrsunov/bp/blob/main/docs/P3-UseCaseModel/UseCaseModel.md UseCaseModel]
    7 – the rubric requires at least three – with every database access shown as real, executed SQL.
    8 An auxiliary program in [https://github.com/StefanTrsunov/bp/tree/main/bots bots/] simulates a
    9 live market so prices move while the prototype is running.
     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.
    108
    11 Build, configure, run and test instructions:
    12 [https://github.com/StefanTrsunov/bp/blob/main/docs/P4-Prototype/BuildInstructions.md BuildInstructions].
     9## Implemented use-cases
    1310
    14 All pages listed below, together with the screenshots of each run, are kept in the project's
    15 GitHub repository, [https://github.com/StefanTrsunov/bp StefanTrsunov/bp], under
    16 `docs/P4-Prototype/`.
     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
    1718
    18 == Implemented use-cases ==
     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/).
    1922
    20 ||=Page=||=Use-case=||=Source=||
    21 ||[https://github.com/StefanTrsunov/bp/blob/main/docs/P4-Prototype/UseCase0001Implementation.md UseCase0001Implementation]||Register a new account||[https://github.com/StefanTrsunov/bp/blob/main/server/auth.go server/auth.go]||
    22 ||[https://github.com/StefanTrsunov/bp/blob/main/docs/P4-Prototype/UseCase0002Implementation.md UseCase0002Implementation]||Log in||[https://github.com/StefanTrsunov/bp/blob/main/server/auth.go server/auth.go]||
    23 ||[https://github.com/StefanTrsunov/bp/blob/main/docs/P4-Prototype/UseCase0003Implementation.md UseCase0003Implementation]||Deposit virtual funds||[https://github.com/StefanTrsunov/bp/blob/main/server/account.go server/account.go]||
    24 ||[https://github.com/StefanTrsunov/bp/blob/main/docs/P4-Prototype/UseCase0004Implementation.md UseCase0004Implementation]||Place market BUY order||[https://github.com/StefanTrsunov/bp/blob/main/server/trade.go server/trade.go]||
    25 ||[https://github.com/StefanTrsunov/bp/blob/main/docs/P4-Prototype/UseCase0005Implementation.md UseCase0005Implementation]||Place market SELL order||[https://github.com/StefanTrsunov/bp/blob/main/server/trade.go server/trade.go]||
    26 ||[https://github.com/StefanTrsunov/bp/blob/main/docs/P4-Prototype/UseCase0006Implementation.md UseCase0006Implementation]||View portfolio and history||[https://github.com/StefanTrsunov/bp/blob/main/server/portfolio.go server/portfolio.go]||
    27 ||[https://github.com/StefanTrsunov/bp/blob/main/docs/P4-Prototype/UseCase0007Implementation.md UseCase0007Implementation]||Manage watchlist||[https://github.com/StefanTrsunov/bp/blob/main/server/watchlist.go server/watchlist.go]||
     23- How to build, configure, run and test the prototype: [BuildInstructions](BuildInstructions.md)
     24- AI usage for this phase: [PrototypeImplementationAIUsage](PrototypeImplementationAIUsage.md)
    2825
    29 Each page mirrors its P3 use-case page and adds the actual SQL emitted by the Go code plus a
    30 screenshot of the corresponding run against the live database. The screenshots are committed
    31 alongside the pages, in
    32 [https://github.com/StefanTrsunov/bp/tree/main/docs/P4-Prototype/screenshots docs/P4-Prototype/screenshots/].
     26## Technology and architecture
    3327
    34 == What the prototype demonstrates about the database design ==
     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.
    3537
    36  * '''The current price is never stored as a column.''' It is always the price of the most recent
    37    row in `market_trades`, read through the `v_latest_prices` view. Both the user's own fills and
    38    the bot's simulated trades feed the same table, so there is exactly one definition of "the
    39    price".
    40  * '''Money movements are transactional.''' Buying touches five tables – `orders`, `users`,
    41    `holdings`, `transactions`, `market_trades` – inside one transaction. A failed balance check
    42    rolls the whole thing back: after a rejected purchase there is no order row, no ledger entry
    43    and no holding. This is verified in the failure-path tests in
    44    [https://github.com/StefanTrsunov/bp/blob/main/docs/P4-Prototype/BuildInstructions.md BuildInstructions].
    45  * '''Constraints do real work.''' `UNIQUE (user_id, crypto_id)` on `holdings` is what makes the
    46    `INSERT … ON CONFLICT DO UPDATE` upsert possible, so the weighted-average entry price is
    47    recomputed by the database in one statement instead of by a read-modify-write in application
    48    code. `CHECK (reserved_quantity >= 0 AND reserved_quantity <= quantity)` is the same idea
    49    applied to the sell path: an inconsistent reservation is impossible at the database level, not
    50    just something `trade.go` is careful about.
    51  * '''Selling reserves before it removes.''' A sell order locks the holding row, reserves the
    52    quantity being sold, then settles by removing it — see
    53    [UseCase0005Implementation](UseCase0005Implementation.md). Two sell orders placed at the same
    54    instant for more than the available quantity are serialised correctly by `SELECT ... FOR
    55    UPDATE`, not just by luck of everything happening in one CLI process; this is demonstrated
    56    there with two concurrent processes.
    57  * '''No identifiers are ever typed.''' Markets are listed with their prices before any choice is
    58    made, and everything else is selected by symbol.
     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 | — |
    5950
    60 == Known limitations ==
     51## No identifiers to remember
    6152
    62 Deliberately out of scope for a first prototype, and the natural content of the later phases:
     53The user never has to type or remember an id, a code or a symbol:
    6354
    64  * Only `market` orders execute. `limit` is accepted by the schema (`orders.type`) but the
    65    matching logic is not implemented.
    66  * Passwords are SHA-256 without a salt. Adequate to demonstrate that the password itself is
    67    never stored; not adequate for real use. A proper password hash belongs in P9 (security).
    68  * Money is handled as `float64` in Go while the database columns are `numeric`. All arithmetic
    69    that must be exact – the weighted average – is done in SQL for that reason, but the Go side
    70    would need a decimal type for real use.
    71  * There is no connection pooling configuration and no explicit isolation level; both are P8
    72    topics.
    73  * Reservation only ever lives inside one transaction, because only market orders (which settle
    74    immediately) exist. A real limit-order matcher would leave `holdings.reserved_quantity` set
    75    and `orders.status = 'open'` between two separate commits, and would need a way to cancel an
    76    order to release the reservation — neither is implemented, since nothing in the prototype
    77    produces an order that stays open.
     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.
    7866
    79 == AI usage ==
     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.
    8069
    81 AI was used in this phase and is logged in full, per the course rule for P1 onward.
     70## What the prototype demonstrates about the database design
    8271
    83  * '''Phase log:'''
    84    [https://github.com/StefanTrsunov/bp/blob/main/docs/P4-Prototype/PrototypeImplementationAIUsage.md PrototypeImplementationAIUsage.md]
    85    – service used, the bugs found and fixed, the test evidence, and what I decided myself.
    86  * '''Full conversation transcript:'''
    87    [https://github.com/StefanTrsunov/bp/blob/main/docs/P1-ConceptualModel/ERModelAIUsage.md ERModelAIUsage.md]
    88    – the same conversation produced the P1–P4 artefacts, so the complete prompt/response log is
    89    kept in one place. Direct links:
    90    [https://github.com/StefanTrsunov/bp/blob/main/docs/P1-ConceptualModel/ERModelAIUsage.md#session-1--2026-04-21 Session 1 – 2026-04-21],
    91    [https://github.com/StefanTrsunov/bp/blob/main/docs/P1-ConceptualModel/ERModelAIUsage.md#session-2--2026-08-06--2026-08-07 Session 2 – 2026-08-06/07],
    92    [https://github.com/StefanTrsunov/bp/blob/main/docs/P1-ConceptualModel/ERModelAIUsage.md#session-3--2026-09-16 Session 3 – 2026-09-16].
     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)).
    9393
    94 '''Service:''' Claude Code (Anthropic), https://claude.com/claude-code – Claude subscription,
    95 model Claude Opus 4.7 (1M context) in sessions 1–2, Claude Sonnet 5 in session 3.
     94## Known limitations
    9695
    97 '''In short:''' session 1 rewrote the existing Chi/HTTP backend as the CLI prototype covering
    98 UC0001–UC0007 and added the market bot. Session 2 was a review pass I asked for, which found and
    99 fixed three bugs – a path-resolution bug that made the documented build instructions fail, an
    100 infinite loop at end of input, and an error check in the wrong order that misreported database
    101 failures as "Insufficient holding" – and replaced the read-modify-write holding update with a
    102 single `INSERT … ON CONFLICT DO UPDATE`. Session 3 added `holdings.reserved_quantity` and changed
    103 `trade.go`'s sell path to reserve crypto before removing it, closing a gap where two sell orders
    104 could be granted the same units; see
    105 [PrototypeImplementationAIUsage](PrototypeImplementationAIUsage.md#session-3--2026-09-16).
     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 TracChangeset for help on using the changeset viewer.