Commit graph

21 commits

Author SHA1 Message Date
6cf61663a5 chore: delete dead platforms.py and fix seed_campaigns mutation bug 2026-04-27 13:03:57 -07:00
a3932aef1e fix: handle ValueError from parse_occurrence and add edge-case occurrence tests
- Wrap parse_occurrence() call in try/except ValueError; return skipped with reason instead of crashing
- Remove redundant `or {}` guard on sub_row (already defaulted to {} via next(..., {}))
- Strengthen test_occurrence_passes assertion to check status == "success"
- Add 3 edge-case tests: occurrence="every", missing occurrence key, invalid occurrence string
2026-04-27 12:57:44 -07:00
08aa019439 feat: add occurrence check to poster before strategy dispatch
Parse the occurrence field from sub_row and skip execution when today
is not the nth weekday specified (e.g. first_sunday). Check runs after
sub_row fetch but before dupe guard. Two new tests confirm skip and
pass paths using patched date.today in app.services.poster.
2026-04-27 12:27:16 -07:00
90d30167f8 fix: add timeout and error wrapping to _find_sticky, clean up test fixture 2026-04-27 12:23:44 -07:00
e37be0935d feat: implement RedditCommentStrategy and register in platform registry
Adds RedditCommentStrategy to app/services/platforms/reddit_comment.py,
resolving thread_id via thread_url_override or _find_sticky title search,
falling back to reconstructed URL when client.comment() returns empty string.
Registers the strategy under "reddit_comment" in the platform _REGISTRY.
7 new tests confirm all execution paths: url override, title pattern lookup,
not-found error, missing-extra error, empty-URL reconstruction, dupe guard,
and registry presence. Full suite: 34/34 passing.
2026-04-27 12:00:08 -07:00
719a1d5aca fix: address code review issues in reddit_comment thread detection helpers 2026-04-27 11:55:55 -07:00
9d955b2c50 feat: add thread detection helpers to reddit_comment strategy 2026-04-27 11:36:36 -07:00
ca9b2ac0b2 feat: add is_nth_weekday() and parse_occurrence() for scheduled comment gating 2026-04-27 11:04:30 -07:00
a06582c028 feat: add store helpers and seed r/Flipping + r/cscareerquestions comment campaigns 2026-04-27 11:00:11 -07:00
9248410cf1 feat: add comment config columns to campaign_subs (thread_title_pattern, thread_url_override, occurrence) 2026-04-27 10:43:05 -07:00
81a63ab0ec refactor: dispatch poster by campaign.type via platform strategy registry
Replace hardcoded platform dispatch with get_client(campaign["type"]) so
any future campaign type (blog_post, email, etc.) routes automatically
through the strategy registry. Adds dupe-guard opt-out per strategy,
sub_row pre-fetch for extra metadata, and 5 new TDD tests (14 total).
2026-04-27 08:38:12 -07:00
de6dc645f6 feat: add platform registry with get_client() dispatch 2026-04-27 08:12:47 -07:00
38d212726e feat: add type param to store.create_campaign() (default reddit_post) 2026-04-27 08:09:41 -07:00
ae96621f6c feat: add RedditPostStrategy wrapping RedditClient.post() 2026-04-27 08:09:03 -07:00
2dd88285a2 feat: add PostingStrategy ABC and PostResult dataclass 2026-04-27 08:00:36 -07:00
e158787b59 feat: add type column to campaigns (default reddit_post) 2026-04-27 07:53:54 -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
2822d36bad feat(#9): opportunities queue — manual posting workflow UI and API
Adds the full signal-to-post pipeline for non-automated opportunities:
- SQLite migration 007: opportunities table (platform, community, thread_url,
  draft title/body, post_type, status, campaign_id, dismiss_note)
- FastAPI endpoints: GET/POST /opportunities, GET/PATCH /{id}, /{id}/approve,
  /{id}/mark-posted, /{id}/dismiss
- approve() returns auto_post_ready (Reddit) or manual_handoff (Lemmy/LinkedIn/etc)
  with clipboard-ready draft and instructions
- OpportunitiesView.vue: status-filtered queue, slide-over detail panel with
  inline draft editor, approve/dismiss actions, manual handoff copy+open flow
- Opportunities now default landing route; nav link added
- MCP tools: list_opportunities, create_opportunity, approve_opportunity,
  dismiss_opportunity, update_opportunity

Closes #9
2026-04-21 16:51:34 -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