satmachineclient/models.py
Padreug 7dac898a10 feat(v2): own dca_lp writes + auto-init on first dashboard access
Pairs with the satmachineadmin Phase 1 refactor that hoisted LP state
into `satoshimachine.dca_lp` (one row per user). This extension is now
the WRITER for that table; satmachineadmin only reads it during
distribution.

API surface:
  - `GET  /api/v1/dca-client/preferences` — returns the LP's
    `dca_lp` row, AUTO-CREATING it with the authenticated wallet
    as the default DCA destination on first call. Hitting this
    endpoint is the act that marks the LP as onboarded on the
    operator side (gating their deposit creation).
  - `PUT  /api/v1/dca-client/preferences` — LP-side update of
    wallet / mode / fixed-mode limit / autoforward fields. Ensures
    the row exists before applying. Replaces the old
    `PUT /autoforward` endpoint (which is gone).
  - `GET  /api/v1/dca-client/positions` — same shape as before
    but also auto-inits dca_lp on entry (so opening the dashboard
    onboards the LP). Now INNER JOINs dca_lp so only onboarded
    LPs see positions (matches the operator-side "must onboard
    before deposits" gate).
  - `GET  /api/v1/dca-client/transactions` — unchanged.

Models:
  - New `LpPreferences` / `UpdateLpPreferences` exposing the
    dca_lp fields.
  - `UpdateClientAutoforward` removed (replaced by the broader
    `UpdateLpPreferences`).
  - `PerMachinePosition.dca_mode` now sourced from `dca_lp` (it's
    LP-wide, echoed on each position row for legacy display
    compatibility).

CRUD:
  - `_fetch_user_clients` rewritten: INNER JOIN dca_lp, drop
    references to removed `dca_clients.wallet_id` / `.dca_mode`
    columns (they don't exist anymore post-Phase-1).
  - New: `get_lp_preferences`, `ensure_lp_preferences`,
    `update_lp_preferences`. The first writes nothing; the second
    is the get-or-create that defends the auto-onboard invariant.
  - `update_lp_autoforward` removed — write path is now
    `update_lp_preferences` against `dca_lp`, not the multi-row
    UPDATE on `dca_clients` that used to be needed because the
    state was denormalised across enrolments.

Note: the legacy static/js/index.js in this extension references
endpoints that no longer exist (`/registration-status`, `/register`,
`/dashboard/summary`, ...) — that's pre-existing tech debt from when
the LP UX was moved to ~/dev/webapp. Not regressed by this commit;
the deprecated frontend is out of scope. For now LP onboarding works
via direct API call (curl `GET /preferences` once with the LP's wallet
admin key); the webapp will own the proper UI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 15:11:27 +02:00

104 lines
3.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Satoshi Machine Client v2 — Pydantic models.
#
# LP-facing read view over the admin extension's v2 schema. An LP can hold
# DCA positions across multiple machines (and across multiple operators on
# the same LNbits instance); summary endpoints aggregate, with an optional
# per-machine breakdown for filtering.
#
# NOTE: this extension is in maintenance mode. The richer LP UI is moving
# to ~/dev/webapp; this surface stays minimal and read-mostly.
from datetime import datetime
from typing import List, Optional
from pydantic import BaseModel
class PerMachinePosition(BaseModel):
"""LP's position at a single machine.
`dca_mode` was previously per-(machine, LP) and is now LP-wide (lives
on `dca_lp.default_dca_mode`). Echoed here for legacy UI display only
— every position for a given LP shares the same value.
"""
machine_id: str
machine_npub: str
machine_name: Optional[str]
machine_location: Optional[str]
currency: str
dca_mode: str
status: str
total_sats_accumulated: int
total_fiat_invested: float
current_fiat_balance: float
total_transactions: int
last_transaction_date: Optional[datetime]
class ClientDashboardSummary(BaseModel):
"""LP's aggregated dashboard across all machines they're registered at."""
user_id: str
total_sats_accumulated: int
total_fiat_invested: float # confirmed deposits across all machines
current_fiat_balance: float # confirmed deposits - DCA - settlement legs
pending_fiat_deposits: float # deposits in 'pending' status
average_cost_basis: float # total_sats / total_fiat_invested-spent
current_sats_fiat_value: float # current rate × total_sats (best-effort)
total_transactions: int
total_machines: int # how many machines this LP is on
last_transaction_date: Optional[datetime]
currency: str # display currency; if multi-currency, "MIX"
positions: List[PerMachinePosition] = []
class LpPreferences(BaseModel):
"""LP-controlled DCA preferences (one row per user in `dca_lp`).
Auto-created on first satmachineclient dashboard access with the LP's
authenticated wallet as the default `dca_wallet_id`; they can change
any field via `PUT /api/v1/dca-client/preferences`. Distribution
reads from here at payout time — operator cannot override.
"""
user_id: str
dca_wallet_id: str
default_dca_mode: str # 'flow' | 'fixed'
fixed_mode_daily_limit: Optional[float]
autoforward_ln_address: Optional[str]
autoforward_enabled: bool
created_at: datetime
updated_at: datetime
class UpdateLpPreferences(BaseModel):
"""LP-side preference updates. All fields optional; only ones provided
are touched. Use to switch DCA wallet, change mode, toggle autoforward."""
dca_wallet_id: Optional[str] = None
default_dca_mode: Optional[str] = None
fixed_mode_daily_limit: Optional[float] = None
autoforward_ln_address: Optional[str] = None
autoforward_enabled: Optional[bool] = None
class ClientTransaction(BaseModel):
"""A single distribution leg landing in the LP's wallet."""
id: str
machine_id: str
machine_npub: str
settlement_id: Optional[str]
leg_type: str # 'dca' | 'settlement' | 'autoforward' (LP-visible)
amount_sats: int
amount_fiat: Optional[float]
exchange_rate: Optional[float]
status: str
created_at: datetime
transaction_time: datetime
# `UpdateClientAutoforward` removed in the dca_lp refactor; preferences
# (autoforward, wallet, mode) now flow through `UpdateLpPreferences`
# against `PUT /api/v1/dca-client/preferences`.