Ignore:
Timestamp:
09/16/26 23:37:15 (13 days ago)
Author:
Stefan <trsunovstefan@…>
Branches:
main
Children:
8b447ef
Parents:
df05838
Message:

add reserved_quantity and modify the phases, add v_03.png and v_03.xml for P1

File:
1 edited

Legend:

Unmodified
Added
Removed
  • docs/P2-RelationalDesign/RelationalDesign.md

    rdf05838 r9577c79  
    1111- **Markets**(<u>**id**</u>, *crypto_id*, quote_currency, is_active, created_at)
    1212  - Candidate keys: `{id}`, `{crypto_id, quote_currency}`. `UNIQUE(crypto_id, quote_currency)`.
    13 - **Holdings**(<u>**id**</u>, *user_id*, *crypto_id*, quantity, avg_price, created_at, updated_at)
     13- **Holdings**(<u>**id**</u>, *user_id*, *crypto_id*, quantity, reserved_quantity, avg_price, created_at, updated_at)
    1414  - Transformation of the M:N relationship `Holds`. Candidate keys: `{id}` and
    1515    `{user_id, crypto_id}` — the latter is the relationship's own key and is
    … …  
    1717    consistency with the other relations.
    1818  - `avg_price` is `NOT NULL DEFAULT 0 CHECK (avg_price >= 0)`.
     19  - `reserved_quantity` is `NOT NULL DEFAULT 0 CHECK (reserved_quantity >= 0
     20    AND reserved_quantity <= quantity)` — the amount already committed to the
     21    user's own open sell orders. `quantity - reserved_quantity` (the amount
     22    actually free to sell) is not a stored column; it is computed wherever
     23    needed, in `v_portfolio` as `available_quantity` and in the sell path of
     24    [UseCase0005](../P3-UseCaseModel/UseCase0005.md). See
     25    [ERModel](../P1-ConceptualModel/ERModel.md#holds--users-m--cryptos-n-partial-on-both-sides-with-attributes)
     26    for why this mirrors `available_balance`/`invested_balance` on `Users`.
    1927- **Orders**(<u>**id**</u>, *user_id*, *market_id*, side, type, status, quantity, price, placed_at, executed_at)
    2028  - `side ∈ {buy, sell}`, `type ∈ {market, limit}`, `status ∈ {open, executed, cancelled}`.
    … …  
    5664### Normalisation
    5765
     66> **Validated in P5.** [Normalization](../P5-Normalization/Normalization.md) derives this
     67> exact schema independently — starting only from a single de-normalized relation of every
     68> model attribute and its functional dependencies, with no reference to the ER-to-relational
     69> transformation below — and shows it decomposes to **BCNF**, one normal form stronger than
     70> the 3NF claimed here. The two designs agree relation for relation and key for key, so
     71> nothing here changed as a result; see that page's
     72> [discussion](../P5-Normalization/Normalization.md#discussion) for what the one real
     73> difference is (`avg_price`, a stored derived value, not a normalisation issue) and why this
     74> design is still the one used from P5 onward.
     75
    5876All relations are in **3NF**:
    5977
    … …  
    7290  yields `NULL`, so a nullable average would have silently blanked the
    7391  unrealised-P/L column for an existing position instead of failing loudly.
     92- `holdings.reserved_quantity`, unlike `avg_price`, is **not** derived — it is
     93  written directly by the application (`trade.go`) as orders are placed and
     94  settled, the same way `quantity` itself is. `quantity - reserved_quantity`
     95  ("available") is the derived value here, and it is never stored, only
     96  computed where it is needed.
     97
     98### Reservation and the order lifecycle
     99
     100`holdings.reserved_quantity` exists so that placing a sell order can be
     101checked against what a user actually has *free* to sell
     102(`quantity - reserved_quantity`), not against the raw `quantity`, which also
     103counts crypto already promised to another order that has not settled yet.
     104`CHECK (reserved_quantity >= 0 AND reserved_quantity <= quantity)` makes an
     105inconsistent reservation impossible at the database level, regardless of what
     106application code does. The exact statement sequence — lock the row, check the
     107available amount, reserve, then settle — is in
     108[UseCase0005](../P3-UseCaseModel/UseCase0005.md); the same
     109`SELECT … FOR UPDATE` locking that already protected `users.available_balance`
     110on the buy path is what makes two concurrent sell orders against the same
     111holding serialize correctly instead of racing.
    74112
    75113## DDL script
    … …  
    80118- 10 tables with check constraints, primary keys, foreign keys and unique constraints.
    81119- 5 performance indexes.
    82 - 2 views: `v_latest_prices` (latest trade price per market) and `v_portfolio` (per-user holdings valuation with unrealised P/L).
     120- 2 views: `v_latest_prices` (latest trade price per market) and `v_portfolio` (per-user holdings valuation with unrealised P/L, plus `reserved_quantity` and the derived `available_quantity`).
    83121
    84122## DML script (sample data)
Note: See TracChangeset for help on using the changeset viewer.