# google-business-profile

Google Business Profile API. The most important integration in the platform; covers the majority of franchise location reviews.

## What we use

- **Reviews list:** `GET accounts/{account}/locations/{location}/reviews?orderBy=updateTime desc&pageSize=50`
- **Single review:** `GET accounts/{account}/locations/{location}/reviews/{review}`
- **Reply to review:** `PUT accounts/{account}/locations/{location}/reviews/{review}/reply` (body: `{ "comment": "<text>" }`)
- **Delete reply:** `DELETE accounts/{account}/locations/{location}/reviews/{review}/reply`
- **Locations list:** `GET accounts/{account}/locations` (used during onboarding to let the operator pick which locations to connect)

## Scopes

OAuth scope: `https://www.googleapis.com/auth/business.manage`.

## How tokens are stored

- OAuth refresh tokens are encrypted at rest in D1 (Cloudflare D1 columns marked encrypted; key in Cloudflare environment variables).
- Access tokens are exchanged on demand from the refresh token and held in memory only.

## Rate limits to expect

- Per-API-key quota: 1,000 requests per minute, scaled by Google's review of the project.
- Per-location read: effectively limited by polling cadence (we poll every 10 minutes).

## Failure modes

- **401:** refresh-token revoked. Mark the location's GBP connection as `needs_reconnect`, alert the operator.
- **403 PERMISSION_DENIED:** the OAuth grantor no longer has the GBP location assigned. Same handling as 401.
- **404 on a review:** the customer or platform deleted it. Mark the review row as `platform_deleted`.
- **429:** back off per `Retry-After` header.

## Response constraints

- Reply text must be 1 to 4,096 characters.
- Reply replaces any prior reply (no edit history).
- Google's policy prohibits offering compensation in a public reply or requesting the customer remove the review. Enforced via respect-platform-tos hook.

## Setup steps for a new location

1. Operator clicks "Connect Google Business Profile" in /app/settings.html.
2. We redirect to Google's OAuth consent.
3. Google returns the refresh token; we store it encrypted, associated with that location id.
4. We list locations under the operator's account and surface the picker.
5. Operator confirms which locations map to which FranchiseFrontline location records.
6. Initial review backfill: pull the trailing 24 months in pages of 50.

## Not done in CL-002

The OAuth code is not yet implemented. This file describes what it will do; the adapter ships in a later CL.
