// Package oppintel is the Opportunity Intelligence ingestion layer. It defines one normalized record // shape and one OpportunitySource protocol that every federal feed (active SAM solicitations, contract // awards, agency forecasts) implements, so the readiness and Command Center layers read a single // provenance tagged catalog instead of one table per feed. The ingester retains each raw payload to // object storage, upserts the normalized record into the global opportunity_records catalog, and writes // one audit event per run. Counts are always derived from records actually fetched, never fabricated. package oppintel import ( "encoding/json" "time" "github.com/shopspring/decimal" ) // RecordKind classifies a normalized record. An active solicitation is an open SAM notice a candidate // could be staffed against now; a contract award carries incumbent and dollar context for past // performance; a forecast is a planned, not yet posted opportunity and is always planning data. type RecordKind string const ( KindActiveSolicitation RecordKind = "active_solicitation" KindContractAward RecordKind = "contract_award" KindForecast RecordKind = "forecast" ) // Valid reports whether k is one of the known kinds (matches the migration CHECK constraint). func (k RecordKind) Valid() bool { switch k { case KindActiveSolicitation, KindContractAward, KindForecast: return true } return false } // Place is a normalized place of performance. type Place struct { City string State string Country string Zip string } // OpportunityRecord is the single normalized shape every feed yields. It is provider independent and // carries its own provenance (SourceName, SourceRecordID, FetchedAt) plus the Raw payload the ingester // retains in object storage. EstimatedValue is a pointer so absent is distinct from a real zero, and is // only ever set from a genuine source field, never fabricated. IsPlanning marks forecast rows the UI // must label as planning data subject to change. type OpportunityRecord struct { SourceName string SourceRecordID string DedupeKey string Kind RecordKind Title string Agency string SubAgency string NAICS string PSC string Place Place SetAside string SetAsideCode string ContractVehicle string EstimatedValue *decimal.Decimal ValueSource string // how the dollar figure is known (the source field), for provenance Posted *time.Time ResponseDeadline *time.Time AwardDate *time.Time EstimatedAwardDate *time.Time PopStart *time.Time PopEnd *time.Time IncumbentName string IncumbentUEI string UILink string IsPlanning bool FetchedAt time.Time Raw json.RawMessage } // OpportunityQuery is the provider independent pull scope. A source uses the subset that applies to it // (SAM iterates NAICS over a posted window; an awards source filters by agency and state). Empty fields // mean no filter on that dimension. type OpportunityQuery struct { NAICS []string States []string Agency string SetAside string From time.Time To time.Time PageCap int }