play data-safety: PSL_SUPPORT_DATA_DELETION_BY_USER as Play's single choice (partialDeletion true | false | 'auto90'), drop the removed PSL_DATA_COLLECTION_USER_REQUEST_DELETE (deletionRequest deprecated, check notes it); ship Google's empty form (cli/data/play-data-safety-form.csv, exported 2026-10-12), take every Answer requirement from it and report pairs not in it (formPairIssues) in check, declarations and play data-safety. Pitfall 21
This commit is contained in:
parent
dfc28c15f8
commit
b5b8f2da9d
35 changed files with 1824 additions and 859 deletions
|
|
@ -31,19 +31,21 @@ deletion requirements" (https://support.google.com/googleplay/android-developer/
|
|||
verifies the email), what is deleted and what is kept (and for how long, e.g. invoices for tax law), and how long it
|
||||
takes. No login wall to read it. `storebound validate --play` checks that it answers.
|
||||
3. In the app: a clear entry, a confirmation step, then the deletion (or the web page). Sign people out afterwards.
|
||||
4. Play Data safety: `dataSafety.deletionRequest: true`, `accountCreation` set to the sign-up methods you offer (not
|
||||
4. Play Data safety: `accountCreation` set to the sign-up methods you offer (not
|
||||
`PSL_ACM_NONE`). Say how people sign up in `accounts.signUp` and `storebound scan` proposes it: `username` (a name
|
||||
picked in the app, no password, no email; a server token on the device) is Play's "Username and other
|
||||
authentication" (`PSL_ACM_USER_ID_OTHER_AUTH`) with User ID as the only account data; `username-password` and
|
||||
`email-password` are "Username and password" (`PSL_ACM_USER_ID_PASSWORD`); `email-link` and `phone` are
|
||||
`PSL_ACM_USER_ID_OTHER_AUTH`; `oauth` is `PSL_ACM_OAUTH`; `other` is `PSL_ACM_OTHER`. An account alone never means
|
||||
an email address: declare Email only when the app asks for one. With accounts Play requires more rows, and storebound
|
||||
writes them: the delete-account URL (`PSL_ACCOUNT_DELETION_URL` = `accounts.deletionUrl`) and "can people delete
|
||||
some or all of their data without deleting the account?" (`PSL_SUPPORT_DATA_DELETION_BY_USER` =
|
||||
`dataSafety.partialDeletion`; ask the owner, never guess), plus its web page when the answer is yes
|
||||
writes them: the delete-account URL (`PSL_ACCOUNT_DELETION_URL` = `accounts.deletionUrl`) and "can people request
|
||||
that some or all of their data is deleted without deleting the account?" (`PSL_SUPPORT_DATA_DELETION_BY_USER`, a
|
||||
single choice = `dataSafety.partialDeletion`: `true` yes, `false` no, `'auto90'` no but the data is deleted
|
||||
automatically within 90 days; ask the owner, never guess), plus its web page when the answer is yes
|
||||
(`PSL_DATA_DELETION_URL` = `dataSafety.partialDeletionUrl`, default `accounts.deletionUrl`). `storebound check` and
|
||||
`play data-safety --dry` say `missing: <id> (... set <field>)` for any of them; without them Play answers 400
|
||||
"Response missing for PSL_ACCOUNT_DELETION_URL".
|
||||
"Response missing for PSL_ACCOUNT_DELETION_URL". Play removed the old "users can request deletion" question, so
|
||||
`dataSafety.deletionRequest` is no longer used (`check` notes it; remove it).
|
||||
5. Privacy policy: a "Deleting your account" section with both paths (`privacy-policy` skill).
|
||||
6. Test it on a fresh account before every submission; the reviewer will.
|
||||
|
||||
|
|
|
|||
|
|
@ -83,13 +83,22 @@ CLI: `storebound` (or `bunx storebound` in a project that has it, or `bun <toolc
|
|||
- Conditional required rows: some questions become required by another answer, and Play refuses the import with
|
||||
"Response missing for <id>" (400). Account creation not `PSL_ACM_NONE` -> `PSL_ACCOUNT_DELETION_URL` (from
|
||||
`accounts.deletionUrl`) and `PSL_SUPPORT_DATA_DELETION_BY_USER` ("delete some or all data without deleting the
|
||||
account?", `dataSafety.partialDeletion: true | false`, ask the owner); that answer true -> `PSL_DATA_DELETION_URL`
|
||||
account?", a single choice: `dataSafety.partialDeletion: true | false | 'auto90'` = `DATA_DELETION_YES` /
|
||||
`DATA_DELETION_NO` / `DATA_DELETION_NO_AUTO_DELETED` "no, but deleted automatically within 90 days", ask the
|
||||
owner); that answer true -> `PSL_DATA_DELETION_URL`
|
||||
(`dataSafety.partialDeletionUrl`, default `accounts.deletionUrl`); `PSL_HAS_OUTSIDE_APP_ACCOUNTS` is refused next
|
||||
to sign-up methods. A selected data type needs collected / shared, ephemeral, required / optional and a purpose
|
||||
(a sharing purpose when shared). `storebound check` and `play data-safety --dry` name each missing row as
|
||||
`missing: <id> (<when>; set <config field>)` and the real run stops before sending. Rules:
|
||||
`DATA_SAFETY_RULES` / `typeRules` in `cli/lib/data-safety.ts`. A `dataSafety.extra` row with a generated
|
||||
question id replaces that question (use it when your Play Console export shows other ids).
|
||||
- Only the current form's ids: Play answers 400 ("Line N: Response ID missing", "Invalid response ID") for a row its
|
||||
form does not have, e.g. a choice question written as a bare TRUE / FALSE, or a removed question
|
||||
(`PSL_DATA_COLLECTION_USER_REQUEST_DELETE` is gone, so `dataSafety.deletionRequest` is no longer used). storebound
|
||||
checks every (Question ID, Response ID) pair, `dataSafety.extra` included, against Google's empty form in
|
||||
`cli/data/play-data-safety-form.csv` (exported 2026-10-12) and takes each row's Answer requirement from it. When
|
||||
Play changes the form: Play Console > App content > Data safety > Export to CSV with nothing answered, save it over
|
||||
that file, run the tests.
|
||||
- "Optional" data is only allowed when the user can really choose for that data; otherwise required.
|
||||
- Ads SDKs: read each network's own Play data safety guidance; adding a network can add data types.
|
||||
- Target audience under 13 pulls the app into the Families policy (certified ad networks, no ad id): only if true.
|
||||
|
|
|
|||
|
|
@ -248,13 +248,20 @@ testers) and answers, in ONE batch at the start, only the facts no file proves (
|
|||
- **Cause:** some questions are required only after another answer. Account creation not `PSL_ACM_NONE` requires the
|
||||
delete-account URL (`PSL_ACCOUNT_DELETION_URL`) and the data-only deletion question
|
||||
(`PSL_SUPPORT_DATA_DELETION_BY_USER`; when yes, `PSL_DATA_DELETION_URL`), and Play then refuses
|
||||
`PSL_HAS_OUTSIDE_APP_ACCOUNTS`. A selected data type needs its whole usage block.
|
||||
- **Do:** set `accounts.deletionUrl`, ask the owner for `dataSafety.partialDeletion: true | false` (and
|
||||
`PSL_HAS_OUTSIDE_APP_ACCOUNTS`. A selected data type needs its whole usage block. The CSV must also use the current
|
||||
form's Response IDs: `PSL_SUPPORT_DATA_DELETION_BY_USER` became a single choice (`DATA_DELETION_YES` /
|
||||
`DATA_DELETION_NO` / `DATA_DELETION_NO_AUTO_DELETED`) and a bare FALSE got 400 "Line 7: Response ID missing";
|
||||
`PSL_DATA_COLLECTION_USER_REQUEST_DELETE` was removed from the form.
|
||||
- **Do:** set `accounts.deletionUrl`, ask the owner for `dataSafety.partialDeletion: true | false | 'auto90'` (and
|
||||
`partialDeletionUrl` when true and it is another page), run `storebound check` / `play data-safety --dry` until no
|
||||
`missing: <id>` is left. If Play names an id storebound does not know, export the form (Play Console > App content >
|
||||
Data safety > Export to CSV) and add the row in `dataSafety.extra` (same id = replaces the generated row).
|
||||
When Play changes the form, export it empty and save it over `cli/data/play-data-safety-form.csv`.
|
||||
- **Guard:** `DATA_SAFETY_RULES` / `typeRules` / `dataSafetyIssues` in `cli/lib/data-safety.ts`; `check`,
|
||||
`project.declarations` and `play data-safety` (dry and real, before the POST) report them.
|
||||
`project.declarations` and `play data-safety` (dry and real, before the POST) report them. storebound checks every
|
||||
(Question ID, Response ID) pair, `dataSafety.extra` included, against Google's exported empty form
|
||||
(`cli/data/play-data-safety-form.csv`, 2026-10-12; `formPairIssues`) and takes each Answer requirement from it;
|
||||
`tests/pure.test.ts` (pairs from Play's exported form).
|
||||
- **Sources:** https://support.google.com/googleplay/android-developer/answer/10787469 (Data safety form, CSV import),
|
||||
https://support.google.com/googleplay/android-developer/answer/13327111 (account deletion: delete-account link;
|
||||
deleting other data is a separate question).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue