← back to NationalPaperHangers
DATA_POLICY.md
134 lines
# NationalPaperHangers.com — Public Directory Data Policy
**Version:** 1.0 · **Effective:** 2026-05-05 · **Owner:** Steve Abrams (operator)
This policy governs what data NationalPaperHangers.com collects from public sources to seed its installer directory, how that data is stored, and how studios reclaim control of their listings. It is the binding document for `scripts/scrape-*.js` and any related ingestion job.
## 1. Purpose
To bootstrap a directory of luxury wallcovering installation studios that exist publicly but are not yet registered users. Listings exist so trade buyers (designers, architects, hospitality groups) can discover them, and so the studios themselves can claim and complete their profiles.
## 2. Allowed sources
Only **public, no-login, no-paywall, no-CAPTCHA** pages on the public web. Initial allow-list:
| Source | URL pattern | Why it's appropriate |
|---|---|---|
| Wallcovering Installers Association | `wallcoveringinstallers.org/*` (public locator + member profile pages) | Trade association with publicly-listed members who self-disclose to be discoverable |
| Studio websites linked from above | per-studio `https://...` | Self-published business website is per-se public marketing |
Any new source must be added to this section before the scraper runs against it.
**Excluded by policy:** Reddit, Nextdoor, NextDoor, LinkedIn, Facebook, Google review pages, Yelp business pages, Apple Maps, login-gated trade portals (Phillip Jeffries, Schumacher Direct, etc.), authenticated Instagram, anything behind a CAPTCHA or rate-limit gate. (The Reddit/Nextdoor exclusion follows `feedback_no_social_scraping_address_history.md`.)
## 3. Allowed fields
Per studio, only these fields may be collected and stored:
- **Business name** (e.g. "Atelier Bond Wallcoverings")
- **City, state, country** (publicly listed mailing locality)
- **Public website URL**
- **Public bio / studio description** (verbatim copy with attribution, ≤ 600 chars)
- **Accreditations / certifications** the studio publicly displays (e.g. "WIA Certified Installer")
- **Public Instagram handle** *only if* it appears as a clickable link on the studio's own public website
- **Source URL + scrape timestamp** for every record (provenance)
**Forbidden fields** (do NOT collect, even if visible):
- Personal email addresses (`name@studio.com`, `info@studio.com`, anything ending in a domain)
- Personal phone numbers (mobile or landline)
- Street addresses (city + state + country only — never `123 Main St`)
- Names of individual installers or owners
- Tax IDs, license numbers, COI numbers, dates of birth, SSN/EIN
- Social media handles other than Instagram (no Twitter/X, TikTok, Facebook, LinkedIn personal)
- Reviews, testimonials, or ratings from other platforms
## 4. Storage and provenance
- All scraped records land in `installers` with `claim_status='unclaimed'`, `status='pending'`, `verified=false`.
- `source_url` and `source_scraped_at` are required, NOT NULL on insert.
- Records do not appear on `/find` until at least one of: (a) staff manually flips `status='active'`, OR (b) the studio claims and completes their profile.
- Provenance is preserved through claim — when a studio claims, the original `source_url` and `source_scraped_at` are kept for audit.
## 5. Crawl etiquette
- Identify ourselves: `User-Agent: NationalPaperHangersBot/1.0 (+https://nationalpaperhangers.com/about)`.
- Respect `robots.txt` for every domain (RFC 9309 is a request, not authorization, but we honor it as good faith).
- Maximum 1 request per 3 seconds per domain.
- Maximum 200 requests per domain per day.
- 30-second timeout per request; abandon on 4xx/5xx after 2 retries.
- Stop immediately on any source's request — `info@nationalpaperhangers.com` is the contact for opt-out.
- Log every request with URL, timestamp, response code to `logs/scrape-*.log`.
## 6. Claim workflow
A studio can claim its unclaimed listing in one of three ways:
1. **Email verification** — claim form sends a verification email to a `info@` or `hello@` address on the studio's public website domain. Studio clicks link → listing converts to `pending`, redirects to signup with prefilled fields.
2. **Domain proof** — studio adds a `nph-verify=<token>` TXT DNS record on their domain. Cron sweep verifies daily.
3. **Manual review** — staff confirms identity via website live chat / public phone displayed on studio website / email reply chain.
Until a successful claim, the listing displays *"Unclaimed listing — Is this your business?"* with a `Claim` CTA. Listings older than 365 days without a claim are auto-archived (`status='archived'`).
## 7. No outbound use without separate consent
**This is the hard rule.** Scraped data may NOT be used for:
- Email marketing (CAN-SPAM, CCPA, GDPR concerns)
- SMS / phone outreach (TCPA, federal/state DNC, Utah CPR)
- Pre-populating a "lead list" sold or shared with third parties
- Bulk newsletter sends
- "Claim your listing" outreach **outside** the explicit, opt-out-honoring channel defined in §6
Any future outbound campaign — including a "claim your listing" mailer to studios that have a public `info@` email on their site — requires prior review by the `comms-compliance` subagent, scrubbing against `comms_suppression`, and a per-message audit row in `comms_send_audit` (per `project_comms_compliance_agent.md`).
## 8. Opt-out
A studio (or anyone) can request listing removal by emailing `info@nationalpaperhangers.com`. We:
1. Remove the listing within 5 business days.
2. Add the domain to `directory_optout` so it cannot be re-scraped.
3. Confirm removal in writing.
## 9. Retention and review
- Unclaimed listings: 365 days max, then auto-archive.
- Claimed listings: indefinite, subject to the studio's own account deletion request.
- Scrape logs: 90 days, then purged.
- This policy is reviewed annually and at any source-list change.
## 10. Legal posture
This policy is informed by:
- **RFC 9309** — robots.txt rules are a request we honor, not a basis for our own claim of authorization.
- **hiQ Labs v. LinkedIn (9th Cir.)** — public, non-authenticated data does not trigger CFAA "without authorization" on its own. Not a license for unlimited scraping; contract / privacy / state law still applies.
- **CAN-SPAM Act** — applies to commercial email, including B2B. We are not sending commercial email under this policy. Any future send is gated by §7.
- **CCPA / CPRA** — California residents (including business contacts) have access / deletion rights. The opt-out in §8 is the primary channel.
- **GDPR / UK GDPR** — if a UK/EU studio is scraped, legitimate-interests basis may apply for directory inclusion, but transparency notice and right-to-object are honored within one month per ICO guidance. Default opt-in for any EU outbound.
- **California §6155 / Bar restrictions** do NOT apply (this is a wallcovering installer directory, not a lawyer-referral service). Cited only to keep the policy adjacent to `feedback_lawyer_directory_compliance.md` precedent.
## 11. Measurement tools (/measure, /book)
The AR Wall Measurement Kit (`/measure`) and the room-capture step of `/book`
measure walls using the visitor's own device sensors (WebXR AR camera + hit-test
on Android Chrome, DeviceOrientation clinometer on iOS Safari).
- **On-device only.** Camera and motion access are requested **only** on an
explicit user tap, never on page load. AR camera frames are processed live in
the browser and **never transmitted, uploaded, or stored** — only the derived
numbers (width/height in feet) exist, and only in the page's memory.
- **No server storage in the standalone /measure tool.** Wall dimensions,
deductions, product format, and the resulting roll/panel estimate stay entirely
client-side; nothing is POSTed to or persisted on our servers. (The `/book`
flow is different: there, dimensions a user chooses to attach to a quote brief
are stored as part of that booking — covered by §4.)
- **Estimates only.** Quantity figures are trade rules-of-thumb and carry an
on-screen "confirm with your installer/manufacturer before ordering" caveat.
## 12. Changes
Material changes to this policy require a new version number and a date in section 1. Prior versions are kept in git history.
— end —