From b624b647b4fb3be801863046b57025bfc0329cb1 Mon Sep 17 00:00:00 2001 From: mindesbunister Date: Tue, 29 Jul 2025 18:12:17 +0200 Subject: [PATCH] fix: replace in-memory storage with database persistence for AI decisions --- app/api/automation/live-decisions/route.js | 91 +++++++++++++++------ prisma/prisma/dev.db | Bin 16199680 -> 16211968 bytes 2 files changed, 66 insertions(+), 25 deletions(-) diff --git a/app/api/automation/live-decisions/route.js b/app/api/automation/live-decisions/route.js index 0a021c1..e86a9f2 100644 --- a/app/api/automation/live-decisions/route.js +++ b/app/api/automation/live-decisions/route.js @@ -1,12 +1,57 @@ import { NextResponse } from 'next/server' +import { PrismaClient } from '@prisma/client' -// In-memory store for live trading decisions and risk management blocks -let liveDecisions = [] -let maxDecisions = 10 // Keep last 10 decisions +const prisma = new PrismaClient() export async function GET() { try { - // Return the most recent decisions with full context + // Get recent AI decisions from database (last 10) + const decisions = await prisma.ai_analysis_sessions.findMany({ + where: { + // Get sessions with actual analysis data + lastAnalysisData: { + not: null + } + }, + orderBy: { + createdAt: 'desc' + }, + take: 10, + select: { + id: true, + symbol: true, + confidence: true, + lastAnalysisData: true, + createdAt: true, + sessionId: true + } + }) + + // Transform database records to match expected format + const liveDecisions = decisions.map(session => { + let analysisData = {} + try { + analysisData = JSON.parse(session.lastAnalysisData || '{}') + } catch (e) { + analysisData = {} + } + + return { + type: 'AI_DECISION', + action: analysisData.recommendation?.toUpperCase() || 'HOLD', + symbol: session.symbol, + blocked: !(analysisData.recommendation?.toLowerCase().includes('buy') || analysisData.recommendation?.toLowerCase().includes('sell')), + executed: false, // Always false for analysis decisions + confidence: session.confidence || analysisData.confidence || 0, + entryPrice: analysisData.entry?.price || analysisData.currentPrice || 0, + stopLoss: analysisData.stopLoss?.price || analysisData.stopLoss || null, + takeProfit: analysisData.takeProfits?.tp1?.price || analysisData.takeProfit || null, + reasoning: analysisData.reasoning || analysisData.summary || 'AI market analysis', + timestamp: session.createdAt.toISOString(), + sessionId: session.sessionId + } + }) + const response = { success: true, decisions: liveDecisions, @@ -26,31 +71,27 @@ export async function GET() { export async function POST(request) { try { - const decision = await request.json() + const data = await request.json() - // Add timestamp if not provided - if (!decision.timestamp) { - decision.timestamp = new Date().toISOString() - } - - // Add to the beginning of the array (most recent first) - liveDecisions.unshift(decision) - - // Keep only the last maxDecisions - if (liveDecisions.length > maxDecisions) { - liveDecisions = liveDecisions.slice(0, maxDecisions) - } - - console.log('📊 Live decision recorded:', { - type: decision.type, - action: decision.action, - blocked: decision.blocked, - confidence: decision.confidence + // Store AI decision in database for persistence + await prisma.ai_analysis_sessions.create({ + data: { + id: `live_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, + symbol: data.symbol || 'SOLUSD', + confidence: data.confidence || 0, + lastAnalysisData: JSON.stringify(data), + sessionId: data.sessionId || `session_${Date.now()}`, + createdAt: new Date() + } }) - return NextResponse.json({ success: true, total: liveDecisions.length }) + return NextResponse.json({ + success: true, + message: 'Decision stored persistently', + timestamp: new Date().toISOString() + }) } catch (error) { - console.error('❌ Live decisions POST error:', error) + console.error('❌ Error storing live decision:', error) return NextResponse.json( { success: false, error: error.message }, { status: 500 } diff --git a/prisma/prisma/dev.db b/prisma/prisma/dev.db index bbd0ebefe5aa1e88a6e4eda1f05866ddfe865297..f5be870640188183369791c26f76290dec3f4e64 100644 GIT binary patch delta 3086 zcmZwIdt6j?769t1`dnmfKt!YK=nzcb;+e2*_2SeE0{nVZT%h=EU@xA|?dw=JibLX6? z@9$ODclW7VC#n);ve5Ny@iT;k20#!H^EGC~T%WQ0_NG=wP# zHz3@IFcl#kAp_wz2u1`Gf*HYrU`4PYhzNEB2SO%77Q!@y=?FI=+>9^-!HF;v;kO90 z5PpX+8(|K@T!d_dc?h>4%tu&&un=Jp!eRs$!mS9mAuK_-9pMgyr3lLq?nJl?;ckR` z5SAm{i;#nmi@^QKLs)^3k5GV6h_Di&2w@dMF~VwuH3(}FN)SpB)*+N3lp|CiR3cO% z+=s9pp&FqEp%&qOga;5FM5se}2w?+4JwgLQBSI5GGXf%PL})>H7~v6wM-et5Y)1G! z!ea8f)pR>15Bc=h!axJbQt?$X;SE zv)ybDdxiax?PagBF7_w3kL_m%*g>hUMoLu+50a{0I-pb(DzfRddTEvKsoL*UMF0_=--F{>Pm1-gzWIx}xYcXoMRmB&at{7kZy3 zk>gdKc)nJ8;#%ee^|C(pIs1b3v$O0=_D}W|`=EZQ@XZ<^KSjiR(yhIG=UcCTF^*RIQYX?vSj zC8yJ$h$#9$78pLlRNs7l6G$M=5KU+H@Yt#bo=DpA%Xmor(~KT%}GtC z{19#SIj+x^Z&3~@Pbxc=wMv(!R^!s7%2Ql=_?RGe1-s6MUUBM%q8Q|wVRshiYy z3&(}W6?dymLYXi(@Td?cyR0w;&XJu8jHOZ-yd&T&H$o;OeaHF8Fq_$8GFlzERfR{%XBcak|7#t9k{6HH0^nyK6P|~qC-yXX`nwLL#LB(g-Y*tHV zuFaNLQdOAg$Q0?=!rswa3@s(agY1%2Qv5v~49FGIWI~#xi64sN_9P5N(4_pqFkvyZ zRdyQae5(-AQj;*mE=x5D!<%yy(*xY3t{+}Q54&fENMXiDACpV*&giWQ|I>yD9u14p zViN7SW_#h<_2z=IS}|?(Fn`FL=@2vRxizNJl|==GnI&TCwUEOsTEtw3rS$&N^()HF z;^b=~yWJ|w0N~yj2jI}CtHRycLb^AMpHb$MM+#~6Ho8sll<{D2N z-J1AplAeng|1^Dg=CKs&AMo19F)*yBB{iEP$+de|JM|n{qNCPr-SadiG0SMnG8)O) z{9XnXc!wJ)aQ64%!QSxG!j7eUZ3|nB8Z1m*0c06z7=~J}pHid-=vDe|kX{86}gcR6j4h@q3NRKZ@8#tAFC& zIPbf71HspaKB1nKkuxNhs0fhLmNaz@wN6ppN=Zc_` zHfVjf3DmzcHHLJj^oz*VtInbBAi0u`PYr#G+W^*e**S38*aa|g#y z3FWoT80(<^=K(5OwLZ^QRm#~({+>>!?x?^-ay=0|+27cW9iJ&5AlEbxe~%ljHEhOdk9 zm7nq#RsO!enE`@b7Ti1`O|vJ!q}VS=`u;`9g0i{R!y}&d#^`j6pMGkK-gl>ecNr)= zu9*iT`HkdvHi;>!*&P9>2 z{ZJH@P308-I`u(V$WmY50)ONB7VvPVj1G60Kgal8MqOH1HkPGFJ90J4Xe~XeMm4XH zdxEYNWY4nMGpyA0>GE{?_k@uKDym-2J@cK2_9r?K&C4N~8nT~D8cQ^8Gg8-^bC=P^ zyg>tPt(hK4-HEnjay~Syqq0(4F7@nNGFFqyUz44TN3){I`Icub6(1fBp+iH9{S_T> z`V$>+az#nkDjL6MNk4n=E-EV;)RX1uu1In|{=hbR_29g*<40GaJsTu0gxhx9cf?hFwqn7sLwNXaE2J delta 1474 zcmXZbX;9T=6bA7Bb{AH;Y^I2UTAjB~_l zTDLh>32A!lQV=>}5GG*}4#G*e2saT#1QQ`dC=o`46Wxdi!b3z7QA9KmL&Or@iR*|S zL{B1)=taa6y@@_V0+C4cCHfKliR+0Qh$JGJ7(fgpZX^Z~HxV}zw-C1yDa38W?ZjXr zl^8+{C591q5O)&8i4nwI#N9+1F_O54xR*#L?juGK8N~fWCNY|LfOwF2h_JIZ;8p zM7&JALcB^WCsq(EiPwlqqKa5WR1>R-*NHWRBGwXb5N{Iei1ow<;w@q$QA51lfZF`| zDlO6HapY-Q@D^3Ipf*NrJGRqfI~LUL($z{=SGY5^Uekh3T)V4iFRB%r#AdNYY!&Z_ zZDPCFA$E#7Q7_&VyToqsp4cPa7axcQ(P+09*-0*ap>mYi4eCINoo?ot8I4QrFheg= z;d5H&R+N_6Vz1aI_KOe2N8)2~KpYfJ;*dBjJ`qR6r{Xj5xi~7m5XVHb_);7fE#fQj zwfIJy5Z{XLM638-{2+c5KZ&31(z0Jl7rA{_s22Dy4WVu4OsA%WA3ZzI{?}}aa_b{h zcxYR)TDbW@WJP9Zn`jrmij(4$I4#bI-^B0Y4{=ufDb9%wabEl-E{KbEW~g^xS(ww- za1sf|ubW*`?H#JC)++B} zb$pfAV@cIyb!vk@T1~9-MySK}xzXy<2EP^97OR3`T^`%1yi45WHQw@?zZ+{V8BGzv z+9a(-3yOF9+|BM0K!`vDE6ZK%&T=OiX+~@yirMPA>S}e>=@<1Qfzi0i zT-o|MeYTnHO3_E_2|)+7D_V=05|p84p>urje&fuwwEyR|LvlN>>gx35&RErFN@rxC zyI(brGy**-X0WhGs)?9o#?&pVV)@ABxWs&iyPOyD@GqA82^d`C2t1Cp zTPplR)`nPCofZ}v+{=}0*`9>m>kM1U8HTm2=t8_2+jmnx)m-6^vd{Lv(lg{gMyYml