140 lines
7.0 KiB
Plaintext
140 lines
7.0 KiB
Plaintext
# 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()`
|
|
|
|
|