search a ads

This commit is contained in:
JiriUhlir
2026-06-18 12:43:42 +02:00
parent 9cd5c8011b
commit 125b112967
12 changed files with 748 additions and 191 deletions
+24 -11
View File
@@ -1,10 +1,17 @@
# analytics — overview
A stateless multi-tenant API proxy exposing two upstream services under one
A stateless multi-tenant API proxy exposing four upstream services under one
FastAPI app:
1. **Google Analytics 4** — Data API (reporting) + Admin API (read).
2. **Sklik** (Seznam) — Drak JSON-RPC API.
2. **Google Search Console** — Search Analytics, Sites, Sitemaps, URL Inspection (read).
3. **Google Ads** — GAQL reporting (search / searchStream).
4. **Sklik** (Seznam) — Drak JSON-RPC API.
The three Google services share one OAuth mechanism (token wins over service
account) — they differ only in the OAuth *scope* and the header prefix
(`X-GA-*`, `X-GSC-*`, `X-GAds-*`). Google Ads additionally needs a developer
token.
The structure mirrors the sibling `idoklad` / `csob` services (config→env,
credentials→headers, client per upstream, routers, central exception handling,
@@ -25,17 +32,19 @@ Swagger at `/docs`), adapted to Python/FastAPI.
```
app/
config.py env-driven config (base URLs, scope, timeout) — no secrets
config.py env-driven config (base URLs, scopes, timeout) — no secrets
logging_config.py get_logger(); secrets are never logged
errors.py MissingCredentialsError, UpstreamError + handlers
credentials.py X- header dependencies (GA + Sklik)
credentials.py X- header dependencies (GA / GSC / Ads / Sklik)
clients/
ga_client.py GA Data/Admin HTTP client + service-account token minting
google.py shared Google client: Bearer/SA token minting + requests
sklik_client.py Sklik JSON-RPC client (login + session + report paging)
routers/
meta.py /health, /version
ga_data.py /ga/data/...
ga_admin.py /ga/admin/...
ga_data.py /ga/data/... (Google Analytics Data)
ga_admin.py /ga/admin/... (Google Analytics Admin)
gsc.py /gsc/... (Search Console)
googleads.py /googleads/... (Google Ads)
sklik.py /sklik/...
main.py app factory, root_path, router + handler registration
```
@@ -50,14 +59,18 @@ routes are unprefixed (Caddy `handle_path` strips the prefix).
| Upstream | Header(s) | Behaviour |
| --- | --- | --- |
| Google Analytics | `X-GA-Access-Token` **or** `X-GA-Credentials` (+ `X-GA-Quota-Project`) | Token used directly; else a token is minted from the base64 service-account JSON (scope `analytics.readonly`) and cached in memory until ~60 s before expiry. |
| Google Analytics | `X-GA-Access-Token` **or** `X-GA-Credentials` (+ `X-GA-Quota-Project`) | Token used directly; else minted from base64 service-account JSON (scope `analytics.readonly`) and cached in memory until ~60 s before expiry. |
| Search Console | `X-GSC-Access-Token` **or** `X-GSC-Credentials` (+ `X-GSC-Quota-Project`) | Same as GA, scope `webmasters.readonly`. |
| Google Ads | `X-GAds-Developer-Token` (req) + `X-GAds-Access-Token` **or** `X-GAds-Credentials` (+ `X-GAds-Login-Customer-Id`, `X-GAds-Quota-Project`) | Same OAuth (scope `adwords`) plus `developer-token` / `login-customer-id` headers forwarded upstream. |
| Sklik | `X-Sklik-Token` (+ `X-Sklik-User-Id`) | `client.loginByToken` per request → session injected into the call. |
## Deliberately not wired
- **GA Admin write operations** (create/update/delete properties, streams). The
requested scope is read-only (`analytics.readonly`); add `analytics.edit` and
endpoints if management is needed later.
- **Write operations** across the Google services: GA Admin (create/update
properties, streams), Search Console (submit/delete sitemaps, add/remove
sites), Google Ads mutates (create/update campaigns etc.). All requested
scopes are read-only; add the read-write scope + endpoints if management is
needed later. Google Ads exposes reporting (GAQL) only for now.
- **Sklik header-credential encryption.** Same deferral as `idoklad`/`csob`:
header values are plaintext over TLS for now.
- **Sklik session reuse across requests** — the chosen model logs in per