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)
27 lines
1 KiB
TypeScript
27 lines
1 KiB
TypeScript
import { createApp } from 'vue'
|
|
import { createPinia } from 'pinia'
|
|
import { createRouter, createWebHistory } from 'vue-router'
|
|
import App from './App.vue'
|
|
import './theme.css'
|
|
|
|
import CampaignList from './components/CampaignList.vue'
|
|
import CampaignDetail from './components/CampaignDetail.vue'
|
|
import SubRulesView from './components/SubRulesView.vue'
|
|
import PostsView from './components/PostsView.vue'
|
|
import OpportunitiesView from './components/OpportunitiesView.vue'
|
|
import SignalsView from './components/SignalsView.vue'
|
|
|
|
const router = createRouter({
|
|
history: createWebHistory(),
|
|
routes: [
|
|
{ path: '/', redirect: '/signals' },
|
|
{ path: '/signals', component: SignalsView },
|
|
{ path: '/opportunities', component: OpportunitiesView },
|
|
{ path: '/campaigns', component: CampaignList },
|
|
{ path: '/campaigns/:id', component: CampaignDetail },
|
|
{ path: '/subs', component: SubRulesView },
|
|
{ path: '/posts', component: PostsView },
|
|
],
|
|
})
|
|
|
|
createApp(App).use(createPinia()).use(router).mount('#app')
|