# LV Media portal integrations — developer handover

This is an integration **foundation**, not a live connected service. No credentials or customer accounts have been connected.

## Setup
1. Set `DATABASE_URL`, `AUTH_SECRET`, and a unique 64-character hex `INTEGRATION_ENCRYPTION_KEY` in your secret manager. Run `npm install`, `npx prisma generate`, `npx prisma db push`.
2. Register a Google OAuth application and enable Google Analytics Data API. Request `analytics.readonly` with consent and store encrypted refresh/access tokens in `Integration(provider="google")`. Set `config.ga4PropertyId` to the client's authorised GA4 property ID. The `/api/portal/summary` route fetches last 30 days' active users, sessions and views.
3. Configure a WordPress/Elementor Pro form submission hook to POST JSON `{id,name,email,phone,message}` to `/api/integrations/elementor`, including `x-lv-business` and `x-lv-signature` (hex HMAC-SHA256 of exact raw body). Provision a unique random `config.webhookSecret` in the business's `Integration(provider="elementor")`. Do not expose secrets in browser scripts. The webhook is idempotent.
4. Register a Xero OAuth 2.0 app with `accounting.transactions.read` and `offline_access`. Store encrypted tokens in `Integration(provider="xero")`; store selected Xero tenant ID in `config.tenantId`. Implement consent callback, tenant selection and scheduled invoice sync before using production data. `xeroToken()` implements token refresh, including rotating refresh tokens.
5. Admins can POST `{phrase,location,device}` to `/api/keywords`. Keyword ranking collection requires a licensed SERP provider and scheduled job, or use Google Search Console for **average search position**, explicitly labelled as such. Insert provider measurements into `KeywordPosition`. Do not present empty records as measured rankings.

## Security before launch
- Add explicit membership-to-client access mapping, rather than using first membership as a tenant selector.
- Provide an admin integrations screen, Google/Xero OAuth state+PKCE handling, connection revocation, and webhook secret rotation.
- Encrypt secrets in the database, use HTTPS, enforce rate limiting, log sync failures, add retries and consent/privacy notices.
- Add pagination and data retention policies; restrict sensitive invoice details by permission.
- Use scheduled jobs to sync Xero and ranking data, monitor errors, and run tenant isolation tests.
- Client dashboard is currently a basic scaffold; Google Analytics is exposed via authenticated JSON API rather than rendered chart widgets.

## October 2026 portal UI update
- `/portal` now renders three live GA4 metrics through the authenticated summary endpoint, with disconnected/error states. It displays the most recent Elementor enquiries, synced Xero invoices and tracked keywords for the signed-in business.
- `/keywords` is an admin-only form to add/remove search terms, locations and devices. It does not generate rankings: configure a licensed ranking service and scheduled collection before reporting positions.
- The design uses LV Media branding and the intended hostname is `portal.lvmedia.co.uk`. DNS and hosting are **not** provisioned.
