# Ghost Node — Session Memory > **What belongs here:** Current architecture state, key gotchas, reusable patterns, dev paths. > **What does NOT belong here:** Session history (→ PROGRESS.md or ARCHIVE.md). > > ### ⚠️ MD Update Rule — DYNAMIC, NOT STATIC > Only update the MD file(s) whose content was actually touched this session. > Do NOT update all files after every task. Each file gets only what is relevant to it. > - Update **this file** only when a new reusable gotcha, pattern, or architecture decision was made. > - Update **PROGRESS.md** whenever any code file was changed. > - Update **CLAUDE.md** only if API endpoints, DB schema, config keys, or architecture changed. > - Move old PROGRESS.md session entries to **ARCHIVE.md** when they're no longer active context. --- ## Project Identity - Ghost Node International Auction Sniper v2.7 - Owner: Abbas, Baghdad, Iraq - Path: `C:\Users\Abbas\Documents\Downloads\ClaudeAuction2\` - Backend: Python FastAPI (worker.py, 5000+ lines), port 8000 - NOT a git repository --- ## Frontend Stack (Current — Session 16, fully migrated) - Location: `frontend/` directory - Next.js 16.1.6, React 19, TypeScript, Tailwind CSS v4 (**NOT v3**) - **Tailwind v4**: CSS variables via `@theme {}` in `globals.css` — NO `tailwind.config.ts` - **Session 27 redesign**: CSS prefix changed from `ghost-*` to `g-*`. Colors: `--color-g-base` (#050510), `--color-g-green` (#00e87b), `--color-g-cyan` (#06b6d4), etc. Classes: `bg-g-base`, `text-g-green`. Components: `.g-card`, `.g-card-glow`, `.g-btn`, `.g-btn-primary`, `.g-badge`, `.g-table`, `.glass`, `.glass-strong`, `.gradient-text`, `.gradient-accent`. Backward compat aliases (`.card-panel`, `.btn-ghost`, `.btn-danger`, `.page-title`, `.page-subtitle`) still work. - `output: 'export'` in next.config.ts → static build at `frontend/out/` - Node.js: default installer `C:\Program Files\nodejs\` (on PATH). Alternative: portable at `C:\Users\Abbas\AppData\Local\nodejs-portable\node-v22.14.0-win-x64\` ### Key Architecture Decisions - SSE route disabled for static build (`app/api/stream/route.ts.disabled`) - All API files use `http://localhost:8000` as BASE (full URL, not relative) - FastAPI serves Next.js static build when `frontend/out/` exists - `if _frontend_out.exists():` guard is safe — `dashboard.html` still works without out/ dir - **SPA routing**: `app.mount("/_next", ...)` for assets only + `@app.get("/{full_path:path}")` catch-all for SPA routing. Never use `app.mount("/", StaticFiles(html=True))` — it shadows all explicit routes ### File Structure ``` frontend/ ├── app/ │ ├── ai-log/page.tsx │ ├── dashboard/page.tsx │ ├── keywords/page.tsx │ ├── listings/page.tsx │ ├── settings/page.tsx │ ├── sites/page.tsx │ ├── globals.css (Tailwind v4 @theme, cyberpunk palette, btn-ghost, btn-danger) │ ├── layout.tsx │ ├── page.tsx (redirects to /dashboard) │ └── providers.tsx ('use client' QueryClientProvider) ├── components/ │ ├── ai-log/ (AILogCard, AILogFeed) │ ├── dashboard/ (StatsGrid, ActivityLog) │ ├── keywords/ (KeywordRow, KeywordsTable — dnd-kit, ScoringRulesPanel) │ ├── layout/ (Header, Nav, StatusBar) │ ├── listings/ (ListingRow, ListingsTable, ListingDetailPanel, ImageGallery) │ └── sites/ (SiteRow, SitesTable — dnd-kit) ├── hooks/ (useSSE, useListings, useCountdown, useKeywords, useSites) ├── lib/ │ ├── api/ (listings, keywords, sites, config, engine, system, ai, scoring-rules) │ ├── types.ts │ └── utils.ts (cn, formatUptime) ├── store/ (engineStore, settingsStore) ├── out/ (static build — served by FastAPI) └── vitest.config.ts (has @/ alias resolution) ``` ### Tests (21 passing) - theme.test.ts (2), types.test.ts (4), engineStore.test.ts (3) - listings-api.test.ts (3), useCountdown.test.ts (2) - StatsGrid.test.tsx (1), StatusBar.test.tsx (3), ListingRow.test.tsx (3) --- ## Dev Paths & Commands ### Node.js - **Default installer** (`C:\Program Files\nodejs\`): usually on system PATH — open new terminal and run `node --version`; no manual PATH needed. - **Portable** (if used): set PATH in each shell before `npx`/`npm`: - PowerShell: `$env:PATH = "C:\Users\Abbas\AppData\Local\nodejs-portable\node-v22.14.0-win-x64;$env:PATH"` - Bash: `export PATH="/c/Users/Abbas/AppData/Local/nodejs-portable/node-v22.14.0-win-x64:$PATH"` ### Common Commands ```bash # Start backend python worker.py # port 8000 # Frontend build (from project root) export PATH="..." && npm run build --prefix frontend # Run tests (from project root) export PATH="..." && cd frontend && npx vitest run # Combined build + test export PATH="..." && cd frontend && npx vitest run && npm run build ``` --- ## Key Gotchas (Never Forget These) ### Python / Backend - **`threading.Event` not `asyncio.Event`** for cross-thread signalling — asyncio.Event is not thread-safe - **SQLite `enabled` field**: Store as `int` (1/0), never `bool` — `filter(enabled==1)` breaks on Python `True` - **JS in f-strings**: Use backtick template literals, never apostrophes — breaks Python f-string parsing - **`db.flush()` before `db.commit()`**: SQLite WAL locking requires this - **`calculate_attribute_score()` opens own DB session** — don't call inside an already-open session loop - **`closing_alerts_sent`**: JSON list — always `json.loads` + append, never overwrite ### FastAPI Routing - **NEVER `app.mount("/", StaticFiles(html=True))`** with explicit routes you want to preserve — the root mount captures ALL paths. SPA fallback returns 200+index.html for unknown paths, shadowing `@app.get("/legacy")` etc. - **Fix**: `app.mount("/_next", ...)` for assets + `@app.get("/{full_path:path}")` explicit catch-all ### API Format - **`/api/config` GET** returns flat `{key: value}` dict, NOT `Config[]` array - **`/api/config` POST** expects flat dict — not `[{key, value}]` array - Frontend `fetchConfig()` must call `.then(data => setConfig(data))` directly — no `.map()` ### Frontend - **SSE disabled in static export** — `EventSource('/api/stream')` always 404s. Use HTTP polling instead - **`createPortal` needs SSR guard** — `document.body` unavailable during Next.js SSR. Use `useEffect(() => setMounted(true), [])` before rendering portal ### HiBid - **Apollo cache**: Search results pages have 0 Lot entries — images only from detail pages - **Image dedup**: Use full URL including query string (HiBid CDN uses same path `img.axd` for all images, differentiated only by query params) --- ## Pending Work (Priority Order) 1. **Redis Cache Layer** — replace in-memory Python dicts; survives restarts; pub/sub for live dashboard 2. **Docker Compose** — one-command startup with PostgreSQL + Redis 3. **Lot Description Extraction** — AI only sees title; detail page descriptions → better AI-first accuracy. Needs `JS_DETAIL_TEXT` + `description` column on Listing + pass to `_ai_analyze()`