Admins can enable or revoke store access per viewer; membership syncs to a configurable Google Group without changing app auth. Co-authored-by: Cursor <cursoragent@cursor.com>
187 lines
6.1 KiB
Markdown
187 lines
6.1 KiB
Markdown
|
|
# Google Play Closed Testing — server-side setup
|
|
|
|
Deze functionaliteit beheert **distributietoegang** tot de Android-app via Google Play Closed Testing.
|
|
Het vervangt **niet** de bestaande app-login of API-autorisatie.
|
|
|
|
## Architectuur
|
|
|
|
```
|
|
Adminpaneel → backend → Google Cloud Identity Groups API → Google Group
|
|
↓
|
|
Google Play Closed Testing track
|
|
```
|
|
|
|
- Gebruikers worden **niet** individueel via de Play Developer API beheerd.
|
|
- De Closed Testing-track wordt **eenmalig** gekoppeld aan `PLAY_ACCESS_GROUP_EMAIL`.
|
|
- Het adminpaneel beheert alleen lidmaatschap van die groep.
|
|
|
|
## Benodigde environment variables
|
|
|
|
Stel deze in op de **master-api** server (niet in de admin UI, niet in Git):
|
|
|
|
| Variabele | Verplicht | Beschrijving |
|
|
|-----------|-----------|--------------|
|
|
| `GOOGLE_CLOUD_PROJECT_ID` | Ja | Google Cloud project ID |
|
|
| `GOOGLE_SERVICE_ACCOUNT_EMAIL` | Ja | Service account e-mail |
|
|
| `GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY` | Ja | PEM private key ( `\n` als `\n` in env) |
|
|
| `PLAY_ACCESS_GROUP_ID` | Ja | Group resource ID (zonder `groups/` prefix mag ook) |
|
|
| `PLAY_ACCESS_GROUP_EMAIL` | Ja | E-mailadres van de Google Group |
|
|
| `GOOGLE_WORKSPACE_ADMIN_EMAIL` | Meestal ja | Admin voor domain-wide delegation |
|
|
| `GOOGLE_WORKSPACE_CUSTOMER_ID` | Optioneel | Workspace customer ID |
|
|
| `GOOGLE_PLAY_OPT_IN_URL` | Aanbevolen | Publieke Closed Testing opt-in URL |
|
|
| `GOOGLE_PLAY_SYNC_INTERVAL_MS` | Optioneel | Reconciliatie-interval (default: 86400000 = 24u) |
|
|
|
|
### Waar instellen
|
|
|
|
- **Lokaal:** `apps/master-api/.env`
|
|
- **Productie/Dokploy:** omgeving van de master-api container (`deploy/master/.env` template)
|
|
|
|
## Google Cloud — handmatige stappen
|
|
|
|
### 1. APIs inschakelen
|
|
|
|
In Google Cloud Console → APIs & Services:
|
|
|
|
- **Cloud Identity Groups API** (`cloudidentity.googleapis.com`)
|
|
|
|
### 2. Service account aanmaken
|
|
|
|
1. IAM & Admin → Service Accounts → Create
|
|
2. Download JSON key **of** kopieer private key naar `GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY`
|
|
3. Noteer `client_email` → `GOOGLE_SERVICE_ACCOUNT_EMAIL`
|
|
|
|
### 3. Domain-wide delegation (Workspace)
|
|
|
|
Als de group in Google Workspace staat:
|
|
|
|
1. Service account → Enable Domain-Wide Delegation
|
|
2. Google Admin Console → Security → API Controls → Domain-wide delegation
|
|
3. Voeg scope toe: `https://www.googleapis.com/auth/cloud-identity.groups`
|
|
4. Stel `GOOGLE_WORKSPACE_ADMIN_EMAIL` in op een super admin
|
|
|
|
### 4. Service account rechten op de group
|
|
|
|
De service account (of geïmpersonateerde admin) moet leden kunnen beheren:
|
|
|
|
- Google Group → **Group member manager** of **Owner**
|
|
- Of via Cloud Identity met de juiste IAM-rollen
|
|
|
|
### 5. Google Group aanmaken
|
|
|
|
Maak een **technische ACL-groep** (geen hardcoded naam in code):
|
|
|
|
- Niet publiek vindbaar
|
|
- Self-join uit
|
|
- Alleen beheerders beheren leden
|
|
- Ledenlijst niet zichtbaar voor gewone members
|
|
- Posten/conversations uit indien mogelijk
|
|
- Externe accounts alleen toestaan als nodig (bijv. `@gmail.com` testers)
|
|
|
|
Noteer:
|
|
|
|
- Group e-mail → `PLAY_ACCESS_GROUP_EMAIL`
|
|
- Group ID → `PLAY_ACCESS_GROUP_ID`
|
|
|
|
#### Group ID vinden
|
|
|
|
Via [Cloud Identity Groups API lookup](https://cloud.google.com/identity/docs/reference/rest/v1/groups/lookup):
|
|
|
|
```
|
|
GET https://cloudidentity.googleapis.com/v1/groups:lookup?groupKey.id=GROUP_EMAIL
|
|
```
|
|
|
|
Het veld `name` is bijv. `groups/03abc123` → `PLAY_ACCESS_GROUP_ID=03abc123`
|
|
|
|
### 6. Google Play Console — Closed Testing koppelen
|
|
|
|
1. Play Console → app → Testing → Closed testing
|
|
2. Maak of open een track
|
|
3. Testers → **Google Groups**
|
|
4. Voeg `PLAY_ACCESS_GROUP_EMAIL` toe
|
|
5. Kopieer de **opt-in URL** → `GOOGLE_PLAY_OPT_IN_URL`
|
|
|
|
## Gebruik in adminpaneel
|
|
|
|
1. Ga naar **Kijkers**
|
|
2. Per kijker: sectie **Google Play access**
|
|
- **Google Play email** — het Google-account voor Play (fallback: account-e-mail)
|
|
- **Store access** — ON/OFF
|
|
- **Status** — sync-status (ACTIVE, ERROR, …)
|
|
- **Retry synchronization** — bij ERROR
|
|
3. Pagina-acties:
|
|
- **Sync all** — alle kijkers synchroniseren
|
|
- **Reconcile** — lokale status vergelijken met Google Group
|
|
|
|
## Testgebruiker toevoegen
|
|
|
|
1. Maak kijker aan (of bestaande)
|
|
2. Vul Google Play e-mail in (bijv. `user@gmail.com`)
|
|
3. Zet **Store access** aan
|
|
4. Status wordt **ACTIVE** na succesvolle sync
|
|
5. Gebruiker opent `GOOGLE_PLAY_OPT_IN_URL` terwijl ingelogd met hetzelfde Google-account
|
|
6. Installeert app via Play Store
|
|
|
|
## Toegang intrekken
|
|
|
|
1. Zet **Store access** uit in adminpaneel
|
|
2. Backend verwijdert lidmaatschap uit de group
|
|
3. Nieuwe installs via Play zijn niet meer mogelijk
|
|
4. **Let op:** reeds geïnstalleerde apps blijven op het toestel — app-login/API blijft leidend voor contenttoegang
|
|
|
|
## Sync & reconciliatie
|
|
|
|
| Lokaal | Google Group | Actie |
|
|
|--------|--------------|-------|
|
|
| ON | member | OK |
|
|
| ON | geen member | toevoegen |
|
|
| OFF | member | verwijderen |
|
|
| OFF | geen member | OK |
|
|
|
|
- **Sync all:** past gewenste status toe voor alle kijkers
|
|
- **Reconcile:** vergelijkt en herstelt afwijkingen
|
|
- **Scheduled:** elke `GOOGLE_PLAY_SYNC_INTERVAL_MS` (default 24u)
|
|
|
|
## Foutafhandeling
|
|
|
|
Bij Google API-fouten:
|
|
|
|
- Gewenste instelling blijft bewaard
|
|
- Status → **ERROR**
|
|
- Fout staat in admin UI + audit log
|
|
- Gebruik **Retry synchronization**
|
|
|
|
Audit log tabel: `google_play_access_audit_logs` (geen tokens/keys gelogd).
|
|
|
|
## API endpoints (admin only)
|
|
|
|
| Method | Route |
|
|
|--------|-------|
|
|
| GET | `/api/v1/admin/google-play-access/config` |
|
|
| PATCH | `/api/v1/admin/viewers/:id/google-play-access` |
|
|
| POST | `/api/v1/admin/viewers/:id/google-play-access/retry` |
|
|
| POST | `/api/v1/admin/google-play-access/sync-all` |
|
|
| POST | `/api/v1/admin/google-play-access/reconcile` |
|
|
|
|
Body PATCH:
|
|
|
|
```json
|
|
{
|
|
"enabled": true,
|
|
"email": "user@gmail.com"
|
|
}
|
|
```
|
|
|
|
## Wat jij nog handmatig moet invullen
|
|
|
|
Stop hier — vul **geen** credentials in deze repo:
|
|
|
|
1. `GOOGLE_CLOUD_PROJECT_ID`
|
|
2. `GOOGLE_SERVICE_ACCOUNT_EMAIL`
|
|
3. `GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY`
|
|
4. `GOOGLE_WORKSPACE_ADMIN_EMAIL` (indien Workspace)
|
|
5. `PLAY_ACCESS_GROUP_ID`
|
|
6. `PLAY_ACCESS_GROUP_EMAIL`
|
|
7. `GOOGLE_PLAY_OPT_IN_URL`
|
|
|
|
Daarna master-api herstarten en in adminpaneel testen met één tester-account.
|