Store encrypted service-account and group config in the database so Dokploy env vars are optional. Co-authored-by: Cursor <cursoragent@cursor.com>
206 lines
7 KiB
Markdown
206 lines
7 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 configuratie
|
|
|
|
**Voorkeur:** vul alles in via het adminpaneel → **Instellingen → Google Play**.
|
|
Credentials worden versleuteld in de database opgeslagen (zoals OpenSubtitles).
|
|
|
|
Optioneel blijven environment variables werken als fallback (bijv. voor lokale development).
|
|
|
|
### Velden in Instellingen
|
|
|
|
| Veld | Verplicht | Beschrijving |
|
|
|------|-----------|--------------|
|
|
| Project ID | Ja | Google Cloud project ID |
|
|
| Service account e-mail | Ja | Service account e-mail |
|
|
| Private key | Ja | PEM private key |
|
|
| Workspace admin e-mail | Meestal ja | Admin voor domain-wide delegation |
|
|
| Workspace customer ID | Optioneel | Workspace customer ID |
|
|
| Play access group ID | Ja | Group resource ID (zonder `groups/` prefix) |
|
|
| Play access group e-mail | Ja | E-mailadres van de Google Group |
|
|
| Opt-in URL | Aanbevolen | Publieke Closed Testing opt-in URL |
|
|
|
|
### Optionele environment variables (fallback)
|
|
|
|
Stel deze alleen in als je géén Settings-UI gebruikt:
|
|
|
|
| Variabele | Beschrijving |
|
|
|-----------|--------------|
|
|
| `GOOGLE_CLOUD_PROJECT_ID` | Google Cloud project ID |
|
|
| `GOOGLE_SERVICE_ACCOUNT_EMAIL` | Service account e-mail |
|
|
| `GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY` | PEM private key (`\n` als `\\n` in env) |
|
|
| `PLAY_ACCESS_GROUP_ID` | Group resource ID |
|
|
| `PLAY_ACCESS_GROUP_EMAIL` | E-mailadres van de Google Group |
|
|
| `GOOGLE_WORKSPACE_ADMIN_EMAIL` | Admin voor domain-wide delegation |
|
|
| `GOOGLE_WORKSPACE_CUSTOMER_ID` | Workspace customer ID |
|
|
| `GOOGLE_PLAY_OPT_IN_URL` | Publieke Closed Testing opt-in URL |
|
|
| `GOOGLE_PLAY_SYNC_INTERVAL_MS` | Reconciliatie-interval (default: 86400000 = 24u) |
|
|
|
|
### Waar instellen
|
|
|
|
- **Productie (aanbevolen):** Admin UI → Instellingen → Google Play
|
|
- **Lokaal fallback:** `apps/master-api/.env`
|
|
- **Dokploy env:** alleen nodig als je Settings-UI niet wilt gebruiken
|
|
|
|
## 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. Maak Google Cloud service account + group + Play Closed Testing-koppeling (stappen hierboven)
|
|
2. Open adminpaneel → **Instellingen → Google Play**
|
|
3. Vul project, service account, private key, group ID/e-mail en opt-in URL in
|
|
4. Opslaan
|
|
5. Ga naar **Kijkers** en zet Store access aan voor een testgebruiker
|
|
|
|
Daarna master-api herstarten is alleen nodig als je de nieuwe code net hebt gedeployed.
|