diff --git a/.changeset/quality-lens-client-core.md b/.changeset/quality-lens-client-core.md new file mode 100644 index 0000000..cc3be17 --- /dev/null +++ b/.changeset/quality-lens-client-core.md @@ -0,0 +1,5 @@ +--- +"tech-stack": minor +--- + +Add a required quality lens (AX and DX for backends, plus UX for frontends), a new reference for apps with child users (a separate child app, no third-party ads, analytics or crash SDKs, content-free push, minimal age data), and two Rust entries: a sans-I/O client core for clients that share protocol rules across platforms, and UniFFI for native bindings over a Kotlin Multiplatform bridge. diff --git a/skills/tech-stack/SKILL.md b/skills/tech-stack/SKILL.md index 7c5979f..162dec5 100644 --- a/skills/tech-stack/SKILL.md +++ b/skills/tech-stack/SKILL.md @@ -24,6 +24,7 @@ Tech-stack owns stack, tooling, code layout and architecture choices; how agents | Git hooks | `references/practices/hooks.md` | | CI | `references/practices/ci.md` | | Security scanning, containers, secrets | `references/practices/security.md` | +| An app with child users (stores, SDKs, push, age data) | `references/practices/child-users.md` | | Database, migrations | `references/practices/data.md` | | API or realtime contracts, generated clients | `references/practices/contracts.md` | | Tests, coverage, complexity, baselines | `references/practices/testing.md` | diff --git a/skills/tech-stack/references/practices/architecture.md b/skills/tech-stack/references/practices/architecture.md index aa4c2c5..cfe3783 100644 --- a/skills/tech-stack/references/practices/architecture.md +++ b/skills/tech-stack/references/practices/architecture.md @@ -1,5 +1,11 @@ # Architecture defaults +### Quality lens — required +setting: judge backend structure by AX and DX, and frontend structure by AX, DX and UX, where a structural change must not make the UI or UX worse +setting: AX: an agent works without reading everything, through fast deterministic checks whose failures arrive as text, predictable structure with much behaviour behind small interfaces, and lean always-loaded context; DX: a person can understand, navigate, review and contribute, and human review is part of DX +why: agents do most of the building and relearn the code every session, while people still navigate and review it; frontends also answer to their users +verified: 2026-10-23 · https://github.com/mattpocock/dictionary-of-ai-coding/blob/main/dictionary/AX.md · https://github.com/mattpocock/dictionary-of-ai-coding/blob/main/dictionary/DX.md + ## Starting shape - One modular monolith per product (over microservices) until a measured need splits it. - PostgreSQL is the durable authority; durable jobs in the database (Oban for Elixir); realtime only wakes clients, it does not carry truth. diff --git a/skills/tech-stack/references/practices/child-users.md b/skills/tech-stack/references/practices/child-users.md new file mode 100644 index 0000000..daaa2df --- /dev/null +++ b/skills/tech-stack/references/practices/child-users.md @@ -0,0 +1,23 @@ +# Apps with child users + +Store rules below are quoted from their sources; the rest are our defaults, stricter than the stores. Age thresholds and consent are legal questions: each project records its jurisdictions and their sources. + +### Separate child app — default (over one app gated by account type) +setting: when the adult app carries social, commerce or other adult-only features; both apps share one backend and client core +why: our choice, not a store rule; Google's Families policy applies whenever "one of the target audiences for your app is children", and Apple 5.1.4 requires children's privacy compliance from any app able to share a minor's personal information, "the ability to chat" included; a separate app keeps adult features out of that scope and out of the child's reach +verified: 2026-10-23 · https://support.google.com/googleplay/android-developer/answer/9893335 · https://developer.apple.com/app-store/review/guidelines/ + +### Third-party ads, analytics and crash SDKs in a child app — rejected +setting: analytics first-party and server-side; crash data from App Store Connect and Play Console +why: our default; the stores allow some "in limited cases" (Apple 1.3) and Families requires approved or self-certified SDKs, so each one needs a review of what it sends about a child; none removes that review +verified: 2026-10-23 · https://developer.apple.com/app-store/review/guidelines/ · https://support.google.com/googleplay/android-developer/answer/9893335 + +### Content-free push to a child's device — default (over payloads that carry message text) +setting: a generic visible alert, then the app syncs over its own connection; the app works without push permission; on the web, show a generic notification for each push and never rely on silent push +why: Apple 4.5.4: push "should not be used to send sensitive personal or confidential information" and "must not be required for the app to function"; Chrome accepts only `userVisibleOnly: true` subscriptions; carrying no content at all is our stricter choice +verified: 2026-10-23 · https://developer.apple.com/app-store/review/guidelines/ · https://web.dev/articles/push-notifications-subscribing-a-user + +### Birth month and year — default (over a full date of birth) +setting: collect only the age data the applicable rules need; keep child protections until a threshold is certainly reached (the month after the birth month); configure thresholds per jurisdiction and purpose, each with its source +why: Apple 5.1.4 allows a birthdate "only for the purpose of complying with these statutes"; less data held about a child, and thresholds that differ by country and feature stay configuration +verified: 2026-10-23 · https://developer.apple.com/app-store/review/guidelines/ diff --git a/skills/tech-stack/references/stacks/rust.md b/skills/tech-stack/references/stacks/rust.md index 4e6b4d0..b255934 100644 --- a/skills/tech-stack/references/stacks/rust.md +++ b/skills/tech-stack/references/stacks/rust.md @@ -27,3 +27,13 @@ verified: 2026-10-06 · https://github.com/bnjbvr/cargo-machete setting: rebuild in CI, then `git diff --exit-code -- ` (for example generated WASM) why: a project's checked-in WASM could lag its Rust source with CI green verified: 2026-10-06 · see `practices/ci.md` + +### Sans-I/O client core — default (over a core that owns its network and storage) +setting: for clients that share protocol and state rules across platforms: one crate holds those rules; it takes commands and completions and emits effects, and per-platform host adapters do HTTP, sockets, storage, timers and randomness +why: each rule lives once, and shared protocol rules can be tested in memory without an emulator or network; host adapters need their own verification +verified: 2026-10-23 · https://sans-io.readthedocs.io/how-to-sans-io.html + +### UniFFI for native bindings — default (over a Kotlin Multiplatform bridge) +setting: Swift and Kotlin call the generated bindings directly; our web build uses `wasm-bindgen`; expose an explicit cancel call, since UniFFI does not directly support cancelling async calls +why: Swift and Kotlin use UniFFI's maintained generators directly, without adding a third-party Kotlin Multiplatform generator and bridge +verified: 2026-10-23 · https://mozilla.github.io/uniffi-rs/latest/futures.html