Add APScheduler-based background task that periodically re-analyzes
tracked companies and alerts on significant patent count changes.
- Add tracked_companies and alerts tables to database schema
- Add SPARC/scheduler.py with configurable interval and threshold
- Add admin endpoints: GET/POST/DELETE /admin/tracked, GET /admin/alerts
- Scheduler starts at app startup; interval via SCHEDULE_INTERVAL_HOURS
- Change threshold configurable via CHANGE_THRESHOLD_PERCENT env var
- apscheduler is optional; graceful fallback if not installed
Closesleeworks-agents/SPARC#22
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add GET /export/{company_name} backend endpoint that returns analysis
records as a downloadable CSV file. Add Export CSV button to the
Analysis page that triggers the download via the API.
Closesleeworks-agents/SPARC#20
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a cursor query parameter to GET /jobs and return a next_cursor
field in the response envelope. Existing clients using only limit
continue to work without modification. The cursor is an opaque token
encoding created_at and job_id for stable keyset pagination.
Closesleeworks-agents/SPARC#25
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Enable Tailwind "class" dark mode strategy
- Use CSS custom properties for theme colors (bg, text, border)
- Add ThemeProvider context with toggle and localStorage persistence
- Add Sun/Moon toggle button in the header navigation
- Inline script in index.html prevents FOUC on page load
- All pages (Layout, Login, Register, ProtectedRoute) support both modes
- Default theme follows system preference (prefers-color-scheme)
Closesleeworks-agents/SPARC#33
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Analytics page now shows skeleton loaders (cards and chart placeholders)
while data loads, and displays a retry button when the API call fails.
Batch page error state now shows the actual error message and suggests
user action.
Closesleeworks-agents/SPARC#16
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When the PDF is not on disk, analyze_single_patent now looks up the
cached PDF link from the database and downloads it automatically.
If no link is cached, a clear FileNotFoundError is raised. Also adds
a GET /analyze/patent/{patent_id} API endpoint that exposes this
functionality and returns 404 when the PDF cannot be obtained.
Closesleeworks-agents/SPARC#36
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add module-level logger to serp_api.py with INFO-level messages for
patent queries and PDF downloads, and DEBUG-level messages for cache
hits and parsing details. All three target files (analyzer.py,
serp_api.py, llm.py) now use structured logging with no print() calls.
Closesleeworks-agents/SPARC#46
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Upgrade lucide-react to v1.7.0 for proper TypeScript declarations and
add a TypeScript type check step to the test workflow. Both ruff (Python)
and tsc --noEmit (TypeScript) now block merging on failure.
Closesleeworks-agents/SPARC#52
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add test job to build.yaml that runs pytest and ruff before building images
- Add standalone test.yaml workflow for PRs
- Add ruff.toml with E/F/I rules configured
- Fix all ruff lint errors: sort imports, remove unused imports, fix re-exports
- Build jobs now depend on test job passing (needs: test)
Closesleeworks-agents/SPARC#18Closesleeworks-agents/SPARC#19
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace get_db_client() creating new DatabaseClient on every call with a
module-level singleton initialized once at startup via init_db_client()
- Add init_db_client() and close_db_client() lifecycle functions called
from FastAPI lifespan handler
- Migrate all DatabaseClient methods from legacy self.connect()/self.conn
to pooled self.get_conn() context manager for thread-safe connection reuse
- Pool is properly torn down on application shutdown
Closesleeworks-agents/SPARC#7
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Make LLM model configurable via MODEL env var, default anthropic/claude-3.5-sonnet (#12)
- Expose SERP cache TTL as SERP_CACHE_TTL_HOURS env var, default 24 hours (#13)
- Fix Patent.patent_id type annotation from int to str in types.py (#14)
- Replace all print() calls with structured logging in analyzer.py and llm.py (#11)
- Add LOG_LEVEL config with basicConfig setup in config.py
- Add model and serp_cache_ttl_hours to config.py
Closesleeworks-agents/SPARC#11Closesleeworks-agents/SPARC#12Closesleeworks-agents/SPARC#13Closesleeworks-agents/SPARC#14
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add jobs table to database schema (job_id, status, progress, result_json, etc.)
- Add DatabaseClient methods: create_job, update_job, get_job, list_jobs
- Add mark_stale_jobs_failed() called at startup to handle interrupted jobs
- Refactor _run_batch_job and job endpoints to read/write from PostgreSQL
- Remove in-memory _jobs dict; job state now survives API restarts
- Update init_database.py to list all tables in output
Closesleeworks-agents/SPARC#8
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add docstring to analyze_single_patent explaining the PDF prerequisite
- Raise FileNotFoundError with helpful message when PDF is missing
- Add patent PDF storage section to README with Docker volume mount example
- Commit frontend/package-lock.json for reproducible builds
Closesleeworks-agents/SPARC#15Closesleeworks-agents/SPARC#17
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add check_jwt_secret() that refuses default JWT secret when APP_ENV != development
- Make CORS origins configurable via CORS_ORIGINS env var (comma-separated)
- Replace hardcoded postgres credentials in docker-compose.yml with env var references
- Add APP_ENV and cors_origins to config.py
- Update .env.example with all required variables and documentation
- Add tests for JWT startup guard and CORS configuration
Closesleeworks-agents/SPARC#4Closesleeworks-agents/SPARC#5Closesleeworks-agents/SPARC#6
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
_analyze_company_safe was calling SERP.query directly, bypassing the
SERP query cache in analyze_company. Now delegates fully to
analyze_company() and reads patent_count from the serp_queries cache.
- Add TestSingleQueryBugFix: verify SERP.query called once per analysis
- Add TestPatentCaching: DB cache hit/miss, SERP query cache hit/miss
- Add TestDynamicDateRange: rolling window, days_back param
- Add TestFilesystemPDFCaching: skip download, redownload empty files
- Add autouse mock_db fixture to prevent real DB connections in all tests
Before querying SERP API, check serp_queries cache (24h TTL). Before
downloading/parsing each patent, check patents table for cached
minimized_content. Store results after processing so repeated analyses
skip all network I/O and PDF parsing entirely.
Replace the sequential per-patent loop with a ThreadPoolExecutor
(workers controlled by PATENT_THREAD_WORKERS config). Each patent is
processed independently in _process_single_patent, which is thread-safe
since SERP methods are stateless and operate on separate files.
The SERP query had a frozen date range (Oct-Nov 2025) that returned
stale patents. Now computes a rolling window from config
(PATENT_SEARCH_DAYS, default 90 days). Also adds filesystem-level PDF
caching to skip re-downloading existing patent PDFs, and adds
PATENT_THREAD_WORKERS config for upcoming parallel processing.
_analyze_company_safe called SERP.query() then passed the company name
to analyze_company() which called SERP.query() again — doubling API
usage. Now analyze_company() accepts an optional patents param so callers
can pass pre-fetched results through.
Add ROOT_PATH environment variable support so FastAPI generates correct
URLs for Swagger UI when served behind nginx at /api. This fixes the
"invalid version field" error when accessing /api/docs.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add trailing slash to proxy_pass directive so nginx strips the /api/
prefix before forwarding requests to the API container. This fixes
routes like /api/docs being passed as /api/docs instead of /docs.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Push images with versioned tags in format TIMESTAMP-COMMIT and
frontend-TIMESTAMP-COMMIT for better traceability and rollback support.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Push images with versioned tags in format TIMESTAMP-COMMIT and
frontend-TIMESTAMP-COMMIT for better traceability and rollback support.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Use nginx template support to allow API_URL to be passed at container
runtime, enabling the same image to be deployed to different environments.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>