gendesign/backend/app/workers
lekss361 ed3c128528 feat(nspd): TIER 4 opportunity layers + red lines (#94 PR2 of 4)
- NSPDClient: QUARTER_OPPORTUNITY_LAYERS (auction/scheme/free/future/oopt)
  + QuarterDump.opportunity field
- nspd_sync: harvest_quarter accepts include_opportunity, denorm cols
  has_auction_parcels + opportunity_count in UPSERT
- quarter_dump_lookup:
  - _get_opportunity_parcels (sort by distance, early-exit on count=0)
  - _get_red_lines (query existing dump.red_lines core path, layer='red_lines')
- SQL 89_*: has_auction_parcels + opportunity_count + partial index
- Pydantic: OpportunityParcel + RedLine schemas
- /analyze: nspd_opportunity_parcels + nspd_red_lines fields
- Frontend: NspdOpportunityBlock + NspdRedLinesBlock + LandTab integration
- Tests: 28 total (11 PR1 + 17 PR2), all pass

Red lines uses existing core harvest path (layer 879243 already in dump.red_lines
from PR1+core) — no duplicate harvest, no red_lines_count_v2 column needed.

Part of #94
2026-05-16 19:06:22 +03:00
..
tasks feat(nspd): TIER 4 opportunity layers + red lines (#94 PR2 of 4) 2026-05-16 19:06:22 +03:00
__init__.py init 2026-04-25 13:45:19 +03:00
beat_schedule.py feat(permits): Celery beat monthly + analyze recent_permits (#105 Phase 4+5) (#213) 2026-05-16 12:23:52 +00:00
celery_app.py feat(permits): ЕКБ РНС/РВЭ xlsx parser + schema + ETL (#105 PR A) (#211) 2026-05-16 11:41:21 +00:00
lifecycle.py refactor(workers): split celery_app.py god-object into 3 modules (#135) 2026-05-15 00:09:38 +03:00