← back to Rentv Adintel

docs/EXPORT_FORMAT.md

75 lines

# RENTV Advertiser Intelligence — Export Format

The one-click **Download Everything** action (§28) produces a single ZIP. It runs through
a job with visible progress (large exports are never streamed unbounded in one request),
and every file honors suppression, do-not-contact, private notes, and source rights.

## ZIP manifest (§28)

```text
RENTV-Advertiser-Intelligence-YYYY-MM-DD/
  executive-viewer.html          # self-contained offline viewer (double-click to open)
  README.html                    # what's in the export + how to read it
  advertisers.csv                # the advertiser table
  advertisers.xlsx               # same, Excel workbook
  contacts.csv                   # public business contacts (rights-filtered)
  contacts.xlsx
  ad-sightings.csv               # verified ad/sponsor sightings + evidence pointers
  creatives.csv                  # creative assets metadata (export-allowed only)
  conference-sponsors.csv        # event ↔ organization sponsor/exhibitor rows
  conferences.csv                # events list
  prospects.csv                  # ranked RENTV opportunities + score factors
  analytics-summary.csv          # GA4/GSC rollup (DEMO or LIVE, labeled)
  ga4-landing-pages.csv
  ga4-geography.csv
  gsc-queries.csv
  gsc-pages.csv
  google-ads-campaigns.csv       # ONLY when Google Ads is connected
  source-manifest.json           # every source + policy + access method + review date
  methodology.json               # score weights, formulas, classification definitions
  export-audit.json              # who exported, when, row counts, rights filters applied
  thumbnails/                    # web thumbnails for export-allowed creatives
  evidence/                      # ONLY assets flagged export-allowed (never internal-only)
  database-readonly.sqlite       # optional portable snapshot (never a second source of truth)
```

`google-ads-campaigns.csv` appears only when the Google Ads connector is configured. The
SQLite snapshot is an **export artifact only** — PostgreSQL remains the canonical source
of truth.

## `executive-viewer.html` behavior

A self-contained, read-only HTML file for handing to a non-technical stakeholder:

- **Works by double-clicking it** — no server, no build step, no network.
- Uses only **relative local assets** inside the ZIP folder.
- Provides **in-browser search and filters** over the advertiser data (California /
  Arizona / All, Verified Only).
- Shows **advertiser cards + thumbnails** with status badges (text, not color-only).
- Opens every **source link in a new tab**.
- Shows the **data date and source coverage** so the reader knows how fresh it is.
- **Omits internal-only evidence images** — only export-allowed thumbnails are embedded.
- Is **accessible and printable**.

## Rights filtering applied to every export

`applyExportRights(rows, kind)` (`src/export/rights.js`) is the single choke point every
dataset passes through before it is written. It removes:

- **suppressed** rows — organizations/people named in an active suppression request
  (matched by id via a suppression set the caller builds from `suppression_requests`),
- **do-not-contact** contacts and any contact with `export_allowed = false`,
- **private notes** (`is_private = true`).

For **creative assets**, the metadata row is retained but the image bytes are gated by
`rights_status`: `EXPORT_ALLOWED` → bundle the file in `thumbnails/`;
`INTERNAL_EVIDENCE_ONLY` / `LINK_ONLY` / `UNKNOWN` → **omit the bytes**, keep only a
link-only placeholder (each row is annotated with an `_exportClass` of `include` or
`link_only`). So an internal-only image's pixels never leave the app even though its
citation remains.

`test/export-filter.test.js` locks each of these in (including that no
`INTERNAL_EVIDENCE_ONLY` or `UNKNOWN`-rights asset is ever classified `include`). Because
the same helper gates the CSV/XLSX rows, the `evidence/` folder, and the offline viewer,
an internal-only image or a suppressed company cannot leak through any one path.