Changes between Initial Version and Version 1 of PrototypeImplementation


Ignore:
Timestamp:
09/24/26 17:07:33 (4 days ago)
Author:
231285
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • PrototypeImplementation

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