| |
| |
|
|
| |
| CREATE TABLE IF NOT EXISTS public.webai_verifications ( |
| id UUID PRIMARY KEY DEFAULT gen_random_uuid(), |
| tender_id UUID NOT NULL REFERENCES public.tenders(id) ON DELETE CASCADE, |
| analysis JSONB NOT NULL, |
| comparison JSONB NOT NULL, |
| created_at TIMESTAMP WITH TIME ZONE DEFAULT now(), |
| updated_at TIMESTAMP WITH TIME ZONE DEFAULT now() |
| ); |
|
|
| |
| CREATE INDEX IF NOT EXISTS idx_webai_verifications_tender_id ON public.webai_verifications(tender_id); |
| CREATE INDEX IF NOT EXISTS idx_webai_verifications_created_at ON public.webai_verifications(created_at); |
|
|
| |
| ALTER TABLE public.tenders |
| ADD COLUMN IF NOT EXISTS verification_status TEXT DEFAULT 'PENDING' CHECK (verification_status IN ('PENDING', 'PROCESSING', 'COMPLETED', 'FAILED')), |
| ADD COLUMN IF NOT EXISTS verification_score FLOAT DEFAULT 0.0 CHECK (verification_score >= 0.0 AND verification_score <= 1.0), |
| ADD COLUMN IF NOT EXISTS last_verified_at TIMESTAMP WITH TIME ZONE; |
|
|
| |
| ALTER TABLE public.processing_jobs |
| ADD CONSTRAINT IF NOT EXISTS check_job_type |
| CHECK (job_type IN ('ANALYZE', 'DRAFT', 'VERIFY')); |
|
|
| |
| CREATE OR REPLACE FUNCTION update_webai_verifications_updated_at() |
| RETURNS TRIGGER AS $$ |
| BEGIN |
| NEW.updated_at = now(); |
| RETURN NEW; |
| END; |
| $$ language plpgsql; |
|
|
| CREATE TRIGGER webai_verifications_updated_at |
| BEFORE UPDATE ON public.webai_verifications |
| FOR EACH ROW |
| EXECUTE FUNCTION update_webai_verifications_updated_at(); |
|
|
| |
| ALTER TABLE public.webai_verifications ENABLE ROW LEVEL SECURITY; |
|
|
| |
| CREATE POLICY "Service role can manage verifications" ON public.webai_verifications |
| FOR ALL USING (auth.jwt() ->> 'role' = 'service_role') |
| WITH CHECK (auth.jwt() ->> 'role' = 'service_role'); |
|
|
| |
| CREATE POLICY "Users can read own org verifications" ON public.webai_verifications |
| FOR SELECT USING ( |
| auth.uid() IS NOT NULL AND |
| EXISTS ( |
| SELECT 1 FROM public.tenders t |
| WHERE t.id = public.webai_verifications.tender_id |
| AND t.organization_id = ( |
| SELECT organization_id FROM public.users |
| WHERE id = auth.uid() |
| ) |
| ) |
| ); |
|
|
| |
| GRANT SELECT, INSERT, UPDATE, DELETE ON public.webai_verifications TO authenticated; |
| GRANT SELECT, INSERT, UPDATE, DELETE ON public.webai_verifications TO service_role; |
| GRANT USAGE ON SEQUENCE public.webai_verifications_id_seq TO authenticated; |
| GRANT USAGE ON SEQUENCE public.webai_verifications_id_seq TO service_role; |
|
|
| |
| CREATE OR REPLACE VIEW public.verification_summary AS |
| SELECT |
| t.id as tender_id, |
| t.title as tender_title, |
| t.organization_id, |
| t.status as tender_status, |
| t.verification_status, |
| t.verification_score, |
| t.last_verified_at, |
| wv.analysis->>'tenderTitle' as webai_title, |
| wv.analysis->>'procuringEntity' as webai_entity, |
| wv.comparison->>'agreement_score' as agreement_score, |
| wv.comparison->'recommendation_comparison' as bid_comparison, |
| wv.created_at as verification_date, |
| CASE |
| WHEN wv.comparison->>'agreement_score'::float >= 0.8 THEN 'HIGH_AGREEMENT' |
| WHEN wv.comparison->>'agreement_score'::float >= 0.6 THEN 'MEDIUM_AGREEMENT' |
| WHEN wv.comparison->>'agreement_score'::float >= 0.4 THEN 'LOW_AGREEMENT' |
| ELSE 'DISAGREEMENT' |
| END as agreement_level |
| FROM public.tenders t |
| LEFT JOIN public.webai_verifications wv ON t.id = wv.tender_id |
| WHERE t.status = 'ANALYSIS_READY' OR t.verification_status != 'PENDING'; |
|
|
| |
| GRANT SELECT ON public.verification_summary TO authenticated; |
| GRANT SELECT ON public.verification_summary TO service_role; |
|
|