Miner-Upgrade
All checks were successful
Deploy / deploy-staging (push) Successful in 7s
Deploy / deploy-production (push) Has been skipped

This commit is contained in:
2026-05-09 00:58:48 +02:00
parent ee5a46254f
commit fc95898a9d
11 changed files with 976 additions and 131 deletions

View File

@@ -229,6 +229,7 @@ final class MiningRepository
'owner_sub' => $this->ownerSub,
'measured_at' => $payload['measured_at'],
'coins_total' => $payload['coins_total'],
'coin_currency' => $payload['coin_currency'] ?? 'DOGE',
'price_per_coin' => $payload['price_per_coin'],
'price_currency' => $payload['price_currency'],
'fx_fetch_id' => $payload['fx_fetch_id'] ?? null,
@@ -243,10 +244,10 @@ final class MiningRepository
if ($this->driver === 'pgsql') {
$stmt = $this->pdo->prepare(
'INSERT INTO ' . $this->table('measurements') . ' (
project_key, owner_sub, measured_at, coins_total, price_per_coin, price_currency, fx_fetch_id, note,
project_key, owner_sub, measured_at, coins_total, coin_currency, price_per_coin, price_currency, fx_fetch_id, note,
source, image_path, ocr_raw_text, ocr_confidence, ocr_flags
) VALUES (
:project_key, :owner_sub, :measured_at, :coins_total, :price_per_coin, :price_currency, :fx_fetch_id, :note,
:project_key, :owner_sub, :measured_at, :coins_total, :coin_currency, :price_per_coin, :price_currency, :fx_fetch_id, :note,
:source, :image_path, :ocr_raw_text, :ocr_confidence, CAST(:ocr_flags AS jsonb)
)
RETURNING *'
@@ -259,10 +260,10 @@ final class MiningRepository
$stmt = $this->pdo->prepare(
'INSERT INTO ' . $this->table('measurements') . ' (
project_key, owner_sub, measured_at, coins_total, price_per_coin, price_currency, fx_fetch_id, note,
project_key, owner_sub, measured_at, coins_total, coin_currency, price_per_coin, price_currency, fx_fetch_id, note,
source, image_path, ocr_raw_text, ocr_confidence, ocr_flags
) VALUES (
:project_key, :owner_sub, :measured_at, :coins_total, :price_per_coin, :price_currency, :fx_fetch_id, :note,
:project_key, :owner_sub, :measured_at, :coins_total, :coin_currency, :price_per_coin, :price_currency, :fx_fetch_id, :note,
:source, :image_path, :ocr_raw_text, :ocr_confidence, :ocr_flags
)'
);
@@ -441,6 +442,71 @@ final class MiningRepository
return $this->normalizeRow($fetch->fetch() ?: []);
}
public function listWalletSnapshots(string $projectKey, int $limit = 100): array
{
$stmt = $this->pdo->prepare(
'SELECT * FROM ' . $this->table('wallet_snapshots') . '
WHERE project_key = :project_key AND owner_sub = :owner_sub
ORDER BY measured_at DESC, id DESC
LIMIT :limit'
);
$stmt->bindValue(':project_key', $projectKey, PDO::PARAM_STR);
$stmt->bindValue(':owner_sub', $this->ownerSub, PDO::PARAM_STR);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
$stmt->execute();
return $this->normalizeRows($stmt->fetchAll() ?: []);
}
public function saveWalletSnapshot(string $projectKey, array $payload): array
{
$params = [
'project_key' => $projectKey,
'owner_sub' => $this->ownerSub,
'measured_at' => $payload['measured_at'],
'total_value_amount' => $payload['total_value_amount'] ?? null,
'total_value_currency' => $payload['total_value_currency'] ?? null,
'wallet_balance' => $payload['wallet_balance'] ?? null,
'wallet_currency' => $payload['wallet_currency'],
'balances_json' => json_encode($payload['balances_json'] ?? [], JSON_UNESCAPED_UNICODE),
'note' => $payload['note'] ?? null,
'source' => $payload['source'] ?? 'manual',
'image_path' => $payload['image_path'] ?? null,
'ocr_raw_text' => $payload['ocr_raw_text'] ?? null,
'ocr_confidence' => $payload['ocr_confidence'] ?? null,
'ocr_flags' => json_encode($payload['ocr_flags'] ?? [], JSON_UNESCAPED_UNICODE),
];
if ($this->driver === 'pgsql') {
$stmt = $this->pdo->prepare(
'INSERT INTO ' . $this->table('wallet_snapshots') . ' (
project_key, owner_sub, measured_at, total_value_amount, total_value_currency, wallet_balance,
wallet_currency, balances_json, note, source, image_path, ocr_raw_text, ocr_confidence, ocr_flags
) VALUES (
:project_key, :owner_sub, :measured_at, :total_value_amount, :total_value_currency, :wallet_balance,
:wallet_currency, CAST(:balances_json AS jsonb), :note, :source, :image_path, :ocr_raw_text, :ocr_confidence, CAST(:ocr_flags AS jsonb)
)
RETURNING *'
);
$stmt->execute($params);
return $this->normalizeRow($stmt->fetch() ?: []);
}
$stmt = $this->pdo->prepare(
'INSERT INTO ' . $this->table('wallet_snapshots') . ' (
project_key, owner_sub, measured_at, total_value_amount, total_value_currency, wallet_balance,
wallet_currency, balances_json, note, source, image_path, ocr_raw_text, ocr_confidence, ocr_flags
) VALUES (
:project_key, :owner_sub, :measured_at, :total_value_amount, :total_value_currency, :wallet_balance,
:wallet_currency, :balances_json, :note, :source, :image_path, :ocr_raw_text, :ocr_confidence, :ocr_flags
)'
);
$stmt->execute($params);
$id = (int) $this->pdo->lastInsertId();
$fetch = $this->pdo->prepare('SELECT * FROM ' . $this->table('wallet_snapshots') . ' WHERE id = :id LIMIT 1');
$fetch->execute(['id' => $id]);
return $this->normalizeRow($fetch->fetch() ?: []);
}
public function listTargets(string $projectKey): array
{
$stmt = $this->pdo->prepare(
@@ -1195,6 +1261,7 @@ final class MiningRepository
'fx_rates' => $this->prefix . 'fx_rates',
'measurement_rates' => $this->prefix . 'measurement_rates',
'payouts' => $this->prefix . 'payouts',
'wallet_snapshots' => $this->prefix . 'wallet_snapshots',
'miner_offers' => $this->prefix . 'miner_offers',
'purchased_miners' => $this->prefix . 'purchased_miners',
default => throw new \RuntimeException('Unknown mining table: ' . $logicalName),
@@ -1273,7 +1340,7 @@ final class MiningRepository
private function normalizeRow(array $row): array
{
foreach (['ocr_flags', 'filters_json', 'preferred_currencies'] as $jsonField) {
foreach (['ocr_flags', 'filters_json', 'preferred_currencies', 'balances_json'] as $jsonField) {
if (array_key_exists($jsonField, $row) && is_string($row[$jsonField]) && trim($row[$jsonField]) !== '') {
$decoded = json_decode($row[$jsonField], true);
if (json_last_error() === JSON_ERROR_NONE) {