From eb8b04a62148c8ad7db1dad16da6a4dfdd9107d1 Mon Sep 17 00:00:00 2001 From: Lars Gebhardt-Kusche Date: Tue, 5 May 2026 20:36:41 +0200 Subject: [PATCH] cyxc --- modules/mining-checker/assets/js/app.js | 298 ------------------ modules/mining-checker/design.json | 1 - modules/mining-checker/docs/README.md | 8 +- .../sql/migrations/001_init.sql | 24 +- .../sql/migrations/002_seed_doge_main.sql | 16 - modules/mining-checker/sql/schema.mysql.sql | 38 +-- modules/mining-checker/sql/schema.pgsql.sql | 42 +-- modules/mining-checker/sql/schema.sql | 38 +-- modules/mining-checker/sql/seed.sql | 16 - modules/mining-checker/src/Api/Router.php | 156 ++------- .../mining-checker/src/Domain/FxService.php | 20 +- .../src/Domain/SeedImporter.php | 4 - .../src/Infrastructure/MiningRepository.php | 288 ----------------- .../src/Infrastructure/SchemaManager.php | 59 ---- 14 files changed, 39 insertions(+), 969 deletions(-) diff --git a/modules/mining-checker/assets/js/app.js b/modules/mining-checker/assets/js/app.js index c5098de..40f3852 100644 --- a/modules/mining-checker/assets/js/app.js +++ b/modules/mining-checker/assets/js/app.js @@ -124,18 +124,6 @@ return `${fxBaseUrl}/latest?base=${encodeURIComponent(String(base || 'USD').toUpperCase())}`; } - function buildExternalCurrenciesUrl() { - if (fxProvider === 'currencyapi') { - const params = new URLSearchParams({ output: 'json' }); - if (fxApiKeyMask) { - params.set('key', fxApiKeyMask); - } - return `${fxCurrenciesUrl}/api/v2/currencies?${params.toString()}`; - } - - return fxCurrenciesUrl; - } - async function loadLatestDebugTrace() { try { const response = await fetch(`${apiBase}/debug/latest`, { @@ -667,8 +655,6 @@ }); const [fxHistory, setFxHistory] = useState([]); const [fxSelection, setFxSelection] = useState(['DOGE', 'USD', 'EUR']); - const [fxDisplayBase, setFxDisplayBase] = useState('USD'); - const [fxSearch, setFxSearch] = useState(''); const [reportCurrencyOverride, setReportCurrencyOverride] = useState(() => { const value = String(getCookie('mining_checker_report_currency') || '').toUpperCase(); return /^[A-Z0-9]{3,10}$/.test(value) ? value : ''; @@ -1147,12 +1133,6 @@ } }, [activeTab, projectKey]); - useEffect(() => { - if (activeTab === 'currencies') { - loadFxHistory(projectKey); - } - }, [activeTab, projectKey]); - useEffect(() => { async function loadSavedDashboards() { if (!payload || !currentDashboards.length) { @@ -1854,83 +1834,6 @@ } } - async function refreshCurrencyCatalog() { - setSaving(true); - setError(''); - setMessage(''); - try { - emitDebug({ - type: 'external:request-plan', - label: 'Ich rufe jetzt extern den Waehrungskatalog auf', - provider: fxProvider, - url: buildExternalCurrenciesUrl(), - method: 'GET', - headers: { Accept: 'application/json' }, - }); - const probe = await request(`${apiBase}/projects/${encodeURIComponent(projectKey)}/currencies-probe`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - timeoutMs: 20000, - }); - emitDebug({ - type: 'external:response', - label: 'Hey, hier ist der Response vor dem DB-Schritt', - url: probe.url, - http_status: probe.http_status, - curl_error: probe.curl_error, - response_headers: probe.response_headers, - response_body: probe.response_body, - }); - const result = await request(`${apiBase}/projects/${encodeURIComponent(projectKey)}/currencies-refresh`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - timeoutMs: 20000, - }); - setPayload((current) => { - const next = normalizeBootstrap(current, projectKey); - return { - ...next, - settings: { - ...next.settings, - currencies: Array.isArray(result.currencies) ? result.currencies : next.settings.currencies, - }, - }; - }); - setMessage(`Waehrungskatalog synchronisiert. ${result.synced_count || 0} Waehrungen verarbeitet.`); - } catch (err) { - setError(err.message); - } finally { - setSaving(false); - } - } - - async function saveFxSelection() { - setSaving(true); - setError(''); - setMessage(''); - try { - await request(`${apiBase}/projects/${encodeURIComponent(projectKey)}/settings`, { - method: 'PUT', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - baseline_measured_at: currentSettings.baseline_measured_at, - baseline_coins_total: currentSettings.baseline_coins_total, - daily_cost_amount: currentSettings.daily_cost_amount, - daily_cost_currency: currentSettings.daily_cost_currency, - report_currency: currentSettings.report_currency || 'EUR', - fx_max_age_hours: currentSettings.fx_max_age_hours || 3, - preferred_currencies: fxSelection, - }), - }); - await loadBootstrap(projectKey); - setMessage('Waehrungs-Auswahl gespeichert.'); - } catch (err) { - setError(err.message); - } finally { - setSaving(false); - } - } - async function copyDebugConsole() { const content = debugEntries .slice() @@ -1964,80 +1867,10 @@ } } - function addFxSelection(code) { - const normalized = String(code || '').toUpperCase().trim(); - if (!normalized) { - return; - } - - setFxSelection((current) => current.includes(normalized) ? current : current.concat([normalized])); - setFxSearch(''); - } - - function removeFxSelection(code) { - const normalized = String(code || '').toUpperCase().trim(); - setFxSelection((current) => current.filter((item) => item !== normalized)); - } - function resetReportCurrencyOverride() { setReportCurrencyOverride(''); setCookie('mining_checker_report_currency', '', 0); } - - const selectedFxCodes = fxSelection.length ? fxSelection.map((code) => String(code || '').toUpperCase()) : ['DOGE', 'USD', 'EUR']; - const fxDisplayBaseNormalized = String(fxDisplayBase || 'USD').toUpperCase(); - const groupedFxHistoryMap = new Map(); - fxHistory.forEach((row, index) => { - const fetchId = row.fetch_id || `legacy-${row.fetched_at || 'none'}-${index}`; - if (!groupedFxHistoryMap.has(fetchId)) { - groupedFxHistoryMap.set(fetchId, { - fetch_id: fetchId, - fetched_at: row.fetched_at || null, - rate_date: row.rate_date || null, - base_currency: row.base_currency || null, - provider: row.provider || null, - rates: {}, - }); - } - - const group = groupedFxHistoryMap.get(fetchId); - group.rates[String(row.target_currency || '').toUpperCase()] = row.rate; - }); - - function computeDisplayedFxRate(group, targetCode, displayBaseCode) { - const normalizedTarget = String(targetCode || '').toUpperCase(); - const normalizedDisplayBase = String(displayBaseCode || '').toUpperCase(); - const fetchBase = String(group.base_currency || '').toUpperCase(); - - if (!normalizedTarget || !normalizedDisplayBase) { - return null; - } - if (normalizedTarget === normalizedDisplayBase) { - return 1; - } - - const targetRateRaw = normalizedTarget === fetchBase ? 1 : group.rates[normalizedTarget]; - const displayBaseRateRaw = normalizedDisplayBase === fetchBase ? 1 : group.rates[normalizedDisplayBase]; - const targetRate = targetRateRaw === null || targetRateRaw === undefined ? null : Number(targetRateRaw); - const displayBaseRate = displayBaseRateRaw === null || displayBaseRateRaw === undefined ? null : Number(displayBaseRateRaw); - - if (!Number.isFinite(targetRate) || !Number.isFinite(displayBaseRate) || displayBaseRate === 0) { - return null; - } - - return targetRate / displayBaseRate; - } - - const groupedFxHistory = Array.from(groupedFxHistoryMap.values()) - .map((group) => ({ - ...group, - selected_rates: selectedFxCodes.map((code) => ({ - code, - rate: computeDisplayedFxRate(group, code, fxDisplayBaseNormalized), - })), - })) - .filter((group) => group.selected_rates.some((item) => item.rate !== null)) - .slice(0, 30); const debugConsoleText = debugEntries .map((entry) => `${entry.time} · ${entry.type}\n${JSON.stringify(entry, null, 2)}`) .join('\n\n'); @@ -2441,137 +2274,6 @@ ]); } - if (activeTab === 'currencies') { - const selectedSet = new Set((fxSelection || []).map((code) => String(code).toUpperCase())); - const searchNeedle = fxSearch.trim().toLowerCase(); - const currencySuggestions = currencies - .filter((currency) => !selectedSet.has(String(currency.code || '').toUpperCase())) - .filter((currency) => { - if (!searchNeedle) { - return false; - } - const code = String(currency.code || '').toLowerCase(); - const name = String(currency.name || '').toLowerCase(); - return code.includes(searchNeedle) || name.includes(searchNeedle); - }) - .slice(0, 12); - return h('div', { className: 'mc-stack' }, [ - h('div', { className: 'mc-stack' }, [ - panel('Waehrungs-Update', 'Auswahl wird in den Mining-Checker-Settings gespeichert und steht damit auf Handy und Desktop gleich zur Verfuegung.', [ - h('div', { key: 'actions', className: 'mc-inline-row' }, [ - h('button', { - key: 'save-selection', - type: 'button', - className: 'mc-button mc-button--ghost', - onClick: saveFxSelection, - disabled: saving, - }, saving ? 'Speichert …' : 'Auswahl speichern'), - h('button', { - key: 'refresh-rates', - type: 'button', - className: 'mc-button mc-button--primary', - onClick: refreshSelectedFxRates, - disabled: saving, - }, saving ? 'Aktualisiert …' : 'Alle Wechselkurse aktualisieren'), - h('button', { - key: 'refresh-catalog', - type: 'button', - className: 'mc-button mc-button--ghost', - onClick: refreshCurrencyCatalog, - disabled: saving, - }, saving ? 'Synchronisiert …' : 'Waehrungskatalog sync'), - ]), - h('div', { key: 'types', className: 'mc-mini-grid' }, [ - h('div', { key: 'fiat', className: 'mc-mini-card' }, [ - h('div', { key: 'fiat-label', className: 'mc-field-label' }, 'Fiat'), - h('div', { key: 'fiat-value' }, `${fiatCurrencies.length} Waehrungen`), - ]), - h('div', { key: 'crypto', className: 'mc-mini-card' }, [ - h('div', { key: 'crypto-label', className: 'mc-field-label' }, 'Krypto'), - h('div', { key: 'crypto-value' }, `${cryptoCurrencies.length} Waehrungen`), - ]), - ]), - h('div', { key: 'selection-title', className: 'mc-field-label' }, 'Bevorzugte Waehrungen fuer Anzeige'), - h('div', { key: 'selection-row', className: 'mc-currency-selection-row' }, [ - h('div', { key: 'selected', className: 'mc-token-list mc-token-list--inline' }, - fxSelection.length - ? fxSelection.map((code) => { - const currency = currencies.find((item) => item.code === code) || { code, name: code }; - return h('button', { - key: `token-${code}`, - type: 'button', - className: 'mc-token', - onClick: () => removeFxSelection(code), - title: `${code} entfernen`, - }, [ - h('span', { key: 'label' }, `${code} (${currency.name || code})`), - h('span', { key: 'close', className: 'mc-token-close' }, 'x'), - ]); - }) - : [h('div', { key: 'empty', className: 'mc-text' }, 'Noch keine bevorzugten Waehrungen ausgewaehlt.')] - ), - h('div', { key: 'search-wrap', className: 'mc-field mc-currency-search' }, [ - h('input', { - key: 'search-input', - type: 'text', - value: fxSearch, - className: 'mc-input', - placeholder: 'Waehrung hinzufuegen: EUR, USD, DOGE oder Euro', - onInput: (event) => setFxSearch(event.target.value), - }), - ]), - ]), - h('div', { key: 'display-base-wrap', className: 'mc-field mc-currency-search' }, [ - h('label', { key: 'display-base-label', className: 'mc-field-label' }, 'Darstellung auf Basis von'), - h('select', { - key: 'display-base', - className: 'mc-select', - value: selectedFxCodes.includes(fxDisplayBaseNormalized) ? fxDisplayBaseNormalized : (selectedFxCodes[0] || 'USD'), - onChange: (event) => setFxDisplayBase(event.target.value), - }, selectedFxCodes.map((code) => h('option', { key: code, value: code }, code))), - ]), - searchNeedle - ? h('div', { key: 'suggestions', className: 'mc-suggestion-list' }, - currencySuggestions.length - ? currencySuggestions.map((currency) => h('button', { - key: `suggestion-${currency.code}`, - type: 'button', - className: 'mc-suggestion', - onClick: () => addFxSelection(currency.code), - }, [ - h('strong', { key: 'code' }, currency.code), - h('span', { key: 'name' }, currency.name || currency.code), - ])) - : [h('div', { key: 'no-match', className: 'mc-text' }, 'Keine passende Waehrung gefunden.')] - ) - : null, - ]), - ]), - h('div', { className: 'mc-stack' }, [ - panel('Letzte 30 Kurs-Uploads', 'Zeigt die zuletzt gespeicherten Wechselkurse aus der Datenbank.', [ - h('div', { key: 'history-table', className: 'mc-table-shell' }, [ - h('table', { key: 'table', className: 'mc-table' }, [ - h('thead', { key: 'head' }, h('tr', null, ['Zeit', 'Stichtag', 'Fetch-Basis'].concat(selectedFxCodes).concat(['Provider']).map((label) => h('th', { key: label }, label)))), - h('tbody', { key: 'body' }, - groupedFxHistory.length - ? groupedFxHistory.map((row, index) => h('tr', { key: `${row.fetch_id || index}-${row.base_currency}` }, [ - h('td', { key: 'fetched' }, fmtDate(row.fetched_at)), - h('td', { key: 'date' }, row.rate_date || 'n/a'), - h('td', { key: 'base' }, row.base_currency), - ].concat( - row.selected_rates.map((item) => h('td', { key: `rate-${item.code}` }, item.rate === null ? 'n/a' : fmtNumber(item.rate, 8))) - ).concat([ - h('td', { key: 'provider' }, row.provider || 'n/a'), - ]))) - : [h('tr', { key: 'empty' }, h('td', { colSpan: 4 + selectedFxCodes.length }, 'Noch keine Wechselkurse fuer die ausgewaehlten Waehrungen gespeichert.'))] - ), - ]), - ]), - ]), - ]), - ]); - } - if (activeTab === 'mining') { const scenarioCurrency = selectedMinerScenario?.scenario_currency || reportCurrency; const scenarioCurrentDailyProfit = selectedMinerScenario ? convertMeasurementMoney(latest, selectedMinerScenario.scenario_current_daily_profit, reportCurrency) : null; diff --git a/modules/mining-checker/design.json b/modules/mining-checker/design.json index 32f7f77..8b82916 100644 --- a/modules/mining-checker/design.json +++ b/modules/mining-checker/design.json @@ -8,7 +8,6 @@ "sections": [ { "key": "overview", "label": "Ueberblick" }, { "key": "measurements", "label": "Messpunkte" }, - { "key": "currencies", "label": "Waehrungen" }, { "key": "mining", "label": "Mining" }, { "key": "dashboards", "label": "Dashboards" }, { "key": "settings", "label": "Settings" } diff --git a/modules/mining-checker/docs/README.md b/modules/mining-checker/docs/README.md index 26d7500..e6f4680 100644 --- a/modules/mining-checker/docs/README.md +++ b/modules/mining-checker/docs/README.md @@ -49,7 +49,6 @@ modules/mining-checker/ - `POST /api/mining-checker/v1/projects/{projectKey}/upgrade` - `GET /api/mining-checker/v1/projects/{projectKey}/connection-test` - `POST /api/mining-checker/v1/projects/{projectKey}/fx-refresh` -- `POST /api/mining-checker/v1/projects/{projectKey}/currencies-refresh` - `GET /api/mining-checker/v1/projects/{projectKey}/fx-history` - `POST /api/mining-checker/v1/projects/{projectKey}/legacy-fx-migrate` @@ -88,9 +87,10 @@ Empfohlene Umgebungsvariablen: Laut OCR.space-Doku wird `POST https://api.ocr.space/parse/image` mit `file`, Header-`apikey`, optional `language`, `scale`, `detectOrientation`, `isTable` und `OCREngine` verwendet. Der Modulparser wertet die OCR.space-Felder `ParsedResults`, `ParsedText`, `IsErroredOnProcessing`, `ErrorMessage` und `OCRExitCode` aus. Quellen: https://ocr.space/ocrapi -## Wechselkurse +## Wechselkurse und Waehrungen Der Endpunkt `POST /api/mining-checker/v1/projects/{projectKey}/fx-refresh` delegiert den Abruf an das Modul `fx-rates`. Der Mining-Checker speichert dabei keine eigenen FX-Snapshots mehr, sondern referenziert die `fetch_id` aus `fx-rates`. +Auch der Waehrungskatalog und die bevorzugten Waehrungen kommen ausschliesslich aus `fx-rates`. Der Mining-Checker fuehrt keine eigene Waehrungstabelle und keine eigene Alias-Verwaltung mehr im Laufzeitpfad. Empfohlene Umgebungsvariablen: @@ -122,7 +122,3 @@ Pro Abruf entsteht genau ein Datensatz in `fx-rates` mit Basiswaehrung, Provider Falls noch historische Mining-Checker-Fetches in `miningcheck_fx_fetches` und `miningcheck_fx_rates` liegen, kann `POST /api/mining-checker/v1/projects/{projectKey}/legacy-fx-migrate` diese nach `fx-rates` ueberfuehren. Danach werden bestehende Messpunkte soweit moeglich auf die passende `fx_fetch_id` aktualisiert. Fuer Auswertungen, Berichte und Listen speichert der Mining-Checker pro Messpunkt die damals passende `fx_fetch_id`. Historische Umrechnungen laufen damit gegen genau den zugeordneten `fx-rates`-Snapshot. - -Mit `POST /api/mining-checker/v1/projects/{projectKey}/currencies-refresh` kann die Waehrungstabelle einmalig oder bei Bedarf aus `GET /api/v2/currencies?output=json&key=...` synchronisiert werden. Dabei werden Code, Name, Symbol und Sortierung in `miningcheck_currencies` gespeichert. - -Die im Tab `Waehrungen` ausgewaehlten Favoriten werden in `miningcheck_settings.preferred_currencies` gespeichert. Dadurch ist die Auswahl geraeteuebergreifend verfuegbar. Fuer bestehende Installationen ist dafuer einmal ein Schema-Upgrade noetig. diff --git a/modules/mining-checker/sql/migrations/001_init.sql b/modules/mining-checker/sql/migrations/001_init.sql index 8df915e..3589f1c 100644 --- a/modules/mining-checker/sql/migrations/001_init.sql +++ b/modules/mining-checker/sql/migrations/001_init.sql @@ -5,22 +5,6 @@ CREATE TABLE IF NOT EXISTS miningcheck_projects ( updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); -CREATE TABLE IF NOT EXISTS miningcheck_currencies ( - code VARCHAR(10) NOT NULL PRIMARY KEY, - name VARCHAR(64) NOT NULL, - symbol VARCHAR(8) NULL, - is_active TINYINT(1) NOT NULL DEFAULT 1, - is_crypto TINYINT(1) NOT NULL DEFAULT 0, - sort_order INT NOT NULL DEFAULT 0 -); - -CREATE TABLE IF NOT EXISTS miningcheck_currency_aliases ( - alias_code VARCHAR(10) NOT NULL PRIMARY KEY, - currency_code VARCHAR(10) NOT NULL, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - CONSTRAINT fk_mining_currency_aliases_currency FOREIGN KEY (currency_code) REFERENCES miningcheck_currencies(code) ON DELETE CASCADE -); - CREATE TABLE IF NOT EXISTS miningcheck_settings ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, project_key VARCHAR(64) NOT NULL, @@ -38,9 +22,6 @@ CREATE TABLE IF NOT EXISTS miningcheck_settings ( created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT fk_mining_settings_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_settings_daily_cost_currency_currency FOREIGN KEY (daily_cost_currency) REFERENCES miningcheck_currencies(code), - CONSTRAINT fk_mining_settings_report_currency_currency FOREIGN KEY (report_currency) REFERENCES miningcheck_currencies(code), - CONSTRAINT fk_mining_settings_crypto_currency_currency FOREIGN KEY (crypto_currency) REFERENCES miningcheck_currencies(code), CONSTRAINT uq_mining_settings_project UNIQUE (project_key) ); @@ -59,8 +40,7 @@ CREATE TABLE IF NOT EXISTS miningcheck_cost_plans ( is_active TINYINT(1) NOT NULL DEFAULT 1, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - CONSTRAINT fk_mining_cost_plans_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_cost_plans_currency_currency FOREIGN KEY (currency) REFERENCES miningcheck_currencies(code) + CONSTRAINT fk_mining_cost_plans_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE ); CREATE INDEX idx_miningcheck_cost_plans_project_start @@ -82,7 +62,6 @@ CREATE TABLE IF NOT EXISTS miningcheck_measurements ( created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT fk_mining_measurements_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_measurements_price_currency_currency FOREIGN KEY (price_currency) REFERENCES miningcheck_currencies(code), CONSTRAINT uq_mining_measurements_unique UNIQUE (project_key, measured_at, coins_total) ); @@ -101,7 +80,6 @@ CREATE TABLE IF NOT EXISTS miningcheck_targets ( created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT fk_mining_targets_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_targets_currency_currency FOREIGN KEY (currency) REFERENCES miningcheck_currencies(code), CONSTRAINT fk_mining_targets_offer FOREIGN KEY (miner_offer_id) REFERENCES miningcheck_miner_offers(id) ON DELETE SET NULL, CONSTRAINT uq_mining_targets_project_label UNIQUE (project_key, label) ); diff --git a/modules/mining-checker/sql/migrations/002_seed_doge_main.sql b/modules/mining-checker/sql/migrations/002_seed_doge_main.sql index f360132..71dc8fa 100644 --- a/modules/mining-checker/sql/migrations/002_seed_doge_main.sql +++ b/modules/mining-checker/sql/migrations/002_seed_doge_main.sql @@ -2,22 +2,6 @@ INSERT INTO miningcheck_projects (project_key, project_name) VALUES ('doge-main', 'DOGE Mining Main') ON DUPLICATE KEY UPDATE project_name = VALUES(project_name); -INSERT INTO miningcheck_currencies (code, name, symbol, is_active, sort_order) -VALUES - ('EUR', 'Euro', 'EUR', 1, 10), - ('USD', 'US-Dollar', 'USD', 1, 20), - ('DOGE', 'Dogecoin', 'DOGE', 1, 100), - ('BTC', 'Bitcoin', 'BTC', 1, 110), - ('ETH', 'Ethereum', 'ETH', 1, 120), - ('LTC', 'Litecoin', 'LTC', 1, 130), - ('USDT', 'Tether', 'USDT', 1, 140), - ('USDC', 'USD Coin', 'USDC', 1, 150) -ON DUPLICATE KEY UPDATE - name = VALUES(name), - symbol = VALUES(symbol), - is_active = VALUES(is_active), - sort_order = VALUES(sort_order); - INSERT INTO miningcheck_settings ( project_key, baseline_measured_at, diff --git a/modules/mining-checker/sql/schema.mysql.sql b/modules/mining-checker/sql/schema.mysql.sql index 5bb1667..bb0165c 100644 --- a/modules/mining-checker/sql/schema.mysql.sql +++ b/modules/mining-checker/sql/schema.mysql.sql @@ -5,22 +5,6 @@ CREATE TABLE IF NOT EXISTS miningcheck_projects ( updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); -CREATE TABLE IF NOT EXISTS miningcheck_currencies ( - code VARCHAR(10) NOT NULL PRIMARY KEY, - name VARCHAR(64) NOT NULL, - symbol VARCHAR(8) NULL, - is_active TINYINT(1) NOT NULL DEFAULT 1, - is_crypto TINYINT(1) NOT NULL DEFAULT 0, - sort_order INT NOT NULL DEFAULT 0 -); - -CREATE TABLE IF NOT EXISTS miningcheck_currency_aliases ( - alias_code VARCHAR(10) NOT NULL PRIMARY KEY, - currency_code VARCHAR(10) NOT NULL, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - CONSTRAINT fk_mining_currency_aliases_currency FOREIGN KEY (currency_code) REFERENCES miningcheck_currencies(code) ON DELETE CASCADE -); - CREATE TABLE IF NOT EXISTS miningcheck_settings ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, project_key VARCHAR(64) NOT NULL, @@ -38,9 +22,6 @@ CREATE TABLE IF NOT EXISTS miningcheck_settings ( created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT fk_mining_settings_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_settings_daily_cost_currency_currency FOREIGN KEY (daily_cost_currency) REFERENCES miningcheck_currencies(code), - CONSTRAINT fk_mining_settings_report_currency_currency FOREIGN KEY (report_currency) REFERENCES miningcheck_currencies(code), - CONSTRAINT fk_mining_settings_crypto_currency_currency FOREIGN KEY (crypto_currency) REFERENCES miningcheck_currencies(code), CONSTRAINT uq_mining_settings_project UNIQUE (project_key) ); @@ -63,8 +44,7 @@ CREATE TABLE IF NOT EXISTS miningcheck_cost_plans ( is_active TINYINT(1) NOT NULL DEFAULT 1, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - CONSTRAINT fk_mining_cost_plans_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_cost_plans_currency_currency FOREIGN KEY (currency) REFERENCES miningcheck_currencies(code) + CONSTRAINT fk_mining_cost_plans_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE ); CREATE INDEX idx_miningcheck_cost_plans_project_start @@ -87,7 +67,6 @@ CREATE TABLE IF NOT EXISTS miningcheck_measurements ( created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT fk_mining_measurements_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_measurements_price_currency_currency FOREIGN KEY (price_currency) REFERENCES miningcheck_currencies(code), CONSTRAINT uq_mining_measurements_unique UNIQUE (project_key, measured_at, coins_total) ); @@ -107,8 +86,6 @@ CREATE TABLE IF NOT EXISTS miningcheck_measurement_rates ( provider VARCHAR(32) NOT NULL DEFAULT 'derived', created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_mining_measurement_rates_measurement FOREIGN KEY (measurement_id) REFERENCES miningcheck_measurements(id) ON DELETE CASCADE, - CONSTRAINT fk_mining_measurement_rates_base_currency_currency FOREIGN KEY (base_currency) REFERENCES miningcheck_currencies(code), - CONSTRAINT fk_mining_measurement_rates_quote_currency_currency FOREIGN KEY (quote_currency) REFERENCES miningcheck_currencies(code), CONSTRAINT uq_mining_measurement_rate_pair UNIQUE (measurement_id, base_currency, quote_currency), KEY idx_miningcheck_measurement_rates_project_measurement (project_key, measurement_id) ); @@ -123,7 +100,6 @@ CREATE TABLE IF NOT EXISTS miningcheck_payouts ( created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT fk_mining_payouts_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_payouts_payout_currency_currency FOREIGN KEY (payout_currency) REFERENCES miningcheck_currencies(code), KEY idx_miningcheck_payouts_project_payout_at (project_key, payout_at) ); @@ -144,8 +120,7 @@ CREATE TABLE IF NOT EXISTS miningcheck_miner_offers ( is_active TINYINT(1) NOT NULL DEFAULT 1, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - CONSTRAINT fk_mining_miner_offers_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_miner_offers_base_price_currency_currency FOREIGN KEY (base_price_currency) REFERENCES miningcheck_currencies(code) + CONSTRAINT fk_mining_miner_offers_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS miningcheck_targets ( @@ -160,7 +135,6 @@ CREATE TABLE IF NOT EXISTS miningcheck_targets ( created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT fk_mining_targets_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_targets_currency_currency FOREIGN KEY (currency) REFERENCES miningcheck_currencies(code), CONSTRAINT fk_mining_targets_offer FOREIGN KEY (miner_offer_id) REFERENCES miningcheck_miner_offers(id) ON DELETE SET NULL, CONSTRAINT uq_mining_targets_project_label UNIQUE (project_key, label) ); @@ -203,9 +177,7 @@ CREATE TABLE IF NOT EXISTS miningcheck_purchased_miners ( created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT fk_mining_purchased_miners_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_purchased_miners_offer FOREIGN KEY (miner_offer_id) REFERENCES miningcheck_miner_offers(id) ON DELETE SET NULL, - CONSTRAINT fk_mining_purchased_miners_currency_currency FOREIGN KEY (currency) REFERENCES miningcheck_currencies(code), - CONSTRAINT fk_mining_purchased_miners_reference_price_currency_currency FOREIGN KEY (reference_price_currency) REFERENCES miningcheck_currencies(code) + CONSTRAINT fk_mining_purchased_miners_offer FOREIGN KEY (miner_offer_id) REFERENCES miningcheck_miner_offers(id) ON DELETE SET NULL ); CREATE TABLE IF NOT EXISTS miningcheck_fx_fetches ( @@ -214,7 +186,6 @@ CREATE TABLE IF NOT EXISTS miningcheck_fx_fetches ( base_currency VARCHAR(10) NOT NULL, rate_date DATE NOT NULL, fetched_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - CONSTRAINT fk_mining_fx_fetches_base_currency_currency FOREIGN KEY (base_currency) REFERENCES miningcheck_currencies(code), KEY idx_miningcheck_fx_fetches_base_fetched (base_currency, fetched_at) ); @@ -225,6 +196,5 @@ CREATE TABLE IF NOT EXISTS miningcheck_fx_rates ( current_value DECIMAL(20,10) NOT NULL, KEY idx_miningcheck_fx_rates_fetch (fetch_id), KEY idx_miningcheck_fx_rates_currency (currency_code), - CONSTRAINT fk_mining_fx_rates_fetch FOREIGN KEY (fetch_id) REFERENCES miningcheck_fx_fetches(id) ON DELETE CASCADE, - CONSTRAINT fk_mining_fx_rates_currency_code_currency FOREIGN KEY (currency_code) REFERENCES miningcheck_currencies(code) + CONSTRAINT fk_mining_fx_rates_fetch FOREIGN KEY (fetch_id) REFERENCES miningcheck_fx_fetches(id) ON DELETE CASCADE ); diff --git a/modules/mining-checker/sql/schema.pgsql.sql b/modules/mining-checker/sql/schema.pgsql.sql index 2a1ca85..0c4f12b 100644 --- a/modules/mining-checker/sql/schema.pgsql.sql +++ b/modules/mining-checker/sql/schema.pgsql.sql @@ -5,22 +5,6 @@ CREATE TABLE IF NOT EXISTS miningcheck_projects ( updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); -CREATE TABLE IF NOT EXISTS miningcheck_currencies ( - code VARCHAR(10) PRIMARY KEY, - name VARCHAR(64) NOT NULL, - symbol VARCHAR(8), - is_active BOOLEAN NOT NULL DEFAULT TRUE, - is_crypto BOOLEAN NOT NULL DEFAULT FALSE, - sort_order INTEGER NOT NULL DEFAULT 0 -); - -CREATE TABLE IF NOT EXISTS miningcheck_currency_aliases ( - alias_code VARCHAR(10) PRIMARY KEY, - currency_code VARCHAR(10) NOT NULL, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - CONSTRAINT fk_mining_currency_aliases_currency FOREIGN KEY (currency_code) REFERENCES miningcheck_currencies(code) ON DELETE CASCADE -); - CREATE TABLE IF NOT EXISTS miningcheck_settings ( id BIGSERIAL PRIMARY KEY, project_key VARCHAR(64) NOT NULL, @@ -39,9 +23,6 @@ CREATE TABLE IF NOT EXISTS miningcheck_settings ( created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_mining_settings_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_settings_daily_cost_currency_currency FOREIGN KEY (daily_cost_currency) REFERENCES miningcheck_currencies(code), - CONSTRAINT fk_mining_settings_report_currency_currency FOREIGN KEY (report_currency) REFERENCES miningcheck_currencies(code), - CONSTRAINT fk_mining_settings_crypto_currency_currency FOREIGN KEY (crypto_currency) REFERENCES miningcheck_currencies(code), CONSTRAINT uq_mining_settings_project_owner UNIQUE (project_key, owner_sub) ); @@ -65,8 +46,7 @@ CREATE TABLE IF NOT EXISTS miningcheck_cost_plans ( is_active BOOLEAN NOT NULL DEFAULT TRUE, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - CONSTRAINT fk_mining_cost_plans_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_cost_plans_currency_currency FOREIGN KEY (currency) REFERENCES miningcheck_currencies(code) + CONSTRAINT fk_mining_cost_plans_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_miningcheck_cost_plans_project_start @@ -90,7 +70,6 @@ CREATE TABLE IF NOT EXISTS miningcheck_measurements ( created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_mining_measurements_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_measurements_price_currency_currency FOREIGN KEY (price_currency) REFERENCES miningcheck_currencies(code), CONSTRAINT uq_mining_measurements_unique UNIQUE (project_key, owner_sub, measured_at, coins_total) ); @@ -111,8 +90,6 @@ CREATE TABLE IF NOT EXISTS miningcheck_measurement_rates ( provider VARCHAR(32) NOT NULL DEFAULT 'derived', created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_mining_measurement_rates_measurement FOREIGN KEY (measurement_id) REFERENCES miningcheck_measurements(id) ON DELETE CASCADE, - CONSTRAINT fk_mining_measurement_rates_base_currency_currency FOREIGN KEY (base_currency) REFERENCES miningcheck_currencies(code), - CONSTRAINT fk_mining_measurement_rates_quote_currency_currency FOREIGN KEY (quote_currency) REFERENCES miningcheck_currencies(code), CONSTRAINT uq_mining_measurement_rate_pair UNIQUE (measurement_id, base_currency, quote_currency) ); @@ -129,8 +106,7 @@ CREATE TABLE IF NOT EXISTS miningcheck_payouts ( note TEXT, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - CONSTRAINT fk_mining_payouts_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_payouts_payout_currency_currency FOREIGN KEY (payout_currency) REFERENCES miningcheck_currencies(code) + CONSTRAINT fk_mining_payouts_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_miningcheck_payouts_project_payout_at @@ -153,8 +129,7 @@ CREATE TABLE IF NOT EXISTS miningcheck_miner_offers ( is_active BOOLEAN NOT NULL DEFAULT TRUE, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - CONSTRAINT fk_mining_miner_offers_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_miner_offers_base_price_currency_currency FOREIGN KEY (base_price_currency) REFERENCES miningcheck_currencies(code) + CONSTRAINT fk_mining_miner_offers_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS miningcheck_targets ( @@ -170,7 +145,6 @@ CREATE TABLE IF NOT EXISTS miningcheck_targets ( created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_mining_targets_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_targets_currency_currency FOREIGN KEY (currency) REFERENCES miningcheck_currencies(code), CONSTRAINT fk_mining_targets_offer FOREIGN KEY (miner_offer_id) REFERENCES miningcheck_miner_offers(id) ON DELETE SET NULL, CONSTRAINT uq_mining_targets_project_label UNIQUE (project_key, owner_sub, label) ); @@ -215,9 +189,7 @@ CREATE TABLE IF NOT EXISTS miningcheck_purchased_miners ( created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_mining_purchased_miners_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_purchased_miners_offer FOREIGN KEY (miner_offer_id) REFERENCES miningcheck_miner_offers(id) ON DELETE SET NULL, - CONSTRAINT fk_mining_purchased_miners_currency_currency FOREIGN KEY (currency) REFERENCES miningcheck_currencies(code), - CONSTRAINT fk_mining_purchased_miners_reference_price_currency_currency FOREIGN KEY (reference_price_currency) REFERENCES miningcheck_currencies(code) + CONSTRAINT fk_mining_purchased_miners_offer FOREIGN KEY (miner_offer_id) REFERENCES miningcheck_miner_offers(id) ON DELETE SET NULL ); CREATE TABLE IF NOT EXISTS miningcheck_fx_fetches ( @@ -225,8 +197,7 @@ CREATE TABLE IF NOT EXISTS miningcheck_fx_fetches ( provider VARCHAR(32) NOT NULL DEFAULT 'currencyapi', base_currency VARCHAR(10) NOT NULL, rate_date DATE NOT NULL, - fetched_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - CONSTRAINT fk_mining_fx_fetches_base_currency_currency FOREIGN KEY (base_currency) REFERENCES miningcheck_currencies(code) + fetched_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX IF NOT EXISTS idx_miningcheck_fx_fetches_base_fetched @@ -237,8 +208,7 @@ CREATE TABLE IF NOT EXISTS miningcheck_fx_rates ( fetch_id BIGINT NOT NULL, currency_code VARCHAR(10) NOT NULL, current_value NUMERIC(20,10) NOT NULL, - CONSTRAINT fk_mining_fx_rates_fetch FOREIGN KEY (fetch_id) REFERENCES miningcheck_fx_fetches(id) ON DELETE CASCADE, - CONSTRAINT fk_mining_fx_rates_currency_code_currency FOREIGN KEY (currency_code) REFERENCES miningcheck_currencies(code) + CONSTRAINT fk_mining_fx_rates_fetch FOREIGN KEY (fetch_id) REFERENCES miningcheck_fx_fetches(id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_miningcheck_fx_rates_fetch diff --git a/modules/mining-checker/sql/schema.sql b/modules/mining-checker/sql/schema.sql index 5bb1667..bb0165c 100644 --- a/modules/mining-checker/sql/schema.sql +++ b/modules/mining-checker/sql/schema.sql @@ -5,22 +5,6 @@ CREATE TABLE IF NOT EXISTS miningcheck_projects ( updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); -CREATE TABLE IF NOT EXISTS miningcheck_currencies ( - code VARCHAR(10) NOT NULL PRIMARY KEY, - name VARCHAR(64) NOT NULL, - symbol VARCHAR(8) NULL, - is_active TINYINT(1) NOT NULL DEFAULT 1, - is_crypto TINYINT(1) NOT NULL DEFAULT 0, - sort_order INT NOT NULL DEFAULT 0 -); - -CREATE TABLE IF NOT EXISTS miningcheck_currency_aliases ( - alias_code VARCHAR(10) NOT NULL PRIMARY KEY, - currency_code VARCHAR(10) NOT NULL, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - CONSTRAINT fk_mining_currency_aliases_currency FOREIGN KEY (currency_code) REFERENCES miningcheck_currencies(code) ON DELETE CASCADE -); - CREATE TABLE IF NOT EXISTS miningcheck_settings ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, project_key VARCHAR(64) NOT NULL, @@ -38,9 +22,6 @@ CREATE TABLE IF NOT EXISTS miningcheck_settings ( created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT fk_mining_settings_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_settings_daily_cost_currency_currency FOREIGN KEY (daily_cost_currency) REFERENCES miningcheck_currencies(code), - CONSTRAINT fk_mining_settings_report_currency_currency FOREIGN KEY (report_currency) REFERENCES miningcheck_currencies(code), - CONSTRAINT fk_mining_settings_crypto_currency_currency FOREIGN KEY (crypto_currency) REFERENCES miningcheck_currencies(code), CONSTRAINT uq_mining_settings_project UNIQUE (project_key) ); @@ -63,8 +44,7 @@ CREATE TABLE IF NOT EXISTS miningcheck_cost_plans ( is_active TINYINT(1) NOT NULL DEFAULT 1, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - CONSTRAINT fk_mining_cost_plans_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_cost_plans_currency_currency FOREIGN KEY (currency) REFERENCES miningcheck_currencies(code) + CONSTRAINT fk_mining_cost_plans_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE ); CREATE INDEX idx_miningcheck_cost_plans_project_start @@ -87,7 +67,6 @@ CREATE TABLE IF NOT EXISTS miningcheck_measurements ( created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT fk_mining_measurements_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_measurements_price_currency_currency FOREIGN KEY (price_currency) REFERENCES miningcheck_currencies(code), CONSTRAINT uq_mining_measurements_unique UNIQUE (project_key, measured_at, coins_total) ); @@ -107,8 +86,6 @@ CREATE TABLE IF NOT EXISTS miningcheck_measurement_rates ( provider VARCHAR(32) NOT NULL DEFAULT 'derived', created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_mining_measurement_rates_measurement FOREIGN KEY (measurement_id) REFERENCES miningcheck_measurements(id) ON DELETE CASCADE, - CONSTRAINT fk_mining_measurement_rates_base_currency_currency FOREIGN KEY (base_currency) REFERENCES miningcheck_currencies(code), - CONSTRAINT fk_mining_measurement_rates_quote_currency_currency FOREIGN KEY (quote_currency) REFERENCES miningcheck_currencies(code), CONSTRAINT uq_mining_measurement_rate_pair UNIQUE (measurement_id, base_currency, quote_currency), KEY idx_miningcheck_measurement_rates_project_measurement (project_key, measurement_id) ); @@ -123,7 +100,6 @@ CREATE TABLE IF NOT EXISTS miningcheck_payouts ( created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT fk_mining_payouts_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_payouts_payout_currency_currency FOREIGN KEY (payout_currency) REFERENCES miningcheck_currencies(code), KEY idx_miningcheck_payouts_project_payout_at (project_key, payout_at) ); @@ -144,8 +120,7 @@ CREATE TABLE IF NOT EXISTS miningcheck_miner_offers ( is_active TINYINT(1) NOT NULL DEFAULT 1, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - CONSTRAINT fk_mining_miner_offers_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_miner_offers_base_price_currency_currency FOREIGN KEY (base_price_currency) REFERENCES miningcheck_currencies(code) + CONSTRAINT fk_mining_miner_offers_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS miningcheck_targets ( @@ -160,7 +135,6 @@ CREATE TABLE IF NOT EXISTS miningcheck_targets ( created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT fk_mining_targets_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_targets_currency_currency FOREIGN KEY (currency) REFERENCES miningcheck_currencies(code), CONSTRAINT fk_mining_targets_offer FOREIGN KEY (miner_offer_id) REFERENCES miningcheck_miner_offers(id) ON DELETE SET NULL, CONSTRAINT uq_mining_targets_project_label UNIQUE (project_key, label) ); @@ -203,9 +177,7 @@ CREATE TABLE IF NOT EXISTS miningcheck_purchased_miners ( created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT fk_mining_purchased_miners_project FOREIGN KEY (project_key) REFERENCES miningcheck_projects(project_key) ON DELETE CASCADE, - CONSTRAINT fk_mining_purchased_miners_offer FOREIGN KEY (miner_offer_id) REFERENCES miningcheck_miner_offers(id) ON DELETE SET NULL, - CONSTRAINT fk_mining_purchased_miners_currency_currency FOREIGN KEY (currency) REFERENCES miningcheck_currencies(code), - CONSTRAINT fk_mining_purchased_miners_reference_price_currency_currency FOREIGN KEY (reference_price_currency) REFERENCES miningcheck_currencies(code) + CONSTRAINT fk_mining_purchased_miners_offer FOREIGN KEY (miner_offer_id) REFERENCES miningcheck_miner_offers(id) ON DELETE SET NULL ); CREATE TABLE IF NOT EXISTS miningcheck_fx_fetches ( @@ -214,7 +186,6 @@ CREATE TABLE IF NOT EXISTS miningcheck_fx_fetches ( base_currency VARCHAR(10) NOT NULL, rate_date DATE NOT NULL, fetched_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - CONSTRAINT fk_mining_fx_fetches_base_currency_currency FOREIGN KEY (base_currency) REFERENCES miningcheck_currencies(code), KEY idx_miningcheck_fx_fetches_base_fetched (base_currency, fetched_at) ); @@ -225,6 +196,5 @@ CREATE TABLE IF NOT EXISTS miningcheck_fx_rates ( current_value DECIMAL(20,10) NOT NULL, KEY idx_miningcheck_fx_rates_fetch (fetch_id), KEY idx_miningcheck_fx_rates_currency (currency_code), - CONSTRAINT fk_mining_fx_rates_fetch FOREIGN KEY (fetch_id) REFERENCES miningcheck_fx_fetches(id) ON DELETE CASCADE, - CONSTRAINT fk_mining_fx_rates_currency_code_currency FOREIGN KEY (currency_code) REFERENCES miningcheck_currencies(code) + CONSTRAINT fk_mining_fx_rates_fetch FOREIGN KEY (fetch_id) REFERENCES miningcheck_fx_fetches(id) ON DELETE CASCADE ); diff --git a/modules/mining-checker/sql/seed.sql b/modules/mining-checker/sql/seed.sql index dc78cd8..7997565 100644 --- a/modules/mining-checker/sql/seed.sql +++ b/modules/mining-checker/sql/seed.sql @@ -2,22 +2,6 @@ INSERT INTO miningcheck_projects (project_key, project_name) VALUES ('doge-main', 'DOGE Mining Main') ON DUPLICATE KEY UPDATE project_name = VALUES(project_name); -INSERT INTO miningcheck_currencies (code, name, symbol, is_active, sort_order) -VALUES - ('EUR', 'Euro', 'EUR', 1, 10), - ('USD', 'US-Dollar', 'USD', 1, 20), - ('DOGE', 'Dogecoin', 'DOGE', 1, 100), - ('BTC', 'Bitcoin', 'BTC', 1, 110), - ('ETH', 'Ethereum', 'ETH', 1, 120), - ('LTC', 'Litecoin', 'LTC', 1, 130), - ('USDT', 'Tether', 'USDT', 1, 140), - ('USDC', 'USD Coin', 'USDC', 1, 150) -ON DUPLICATE KEY UPDATE - name = VALUES(name), - symbol = VALUES(symbol), - is_active = VALUES(is_active), - sort_order = VALUES(sort_order); - INSERT INTO miningcheck_settings ( project_key, baseline_measured_at, diff --git a/modules/mining-checker/src/Api/Router.php b/modules/mining-checker/src/Api/Router.php index ff0d2a7..3d8502c 100644 --- a/modules/mining-checker/src/Api/Router.php +++ b/modules/mining-checker/src/Api/Router.php @@ -151,14 +151,6 @@ final class Router $this->respond(['data' => $this->probeFxRates(Http::input())], 200); } - if ($resource === 'currencies-refresh' && $method === 'POST') { - $this->respond(['data' => $this->refreshCurrencies()], 201); - } - - if ($resource === 'currencies-probe' && $method === 'POST') { - $this->respond(['data' => $this->probeCurrencies()], 200); - } - if ($resource === 'fx-history' && $method === 'GET') { $this->respond(['data' => $this->fxHistory()]); } @@ -297,18 +289,6 @@ final class Router Http::json(['data' => $this->purchaseMiner($projectKey, (int) $matches[1], Http::input())], 201); } - if ($resource === 'currencies' && $method === 'GET') { - Http::json(['data' => $this->currencies()]); - } - - if ($resource === 'currency-aliases' && $method === 'GET') { - Http::json(['data' => $this->currencyAliases()]); - } - - if ($resource === 'currency-aliases' && $method === 'POST') { - Http::json(['data' => $this->saveCurrencyAlias(Http::input())], 201); - } - throw new ApiException('Ressource nicht gefunden.', 404, ['resource' => $resource, 'method' => $method]); } catch (ApiException $exception) { $this->debug->add('router.handle.api_exception', [ @@ -513,8 +493,6 @@ final class Router $backup = [ 'project' => $this->repository()->getProject($projectKey), 'settings' => $this->safeRead(fn () => $this->repository()->getSettings($projectKey)), - 'currencies' => $this->safeRead(fn () => $this->repository()->listCurrencies(), []), - 'currency_aliases' => $this->safeRead(fn () => $this->repository()->listCurrencyAliases(), []), 'cost_plans' => $this->safeRead(fn () => $this->repository()->listCostPlans($projectKey), []), 'measurements' => $this->safeRead(fn () => $this->repository()->listAllMeasurements($projectKey), []), 'measurement_rates' => $this->safeRead(fn () => $this->repository()->listMeasurementRates($projectKey), []), @@ -538,23 +516,6 @@ final class Router $projectName = is_array($backup['project']) ? ($backup['project']['project_name'] ?? null) : null; $this->repository()->ensureProject($projectKey, is_string($projectName) ? $projectName : null); - foreach ($backup['currencies'] as $currency) { - $this->repository()->saveCurrency([ - 'code' => $currency['code'], - 'name' => $currency['name'], - 'symbol' => $currency['symbol'] ?? null, - 'is_active' => !empty($currency['is_active']) ? 1 : 0, - 'is_crypto' => !empty($currency['is_crypto']) ? 1 : 0, - 'sort_order' => (int) ($currency['sort_order'] ?? 0), - ]); - } - - foreach ($backup['currency_aliases'] as $alias) { - if (!empty($alias['alias_code']) && !empty($alias['currency_code'])) { - $this->repository()->saveCurrencyAlias((string) $alias['alias_code'], (string) $alias['currency_code']); - } - } - if (is_array($backup['settings'])) { $this->repository()->saveSettings($projectKey, [ 'baseline_measured_at' => $backup['settings']['baseline_measured_at'], @@ -750,7 +711,6 @@ final class Router 'targets' => count($backup['targets']), 'dashboards' => count($backup['dashboards']), 'miner_offers' => count($backup['miner_offers']), - 'currency_aliases' => count($backup['currency_aliases']), 'fx_rates' => $restoredFxRates, ], ]); @@ -795,20 +755,6 @@ final class Router return $this->fx()->probeLatestRates($base); } - private function refreshCurrencies(): array - { - $result = $this->fx()->refreshCurrencyCatalog(); - $synced = $this->syncLocalCurrencyCatalogFromFxRates(true); - return $result + [ - 'local_catalog_synced' => count($synced), - ]; - } - - private function probeCurrencies(): array - { - return $this->fx()->probeCurrencyCatalog(); - } - private function fxHistory(): array { if (!modules()->isEnabled('fx-rates') || !modules()->hasFunction('fx-rates', 'recent_fetches')) { @@ -1293,7 +1239,7 @@ final class Router private function bootstrapMeasurements(string $projectKey, array $settings, string $view): array { - if (in_array($view, ['settings', 'currencies', 'dashboards'], true)) { + if (in_array($view, ['settings', 'dashboards'], true)) { return []; } @@ -1373,7 +1319,7 @@ final class Router private function normalizeBootstrapView(string $view): string { $normalized = trim(strtolower($view)); - return in_array($normalized, ['overview', 'measurements', 'dashboards', 'currencies', 'mining', 'settings'], true) + return in_array($normalized, ['overview', 'measurements', 'dashboards', 'mining', 'settings'], true) ? $normalized : 'overview'; } @@ -1475,22 +1421,12 @@ final class Router return; } - $knownCodes = array_map( - static fn (array $currency): string => strtoupper((string) ($currency['code'] ?? '')), - $this->currencies() - ); - - if (in_array($priceCurrency, $knownCodes, true)) { - return; - } - - $matched = $this->currencyCatalogEntry($priceCurrency); - $this->repository()->ensureCurrencyCode($priceCurrency, $matched['name'] ?? $priceCurrency); - - try { - $this->refreshCurrencies(); - } catch (\Throwable) { - // Measurement save must not fail because the external currency sync is unavailable. + if ($this->currencyCatalogEntry($priceCurrency) === null) { + throw new ApiException( + 'Waehrung ist im fx-rates Katalog nicht vorhanden.', + 422, + ['currency' => $priceCurrency] + ); } } @@ -1580,25 +1516,7 @@ final class Router private function currencies(): array { - $catalog = $this->syncLocalCurrencyCatalogFromFxRates(); - return $catalog !== [] ? $catalog : $this->repository()->listCurrencies(); - } - - private function currencyAliases(): array - { - return $this->repository()->listCurrencyAliases(); - } - - private function saveCurrencyAlias(array $input): array - { - $aliasCode = strtoupper(trim((string) ($input['alias_code'] ?? ''))); - $currencyCode = $this->requiredCurrency($input['currency_code'] ?? null, 'currency_code'); - - if (!preg_match('/^[A-Z0-9]{3,10}$/', $aliasCode)) { - throw new ApiException('Feld alias_code muss ein gueltiger Waehrungscode sein.', 422); - } - - return $this->repository()->saveCurrencyAlias($aliasCode, $currencyCode); + return $this->currencyCatalog(); } private function minerOffers(string $projectKey): array @@ -1945,24 +1863,18 @@ final class Router throw new ApiException("Feld {$field} muss ein gueltiger Waehrungscode sein.", 422); } - $resolved = $this->repository()->resolveCurrencyCode($currency); - if ($resolved !== null && !empty($resolved['code'])) { - return (string) $resolved['code']; - } - $catalogEntry = $this->currencyCatalogEntry($currency); if (is_array($catalogEntry)) { - $this->repository()->ensureCurrencyCode($currency, (string) ($catalogEntry['name'] ?? $currency)); return $currency; } throw new ApiException( - "Feld {$field} verweist auf keinen vorhandenen Waehrungsrecord.", + "Feld {$field} verweist auf keinen vorhandenen fx-rates Waehrungscode.", 422, [ 'field' => $field, 'missing_currency' => $currency, - 'hint' => 'Synchronisiere zuerst den Waehrungskatalog aus fx-rates oder hinterlege einen Alias auf einen bestehenden Waehrungsrecord.', + 'hint' => 'Synchronisiere zuerst den Waehrungskatalog im Modul fx-rates.', 'available_currencies' => array_slice(array_map( static fn (array $item): string => (string) ($item['code'] ?? ''), $this->currencies() @@ -1981,10 +1893,15 @@ final class Router private function assertCurrencyType(string $code, bool $expectedCrypto, string $field): void { - $this->ensureLocalCurrencyRecord($code); - $resolved = $this->repository()->resolveCurrencyCode($code); - $currency = is_array($resolved) ? ($resolved['currency'] ?? null) : null; - $isCrypto = !empty($currency['is_crypto']); + if ($this->currencyCatalogEntry($code) === null) { + throw new ApiException( + "Feld {$field} verweist auf keinen vorhandenen fx-rates Waehrungscode.", + 422, + ['field' => $field, 'currency' => $code] + ); + } + + $isCrypto = $this->isCryptoCurrencyCode($code); if ($isCrypto !== $expectedCrypto) { throw new ApiException( $expectedCrypto @@ -2248,22 +2165,6 @@ final class Router return null; } - private function syncLocalCurrencyCatalogFromFxRates(bool $forceRefresh = false): array - { - if ($forceRefresh) { - $this->fxRatesSettingsCache = null; - $this->currencyCatalogCache = null; - } - - $catalog = $this->currencyCatalog(); - if ($catalog === []) { - return []; - } - - $this->repository()->saveCurrencies($catalog); - return $this->repository()->listCurrencies(); - } - private function syncFxRatesPreferredCurrencies(array $preferredCurrencies): void { if (!modules()->isEnabled('fx-rates') || !modules()->hasFunction('fx-rates', 'save_runtime_settings')) { @@ -2274,22 +2175,7 @@ final class Router 'preferred_currencies' => $preferredCurrencies, ]); $this->fxRatesSettingsCache = null; - } - - private function ensureLocalCurrencyRecord(string $code): void - { - $resolved = $this->repository()->resolveCurrencyCode($code); - if ($resolved !== null) { - return; - } - - $catalogEntry = $this->currencyCatalogEntry($code); - if ($catalogEntry !== null) { - $this->repository()->saveCurrency($catalogEntry); - return; - } - - $this->repository()->ensureCurrencyCode($code, $code); + $this->currencyCatalogCache = null; } private function isCryptoCurrencyCode(string $code): bool diff --git a/modules/mining-checker/src/Domain/FxService.php b/modules/mining-checker/src/Domain/FxService.php index ebe1d24..a270697 100644 --- a/modules/mining-checker/src/Domain/FxService.php +++ b/modules/mining-checker/src/Domain/FxService.php @@ -310,13 +310,6 @@ final class FxService return $shared->refreshCurrencyCatalog(); } - if ($this->repository === null) { - return [ - 'synced_count' => 0, - 'currencies' => [], - ]; - } - $payload = $this->fetchCurrenciesPayload(); $items = is_array($payload['currencies'] ?? null) ? $payload['currencies'] : []; if ($items === []) { @@ -349,8 +342,6 @@ final class FxService $sortOrder++; } - $this->repository->saveCurrencies($synced); - usort($synced, static function (array $left, array $right): int { return [$left['sort_order'], $left['code']] <=> [$right['sort_order'], $right['code']]; }); @@ -796,16 +787,7 @@ final class FxService private function defaultCurrencies(): array { - if ($this->repository === null) { - return ['EUR', 'USD']; - } - - try { - $currencies = $this->repository->listActiveFiatCurrencies(); - return array_map(static fn (array $currency): string => (string) $currency['code'], $currencies); - } catch (\Throwable) { - return ['EUR', 'USD']; - } + return ['EUR', 'USD']; } private function normalizeRateDate(mixed $value): string diff --git a/modules/mining-checker/src/Domain/SeedImporter.php b/modules/mining-checker/src/Domain/SeedImporter.php index bc84e5a..b533e2b 100644 --- a/modules/mining-checker/src/Domain/SeedImporter.php +++ b/modules/mining-checker/src/Domain/SeedImporter.php @@ -22,9 +22,6 @@ final class SeedImporter } $this->repository->ensureProject($projectKey, SeedData::projectName()); - foreach (SeedData::currencies() as $currency) { - $this->repository->saveCurrency($currency); - } $this->repository->saveSettings($projectKey, SeedData::settings()); $insertedMeasurements = 0; @@ -60,7 +57,6 @@ final class SeedImporter 'historical_rows_total' => count(SeedData::measurements()), 'targets_synced' => $targetCount, 'dashboards_synced' => $dashboardCount, - 'currencies_synced' => count(SeedData::currencies()), ]; } } diff --git a/modules/mining-checker/src/Infrastructure/MiningRepository.php b/modules/mining-checker/src/Infrastructure/MiningRepository.php index d93b23c..b5ca463 100644 --- a/modules/mining-checker/src/Infrastructure/MiningRepository.php +++ b/modules/mining-checker/src/Infrastructure/MiningRepository.php @@ -111,231 +111,6 @@ final class MiningRepository ]); } - public function listCurrencies(): array - { - $this->debug?->add('db.listCurrencies.start'); - $stmt = $this->pdo->query( - 'SELECT * FROM ' . $this->table('currencies') . ' WHERE ' . ($this->driver === 'pgsql' ? 'is_active = TRUE' : 'is_active = 1') . ' ORDER BY sort_order ASC, code ASC' - ); - $rows = $this->normalizeRows($stmt->fetchAll() ?: []); - $this->debug?->add('db.listCurrencies.end', ['rows' => count($rows)]); - return $rows; - } - - public function listCurrencyAliases(): array - { - $stmt = $this->pdo->query( - 'SELECT - a.alias_code, - a.currency_code, - c.name AS currency_name, - a.created_at - FROM ' . $this->table('currency_aliases') . ' a - INNER JOIN ' . $this->table('currencies') . ' c ON c.code = a.currency_code - ORDER BY a.alias_code ASC' - ); - return $this->normalizeRows($stmt->fetchAll() ?: []); - } - - public function resolveCurrencyCode(string $code): ?array - { - $normalizedCode = strtoupper(trim($code)); - if ($normalizedCode === '') { - return null; - } - - $currencyStmt = $this->pdo->prepare('SELECT * FROM ' . $this->table('currencies') . ' WHERE code = :code LIMIT 1'); - $currencyStmt->execute(['code' => $normalizedCode]); - $currency = $currencyStmt->fetch(); - if (is_array($currency)) { - return [ - 'input_code' => $normalizedCode, - 'code' => $normalizedCode, - 'matched_via' => 'code', - 'currency' => $this->normalizeRow($currency), - ]; - } - - if (!$this->tableExists('currency_aliases')) { - return null; - } - - $aliasStmt = $this->pdo->prepare( - 'SELECT - a.alias_code, - a.currency_code, - c.name AS currency_name, - c.symbol AS currency_symbol, - c.is_active, - c.sort_order - FROM ' . $this->table('currency_aliases') . ' a - INNER JOIN ' . $this->table('currencies') . ' c ON c.code = a.currency_code - WHERE a.alias_code = :alias_code - LIMIT 1' - ); - $aliasStmt->execute(['alias_code' => $normalizedCode]); - $alias = $aliasStmt->fetch(); - if (!is_array($alias)) { - return null; - } - - return [ - 'input_code' => $normalizedCode, - 'code' => (string) $alias['currency_code'], - 'matched_via' => 'alias', - 'alias_code' => (string) $alias['alias_code'], - 'currency' => $this->normalizeRow([ - 'code' => $alias['currency_code'], - 'name' => $alias['currency_name'], - 'symbol' => $alias['currency_symbol'] ?? null, - 'is_active' => $alias['is_active'] ?? 1, - 'sort_order' => $alias['sort_order'] ?? 1000, - ]), - ]; - } - - public function saveCurrencyAlias(string $aliasCode, string $currencyCode): array - { - $normalizedAlias = strtoupper(trim($aliasCode)); - $normalizedCurrency = strtoupper(trim($currencyCode)); - - $stmt = $this->pdo->prepare($this->driver === 'pgsql' - ? 'INSERT INTO ' . $this->table('currency_aliases') . ' (alias_code, currency_code) - VALUES (:alias_code, :currency_code) - ON CONFLICT (alias_code) DO UPDATE SET currency_code = EXCLUDED.currency_code - RETURNING *' - : 'INSERT INTO ' . $this->table('currency_aliases') . ' (alias_code, currency_code) - VALUES (:alias_code, :currency_code) - ON DUPLICATE KEY UPDATE currency_code = VALUES(currency_code)' - ); - $stmt->execute([ - 'alias_code' => $normalizedAlias, - 'currency_code' => $normalizedCurrency, - ]); - - if ($this->driver === 'pgsql') { - $row = $stmt->fetch(); - return is_array($row) ? $this->normalizeRow($row) : ['alias_code' => $normalizedAlias, 'currency_code' => $normalizedCurrency]; - } - - return ['alias_code' => $normalizedAlias, 'currency_code' => $normalizedCurrency]; - } - - public function saveCurrency(array $currency): void - { - $this->debug?->add('db.saveCurrency.start', ['code' => $currency['code'] ?? null]); - $stmt = $this->pdo->prepare($this->driver === 'pgsql' - ? 'INSERT INTO ' . $this->table('currencies') . ' (code, name, symbol, is_active, is_crypto, sort_order) - VALUES (:code, :name, :symbol, :is_active, :is_crypto, :sort_order) - ON CONFLICT (code) DO UPDATE SET - name = EXCLUDED.name, - symbol = EXCLUDED.symbol, - is_active = EXCLUDED.is_active, - is_crypto = EXCLUDED.is_crypto, - sort_order = EXCLUDED.sort_order' - : 'INSERT INTO ' . $this->table('currencies') . ' (code, name, symbol, is_active, is_crypto, sort_order) - VALUES (:code, :name, :symbol, :is_active, :is_crypto, :sort_order) - ON DUPLICATE KEY UPDATE - name = VALUES(name), - symbol = VALUES(symbol), - is_active = VALUES(is_active), - is_crypto = VALUES(is_crypto), - sort_order = VALUES(sort_order)' - ); - $stmt->execute([ - 'code' => $currency['code'], - 'name' => $currency['name'], - 'symbol' => $currency['symbol'], - 'is_active' => $currency['is_active'], - 'is_crypto' => $currency['is_crypto'] ?? 0, - 'sort_order' => $currency['sort_order'], - ]); - $this->debug?->add('db.saveCurrency.end', ['code' => $currency['code'] ?? null]); - } - - public function saveCurrencies(array $currencies): int - { - if ($currencies === []) { - return 0; - } - - $this->debug?->add('db.saveCurrencies.start', ['count' => count($currencies)]); - - $statement = $this->pdo->prepare($this->driver === 'pgsql' - ? 'INSERT INTO ' . $this->table('currencies') . ' (code, name, symbol, is_active, is_crypto, sort_order) - VALUES (:code, :name, :symbol, :is_active, :is_crypto, :sort_order) - ON CONFLICT (code) DO UPDATE SET - name = EXCLUDED.name, - symbol = EXCLUDED.symbol, - is_active = EXCLUDED.is_active, - is_crypto = EXCLUDED.is_crypto, - sort_order = EXCLUDED.sort_order' - : 'INSERT INTO ' . $this->table('currencies') . ' (code, name, symbol, is_active, is_crypto, sort_order) - VALUES (:code, :name, :symbol, :is_active, :is_crypto, :sort_order) - ON DUPLICATE KEY UPDATE - name = VALUES(name), - symbol = VALUES(symbol), - is_active = VALUES(is_active), - is_crypto = VALUES(is_crypto), - sort_order = VALUES(sort_order)' - ); - - $count = 0; - $startedTransaction = false; - if (!$this->pdo->inTransaction()) { - $this->pdo->beginTransaction(); - $startedTransaction = true; - } - - try { - foreach ($currencies as $currency) { - if (!is_array($currency) || empty($currency['code'])) { - continue; - } - - $statement->execute([ - 'code' => $currency['code'], - 'name' => $currency['name'] ?? $currency['code'], - 'symbol' => $currency['symbol'] ?? $currency['code'], - 'is_active' => $currency['is_active'] ?? 1, - 'is_crypto' => $currency['is_crypto'] ?? 0, - 'sort_order' => $currency['sort_order'] ?? 1000, - ]); - $count++; - } - - if ($startedTransaction) { - $this->pdo->commit(); - } - $this->debug?->add('db.saveCurrencies.end', ['count' => $count]); - } catch (\Throwable $exception) { - if ($startedTransaction && $this->pdo->inTransaction()) { - $this->pdo->rollBack(); - } - $this->debug?->add('db.saveCurrencies.error', ['message' => $exception->getMessage()]); - throw $exception; - } - - return $count; - } - - public function ensureCurrencyCode(string $code, ?string $name = null): void - { - $normalizedCode = strtoupper(trim($code)); - if ($normalizedCode === '') { - return; - } - - $this->saveCurrency([ - 'code' => substr($normalizedCode, 0, 10), - 'name' => $name !== null && trim($name) !== '' ? trim($name) : $normalizedCode, - 'symbol' => substr($normalizedCode, 0, 8), - 'is_active' => 1, - 'is_crypto' => $this->isCryptoCode($normalizedCode) ? 1 : 0, - 'sort_order' => 1000, - ]); - } - public function tableExists(string $logicalName): bool { $tableName = $this->table($logicalName); @@ -1099,32 +874,6 @@ final class MiningRepository return ['fetch' => null, 'rates' => []]; } - $currenciesToEnsure = [ - [ - 'code' => substr($baseCurrency, 0, 10), - 'name' => $baseCurrency, - 'symbol' => substr($baseCurrency, 0, 8), - 'is_active' => 1, - 'is_crypto' => $this->isCryptoCode($baseCurrency) ? 1 : 0, - 'sort_order' => 1000, - ], - ]; - foreach (array_keys($rates) as $currencyCode) { - $normalizedCurrencyCode = strtoupper(trim((string) $currencyCode)); - if ($normalizedCurrencyCode === '') { - continue; - } - $currenciesToEnsure[] = [ - 'code' => substr($normalizedCurrencyCode, 0, 10), - 'name' => $normalizedCurrencyCode, - 'symbol' => substr($normalizedCurrencyCode, 0, 8), - 'is_active' => 1, - 'is_crypto' => $this->isCryptoCode($normalizedCurrencyCode) ? 1 : 0, - 'sort_order' => 1000, - ]; - } - $this->saveCurrencies($currenciesToEnsure); - if ($this->driver === 'pgsql') { $fetchStmt = $this->pdo->prepare( 'INSERT INTO ' . $this->table('fx_fetches') . ' ( @@ -1247,16 +996,6 @@ final class MiningRepository $provider = trim($provider) !== '' ? trim($provider) : 'currencyapi'; $fetchedAt = $this->currentUtcTimestamp(); $normalizedRates = []; - $currenciesToEnsure = [ - [ - 'code' => substr($baseCurrency, 0, 10), - 'name' => $baseCurrency, - 'symbol' => substr($baseCurrency, 0, 8), - 'is_active' => 1, - 'is_crypto' => $this->isCryptoCode($baseCurrency) ? 1 : 0, - 'sort_order' => 1000, - ], - ]; foreach ($rates as $currencyCode => $rate) { if (!is_numeric($rate)) { @@ -1269,14 +1008,6 @@ final class MiningRepository } $normalizedRates[$normalizedCurrencyCode] = (float) $rate; - $currenciesToEnsure[] = [ - 'code' => substr($normalizedCurrencyCode, 0, 10), - 'name' => $normalizedCurrencyCode, - 'symbol' => substr($normalizedCurrencyCode, 0, 8), - 'is_active' => 1, - 'is_crypto' => $this->isCryptoCode($normalizedCurrencyCode) ? 1 : 0, - 'sort_order' => 1000, - ]; } $this->debug?->add('db.saveFxFetch.start', [ @@ -1304,14 +1035,6 @@ final class MiningRepository } try { - $this->debug?->add('db.saveFxFetch.saveCurrencies.start', [ - 'currency_count' => count($currenciesToEnsure), - ]); - $this->saveCurrencies($currenciesToEnsure); - $this->debug?->add('db.saveFxFetch.saveCurrencies.end', [ - 'currency_count' => count($currenciesToEnsure), - ]); - if ($this->driver === 'pgsql') { $this->debug?->add('db.saveFxFetch.insertFetch.start', [ 'driver' => $this->driver, @@ -1459,21 +1182,10 @@ final class MiningRepository } } - public function listActiveFiatCurrencies(): array - { - $currencies = $this->listCurrencies(); - - return array_values(array_filter($currencies, static function (array $currency): bool { - $code = strtoupper((string) ($currency['code'] ?? '')); - return $code !== '' && empty($currency['is_crypto']); - })); - } - private function table(string $logicalName): string { return match ($logicalName) { 'projects' => $this->prefix . 'projects', - 'currencies' => $this->prefix . 'currencies', 'settings' => $this->prefix . 'settings', 'cost_plans' => $this->prefix . 'cost_plans', 'measurements' => $this->prefix . 'measurements', diff --git a/modules/mining-checker/src/Infrastructure/SchemaManager.php b/modules/mining-checker/src/Infrastructure/SchemaManager.php index 9cc79f3..cd4102f 100644 --- a/modules/mining-checker/src/Infrastructure/SchemaManager.php +++ b/modules/mining-checker/src/Infrastructure/SchemaManager.php @@ -213,18 +213,6 @@ final class SchemaManager $this->upgradeTargetOfferColumn(); $applied[] = 'target_offer_column'; } - if (!$this->tableExists($this->prefix . 'currency_aliases')) { - $this->ensureCurrencyAliasesTable(); - $applied[] = 'currency_aliases_table'; - } - if ($this->tableExists($this->prefix . 'currencies') && !$this->columnExists($this->prefix . 'currencies', 'is_crypto')) { - $this->upgradeCurrenciesClassificationColumns(); - $applied[] = 'currency_classification'; - } - if ($this->tableExists($this->prefix . 'currencies')) { - $this->ensureCurrencyForeignKeys(); - $applied[] = 'currency_foreign_keys'; - } if ($this->tableExists($this->prefix . 'miner_offers') && ( !$this->columnExists($this->prefix . 'miner_offers', 'base_price_amount') || !$this->columnExists($this->prefix . 'miner_offers', 'base_price_currency') || @@ -264,7 +252,6 @@ final class SchemaManager { $coreTables = [ $this->prefix . 'projects', - $this->prefix . 'currencies', $this->prefix . 'settings', $this->prefix . 'cost_plans', $this->prefix . 'measurements', @@ -335,18 +322,6 @@ final class SchemaManager $this->upgradeTargetOfferColumn(); $applied[] = 'target_offer_column'; } - if (!$this->tableExists($this->prefix . 'currency_aliases')) { - $this->ensureCurrencyAliasesTable(); - $applied[] = 'currency_aliases_table'; - } - if ($this->tableExists($this->prefix . 'currencies') && !$this->columnExists($this->prefix . 'currencies', 'is_crypto')) { - $this->upgradeCurrenciesClassificationColumns(); - $applied[] = 'currency_classification'; - } - if ($this->tableExists($this->prefix . 'currencies')) { - $this->ensureCurrencyForeignKeys(); - $applied[] = 'currency_foreign_keys'; - } if ($this->tableExists($this->prefix . 'miner_offers') && ( !$this->columnExists($this->prefix . 'miner_offers', 'base_price_amount') || !$this->columnExists($this->prefix . 'miner_offers', 'base_price_currency') || @@ -788,36 +763,6 @@ final class SchemaManager $this->ensureMeasurementRatesTable(); $this->ensurePayoutsTable(); $this->ensureMinerTables(); - $this->ensureCurrencyAliasesTable(); - } - - public function ensureCurrencyAliasesTable(): void - { - if ($this->tableExists($this->prefix . 'currency_aliases')) { - return; - } - - $table = $this->prefix . 'currency_aliases'; - $currencyTable = $this->prefix . 'currencies'; - $statements = $this->driver === 'pgsql' - ? [ - 'CREATE TABLE IF NOT EXISTS ' . $table . ' ( - alias_code VARCHAR(10) PRIMARY KEY, - currency_code VARCHAR(10) NOT NULL, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - CONSTRAINT fk_mining_currency_aliases_currency FOREIGN KEY (currency_code) REFERENCES ' . $currencyTable . '(code) ON DELETE CASCADE - )', - ] - : [ - 'CREATE TABLE IF NOT EXISTS `' . $table . '` ( - alias_code VARCHAR(10) NOT NULL PRIMARY KEY, - currency_code VARCHAR(10) NOT NULL, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - CONSTRAINT fk_mining_currency_aliases_currency FOREIGN KEY (currency_code) REFERENCES `' . $currencyTable . '`(code) ON DELETE CASCADE - )', - ]; - - $this->executeUpgradeStatements($statements, 'Schema-Upgrade fuer Waehrungs-Aliase fehlgeschlagen.'); } public function ensureMeasurementRatesTable(): void @@ -1361,7 +1306,6 @@ final class SchemaManager { return [ $this->prefix . 'projects', - $this->prefix . 'currencies', $this->prefix . 'settings', $this->prefix . 'cost_plans', $this->prefix . 'measurements', @@ -1379,7 +1323,6 @@ final class SchemaManager $this->prefix . 'payouts', $this->prefix . 'miner_offers', $this->prefix . 'purchased_miners', - $this->prefix . 'currency_aliases', ]; } @@ -1392,8 +1335,6 @@ final class SchemaManager { return [ $this->prefix . 'projects', - $this->prefix . 'currencies', - $this->prefix . 'currency_aliases', $this->prefix . 'settings', $this->prefix . 'cost_plans', $this->prefix . 'measurements',