Commit graph

5 commits

Author SHA1 Message Date
a863960266 feat: structured logging, frontend error toasts, stats bar (#14 #15 #16)
#14 — Structured logging
- app/core/logging_config.py: configure_logging() sets stdout handler
  with timestamped format; called at import time in main.py
- Global FastAPI exception_handler logs 500s with full traceback
- opportunities.py: logger added; create/approve/mark-posted/dismiss
  each emit an info line so failures are traceable

#15 — Frontend error handling
- frontend/src/composables/useToast.ts: shared toast composable
  (error/success/info, auto-dismiss, module-level singleton)
- frontend/src/components/ToastList.vue: fixed-position overlay,
  theme-aware, accessible (role=alert, aria-live=polite)
- OpportunitiesView: all 6 async actions have catch + toast.error()
- CampaignDetail: onMounted + all 6 mutation functions wrapped

#16 — Aggregate stats
- app/api/endpoints/stats.py: GET /api/v1/stats — single DB pass
  via GROUP BY; returns posts totals, 7-day count, top communities,
  platform breakdown, and opportunity queue counts
- frontend/src/components/StatsBar.vue: slim header bar above
  router-view; chips for posts ok/failed/week, queue pending/approved/
  posted, top community; hides gracefully on API error
2026-05-25 15:02:15 -07:00
c7c57fe4e5 feat: opportunities UI improvements, MCP tools, session refresh, migrations 013-014 2026-04-27 07:49:34 -07:00
add5475d50 feat: add Directus blog post publisher and MCP tool
- app/services/directus.py: Directus CMS client using docker run
  curlimages/curl on website_cf-internal network; supports static admin
  token with fresh JWT login fallback; get/publish/update blog_posts
- app/api/endpoints/blog.py: POST /api/v1/blog (publish), GET /slug,
  PATCH /id endpoints
- app/api/routes.py: register blog router
- app/core/config.py: add directus_url/token/email/password/network settings
- mcp/server.js: add publish_blog_post and get_blog_post MCP tools

Key gotcha: Directus filter[field][_eq] brackets must be percent-encoded
when passed as a curl CLI URL arg — raw brackets cause curl to exit
non-zero with empty stderr.
2026-04-26 14:14:35 -07:00
a6ea0b9c58 feat(#7,#10): signal crawler -- Reddit + Lemmy community monitoring
Implements the full signal detection pipeline:

Backend:
- app/services/lemmy/client.py: async Lemmy API v3 client, community@instance
  addressing, integer cursor dedup, normalised post dicts
- app/services/scraper.py: platform-agnostic scraper; Reddit (.json API,
  fullname cursor) + Lemmy (integer ID cursor); keyword/regex/all match modes,
  min_score gate, NormalizedPost shape, upsert dedup via UNIQUE post_id
- app/api/endpoints/signals.py: CRUD for signal_rules + signals queue;
  POST /signals/scrape manual trigger; scrape-state viewer
- migrations 010-012: signal_rules, signals, signal_scrape_state tables
- scheduler: interval job every 30 min (scraper_enabled=True in config)
- Fixed migration collision: 007_signal_rules.sql → 010, 008 → 011, 009 → 012

Frontend:
- SignalsView.vue: signal feed with status filter (new/saved/dismissed),
  keyword chips, score/comment counts, save/dismiss actions, rules editor panel
- api.ts: SignalRule, Signal types + signalRules/signals API methods
- Nav: Signals as default landing route (replaces /campaigns default)

Closes #7 (signal extraction), closes #10 (Lemmy JSON crawler)
2026-04-22 11:00:14 -07:00
2cc85d8fc5 feat: scaffold Magpie — campaign scheduler + social posting platform
FastAPI backend (SQLite + APScheduler), Vue 3 frontend, MCP server for
Claude integration, and Docker Compose stack. Includes campaign data model
(campaigns → variants → subs), post history, sub rules, and Playwright-based
Reddit posting layer migrated from claude-bridge/reddit-poster.

Also seeds legacy campaigns (6) and sub rules (14) from reddit-poster history.

Closes #1 (scaffold), resolves migration from claude-bridge.
2026-04-21 16:51:33 -07:00