-- Order provenance: which platform the receipt came from, and the message it -- came from. -- -- The parser has always known the platform (it has to, to read the template) -- and then threw it away. Without it a transaction reads "Order - Burger -- Corner" with no way to tell whether to look in DoorDash or Uber Eats for the -- detail, and no way to answer "how much of this is DoorDash?" at all. -- -- `source_email_subject` / `source_email_from` already existed for the -- Paperless expense path and were simply never populated by order ingestion. ALTER TABLE expense_metadata ADD COLUMN IF NOT EXISTS platform text; COMMENT ON COLUMN expense_metadata.platform IS 'doordash | ubereats | uber — the receipt template the order was read from.'; -- Backfill the 101 rows written by the 2026-07-27 backfill. DoorDash receipts -- carry no order id of their own, so ingestion synthesises `msg:`; -- Uber receipts carry a real trip UUID. That is the only surviving -- discriminator, and it is exact. UPDATE expense_metadata SET platform = CASE WHEN order_reference LIKE 'msg:%' THEN 'doordash' ELSE 'ubereats' END WHERE platform IS NULL AND source = 'email' AND paperless_doc_id IS NULL -- exclude the Paperless expense path AND order_reference IS NOT NULL; -- Pick-up / delivery stops, as the receipt prints them. Uber puts these on -- every order under `Order details`; DoorDash prints no addresses at all, so -- this stays '[]' there. Same block a *trip* receipt uses for start and -- destination, so this column already fits rides when they come into scope. ALTER TABLE expense_metadata ADD COLUMN IF NOT EXISTS route jsonb NOT NULL DEFAULT '[]'::jsonb; COMMENT ON COLUMN expense_metadata.route IS 'Uber only: [{label, time, address}] — pick-up and delivery stops as printed.'; CREATE INDEX IF NOT EXISTS idx_expense_metadata_platform ON expense_metadata (platform) WHERE platform IS NOT NULL;