diff --git a/client/components/admin/BankSyncAdminCard.jsx b/client/components/admin/BankSyncAdminCard.jsx index 38e62bb..1706f3c 100644 --- a/client/components/admin/BankSyncAdminCard.jsx +++ b/client/components/admin/BankSyncAdminCard.jsx @@ -25,12 +25,13 @@ function timeUntil(iso) { } export default function BankSyncAdminCard() { - const [config, setConfig] = useState(null); - const [loading, setLoading] = useState(true); - const [loadError, setLoadError] = useState(''); - const [saving, setSaving] = useState(false); - const [enabled, setEnabled] = useState(false); + const [config, setConfig] = useState(null); + const [loading, setLoading] = useState(true); + const [loadError, setLoadError] = useState(''); + const [saving, setSaving] = useState(false); + const [enabled, setEnabled] = useState(false); const [syncInterval, setSyncInterval] = useState(4); + const [syncDays, setSyncDays] = useState(90); useEffect(() => { api.bankSyncConfig() @@ -38,6 +39,7 @@ export default function BankSyncAdminCard() { setConfig(d); setEnabled(!!d.enabled); setSyncInterval(d.sync_interval_hours ?? 4); + setSyncDays(d.sync_days ?? 90); }) .catch(err => setLoadError(err.message || 'Failed to load bank sync config')) .finally(() => setLoading(false)); @@ -45,16 +47,22 @@ export default function BankSyncAdminCard() { const handleSave = async () => { const hours = parseFloat(syncInterval); + const days = parseInt(syncDays, 10); if (!Number.isFinite(hours) || hours < 0.5 || hours > 168) { toast.error('Sync interval must be between 0.5 and 168 hours.'); return; } + if (!Number.isFinite(days) || days < 1 || days > 730) { + toast.error('Transaction history must be between 1 and 730 days.'); + return; + } setSaving(true); try { - const result = await api.setBankSyncConfig({ enabled, sync_interval_hours: hours }); + const result = await api.setBankSyncConfig({ enabled, sync_interval_hours: hours, sync_days: days }); setConfig(result); setEnabled(!!result.enabled); setSyncInterval(result.sync_interval_hours ?? 4); + setSyncDays(result.sync_days ?? 90); toast.success('Bank sync settings saved.'); } catch (err) { toast.error(err.message || 'Failed to update bank sync setting.'); @@ -83,7 +91,9 @@ export default function BankSyncAdminCard() { ); } - const changed = enabled !== !!config?.enabled || parseFloat(syncInterval) !== config?.sync_interval_hours; + const changed = enabled !== !!config?.enabled + || parseFloat(syncInterval) !== config?.sync_interval_hours + || parseInt(syncDays, 10) !== config?.sync_days; const worker = config?.worker; return ( @@ -135,6 +145,28 @@ export default function BankSyncAdminCard() { + {/* Transaction history lookback */} +
+
+

Transaction history

+

+ How far back to fetch on first connect. Re-syncs only fetch recent activity. +

+
+
+ setSyncDays(e.target.value)} + className="w-20 text-sm text-right" + /> + days +
+
+ {/* Auto-sync worker status */} {config?.enabled && worker && (
diff --git a/docs/top_200_us_subscriptions.csv b/docs/top_200_us_subscriptions.csv new file mode 100644 index 0000000..0d5ef20 --- /dev/null +++ b/docs/top_200_us_subscriptions.csv @@ -0,0 +1,201 @@ +Rank,Service,Category,Subcategory,Subscription_or_Plan,US_Availability,Website,Source_URL,Ranking_Basis +1,Netflix,Video Streaming,SVOD,Netflix subscription,United States,https://www.netflix.com/,https://www.netflix.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +2,Amazon Prime Video,Video Streaming,SVOD / Prime benefit,Prime Video / Amazon Prime,United States,https://www.primevideo.com/,https://www.primevideo.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +3,Hulu,Video Streaming,SVOD / Live TV,Hulu,United States,https://www.hulu.com/,https://www.hulu.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +4,Disney+,Video Streaming,SVOD,Disney+,United States,https://www.disneyplus.com/,https://www.disneyplus.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +5,Max,Video Streaming,SVOD,Max,United States,https://www.max.com/,https://www.max.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +6,Peacock,Video Streaming,SVOD / live sports,Peacock Premium,United States,https://www.peacocktv.com/,https://www.peacocktv.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +7,Paramount+,Video Streaming,SVOD / live sports,Paramount+,United States,https://www.paramountplus.com/,https://www.paramountplus.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +8,Apple TV+,Video Streaming,SVOD,Apple TV+,United States,https://tv.apple.com/,https://tv.apple.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +9,YouTube Premium,Video Streaming,Ad-free video / music bundle,YouTube Premium,United States,https://www.youtube.com/premium,https://www.youtube.com/premium,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +10,ESPN+,Sports Streaming,Live sports,ESPN+,United States,https://plus.espn.com/,https://plus.espn.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +11,YouTube TV,Live TV Streaming,Virtual MVPD,YouTube TV,United States,https://tv.youtube.com/,https://tv.youtube.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +12,Sling TV,Live TV Streaming,Virtual MVPD,Sling TV,United States,https://www.sling.com/,https://www.sling.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +13,Fubo,Live TV Streaming,Sports-focused live TV,Fubo,United States,https://www.fubo.tv/,https://www.fubo.tv/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +14,DirecTV Stream,Live TV Streaming,Virtual MVPD,DirecTV Stream,United States,https://streamtv.directv.com/,https://streamtv.directv.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +15,Philo,Live TV Streaming,Entertainment live TV,Philo,United States,https://www.philo.com/,https://www.philo.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +16,Starz,Video Streaming,Premium network,Starz,United States,https://www.starz.com/,https://www.starz.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +17,MGM+,Video Streaming,Premium network,MGM+,United States,https://www.mgmplus.com/,https://www.mgmplus.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +18,AMC+,Video Streaming,Premium network bundle,AMC+,United States,https://www.amcplus.com/,https://www.amcplus.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +19,BET+,Video Streaming,Black entertainment,BET+,United States,https://www.bet.plus/,https://www.bet.plus/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +20,Crunchyroll,Video Streaming,Anime,Crunchyroll Premium,United States,https://www.crunchyroll.com/,https://www.crunchyroll.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +21,HIDIVE,Video Streaming,Anime,HIDIVE,United States,https://www.hidive.com/,https://www.hidive.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +22,Shudder,Video Streaming,Horror,Shudder,United States,https://www.shudder.com/,https://www.shudder.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +23,Acorn TV,Video Streaming,British/International TV,Acorn TV,United States,https://acorn.tv/,https://acorn.tv/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +24,BritBox,Video Streaming,British TV,BritBox,United States,https://www.britbox.com/,https://www.britbox.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +25,The Criterion Channel,Video Streaming,Classic/arthouse film,Criterion Channel,United States,https://www.criterionchannel.com/,https://www.criterionchannel.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +26,MUBI,Video Streaming,Curated film,MUBI,United States,https://mubi.com/,https://mubi.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +27,Discovery+,Video Streaming,Lifestyle / factual,Discovery+,United States,https://www.discoveryplus.com/,https://www.discoveryplus.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +28,Hallmark+,Video Streaming,Family/romance,Hallmark+,United States,https://www.hallmarkplus.com/,https://www.hallmarkplus.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +29,PBS Passport,Video Streaming,Public television,PBS Passport,United States,https://www.pbs.org/passport/,https://www.pbs.org/passport/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +30,MagellanTV,Video Streaming,Documentaries,MagellanTV,United States,https://www.magellantv.com/,https://www.magellantv.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +31,Curiosity Stream,Video Streaming,Documentaries,Curiosity Stream,United States,https://curiositystream.com/,https://curiositystream.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +32,Nebula,Video Streaming,Creator video,Nebula,United States,https://nebula.tv/,https://nebula.tv/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +33,WOW Presents Plus,Video Streaming,LGBTQ+ entertainment,WOW Presents Plus,United States,https://www.wowpresentsplus.com/,https://www.wowpresentsplus.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +34,ViX Premium,Video Streaming,Spanish-language entertainment,ViX Premium,United States,https://vix.com/,https://vix.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +35,FloSports,Sports Streaming,Niche live sports,FloSports,United States,https://www.flosports.tv/,https://www.flosports.tv/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +36,DAZN,Sports Streaming,Combat sports / live sports,DAZN,United States,https://www.dazn.com/,https://www.dazn.com/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +37,MLB.TV,Sports Streaming,Baseball,MLB.TV,United States,https://www.mlb.com/live-stream-games/subscribe,https://www.mlb.com/live-stream-games/subscribe,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +38,NBA League Pass,Sports Streaming,Basketball,NBA League Pass,United States,https://www.nba.com/watch/league-pass-stream,https://www.nba.com/watch/league-pass-stream,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +39,NHL Power Play on ESPN+,Sports Streaming,Hockey,NHL Power Play,United States,https://www.espn.com/espnplus/catalog/nhl,https://www.espn.com/espnplus/catalog/nhl,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +40,NFL+,Sports Streaming,Football,NFL+,United States,https://www.nfl.com/plus/,https://www.nfl.com/plus/,U.S. SVOD prominence; Parks/industry lists where applicable; curated within category +41,Spotify Premium,Music & Audio,Music streaming,Spotify Premium,United States,https://www.spotify.com/premium/,https://www.spotify.com/premium/,U.S. paid audio and audiobook prominence; curated within category +42,Apple Music,Music & Audio,Music streaming,Apple Music,United States,https://www.apple.com/apple-music/,https://www.apple.com/apple-music/,U.S. paid audio and audiobook prominence; curated within category +43,Amazon Music Unlimited,Music & Audio,Music streaming,Amazon Music Unlimited,United States,https://music.amazon.com/,https://music.amazon.com/,U.S. paid audio and audiobook prominence; curated within category +44,Pandora Premium,Music & Audio,Music streaming / radio,Pandora Premium,United States,https://www.pandora.com/upgrade,https://www.pandora.com/upgrade,U.S. paid audio and audiobook prominence; curated within category +45,SiriusXM,Music & Audio,Satellite radio / streaming,SiriusXM,United States,https://www.siriusxm.com/,https://www.siriusxm.com/,U.S. paid audio and audiobook prominence; curated within category +46,TIDAL,Music & Audio,Hi-fi music streaming,TIDAL,United States,https://tidal.com/,https://tidal.com/,U.S. paid audio and audiobook prominence; curated within category +47,Qobuz,Music & Audio,Hi-res music streaming,Qobuz,United States,https://www.qobuz.com/us-en/music/streaming/offers,https://www.qobuz.com/us-en/music/streaming/offers,U.S. paid audio and audiobook prominence; curated within category +48,SoundCloud Go+,Music & Audio,Music / creators,SoundCloud Go+,United States,https://soundcloud.com/go,https://soundcloud.com/go,U.S. paid audio and audiobook prominence; curated within category +49,Deezer,Music & Audio,Music streaming,Deezer Premium,United States,https://www.deezer.com/us/offers,https://www.deezer.com/us/offers,U.S. paid audio and audiobook prominence; curated within category +50,iHeartRadio Plus,Music & Audio,Radio / music,iHeartRadio Plus,United States,https://www.iheart.com/plus/,https://www.iheart.com/plus/,U.S. paid audio and audiobook prominence; curated within category +51,Audible,Audiobooks,Audiobooks,Audible Premium Plus,United States,https://www.audible.com/,https://www.audible.com/,U.S. paid audio and audiobook prominence; curated within category +52,Spotify Audiobooks,Audiobooks,Audiobooks,Spotify Audiobooks access,United States,https://www.spotify.com/us/audiobooks/,https://www.spotify.com/us/audiobooks/,U.S. paid audio and audiobook prominence; curated within category +53,Everand,Audiobooks & Ebooks,Books / audiobooks,Everand,United States,https://www.everand.com/,https://www.everand.com/,U.S. paid audio and audiobook prominence; curated within category +54,Scribd,Documents & Ebooks,Documents / books,Scribd,United States,https://www.scribd.com/,https://www.scribd.com/,U.S. paid audio and audiobook prominence; curated within category +55,Kindle Unlimited,Ebooks,Ebooks,Kindle Unlimited,United States,https://www.amazon.com/kindle-dbs/hz/subscribe/ku,https://www.amazon.com/kindle-dbs/hz/subscribe/ku,U.S. paid audio and audiobook prominence; curated within category +56,Kobo Plus,Ebooks & Audiobooks,Books / audiobooks,Kobo Plus,United States,https://www.kobo.com/us/en/plus,https://www.kobo.com/us/en/plus,U.S. paid audio and audiobook prominence; curated within category +57,Libro.fm,Audiobooks,Audiobooks,Libro.fm membership,United States,https://libro.fm/,https://libro.fm/,U.S. paid audio and audiobook prominence; curated within category +58,Blinkist,Books & Learning,Book summaries,Blinkist Premium,United States,https://www.blinkist.com/,https://www.blinkist.com/,U.S. paid audio and audiobook prominence; curated within category +59,Pocket Casts Plus,Podcasts,Podcast app,Pocket Casts Plus,United States,https://pocketcasts.com/plus/,https://pocketcasts.com/plus/,U.S. paid audio and audiobook prominence; curated within category +60,Wondery+,Podcasts,Podcast network,Wondery+,United States,https://wondery.com/plus/,https://wondery.com/plus/,U.S. paid audio and audiobook prominence; curated within category +61,The New York Times,News & Magazines,National news,NYT All Access,United States,https://www.nytimes.com/subscription,https://www.nytimes.com/subscription,Major U.S. news and magazine subscriptions; curated within category +62,The Wall Street Journal,News & Magazines,Business news,WSJ Digital,United States,https://www.wsj.com/news/subscribe,https://www.wsj.com/news/subscribe,Major U.S. news and magazine subscriptions; curated within category +63,The Washington Post,News & Magazines,National news,Digital subscription,United States,https://subscribe.washingtonpost.com/,https://subscribe.washingtonpost.com/,Major U.S. news and magazine subscriptions; curated within category +64,The Atlantic,News & Magazines,Magazine,The Atlantic subscription,United States,https://www.theatlantic.com/subscribe/,https://www.theatlantic.com/subscribe/,Major U.S. news and magazine subscriptions; curated within category +65,The New Yorker,News & Magazines,Magazine,The New Yorker subscription,United States,https://www.newyorker.com/subscribe,https://www.newyorker.com/subscribe,Major U.S. news and magazine subscriptions; curated within category +66,Bloomberg.com,News & Magazines,Business news,Bloomberg Digital,United States,https://www.bloomberg.com/subscriptions,https://www.bloomberg.com/subscriptions,Major U.S. news and magazine subscriptions; curated within category +67,Financial Times,News & Magazines,Business news,FT Digital,United States,https://www.ft.com/products,https://www.ft.com/products,Major U.S. news and magazine subscriptions; curated within category +68,The Economist,News & Magazines,Global news magazine,The Economist subscription,United States,https://www.economist.com/subscribe,https://www.economist.com/subscribe,Major U.S. news and magazine subscriptions; curated within category +69,TIME,News & Magazines,Magazine,TIME subscription,United States,https://time.com/subscribe/,https://time.com/subscribe/,Major U.S. news and magazine subscriptions; curated within category +70,WIRED,News & Magazines,Technology magazine,WIRED subscription,United States,https://www.wired.com/subscribe/,https://www.wired.com/subscribe/,Major U.S. news and magazine subscriptions; curated within category +71,Consumer Reports,News & Magazines,Product reviews,Consumer Reports membership,United States,https://www.consumerreports.org/join/,https://www.consumerreports.org/join/,Major U.S. news and magazine subscriptions; curated within category +72,Politico Pro,News & Magazines,Policy intelligence,Politico Pro,United States,https://www.politicopro.com/,https://www.politicopro.com/,Major U.S. news and magazine subscriptions; curated within category +73,The Athletic,Sports Media,Sports journalism,The Athletic subscription,United States,https://theathletic.com/,https://theathletic.com/,Major U.S. news and magazine subscriptions; curated within category +74,Substack,Creator Media,Newsletter subscriptions,Substack paid subscriptions,United States,https://substack.com/,https://substack.com/,Major U.S. news and magazine subscriptions; curated within category +75,Medium,Creator Media,Publishing platform,Medium Membership,United States,https://medium.com/membership,https://medium.com/membership,Major U.S. news and magazine subscriptions; curated within category +76,Patreon,Creator Media,Creator memberships,Patreon memberships,United States,https://www.patreon.com/,https://www.patreon.com/,Major U.S. news and magazine subscriptions; curated within category +77,Apple News+,News & Magazines,News bundle,Apple News+,United States,https://www.apple.com/apple-news/,https://www.apple.com/apple-news/,Major U.S. news and magazine subscriptions; curated within category +78,Readly,News & Magazines,Magazine bundle,Readly,United States,https://us.readly.com/,https://us.readly.com/,Major U.S. news and magazine subscriptions; curated within category +79,PressReader,News & Magazines,Newspaper/magazine bundle,PressReader Premium,United States,https://www.pressreader.com/,https://www.pressreader.com/,Major U.S. news and magazine subscriptions; curated within category +80,The Information,News & Magazines,Technology/business news,The Information subscription,United States,https://www.theinformation.com/subscribe,https://www.theinformation.com/subscribe,Major U.S. news and magazine subscriptions; curated within category +81,Microsoft 365,Software & Productivity,Office suite,Microsoft 365,United States,https://www.microsoft.com/microsoft-365,https://www.microsoft.com/microsoft-365,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +82,Google One,Cloud & Storage,Cloud storage,Google One,United States,https://one.google.com/,https://one.google.com/,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +83,iCloud+,Cloud & Storage,Cloud storage,iCloud+,United States,https://www.apple.com/icloud/,https://www.apple.com/icloud/,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +84,Dropbox,Cloud & Storage,Cloud storage,Dropbox plans,United States,https://www.dropbox.com/plans,https://www.dropbox.com/plans,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +85,Box,Cloud & Storage,Cloud content management,Box plans,United States,https://www.box.com/pricing,https://www.box.com/pricing,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +86,Adobe Creative Cloud,Software & Design,Creative software,Creative Cloud,United States,https://www.adobe.com/creativecloud.html,https://www.adobe.com/creativecloud.html,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +87,Canva Pro,Software & Design,Design platform,Canva Pro,United States,https://www.canva.com/pro/,https://www.canva.com/pro/,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +88,Figma,Software & Design,Design/collaboration,Figma plans,United States,https://www.figma.com/pricing/,https://www.figma.com/pricing/,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +89,Notion,Software & Productivity,Workspace / notes,Notion Plus,United States,https://www.notion.so/pricing,https://www.notion.so/pricing,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +90,Evernote,Software & Productivity,Notes,Evernote plans,United States,https://evernote.com/compare-plans,https://evernote.com/compare-plans,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +91,Todoist,Software & Productivity,Task management,Todoist Pro,United States,https://todoist.com/pricing,https://todoist.com/pricing,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +92,Grammarly,Writing & AI,Writing assistant,Grammarly Pro,United States,https://www.grammarly.com/plans,https://www.grammarly.com/plans,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +93,ChatGPT,AI,AI assistant,ChatGPT Plus / Pro,United States,https://chatgpt.com/pricing,https://chatgpt.com/pricing,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +94,Claude,AI,AI assistant,Claude Pro,United States,https://claude.ai/upgrade,https://claude.ai/upgrade,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +95,Perplexity,AI,AI search,Perplexity Pro,United States,https://www.perplexity.ai/pro,https://www.perplexity.ai/pro,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +96,Gemini Advanced,AI,AI assistant / Google One AI,Google AI plans,United States,https://one.google.com/about/google-ai-plans/,https://one.google.com/about/google-ai-plans/,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +97,GitHub Copilot,Developer Tools,AI coding,GitHub Copilot,United States,https://github.com/features/copilot/plans,https://github.com/features/copilot/plans,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +98,Cursor,Developer Tools,AI coding,Cursor Pro,United States,https://www.cursor.com/pricing,https://www.cursor.com/pricing,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +99,Replit,Developer Tools,Cloud coding,Replit Core,United States,https://replit.com/pricing,https://replit.com/pricing,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +100,Setapp,Software & Productivity,Mac app bundle,Setapp,United States,https://setapp.com/,https://setapp.com/,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +101,1Password,Security,Password manager,1Password,United States,https://1password.com/pricing,https://1password.com/pricing,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +102,Dashlane,Security,Password manager,Dashlane,United States,https://www.dashlane.com/pricing,https://www.dashlane.com/pricing,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +103,NordVPN,Security,VPN,NordVPN,United States,https://nordvpn.com/pricing/,https://nordvpn.com/pricing/,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +104,ExpressVPN,Security,VPN,ExpressVPN,United States,https://www.expressvpn.com/,https://www.expressvpn.com/,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +105,Surfshark,Security,VPN,Surfshark,United States,https://surfshark.com/pricing,https://surfshark.com/pricing,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +106,Norton 360,Security,Device security,Norton 360,United States,https://us.norton.com/products,https://us.norton.com/products,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +107,McAfee+,Security,Device security,McAfee+,United States,https://www.mcafee.com/en-us/consumer-support/pricing.html,https://www.mcafee.com/en-us/consumer-support/pricing.html,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +108,QuickBooks Online,Finance Software,Small business accounting,QuickBooks Online,United States,https://quickbooks.intuit.com/pricing/,https://quickbooks.intuit.com/pricing/,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +109,TurboTax Live,Finance Software,Tax filing support,TurboTax Live,United States,https://turbotax.intuit.com/personal-taxes/online/live/,https://turbotax.intuit.com/personal-taxes/online/live/,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +110,YNAB,Finance Software,Budgeting,YNAB,United States,https://www.ynab.com/pricing,https://www.ynab.com/pricing,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +111,Rocket Money Premium,Finance Software,Personal finance,Rocket Money Premium,United States,https://www.rocketmoney.com/premium,https://www.rocketmoney.com/premium,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +112,Copilot Money,Finance Software,Personal finance,Copilot Money,United States,https://copilot.money/,https://copilot.money/,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +113,Calendly,Software & Productivity,Scheduling,Calendly plans,United States,https://calendly.com/pricing,https://calendly.com/pricing,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +114,Zoom Workplace,Software & Productivity,Video meetings,Zoom plans,United States,https://www.zoom.com/en/pricing/,https://www.zoom.com/en/pricing/,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +115,Slack,Software & Productivity,Team messaging,Slack Pro / Business+,United States,https://slack.com/pricing,https://slack.com/pricing,Major U.S. consumer/professional software subscriptions; app revenue and SaaS prominence where applicable; curated +116,Xbox Game Pass,Gaming,Game subscription,Xbox Game Pass,United States,https://www.xbox.com/en-US/xbox-game-pass,https://www.xbox.com/en-US/xbox-game-pass,"Major U.S. gaming, creator, and social paid memberships; curated within category" +117,PlayStation Plus,Gaming,Game subscription,PlayStation Plus,United States,https://www.playstation.com/en-us/ps-plus/,https://www.playstation.com/en-us/ps-plus/,"Major U.S. gaming, creator, and social paid memberships; curated within category" +118,Nintendo Switch Online,Gaming,Online/game library,Nintendo Switch Online,United States,https://www.nintendo.com/us/switch/online/,https://www.nintendo.com/us/switch/online/,"Major U.S. gaming, creator, and social paid memberships; curated within category" +119,Apple Arcade,Gaming,Mobile games,Apple Arcade,United States,https://www.apple.com/apple-arcade/,https://www.apple.com/apple-arcade/,"Major U.S. gaming, creator, and social paid memberships; curated within category" +120,EA Play,Gaming,Game subscription,EA Play,United States,https://www.ea.com/ea-play,https://www.ea.com/ea-play,"Major U.S. gaming, creator, and social paid memberships; curated within category" +121,Ubisoft+,Gaming,Game subscription,Ubisoft+,United States,https://www.ubisoft.com/en-us/ubisoft-plus,https://www.ubisoft.com/en-us/ubisoft-plus,"Major U.S. gaming, creator, and social paid memberships; curated within category" +122,NVIDIA GeForce NOW,Gaming,Cloud gaming,GeForce NOW,United States,https://www.nvidia.com/en-us/geforce-now/memberships/,https://www.nvidia.com/en-us/geforce-now/memberships/,"Major U.S. gaming, creator, and social paid memberships; curated within category" +123,Roblox Premium,Gaming,Creator/game currency membership,Roblox Premium,United States,https://www.roblox.com/premium/membership,https://www.roblox.com/premium/membership,"Major U.S. gaming, creator, and social paid memberships; curated within category" +124,Fortnite Crew,Gaming,Game membership,Fortnite Crew,United States,https://www.fortnite.com/fortnite-crew-subscription,https://www.fortnite.com/fortnite-crew-subscription,"Major U.S. gaming, creator, and social paid memberships; curated within category" +125,Minecraft Realms,Gaming,Private server subscription,Minecraft Realms,United States,https://www.minecraft.net/realms,https://www.minecraft.net/realms,"Major U.S. gaming, creator, and social paid memberships; curated within category" +126,Twitch Turbo,Creator & Social,Ad-free streaming,Twitch Turbo,United States,https://www.twitch.tv/turbo,https://www.twitch.tv/turbo,"Major U.S. gaming, creator, and social paid memberships; curated within category" +127,Discord Nitro,Creator & Social,Social / gaming chat,Discord Nitro,United States,https://discord.com/nitro,https://discord.com/nitro,"Major U.S. gaming, creator, and social paid memberships; curated within category" +128,X Premium,Creator & Social,Social network subscription,X Premium,United States,https://help.x.com/en/using-x/x-premium,https://help.x.com/en/using-x/x-premium,"Major U.S. gaming, creator, and social paid memberships; curated within category" +129,Snapchat+,Creator & Social,Social network subscription,Snapchat+,United States,https://www.snapchat.com/plus,https://www.snapchat.com/plus,"Major U.S. gaming, creator, and social paid memberships; curated within category" +130,TikTok Live Subscription,Creator & Social,Creator memberships,TikTok LIVE Subscription,United States,https://www.tiktok.com/live/creators/en-US/subscription/,https://www.tiktok.com/live/creators/en-US/subscription/,"Major U.S. gaming, creator, and social paid memberships; curated within category" +131,Meta Verified,Creator & Social,Creator/business verification,Meta Verified,United States,https://about.meta.com/technologies/meta-verified/,https://about.meta.com/technologies/meta-verified/,"Major U.S. gaming, creator, and social paid memberships; curated within category" +132,LinkedIn Premium,Career & Social,Professional network,LinkedIn Premium,United States,https://premium.linkedin.com/,https://premium.linkedin.com/,"Major U.S. gaming, creator, and social paid memberships; curated within category" +133,Tinder Gold,Dating,Dating app,Tinder Gold,United States,https://tinder.com/feature/plus,https://tinder.com/feature/plus,"Major U.S. gaming, creator, and social paid memberships; curated within category" +134,Bumble Premium,Dating,Dating app,Bumble Premium,United States,https://bumble.com/en/the-buzz/bumble-premium,https://bumble.com/en/the-buzz/bumble-premium,"Major U.S. gaming, creator, and social paid memberships; curated within category" +135,Hinge+,Dating,Dating app,Hinge+,United States,https://hinge.co/hinge-plus,https://hinge.co/hinge-plus,"Major U.S. gaming, creator, and social paid memberships; curated within category" +136,Amazon Prime,Shopping & Delivery,Retail membership,Amazon Prime,United States,https://www.amazon.com/amazonprime,https://www.amazon.com/amazonprime,"Major U.S. shopping, grocery, and delivery memberships; curated within category" +137,Walmart+,Shopping & Delivery,Retail membership,Walmart+,United States,https://www.walmart.com/plus,https://www.walmart.com/plus,"Major U.S. shopping, grocery, and delivery memberships; curated within category" +138,Target Circle 360,Shopping & Delivery,Retail membership,Target Circle 360,United States,https://www.target.com/circle/target-circle-360,https://www.target.com/circle/target-circle-360,"Major U.S. shopping, grocery, and delivery memberships; curated within category" +139,Costco,Warehouse Clubs,Retail membership,Costco Membership,United States,https://www.costco.com/join-costco.html,https://www.costco.com/join-costco.html,"Major U.S. shopping, grocery, and delivery memberships; curated within category" +140,Sam's Club,Warehouse Clubs,Retail membership,Sam's Club Membership,United States,https://www.samsclub.com/join,https://www.samsclub.com/join,"Major U.S. shopping, grocery, and delivery memberships; curated within category" +141,BJ's Wholesale Club,Warehouse Clubs,Retail membership,BJ's Membership,United States,https://www.bjs.com/membership,https://www.bjs.com/membership,"Major U.S. shopping, grocery, and delivery memberships; curated within category" +142,Instacart+,Grocery & Delivery,Grocery delivery,Instacart+,United States,https://www.instacart.com/instacart-plus,https://www.instacart.com/instacart-plus,"Major U.S. shopping, grocery, and delivery memberships; curated within category" +143,DoorDash DashPass,Food Delivery,Delivery membership,DashPass,United States,https://www.doordash.com/dashpass/,https://www.doordash.com/dashpass/,"Major U.S. shopping, grocery, and delivery memberships; curated within category" +144,Uber One,Food & Rides,Delivery/rides membership,Uber One,United States,https://www.uber.com/us/en/u/uber-one/,https://www.uber.com/us/en/u/uber-one/,"Major U.S. shopping, grocery, and delivery memberships; curated within category" +145,Grubhub+,Food Delivery,Delivery membership,Grubhub+,United States,https://www.grubhub.com/plus,https://www.grubhub.com/plus,"Major U.S. shopping, grocery, and delivery memberships; curated within category" +146,Shipt,Grocery & Delivery,Same-day delivery,Shipt membership,United States,https://www.shipt.com/membership/,https://www.shipt.com/membership/,"Major U.S. shopping, grocery, and delivery memberships; curated within category" +147,Kroger Boost,Grocery & Delivery,Grocery delivery,Kroger Boost,United States,https://www.kroger.com/pr/boost,https://www.kroger.com/pr/boost,"Major U.S. shopping, grocery, and delivery memberships; curated within category" +148,Thrive Market,Grocery & Delivery,Online grocery,Thrive Market membership,United States,https://thrivemarket.com/,https://thrivemarket.com/,"Major U.S. shopping, grocery, and delivery memberships; curated within category" +149,Misfits Market,Grocery & Delivery,Produce/grocery box,Misfits Market,United States,https://www.misfitsmarket.com/,https://www.misfitsmarket.com/,"Major U.S. shopping, grocery, and delivery memberships; curated within category" +150,Imperfect Foods,Grocery & Delivery,Grocery delivery,Imperfect Foods,United States,https://www.imperfectfoods.com/,https://www.imperfectfoods.com/,"Major U.S. shopping, grocery, and delivery memberships; curated within category" +151,Chewy Autoship,Pet Retail,Pet product autoship,Chewy Autoship,United States,https://www.chewy.com/app/content/autoship,https://www.chewy.com/app/content/autoship,"Major U.S. shopping, grocery, and delivery memberships; curated within category" +152,Petco Vital Care Premier,Pet Retail,Pet care membership,Vital Care Premier,United States,https://www.petco.com/shop/en/petcostore/c/vitalcare,https://www.petco.com/shop/en/petcostore/c/vitalcare,"Major U.S. shopping, grocery, and delivery memberships; curated within category" +153,PetSmart Treats Rewards VIPP,Pet Retail,Pet care membership,Treats Rewards VIPP,United States,https://www.petsmart.com/treats-rewards-vipp.html,https://www.petsmart.com/treats-rewards-vipp.html,"Major U.S. shopping, grocery, and delivery memberships; curated within category" +154,GameStop Pro,Retail Memberships,Gaming retail,GameStop Pro,United States,https://www.gamestop.com/pro/,https://www.gamestop.com/pro/,"Major U.S. shopping, grocery, and delivery memberships; curated within category" +155,Barnes & Noble Membership,Retail Memberships,Books retail,B&N Membership,United States,https://www.barnesandnoble.com/membership,https://www.barnesandnoble.com/membership,"Major U.S. shopping, grocery, and delivery memberships; curated within category" +156,HelloFresh,Food & Meal Kits,Meal kits,HelloFresh,United States,https://www.hellofresh.com/,https://www.hellofresh.com/,"U.S. meal kit, prepared food, coffee, and snack subscriptions; curated from current editorial/brand sources" +157,Blue Apron,Food & Meal Kits,Meal kits,Blue Apron,United States,https://www.blueapron.com/,https://www.blueapron.com/,"U.S. meal kit, prepared food, coffee, and snack subscriptions; curated from current editorial/brand sources" +158,Home Chef,Food & Meal Kits,Meal kits,Home Chef,United States,https://www.homechef.com/,https://www.homechef.com/,"U.S. meal kit, prepared food, coffee, and snack subscriptions; curated from current editorial/brand sources" +159,Marley Spoon,Food & Meal Kits,Meal kits,Marley Spoon,United States,https://marleyspoon.com/,https://marleyspoon.com/,"U.S. meal kit, prepared food, coffee, and snack subscriptions; curated from current editorial/brand sources" +160,Dinnerly,Food & Meal Kits,Budget meal kits,Dinnerly,United States,https://dinnerly.com/,https://dinnerly.com/,"U.S. meal kit, prepared food, coffee, and snack subscriptions; curated from current editorial/brand sources" +161,EveryPlate,Food & Meal Kits,Budget meal kits,EveryPlate,United States,https://www.everyplate.com/,https://www.everyplate.com/,"U.S. meal kit, prepared food, coffee, and snack subscriptions; curated from current editorial/brand sources" +162,Green Chef,Food & Meal Kits,Meal kits,Green Chef,United States,https://www.greenchef.com/,https://www.greenchef.com/,"U.S. meal kit, prepared food, coffee, and snack subscriptions; curated from current editorial/brand sources" +163,Purple Carrot,Food & Meal Kits,Plant-based meal kits,Purple Carrot,United States,https://www.purplecarrot.com/,https://www.purplecarrot.com/,"U.S. meal kit, prepared food, coffee, and snack subscriptions; curated from current editorial/brand sources" +164,Sunbasket,Food & Meal Kits,Meal kits,Sunbasket,United States,https://sunbasket.com/,https://sunbasket.com/,"U.S. meal kit, prepared food, coffee, and snack subscriptions; curated from current editorial/brand sources" +165,Factor,Prepared Meals,Prepared meals,Factor,United States,https://www.factor75.com/,https://www.factor75.com/,"U.S. meal kit, prepared food, coffee, and snack subscriptions; curated from current editorial/brand sources" +166,CookUnity,Prepared Meals,Prepared meals,CookUnity,United States,https://www.cookunity.com/,https://www.cookunity.com/,"U.S. meal kit, prepared food, coffee, and snack subscriptions; curated from current editorial/brand sources" +167,Fresh N Lean,Prepared Meals,Prepared meals,Fresh N Lean,United States,https://www.freshnlean.com/,https://www.freshnlean.com/,"U.S. meal kit, prepared food, coffee, and snack subscriptions; curated from current editorial/brand sources" +168,Hungryroot,Food & Meal Kits,Groceries/meal planning,Hungryroot,United States,https://www.hungryroot.com/,https://www.hungryroot.com/,"U.S. meal kit, prepared food, coffee, and snack subscriptions; curated from current editorial/brand sources" +169,Daily Harvest,Prepared Meals,Frozen plant-based food,Daily Harvest,United States,https://www.daily-harvest.com/,https://www.daily-harvest.com/,"U.S. meal kit, prepared food, coffee, and snack subscriptions; curated from current editorial/brand sources" +170,Tovala,Prepared Meals,Smart oven meals,Tovala meals,United States,https://www.tovala.com/,https://www.tovala.com/,"U.S. meal kit, prepared food, coffee, and snack subscriptions; curated from current editorial/brand sources" +171,MistoBox,Coffee & Tea,Coffee subscription,MistoBox,United States,https://mistobox.com/,https://mistobox.com/,"U.S. meal kit, prepared food, coffee, and snack subscriptions; curated from current editorial/brand sources" +172,Trade Coffee,Coffee & Tea,Coffee subscription,Trade Coffee,United States,https://www.drinktrade.com/,https://www.drinktrade.com/,"U.S. meal kit, prepared food, coffee, and snack subscriptions; curated from current editorial/brand sources" +173,Atlas Coffee Club,Coffee & Tea,Coffee subscription,Atlas Coffee Club,United States,https://atlascoffeeclub.com/,https://atlascoffeeclub.com/,"U.S. meal kit, prepared food, coffee, and snack subscriptions; curated from current editorial/brand sources" +174,Bean Box,Coffee & Tea,Coffee subscription,Bean Box,United States,https://beanbox.com/,https://beanbox.com/,"U.S. meal kit, prepared food, coffee, and snack subscriptions; curated from current editorial/brand sources" +175,Universal Yums,Snacks,International snack box,Universal Yums,United States,https://www.universalyums.com/,https://www.universalyums.com/,"U.S. meal kit, prepared food, coffee, and snack subscriptions; curated from current editorial/brand sources" +176,Peloton App,Fitness & Wellness,Connected fitness,Peloton App,United States,https://www.onepeloton.com/app,https://www.onepeloton.com/app,"Major U.S. fitness, wellness, and health app subscriptions; curated within category" +177,ClassPass,Fitness & Wellness,Fitness class credits,ClassPass,United States,https://classpass.com/,https://classpass.com/,"Major U.S. fitness, wellness, and health app subscriptions; curated within category" +178,Apple Fitness+,Fitness & Wellness,Workout streaming,Apple Fitness+,United States,https://www.apple.com/apple-fitness-plus/,https://www.apple.com/apple-fitness-plus/,"Major U.S. fitness, wellness, and health app subscriptions; curated within category" +179,Strava,Fitness & Wellness,Fitness tracking,Strava Subscription,United States,https://www.strava.com/subscribe,https://www.strava.com/subscribe,"Major U.S. fitness, wellness, and health app subscriptions; curated within category" +180,Fitbit Premium,Fitness & Wellness,Fitness/health insights,Fitbit Premium,United States,https://www.fitbit.com/global/us/products/services/premium,https://www.fitbit.com/global/us/products/services/premium,"Major U.S. fitness, wellness, and health app subscriptions; curated within category" +181,MyFitnessPal Premium,Fitness & Wellness,Nutrition tracking,MyFitnessPal Premium,United States,https://www.myfitnesspal.com/premium,https://www.myfitnesspal.com/premium,"Major U.S. fitness, wellness, and health app subscriptions; curated within category" +182,Noom,Fitness & Wellness,Weight management,Noom,United States,https://www.noom.com/,https://www.noom.com/,"Major U.S. fitness, wellness, and health app subscriptions; curated within category" +183,WW,Fitness & Wellness,Weight management,WeightWatchers membership,United States,https://www.weightwatchers.com/us/plans,https://www.weightwatchers.com/us/plans,"Major U.S. fitness, wellness, and health app subscriptions; curated within category" +184,Headspace,Meditation & Wellness,Meditation,Headspace,United States,https://www.headspace.com/,https://www.headspace.com/,"Major U.S. fitness, wellness, and health app subscriptions; curated within category" +185,Calm,Meditation & Wellness,Meditation/sleep,Calm Premium,United States,https://www.calm.com/premium,https://www.calm.com/premium,"Major U.S. fitness, wellness, and health app subscriptions; curated within category" +186,Sleep Cycle Premium,Sleep & Wellness,Sleep tracking,Sleep Cycle Premium,United States,https://www.sleepcycle.com/premium/,https://www.sleepcycle.com/premium/,"Major U.S. fitness, wellness, and health app subscriptions; curated within category" +187,Oura Membership,Fitness & Wellness,Wearable insights,Oura Membership,United States,https://ouraring.com/membership,https://ouraring.com/membership,"Major U.S. fitness, wellness, and health app subscriptions; curated within category" +188,Whoop,Fitness & Wellness,Wearable membership,Whoop Membership,United States,https://www.whoop.com/us/en/membership/,https://www.whoop.com/us/en/membership/,"Major U.S. fitness, wellness, and health app subscriptions; curated within category" +189,Aaptiv,Fitness & Wellness,Workout app,Aaptiv,United States,https://aaptiv.com/,https://aaptiv.com/,"Major U.S. fitness, wellness, and health app subscriptions; curated within category" +190,Fitbod,Fitness & Wellness,Strength training app,Fitbod Elite,United States,https://fitbod.me/pricing/,https://fitbod.me/pricing/,"Major U.S. fitness, wellness, and health app subscriptions; curated within category" +191,Alo Moves,Fitness & Wellness,Yoga/fitness streaming,Alo Moves,United States,https://www.alomoves.com/,https://www.alomoves.com/,"Major U.S. fitness, wellness, and health app subscriptions; curated within category" +192,Obé Fitness,Fitness & Wellness,Workout streaming,Obé Fitness,United States,https://obefitness.com/,https://obefitness.com/,"Major U.S. fitness, wellness, and health app subscriptions; curated within category" +193,Centr,Fitness & Wellness,Fitness/wellness app,Centr,United States,https://centr.com/,https://centr.com/,"Major U.S. fitness, wellness, and health app subscriptions; curated within category" +194,Future,Fitness & Wellness,Remote personal training,Future,United States,https://www.future.co/,https://www.future.co/,"Major U.S. fitness, wellness, and health app subscriptions; curated within category" +195,Tonal Membership,Fitness & Wellness,Connected strength training,Tonal Membership,United States,https://www.tonal.com/membership/,https://www.tonal.com/membership/,"Major U.S. fitness, wellness, and health app subscriptions; curated within category" +196,Duolingo Super,Education,Language learning,Super Duolingo,United States,https://www.duolingo.com/super,https://www.duolingo.com/super,Major U.S. education and family subscriptions; curated within category +197,MasterClass,Education,Online classes,MasterClass,United States,https://www.masterclass.com/,https://www.masterclass.com/,Major U.S. education and family subscriptions; curated within category +198,Coursera Plus,Education,Online courses,Coursera Plus,United States,https://www.coursera.org/courseraplus,https://www.coursera.org/courseraplus,Major U.S. education and family subscriptions; curated within category +199,Skillshare,Education,Creative/business courses,Skillshare membership,United States,https://www.skillshare.com/,https://www.skillshare.com/,Major U.S. education and family subscriptions; curated within category +200,Book of the Month,Books & Subscription Boxes,Book box,Book of the Month,United States,https://www.bookofthemonth.com/,https://www.bookofthemonth.com/,Major U.S. subscription boxes and recurring memberships; curated from editorial/brand sources diff --git a/package.json b/package.json index 31bbc2c..5eb7d18 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bill-tracker", - "version": "0.33.0", + "version": "0.33.1", "description": "Monthly bill tracking system", "main": "server.js", "scripts": { diff --git a/routes/admin.js b/routes/admin.js index be5cc71..773e40a 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -1,7 +1,7 @@ const express = require('express'); const router = express.Router(); const { getDb, rollbackMigration } = require('../db/database'); -const { getBankSyncConfig, setBankSyncEnabled, setSyncIntervalHours } = require('../services/bankSyncConfigService'); +const { getBankSyncConfig, setBankSyncEnabled, setSyncIntervalHours, setSyncDays } = require('../services/bankSyncConfigService'); const { getStatus: getBankSyncWorkerStatus } = require('../services/bankSyncWorker'); const { hashPassword } = require('../services/authService'); const { logAudit } = require('../services/auditService'); @@ -407,15 +407,12 @@ router.get('/bank-sync-config', (req, res) => { // PUT /api/admin/bank-sync-config router.put('/bank-sync-config', (req, res) => { - const { enabled, sync_interval_hours } = req.body || {}; + const { enabled, sync_interval_hours, sync_days } = req.body || {}; try { let config = getBankSyncConfig(); - if (typeof enabled === 'boolean') { - config = setBankSyncEnabled(enabled); - } - if (sync_interval_hours !== undefined) { - config = setSyncIntervalHours(sync_interval_hours); - } + if (typeof enabled === 'boolean') config = setBankSyncEnabled(enabled); + if (sync_interval_hours !== undefined) config = setSyncIntervalHours(sync_interval_hours); + if (sync_days !== undefined) config = setSyncDays(sync_days); res.json(config); } catch (err) { res.status(err.status || 500).json({ error: err.message || 'Failed to update bank sync config' }); diff --git a/services/bankSyncConfigService.js b/services/bankSyncConfigService.js index f96b632..99629bb 100644 --- a/services/bankSyncConfigService.js +++ b/services/bankSyncConfigService.js @@ -55,4 +55,13 @@ function setSyncIntervalHours(hours) { return getBankSyncConfig(); } -module.exports = { getBankSyncConfig, setBankSyncEnabled, setSyncIntervalHours }; +function setSyncDays(days) { + const n = parseInt(days, 10); + if (!Number.isFinite(n) || n < 1 || n > 730) { + throw Object.assign(new Error('sync_days must be between 1 and 730'), { status: 400 }); + } + setSetting('simplefin_sync_days', String(n)); + return getBankSyncConfig(); +} + +module.exports = { getBankSyncConfig, setBankSyncEnabled, setSyncIntervalHours, setSyncDays }; diff --git a/services/bankSyncService.js b/services/bankSyncService.js index 6e21f14..df75ac4 100644 --- a/services/bankSyncService.js +++ b/services/bankSyncService.js @@ -8,22 +8,17 @@ const { normalizeTransaction, sanitizeErrorMessage, } = require('./simplefinService'); +const { getBankSyncConfig } = require('./bankSyncConfigService'); const { decorateDataSource } = require('./transactionService'); -const SYNC_DAYS_DEFAULT = 90; - -function syncDaysBack() { - const n = parseInt(process.env.SIMPLEFIN_SYNC_DAYS, 10); - return Number.isFinite(n) && n > 0 ? n : SYNC_DAYS_DEFAULT; -} - function sinceEpoch(dataSource) { if (dataSource.last_sync_at) { // Overlap by 2 days to catch late-posted transactions const ts = new Date(dataSource.last_sync_at).getTime(); if (Number.isFinite(ts)) return Math.floor((ts - 2 * 86400 * 1000) / 1000); } - return Math.floor((Date.now() - syncDaysBack() * 86400 * 1000) / 1000); + const { sync_days } = getBankSyncConfig(); + return Math.floor((Date.now() - sync_days * 86400 * 1000) / 1000); } function safeErrorMessage(err) { @@ -94,6 +89,10 @@ async function runSync(db, userId, dataSource) { const raw = await fetchAccountsAndTransactions(accessUrl, since); const accounts = Array.isArray(raw.accounts) ? raw.accounts : []; + if (raw._errlistSummary) { + console.warn(`[bankSync] errlist for source ${dataSource.id}: ${raw._errlistSummary}`); + } + let accountsUpserted = 0; let transactionsNew = 0; let transactionsSkip = 0; @@ -113,13 +112,18 @@ async function runSync(db, userId, dataSource) { } } + // Store any errlist warnings alongside a successful sync so users can see them + const partialError = raw._errlistSummary + ? sanitizeErrorMessage(`Partial sync — some connections failed: ${raw._errlistSummary}`) + : null; + db.prepare(` UPDATE data_sources - SET last_sync_at = datetime('now'), last_error = NULL, status = 'active', updated_at = datetime('now') + SET last_sync_at = datetime('now'), last_error = ?, status = 'active', updated_at = datetime('now') WHERE id = ? AND user_id = ? - `).run(dataSource.id, userId); + `).run(partialError, dataSource.id, userId); - return { accountsUpserted, transactionsNew, transactionsSkip }; + return { accountsUpserted, transactionsNew, transactionsSkip, errlist: raw._errlistSummary || null }; } // ─── Public API ─────────────────────────────────────────────────────────────── diff --git a/services/simplefinService.js b/services/simplefinService.js index d962bf5..728ed92 100644 --- a/services/simplefinService.js +++ b/services/simplefinService.js @@ -93,7 +93,7 @@ async function fetchAccountsAndTransactions(accessUrl, sinceEpoch) { const basicAuth = Buffer.from(`${url.username}:${url.password}`).toString('base64'); const baseUrl = `${url.protocol}//${url.host}${url.pathname.replace(/\/?$/, '')}`; - const endpoint = `${baseUrl}/accounts?start-date=${Math.floor(sinceEpoch)}`; + const endpoint = `${baseUrl}/accounts?start-date=${Math.floor(sinceEpoch)}&version=2`; let data; try { @@ -111,6 +111,14 @@ async function fetchAccountsAndTransactions(accessUrl, sinceEpoch) { throw sanitizeError(err); } + // Surface any connection-level errors from the errlist so callers can log them + if (Array.isArray(data.errlist) && data.errlist.length > 0) { + const msgs = data.errlist + .map(e => sanitizeErrorMessage(e.message || e.msg || e.code || 'Unknown error')) + .join('; '); + data._errlistSummary = msgs; + } + return data; } @@ -123,7 +131,7 @@ function normalizeAccount(rawAccount, dataSourceId, userId) { data_source_id: dataSourceId, provider_account_id: String(rawAccount.id), name: String(rawAccount.name || 'Account').slice(0, 255), - org_name: rawAccount.org?.name ? String(rawAccount.org.name).slice(0, 255) : null, + org_name: (rawAccount.org?.name || rawAccount.conn_name) ? String(rawAccount.org?.name || rawAccount.conn_name).slice(0, 255) : null, account_type: null, currency: rawAccount.currency ? String(rawAccount.currency).slice(0, 10) : 'USD', balance: Number.isFinite(balance) ? balance : null,