design(app-creator): S6 — forfatt ios-app referanse-domain-pack + start claude-code-plugin-pakke
- domain-packs/ios-app/: komplett referanse-pakke (8 komponenter) — pack.json med components-map, conventions.md, 4 patterns/, gotchas.md, checklist.md splittet i 3 (App Store-submission + security-privacy/MASVS 2.1 + accessibility/WCAG 2.2 AA), 3 scaffold/-maler (PrivacyInfo.xcprivacy-plist, NSUsageDescription-inventar, ASC-metadata), eksempel-feature-brief i Voyage strict-mode-format, glossary.md. Hver teknisk påstand verifisert mot Apple Developer / W3C WAI / OWASP MAS. - domain-packs/claude-code-plugin/: stub — pack.json + conventions.md + gotchas.md + checklist.md + glossary.md ferdige (ekstrahert fra ktg-privat-konvensjoner); patterns/scaffold/examples er stubs. - docs/domain-pack-spec.md: § D2/D3/D4/D7 + restrisiko oppdatert — pack.json components-felt, core/supplementary låst til manifestet, checklist-splitt-konvensjon, snapshot-materialiserings-mekanikk presisert, iOS-versjons-korreksjon (iOS 26, ikke "iOS 18/19"), D7 → "forfattet i S6". - prototype-run/friksjon.md: #9 (Akashic-briefen refererer "iOS 19" som ikke finnes — rettes i S7) + S6-prosessnotater (checklist-splitt bekreftet nødvendig, components-gap fylt, verifiserings-asymmetri ios-app vs claude-code-plugin notert). - CLAUDE.md: peker til domain-packs/ under § Status. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
e4ae4ac5b4
commit
2011507ea1
27 changed files with 1059 additions and 17 deletions
|
|
@ -11,6 +11,8 @@ Implementering starter ikke før:
|
||||||
|
|
||||||
Inntil det: dette repoet eksisterer som et tenke-rom. Hvis du som Claude blir bedt om å "begynne å bygge", stopp og bekreft at forutsetningene over er oppfylt.
|
Inntil det: dette repoet eksisterer som et tenke-rom. Hvis du som Claude blir bedt om å "begynne å bygge", stopp og bekreft at forutsetningene over er oppfylt.
|
||||||
|
|
||||||
|
Design-/kunnskaps-artefakter finnes (de er *ikke* implementerings-kode): `docs/phase-design-draft.md` (7-fase-designet), `docs/domain-pack-spec.md` (domene-nøytral spec), `domain-packs/` (referanse-domain-packs — `ios-app` komplett, `claude-code-plugin` som stub), `prototype-run/` (friksjons-logg + research fra prototype-arbeidet drevet av Akashic-instansen). "Ingen kode i pre-design" gjelder Swift/implementerings-kode, ikke disse markdown-/data-fil-artefaktene.
|
||||||
|
|
||||||
Lag-alignment mot Voyage og app-factory er dokumentert i `../app-factory/docs/alignment-brief.md` (kontrakter) og `../app-factory/docs/architecture-brief.md` (tre-tier HTML-arkitektur og verktøy-agnostisk invariant). Disse dokumentene låser kontrakter og arkitektur-invarianter; runtime-asymmetrien (app-creator vet ikke om app-factory) er bevart — referansene er kun for design-fasen.
|
Lag-alignment mot Voyage og app-factory er dokumentert i `../app-factory/docs/alignment-brief.md` (kontrakter) og `../app-factory/docs/architecture-brief.md` (tre-tier HTML-arkitektur og verktøy-agnostisk invariant). Disse dokumentene låser kontrakter og arkitektur-invarianter; runtime-asymmetrien (app-creator vet ikke om app-factory) er bevart — referansene er kun for design-fasen.
|
||||||
|
|
||||||
## Hva app-creator er
|
## Hva app-creator er
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
# Domain-pack-spec (app-creator)
|
# Domain-pack-spec (app-creator)
|
||||||
|
|
||||||
<!-- Skrevet: 2026-05-11 (S5) -->
|
<!-- Skrevet: 2026-05-11 (S5). Revidert: 2026-05-12 (S6) — pack.json `components`-felt + status; core/supplementary-merking låst til pack.json; checklist-splitt-konvensjon; D7 oppdatert (pakkene forfattet); iOS-versjons-korreksjon (iOS 26, ikke "iOS 18/19"); restrisiko-lista oppdatert. -->
|
||||||
<!-- Status: FØRSTEUTKAST. Domene-nøytral spec. Referanse-pakkene (ios-app, claude-code-plugin) forfattes i S6 — kun skissert her (§ 7). Spec-en er hypotese inntil den første referanse-pakken faktisk er bygget og konsumert av en pipeline-fase. -->
|
<!-- Status: ANDREUTKAST. Domene-nøytral spec. Referanse-pakkene (ios-app komplett, claude-code-plugin som stub) er forfattet i `../domain-packs/` (S6). Spec-en er fortsatt hypotese inntil den første referanse-pakken faktisk er konsumert av en pipeline-fase (S8+). -->
|
||||||
<!-- Begrunnelse / research-grunnlag: prototype-run/research/research-brief.md § 5 (D1–D7), prototype-run/research/C-domain-packs.md § 5, friksjon #5 og #7. -->
|
<!-- Begrunnelse / research-grunnlag: prototype-run/research/research-brief.md § 5 (D1–D7), prototype-run/research/C-domain-packs.md § 5, friksjon #5, #7, #9. -->
|
||||||
|
|
||||||
## D1 — Hva en domain pack er
|
## D1 — Hva en domain pack er
|
||||||
|
|
||||||
|
|
@ -35,7 +35,7 @@ Hver komponent er en dedikert fil eller katalog under en `domain-pack/`-rot. Sek
|
||||||
| 7 | Reference impl | `examples/` | Eksempel-briefer, eksempel-artefakter — konsumeres av brief-generator i fase 6/7 som "slik ser en god feature-brief ut i dette domenet". | supplementary |
|
| 7 | Reference impl | `examples/` | Eksempel-briefer, eksempel-artefakter — konsumeres av brief-generator i fase 6/7 som "slik ser en god feature-brief ut i dette domenet". | supplementary |
|
||||||
| 8 | Glossary | `glossary.md` | Domene-vokabular — lastes selektivt (fase 1 ved behov, ved oppslag). | supplementary |
|
| 8 | Glossary | `glossary.md` | Domene-vokabular — lastes selektivt (fase 1 ved behov, ved oppslag). | supplementary |
|
||||||
|
|
||||||
**Hard lengde-grense per fil:** ~500 ord / én skjerm der mulig. Lange filer er usynlige for agenten (Cursor-erfaringen: regler ignoreres når de blir for lange). Hvis en pattern-fil eller checklist sprenger grensen: del den i flere filer under `patterns/` eller seksjoner i `checklist.md` som lastes uavhengig. `examples/`-filer er unntatt grensen (de er referanse-materiale, ikke instruksjon).
|
**Hard lengde-grense per fil:** ~500 ord / én skjerm der mulig. Lange filer er usynlige for agenten (Cursor-erfaringen: regler ignoreres når de blir for lange). Hvis en pattern-fil eller checklist sprenger grensen: del den i flere filer — `patterns/{a}.md`, `patterns/{b}.md`, eller `checklist.md` + `checklist-{tema}.md` (som i `ios-app`: `checklist.md` = App Store-submission + index, `checklist-security-privacy.md` = MASVS + privacy-manifest, `checklist-accessibility.md` = WCAG 2.2 AA — hver lastes uavhengig). Hver split-fil får sin egen `components`-oppføring i `pack.json`. `examples/`-filer er unntatt grensen (referanse-materiale, ikke instruksjon).
|
||||||
|
|
||||||
**Katalog-layout:**
|
**Katalog-layout:**
|
||||||
```
|
```
|
||||||
|
|
@ -43,7 +43,7 @@ domain-pack/ ({name}/)
|
||||||
├── pack.json
|
├── pack.json
|
||||||
├── conventions.md
|
├── conventions.md
|
||||||
├── gotchas.md
|
├── gotchas.md
|
||||||
├── checklist.md
|
├── checklist.md # + valgfri checklist-{tema}.md-splitt
|
||||||
├── glossary.md
|
├── glossary.md
|
||||||
├── patterns/
|
├── patterns/
|
||||||
│ ├── {pattern-a}.md
|
│ ├── {pattern-a}.md
|
||||||
|
|
@ -64,10 +64,17 @@ Minimalt JSON-manifest. Ingen npm-semantikk, ingen build-step, ingen lock-fil.
|
||||||
"schema": "domain-pack/v1",
|
"schema": "domain-pack/v1",
|
||||||
"name": "ios-app",
|
"name": "ios-app",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"domain": "iOS-app-utvikling (Swift/SwiftUI)",
|
"domain": "iOS-app-utvikling (Swift/SwiftUI, App Store-distribusjon)",
|
||||||
"description": "Domene-kunnskap for iOS-app-utvikling med Swift/SwiftUI",
|
"description": "Domene-kunnskap for iOS-app-utvikling: HIG/Liquid Glass, Swift/SwiftUI, offline-first, App Store-submission, MASVS 2.1, WCAG 2.2 AA, privacy manifest.",
|
||||||
"phases": [1, 3, 4, 5, 6, 7],
|
"phases": [1, 3, 4, 5, 6, 7],
|
||||||
"verified": { "date": "2026-05-11", "against": "iOS 18, HIG WWDC2025, MASVS 2.1, WCAG 2.2" }
|
"verified": { "date": "2026-05-12", "against": "iOS 26 (gjeldende SDK), HIG/Liquid Glass (WWDC 2025), deployment-baseline iOS 17–18, OWASP MASVS 2.1.0, WCAG 2.2 AA", "note": "kildebelegg inline i pack-filene" },
|
||||||
|
"components": {
|
||||||
|
"conventions.md": "core",
|
||||||
|
"gotchas.md": "core",
|
||||||
|
"checklist.md": "core",
|
||||||
|
"patterns/offline-first-swiftdata.md": "supplementary",
|
||||||
|
"scaffold/PrivacyInfo.xcprivacy": "supplementary"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -79,7 +86,9 @@ Minimalt JSON-manifest. Ingen npm-semantikk, ingen build-step, ingen lock-fil.
|
||||||
| `domain` | string | ja | Menneskelesbar domene-beskrivelse. |
|
| `domain` | string | ja | Menneskelesbar domene-beskrivelse. |
|
||||||
| `description` | string | ja | Én-linjes formålsbeskrivelse. |
|
| `description` | string | ja | Én-linjes formålsbeskrivelse. |
|
||||||
| `phases` | number[] | ja | Hvilke pipeline-faser som *kan* laste fra pakken (1–7). En fase som ikke er i lista laster ikke pack-filer. |
|
| `phases` | number[] | ja | Hvilke pipeline-faser som *kan* laste fra pakken (1–7). En fase som ikke er i lista laster ikke pack-filer. |
|
||||||
| `verified` | object | ja | `{ "date": "YYYY-MM-DD", "against": "..." }` — sist-verifisert-dato + mot hvilken versjon av domenet (iOS-versjon, HIG-utgave, standard-versjoner). Gjør at man ser når en pakke er i ferd med å råtne. |
|
| `verified` | object | ja | `{ "date": "YYYY-MM-DD", "against": "...", "note"?: "..." }` — sist-verifisert-dato + mot hvilken versjon av domenet (iOS-versjon, HIG-utgave, standard-versjoner) + valgfri kilde-note. Gjør at man ser når en pakke er i ferd med å råtne. |
|
||||||
|
| `components` | object | ja | Map fra hver pack-fil-sti (relativt pakke-roten) til `"core"` eller `"supplementary"`. **Dette er den autoritative core/supplementary-merkingen** (S6-beslutning — sentralt i manifestet, ikke spredt i fil-headere; en kort `<!-- core/supplementary -->`-kommentar i toppen av hver fil er kun en menneske-leselig redundans). `core`-filene materialiseres sammenslått inn i `00-context/domain-pack-{name}.md`; `supplementary` lastes on-demand. |
|
||||||
|
| `status` | string | nei | Fritekst om pakkens modenhet (f.eks. "stub — kun core-filene ferdige"). Kun for pakker under arbeid. |
|
||||||
|
|
||||||
Ingenting i `pack.json` er menneske-leselig *innhold* — alt innhold lever i markdown-filene. Manifestet er kun maskinlesbart metadata.
|
Ingenting i `pack.json` er menneske-leselig *innhold* — alt innhold lever i markdown-filene. Manifestet er kun maskinlesbart metadata.
|
||||||
|
|
||||||
|
|
@ -102,7 +111,7 @@ Ingenting i `pack.json` er menneske-leselig *innhold* — alt innhold lever i ma
|
||||||
|
|
||||||
**Materialisert snapshot i `00-context/`.** Ved init av app-creator-instansen (eller når en pack legges til) materialiseres et snapshot av pakken — versjonen appen bruker — inn i `{app-creator-instance-dir}/00-context/domain-pack-{name}.md`. Snapshotet er en sammenslått, lesbar form av pakkens core-komponenter (conventions + gotchas + checklist + de patterns appen faktisk bruker), med pack-versjonen innskrevet i toppen. Begrunnelse: embedding slår linking for AI-konsum (BMAD-prinsippet) — fase 7-`context.md` embedder utdrag fra dette snapshotet, ikke pekere til en ekstern pakke som kan ha endret seg. (Copier-mønsteret: den genererte appen "kjenner" sin egen versjon av kilden.)
|
**Materialisert snapshot i `00-context/`.** Ved init av app-creator-instansen (eller når en pack legges til) materialiseres et snapshot av pakken — versjonen appen bruker — inn i `{app-creator-instance-dir}/00-context/domain-pack-{name}.md`. Snapshotet er en sammenslått, lesbar form av pakkens core-komponenter (conventions + gotchas + checklist + de patterns appen faktisk bruker), med pack-versjonen innskrevet i toppen. Begrunnelse: embedding slår linking for AI-konsum (BMAD-prinsippet) — fase 7-`context.md` embedder utdrag fra dette snapshotet, ikke pekere til en ekstern pakke som kan ha endret seg. (Copier-mønsteret: den genererte appen "kjenner" sin egen versjon av kilden.)
|
||||||
|
|
||||||
**core vs supplementary-merking.** Hver pack-fil merkes `core` (alltid relevant for de fasene den gjelder) eller `supplementary` (lastes kun ved eksplisitt behov). Snapshotet i `00-context/` inkluderer core-komponentene; supplementary lastes on-demand fra `domain-packs/{name}/` direkte.
|
**core vs supplementary-merking (S6-beslutning).** Hver pack-fil merkes `core` (alltid relevant for de fasene den gjelder) eller `supplementary` (lastes kun ved eksplisitt behov). **Merkingen ligger sentralt i `pack.json` under `components`** — ikke spredt i fil-headere; en kort `<!-- domain-pack: {name} · component: {type} · core/supplementary -->`-kommentar i toppen av hver fil er kun menneske-leselig redundans, ikke kilden. Snapshotet i `00-context/` inkluderer core-komponentene; supplementary lastes on-demand fra `domain-packs/{name}/` direkte. (Begrunnelse: én autoritativ kilde for hva som er core, og maskinlesbar — en snapshot-generator kan lese `components` direkte uten å parse fil-headere.)
|
||||||
|
|
||||||
**Ingen runtime-framework.** Hele mekanikken er: fase-agent leser `state.json` → finner `domain_pack`-verdien → resolver stien (`domain-packs/{name}/` i plugin-roten) → leser den/de fil(ene) fase-prompten ber om → bruker `00-context/`-snapshotet for embedding i fase 7. Matcher filsystem-som-state-invarianten. Zero eksterne verktøy.
|
**Ingen runtime-framework.** Hele mekanikken er: fase-agent leser `state.json` → finner `domain_pack`-verdien → resolver stien (`domain-packs/{name}/` i plugin-roten) → leser den/de fil(ene) fase-prompten ber om → bruker `00-context/`-snapshotet for embedding i fase 7. Matcher filsystem-som-state-invarianten. Zero eksterne verktøy.
|
||||||
|
|
||||||
|
|
@ -144,13 +153,13 @@ Når en feature-brief overleveres til Voyage (fase 7):
|
||||||
|
|
||||||
Praktisk: når fase 7 skriver `context.md`, henter den relevante avsnitt fra `00-context/domain-pack-{name}.md`-snapshotet (med `pack-overrides.md` anvendt), parafraserer/utdrag-er dem inn under `## Domain-pack-utdrag`-seksjonen som *bare kontekst* — uten metadata om hvor det kom fra.
|
Praktisk: når fase 7 skriver `context.md`, henter den relevante avsnitt fra `00-context/domain-pack-{name}.md`-snapshotet (med `pack-overrides.md` anvendt), parafraserer/utdrag-er dem inn under `## Domain-pack-utdrag`-seksjonen som *bare kontekst* — uten metadata om hvor det kom fra.
|
||||||
|
|
||||||
## D7 — Referanse-pakkene (skisse — S6 forfatter dem)
|
## D7 — Referanse-pakkene (forfattet i S6)
|
||||||
|
|
||||||
app-creator shipper to referanse-pakker som eksempel-implementasjoner. Fork-and-own-brukere lager egne. **Disse skisseres her, ikke spesifiseres — S6 er forfatter-sesjonen.**
|
app-creator shipper to referanse-pakker som eksempel-implementasjoner i [`../domain-packs/`](../domain-packs/). Fork-and-own-brukere lager egne. **Skissen under er beholdt for kontekst; den realiserte tilstanden er i `domain-packs/`.** S6 (2026-05-12) forfattet `ios-app` komplett (alle 8 komponenter; `checklist.md` splittet i 3); `claude-code-plugin` som stub (`pack.json` + `conventions.md` + `gotchas.md` + `checklist.md` + `glossary.md` ferdige). **Korreksjon under verifisering (S6):** "iOS 18 / HIG WWDC2025" i skissen var basert på prototype-data — den verifiserte tilstanden er at gjeldende iOS er **iOS 26** (Liquid Glass, WWDC 2025; iOS 19–25 finnes ikke — Apple gikk fra iOS 18 til iOS 26), deployment-target-baseline iOS 17–18, MASVS **2.1.0**, WCAG 2.2 AA (W3C Rec 2023-10-05). `ios-app/pack.json` `verified` reflekterer dette. (Akashic-`01-app-brief.md`s "iOS 19" rettes i S7 — se `prototype-run/friksjon.md` #9.)
|
||||||
|
|
||||||
### `ios-app`-pakke (fra Akashics reelle behov)
|
### `ios-app`-pakke (fra Akashics reelle behov)
|
||||||
|
|
||||||
- **`pack.json`:** `name: "ios-app"`, `version: "0.1.0"`, `phases: [1, 3, 4, 5, 6, 7]`, `verified` mot iOS 18 / HIG WWDC2025 / MASVS 2.1 / WCAG 2.2.
|
- **`pack.json`:** `name: "ios-app"`, `version: "0.1.0"`, `phases: [1, 3, 4, 5, 6, 7]`, `verified` mot iOS 26 / HIG/Liquid Glass (WWDC 2025) / deployment-baseline iOS 17–18 / OWASP MASVS 2.1.0 / WCAG 2.2 AA; `components`-map merker core/supplementary.
|
||||||
- **`conventions.md`:** HIG-regler (navigasjon, layout, "Liquid Glass"-konformans-notat); Swift/SwiftUI-konvensjoner; MVVM-vs-TCA-veiledning (når hva); min-iOS-versjon-policy; guardrails-underseksjon (App Store-constraints du ikke avviker fra; GDPR-håndtering).
|
- **`conventions.md`:** HIG-regler (navigasjon, layout, "Liquid Glass"-konformans-notat); Swift/SwiftUI-konvensjoner; MVVM-vs-TCA-veiledning (når hva); min-iOS-versjon-policy; guardrails-underseksjon (App Store-constraints du ikke avviker fra; GDPR-håndtering).
|
||||||
- **`patterns/`:** `offline-first-swiftdata.md`, `local-notifications.md`, `widget-live-activities-shared-model.md` (deling av datamodell mellom app/widget/Live Activity), `current-location-regeneration.md` (current-location-basert beregning + fallback ved nektet permission).
|
- **`patterns/`:** `offline-first-swiftdata.md`, `local-notifications.md`, `widget-live-activities-shared-model.md` (deling av datamodell mellom app/widget/Live Activity), `current-location-regeneration.md` (current-location-basert beregning + fallback ved nektet permission).
|
||||||
- **`gotchas.md`:** required-reason-API-deklarasjon (manglende = avvisning); ATS-unntak uten begrunnelse; `NSUsageDescription` manglende = umiddelbar App Store-avvisning; vanlige App Store Review-avvisnings-triggere.
|
- **`gotchas.md`:** required-reason-API-deklarasjon (manglende = avvisning); ATS-unntak uten begrunnelse; `NSUsageDescription` manglende = umiddelbar App Store-avvisning; vanlige App Store Review-avvisnings-triggere.
|
||||||
|
|
@ -172,10 +181,13 @@ app-creator shipper to referanse-pakker som eksempel-implementasjoner. Fork-and-
|
||||||
|
|
||||||
## Åpne spørsmål / restrisiko
|
## Åpne spørsmål / restrisiko
|
||||||
|
|
||||||
- **Snapshot-materialiserings-mekanikk.** Nøyaktig hvordan `00-context/domain-pack-{name}.md` genereres fra `domain-packs/{name}/` (hvilke filer slås sammen, i hvilken rekkefølge, hvor mye trimmes) — låses når den første pakken faktisk materialiseres i S7. Inntil da: "core-komponentene, sammenslått, pack-versjon innskrevet".
|
- **Snapshot-materialiserings-mekanikk.** Nøyaktig hvordan `00-context/domain-pack-{name}.md` genereres fra `domain-packs/{name}/` — låses når den første pakken faktisk materialiseres i **S7**. S6-presisering: generatoren leser `pack.json` → `components`, slår sammen alle `"core"`-filene i den rekkefølgen `components` lister dem (`conventions.md`, `gotchas.md`, `checklist.md` + evt. `checklist-{tema}.md`), skriver pack-navn + `version` + materialiserings-dato i toppen, anvender `00-context/pack-overrides.md` på slutten. `supplementary` tas *ikke* med — lastes on-demand. Eksakt trimming/seksjonering avgjøres i S7 mot den faktiske `ios-app`-pakken.
|
||||||
- **`pack.md` med YAML-frontmatter som alternativ til `pack.json`.** Thread C nevnte begge. S5-valg: `pack.json` (rent maskinlesbart, ingen risiko for at noen putter innhold i frontmatter). Revurderes hvis det viser seg upraktisk.
|
- **`core` vs `supplementary`-merking — LÅST (S6).** Ligger i `pack.json` → `components` (map fil-sti → `"core"`/`"supplementary"`). Fil-headere har en redundant kommentar for menneske-lesere, men `components` er kilden. Se § D2 / § D3 / § D4.
|
||||||
- **Når en fase trenger en `patterns/`-fil som ikke er i `phases`-lista.** Skal pakken da utvides, eller skal fasen klare seg uten? Sannsynlig: utvid pakken (en pattern relevant for en fase hører i pakken) — men det er en S6+-beslutning per konkret tilfelle.
|
- **`pack.md` med YAML-frontmatter som alternativ til `pack.json` — LUKKET (S5/S6).** `pack.json` valgt og brukt; ingen grunn til å revurdere. Tatt ut av risiko-lista.
|
||||||
- **Pakke-deling på tvers av repos.** Hvis app-creator-instanser i ulike repos vil dele samme `ios-app`-pakke: da må lagrings-stedet flyttes til `~/.claude/domain-packs/` eller eget repo. Ikke et problem så lenge forfatteren er eneste konsument med pakkene i plugin-roten.
|
- **Når en fase trenger en `patterns/`-fil som ikke er i `phases`-lista.** Skal pakken da utvides, eller skal fasen klare seg uten? Sannsynlig: utvid pakken (en pattern relevant for en fase hører i pakken) — men det er en per-tilfelle-beslutning. Ikke truffet i S6 (ingen fase ble kjørt).
|
||||||
|
- **`pack.json` `verified` håndheves ikke automatisk.** Ingen mekanisme sjekker at `verified.date` ikke er for gammel; det er en menneskelig disiplin. Hvis pakker råtner i praksis: vurder en lett validator (`.mjs`) som flagger gamle `verified`-datoer. YAGNI inntil bevist behov.
|
||||||
|
- **Pakke-deling på tvers av repos.** Hvis app-creator-instanser i ulike repos vil dele samme `ios-app`-pakke: lagrings-stedet må flyttes til `~/.claude/domain-packs/` eller eget repo. Ikke et problem så lenge forfatteren er eneste konsument med pakkene i plugin-roten.
|
||||||
|
- **Domene-versjons-drift (iOS spesielt).** `ios-app`-pakken er verifisert mot iOS 26 / WCAG 2.2 / MASVS 2.1.0 per 2026-05-12. iOS 27 kommer høst 2026 — da må `conventions.md`, `gotchas.md`, `checklist*.md` og `pack.json` `verified` revideres, minor- eller major-bump avhengig av om noe brytende endres. Logget mønster, ikke et åpent designspørsmål.
|
||||||
|
|
||||||
## Kilder
|
## Kilder
|
||||||
|
|
||||||
|
|
@ -184,3 +196,4 @@ app-creator shipper to referanse-pakker som eksempel-implementasjoner. Fork-and-
|
||||||
- `prototype-run/research/D-feature-artifacts.md` § 2 — BMAD-prinsippet (embedding slår linking for AI-konsum) som begrunner `00-context/`-snapshot framfor ekstern peker.
|
- `prototype-run/research/D-feature-artifacts.md` § 2 — BMAD-prinsippet (embedding slår linking for AI-konsum) som begrunner `00-context/`-snapshot framfor ekstern peker.
|
||||||
- `prototype-run/friksjon.md` #5 (flat layout antok ikke domain-pack-kontekst), #7 (tre sjekkliste-grupper uten eierfase — løses av `checklist.md`-komponenten).
|
- `prototype-run/friksjon.md` #5 (flat layout antok ikke domain-pack-kontekst), #7 (tre sjekkliste-grupper uten eierfase — løses av `checklist.md`-komponenten).
|
||||||
- `phase-design-draft.md` — fase-seksjonene som konsumerer pakkene; `CLAUDE.md` — verktøy-agnostisk- og Voyage-agnostisk-invariantene D6 respekterer.
|
- `phase-design-draft.md` — fase-seksjonene som konsumerer pakkene; `CLAUDE.md` — verktøy-agnostisk- og Voyage-agnostisk-invariantene D6 respekterer.
|
||||||
|
- **S6-verifiseringskilder for `ios-app`-pakken** (per-påstand inline i pack-filene): Apple Developer (developer.apple.com — privacy-manifest, required-reason API, App Store Connect screenshot specs, Upcoming Requirements, ATT/ATS, UNUserNotificationCenter, Live Activities, Liquid Glass/HIG, App Store Review Guidelines); W3C WAI (w3.org/WAI — WCAG 2.2 What's New + W3C Recommendation 2023-10-05); OWASP MAS (mas.owasp.org — MASVS 2.1.0, 8 kontroll-grupper). `claude-code-plugin`-pakken: ekstrahert fra ktg-privat `CLAUDE.md` + `.claude/rules/{plugin-convention,hook-format}.md` (intern konvensjon) — plattform-detaljer (hooks-API, `${CLAUDE_PLUGIN_ROOT}`, auto-discovery) bør re-verifiseres mot offisiell Claude Code-dokumentasjon ved neste oppdatering (ikke gjort uttømmende i S6 — pakken er en stub).
|
||||||
|
|
|
||||||
14
domain-packs/README.md
Normal file
14
domain-packs/README.md
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
# domain-packs/
|
||||||
|
|
||||||
|
Referanse-domain-packs som shippes med app-creator. En **domain pack** er en gjenbrukbar kunnskaps-bunt (conventions, patterns, gotchas, checklists, scaffolding, examples, glossary) som pipeline-fasene 1 og 3–7 konsumerer for å realisere en app i et bestemt domene.
|
||||||
|
|
||||||
|
**Full spec:** [`../docs/domain-pack-spec.md`](../docs/domain-pack-spec.md) — komponent-liste, `pack.json`-skjema, aktiverings-mekanisme, versjonering, Voyage-agnostisk håndtering.
|
||||||
|
|
||||||
|
| Pack | Domene | Status | Faser |
|
||||||
|
|------|--------|--------|-------|
|
||||||
|
| [`ios-app/`](ios-app/) | iOS-app-utvikling (Swift/SwiftUI, App Store) | Komplett referanse-pakke (alle 8 komponenter) | 1, 3, 4, 5, 6, 7 |
|
||||||
|
| [`claude-code-plugin/`](claude-code-plugin/) | Claude Code-plugin-utvikling | Stub — `pack.json` + `conventions.md` + `gotchas.md` + `checklist.md` + `glossary.md` ferdige; `patterns/`/`scaffold/`/`examples/` er stubs | 1, 3, 5, 6, 7 |
|
||||||
|
|
||||||
|
Fork-and-own-brukere lager egne pakker. Disse to er eksempel-implementasjoner.
|
||||||
|
|
||||||
|
**Lengde-grense:** ~500 ord / én skjerm per fil (`examples/` unntatt). **core/supplementary**-merking ligger i hver `pack.json` under `components`. core-filene materialiseres sammenslått inn i en app-instans' `00-context/domain-pack-{name}.md`-snapshot; supplementary lastes on-demand.
|
||||||
64
domain-packs/claude-code-plugin/checklist.md
Normal file
64
domain-packs/claude-code-plugin/checklist.md
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
<!-- domain-pack: claude-code-plugin · component: checklists · core -->
|
||||||
|
<!-- Ekstrahert 2026-05-12 fra ktg-privat CLAUDE.md + .claude/rules/. -->
|
||||||
|
|
||||||
|
# Claude Code-plugin — sjekkliste
|
||||||
|
|
||||||
|
Fase-exit-kriterier for en plugin i ktg-privat-mønsteret. En `[skip]`-merket linje begrunnes i `00-context/pack-overrides.md`.
|
||||||
|
|
||||||
|
## A. Struktur & manifest
|
||||||
|
|
||||||
|
- [ ] `.claude-plugin/plugin.json` finnes, gyldig JSON, `auto_discover: true`.
|
||||||
|
- [ ] Mappestruktur følger mønsteret (`commands/`, `agents/`, `skills/`, `hooks/`, `templates/` etter behov).
|
||||||
|
- [ ] `README.md` finnes og beskriver plugin-formål + hovedcommand.
|
||||||
|
- [ ] `CLAUDE.md` finnes, **< 100 linjer**, tabell-basert.
|
||||||
|
- [ ] `*.local.md` i `.gitignore`.
|
||||||
|
- [ ] **`plugin-dev:plugin-validator` kjørt og passerer** (struktur, frontmatter, cross-komponent-koherens).
|
||||||
|
|
||||||
|
## B. Navnekonvensjoner
|
||||||
|
|
||||||
|
- [ ] Commands: `command.md` → `/plugin:command`.
|
||||||
|
- [ ] Agents: `descriptive-name-agent.md`.
|
||||||
|
- [ ] Skills: `skill-name/SKILL.md` (+ `references/*.md` ved behov).
|
||||||
|
|
||||||
|
## C. Frontmatter
|
||||||
|
|
||||||
|
- [ ] Hver command har `name`, `description`, `allowed-tools`, `model`.
|
||||||
|
- [ ] Hver agent har `name`, multi-line `description` med **when-to-use** + eksempler, `model`, `color`, `tools`.
|
||||||
|
- [ ] Hver skill har `name` + en `description` som beskriver hva **og når** (triggering-effektiv — kjør `plugin-dev:skill-reviewer`).
|
||||||
|
|
||||||
|
## D. Hooks (hvis pluginen har hooks)
|
||||||
|
|
||||||
|
- [ ] `hooks/hooks.json` finnes; `hooks` er et **objekt** med event-nøkler.
|
||||||
|
- [ ] `matcher` er en string, ikke et objekt.
|
||||||
|
- [ ] Stier bruker `${CLAUDE_PLUGIN_ROOT}`.
|
||||||
|
- [ ] `"hooks"` er **ikke** deklarert i `plugin.json`.
|
||||||
|
- [ ] Hook-scripts er `.mjs` (eller bash 3.2-kompatible hvis bash er nødvendig).
|
||||||
|
- [ ] Hver hook står i `CLAUDE.md`s hook-tabell (event, script, formål).
|
||||||
|
|
||||||
|
## E. Context-budget
|
||||||
|
|
||||||
|
- [ ] Ingen agent-invokasjon laster > 3 knowledge-filer.
|
||||||
|
- [ ] Ingen hele-katalog-lasting — spesifikke filer navngis.
|
||||||
|
- [ ] Registrerte `subagent_type` brukes (ikke `general-purpose` + "les agentfilen").
|
||||||
|
- [ ] Sekvensiell agent-spawning som default (parallell begrunnet der brukt).
|
||||||
|
- [ ] SKILL.md bruker progressive disclosure.
|
||||||
|
|
||||||
|
## F. Dokumentasjon & kvalitet
|
||||||
|
|
||||||
|
- [ ] `CLAUDE.md` har alle påkrevde seksjoner: tittel/beskrivelse, commands-tabell, agents-tabell, hooks-tabell, arkitektur, state-håndtering (hvis relevant).
|
||||||
|
- [ ] `CLAUDE.md` scorer **Grade B (70+/100)** på config-audit-kvalitetsvurderingen.
|
||||||
|
- [ ] `CLAUDE.md`-oppdatering er i **samme commit** som endringen den dokumenterer.
|
||||||
|
- [ ] Linear-label dokumentert i `CLAUDE.md` (hvis konvensjonen gjelder).
|
||||||
|
|
||||||
|
## G. Commit & release
|
||||||
|
|
||||||
|
- [ ] Conventional Commits (`type(scope): beskrivelse`).
|
||||||
|
- [ ] Versjonsbump → alle versjons-refererende filer oppdatert i samme commit (`plugin.json`, README-badges, CHANGELOG, konstanter).
|
||||||
|
- [ ] Committet + pushet (Forgejo, ikke GitHub).
|
||||||
|
- [ ] Marketplace-sync hvis pluginen er nyregistrert/omdøpt.
|
||||||
|
|
||||||
|
## H. Røyktest
|
||||||
|
|
||||||
|
- [ ] Alle slash-commands kjører uten feil.
|
||||||
|
- [ ] Agenter triggerer på sine beskrevne situasjoner.
|
||||||
|
- [ ] Hooks fyrer og oppfører seg som forventet (ingen falske positiver som blokkerer arbeid).
|
||||||
101
domain-packs/claude-code-plugin/conventions.md
Normal file
101
domain-packs/claude-code-plugin/conventions.md
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
<!-- domain-pack: claude-code-plugin · component: conventions · core -->
|
||||||
|
<!-- Ekstrahert 2026-05-12 fra ktg-privat CLAUDE.md + .claude/rules/. Re-verifiser plattform-detaljer mot offisiell Claude Code-dokumentasjon. -->
|
||||||
|
|
||||||
|
# Claude Code-plugin — konvensjoner
|
||||||
|
|
||||||
|
Ikke-forhandlbare beslutninger for plugins i ktg-privat-mønsteret. Avvik krever en `00-context/pack-overrides.md`-oppføring.
|
||||||
|
|
||||||
|
## Mappestruktur
|
||||||
|
|
||||||
|
```
|
||||||
|
plugin-name/
|
||||||
|
├── .claude-plugin/plugin.json # Manifest (auto_discover: true)
|
||||||
|
├── commands/ # Slash-commands → /plugin:command
|
||||||
|
├── agents/ # Subagenter med frontmatter
|
||||||
|
├── skills/ # skill-name/SKILL.md + references/
|
||||||
|
├── hooks/
|
||||||
|
│ ├── hooks.json # Hook-konfig (auto-discovered)
|
||||||
|
│ └── scripts/ # Executable scripts (.mjs)
|
||||||
|
├── templates/ # Prosjekt-templates (valgfri)
|
||||||
|
├── README.md # Plugin-dokumentasjon
|
||||||
|
├── CLAUDE.md # Plugin-instruksjoner
|
||||||
|
└── plugin.local.md # Lokal konfig (gitignored)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Navnekonvensjoner
|
||||||
|
|
||||||
|
| Komponent | Mønster | Eksempel |
|
||||||
|
|-----------|---------|----------|
|
||||||
|
| Commands | `command.md` | `build.md` → `/plugin:build` |
|
||||||
|
| Agents | `descriptive-name-agent.md` | `gap-analysis-agent.md` |
|
||||||
|
| Skills | `skill-name/SKILL.md` | `prd-writing/SKILL.md` |
|
||||||
|
| References | `skill-name/references/*.md` | `prd-writing/references/task-format.md` |
|
||||||
|
|
||||||
|
## Frontmatter
|
||||||
|
|
||||||
|
**Commands:**
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
name: plugin:command
|
||||||
|
description: Short description
|
||||||
|
allowed-tools: Read, Write, Bash, Task
|
||||||
|
model: sonnet
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
**Agents:**
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
name: agent-name
|
||||||
|
description: |
|
||||||
|
Multi-line description for WHEN to use this agent (triggering matters).
|
||||||
|
model: opus|sonnet|haiku
|
||||||
|
color: blue|green|yellow|purple|cyan
|
||||||
|
tools: ["Read", "Glob", "Task"]
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
**Skills:** `SKILL.md` har `name` + en `description` som avgjør triggering — beskriv hva skillen gjør *og når den skal aktiveres*. Bruk progressive disclosure: kompakt SKILL.md + `references/` for detaljer.
|
||||||
|
|
||||||
|
## Hooks-format
|
||||||
|
|
||||||
|
- `hooks` er et **objekt** med event-nøkler (`SessionStart`, `UserPromptSubmit`, `PreToolUse`, `PostToolUse`, `Stop`, …) — **ikke** en array.
|
||||||
|
- `matcher` er en **enkel string** (`"Bash"`, `"Write|Edit"`) — **ikke** et nestet objekt.
|
||||||
|
- Bruk `${CLAUDE_PLUGIN_ROOT}` for script-stier.
|
||||||
|
- **Ikke** deklarer `"hooks"` i `plugin.json` — Claude Code auto-discoverer `hooks/hooks.json`.
|
||||||
|
- Runtime-hooks er Node.js `.mjs` (cross-platform: macOS/Linux/Windows) — ingen bash/Python-runtime-avhengighet.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"hooks": {
|
||||||
|
"PreToolUse": [
|
||||||
|
{ "matcher": "Bash",
|
||||||
|
"hooks": [{ "type": "command", "command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/firewall.mjs" }] }
|
||||||
|
],
|
||||||
|
"Stop": [
|
||||||
|
{ "hooks": [{ "type": "prompt", "prompt": "Reminder text." }] }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Context-budget-regler (gjelder alle plugins)
|
||||||
|
|
||||||
|
1. Max **3 knowledge-filer** per agent-invokasjon — les kun det oppgaven trenger.
|
||||||
|
2. Aldri last hele kataloger — navngi spesifikke filer, ikke `references/`.
|
||||||
|
3. Bruk **registrerte `subagent_type`** — ikke `general-purpose` + "les agentfilen".
|
||||||
|
4. **Sekvensiell agent-spawning** som default; parallell kun med begrunnelse.
|
||||||
|
5. Supplementære filer (templates, matrices) lastes kun ved eksplisitt behov.
|
||||||
|
6. SKILL.md = progressive disclosure (kompakt oversikt + `references/`).
|
||||||
|
7. Plugin-`CLAUDE.md` **under 100 linjer** — tabeller, ikke prosa. Påkrevde seksjoner: tittel/beskrivelse, commands-tabell, agents-tabell, hooks-tabell, arkitektur, state-håndtering.
|
||||||
|
|
||||||
|
## Guardrails
|
||||||
|
|
||||||
|
- **`CLAUDE.md` oppdateres i samme commit som endringen den dokumenterer** — ny agent → agent-tabell; ny command → command-tabell; ny hook → hook-oversikt; strukturendring → relevant seksjon. Ikke batch dokumentasjon til en separat commit.
|
||||||
|
- **Plugin-`CLAUDE.md` skal score Grade B (70+/100)** på config-audit-kvalitetsvurderingen.
|
||||||
|
- **Bash 3.2-kompatibilitet** for alle shell-/hook-scripts (macOS-default): ingen `declare -A`, ingen `readarray`/`mapfile`, ingen `|&`. (Foretrekk `.mjs`.)
|
||||||
|
- Conventional Commits: `type(scope): beskrivelse`.
|
||||||
|
|
||||||
|
## core / supplementary
|
||||||
|
|
||||||
|
`pack.json` → `components` er autoritativ. `00-context/`-snapshotet inkluderer core (`conventions.md`, `gotchas.md`, `checklist.md`); supplementary lastes on-demand.
|
||||||
14
domain-packs/claude-code-plugin/examples/README.md
Normal file
14
domain-packs/claude-code-plugin/examples/README.md
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<!-- domain-pack: claude-code-plugin · component: examples · supplementary · STUB -->
|
||||||
|
|
||||||
|
# examples/ — STUB (forfattes senere)
|
||||||
|
|
||||||
|
Planlagt referanse-materiale:
|
||||||
|
|
||||||
|
- `feature-brief-add-command.md` — eksempel-feature-brief (Voyage strict-mode) for "legg til en ny slash-command i en plugin" — illustrerer hvordan en plugin-feature-brief ser ut.
|
||||||
|
- Pekere til eksisterende ktg-privat-plugins som referanse-implementasjoner:
|
||||||
|
- `kiur` — 3-lags-arkitektur, max-3-regel, hooks.
|
||||||
|
- `harness` — "ikke last alt på en gang", multi-session state.
|
||||||
|
- `vegnormalene` — ren MCP/RAG-plugin.
|
||||||
|
- `newsletter` — mange-agent-orkestrering (18 agenter).
|
||||||
|
|
||||||
|
Forfatt et faktisk eksempel-brief når en plugin-feature faktisk drives gjennom pipelinen — da blir det informert av reell bruk, ikke spekulasjon (samme prinsipp som `ios-app/examples/`).
|
||||||
28
domain-packs/claude-code-plugin/glossary.md
Normal file
28
domain-packs/claude-code-plugin/glossary.md
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
<!-- domain-pack: claude-code-plugin · component: glossary · supplementary -->
|
||||||
|
<!-- Ekstrahert 2026-05-12 fra ktg-privat-konvensjoner + Claude Code-terminologi. -->
|
||||||
|
|
||||||
|
# Claude Code-plugin — glossar
|
||||||
|
|
||||||
|
**Agent (subagent)** — et avgrenset Claude-instans med egen system-prompt, verktøy-sett og modell, spawnet for en deloppgave. Defineres i `agents/descriptive-name-agent.md` med frontmatter (`name`, `description`, `model`, `color`, `tools`). Velges automatisk på `description`-en.
|
||||||
|
|
||||||
|
**Auto-discovery** — Claude Code finner commands/agents/skills/hooks ved konvensjonelle stier uten manuell deklarasjon i `plugin.json` (forutsetter `auto_discover: true`). Hooks auto-discoveres fra `hooks/hooks.json`.
|
||||||
|
|
||||||
|
**`${CLAUDE_PLUGIN_ROOT}`** — miljøvariabel som ekspanderer til plugin-rotmappa ved kjøretid; brukes i hook-command-stier slik at plugin-en virker uavhengig av installasjonssted.
|
||||||
|
|
||||||
|
**Command (slash-command)** — `/plugin:command`, definert i `commands/command.md` med frontmatter (`name`, `description`, `allowed-tools`, `model`). Kjøres av brukeren i terminalen.
|
||||||
|
|
||||||
|
**Hook** — event-drevet automasjon. Konfigureres i `hooks/hooks.json` som et **objekt** med event-nøkler (`SessionStart`, `UserPromptSubmit`, `PreToolUse`, `PostToolUse`, `Stop`, `SubagentStop`, `PreCompact`, `Notification`, `SessionEnd`). To typer: `command` (kjør et script) eller `prompt` (injiser tekst).
|
||||||
|
|
||||||
|
**`matcher`** — i en hook-oppføring: en string som bestemmer hvilke verktøy/eventer hooken gjelder (`"Bash"`, `"Write|Edit"`). Ikke et nestet objekt.
|
||||||
|
|
||||||
|
**MCP (Model Context Protocol)** — protokoll for å koble eksterne verktøy/tjenester til Claude Code; konfigureres via `.mcp.json` i plugin-en. Server-typer: stdio, SSE, HTTP, WebSocket.
|
||||||
|
|
||||||
|
**Marketplace** — register over plugins (her: `ktg-privat`, `ktg-plugin-marketplace`). Plugins aktiveres i `~/.claude/settings.json` under `enabledPlugins` med `plugin@marketplace`-notasjon.
|
||||||
|
|
||||||
|
**Progressive disclosure** — skill-mønster: en kompakt `SKILL.md` med oversikt + `references/*.md` for detaljer som lastes kun ved behov. Holder kontekst-forbruket lavt.
|
||||||
|
|
||||||
|
**Skill** — `skills/skill-name/SKILL.md` (+ `references/`). En `description` som beskriver hva skillen gjør *og når den skal aktiveres* (triggering avhenger av dette). Kan være user-invocable (`/skill-name`) eller modell-invoked.
|
||||||
|
|
||||||
|
**`subagent_type`** — den registrerte typen som velges når man spawner en agent; å bruke `general-purpose` + "les agentfilen" i stedet er en context-budget-anti-pattern.
|
||||||
|
|
||||||
|
**Three-layer architecture** — referansemønster (fra `kiur`): orkestrator-lag (hovedkontekst) / agent-lag (delegert arbeid) / knowledge-lag (`references/`, lastes max 3 av gangen). Brukes for å holde plugins skalerbare uten kontekst-eksplosjon.
|
||||||
35
domain-packs/claude-code-plugin/gotchas.md
Normal file
35
domain-packs/claude-code-plugin/gotchas.md
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
<!-- domain-pack: claude-code-plugin · component: gotchas · core -->
|
||||||
|
<!-- Ekstrahert 2026-05-12 fra ktg-privat CLAUDE.md + .claude/rules/hook-format.md. -->
|
||||||
|
|
||||||
|
# Claude Code-plugin — gotchas ("ikke gjør dette")
|
||||||
|
|
||||||
|
Feil som faktisk har brutt plugins i dette repoet.
|
||||||
|
|
||||||
|
## Hooks
|
||||||
|
|
||||||
|
- **`hooks` som array.** Det er et **objekt** med event-nøkler (`PreToolUse`, `PostToolUse`, `Stop`, `SessionStart`, `UserPromptSubmit`, …). En array feiler stille / lastes ikke.
|
||||||
|
- **`matcher` som nestet objekt.** Det er en **enkel string** — `"Bash"`, `"Write|Edit"`. Et objekt der er feil.
|
||||||
|
- **Deklarere `"hooks"` i `plugin.json`.** Ikke gjør det — Claude Code auto-discoverer `hooks/hooks.json`. Dobbel-deklarasjon = uforutsigbar oppførsel.
|
||||||
|
- **Hardkode stier i hook-commands.** Bruk `${CLAUDE_PLUGIN_ROOT}` — plugin-roten varierer per installasjon.
|
||||||
|
- **Bash-/Python-avhengige hooks.** Runtime-hooks skal være Node.js `.mjs` (cross-platform). Hvis du *må* bruke bash: bash 3.2-kompatibel (ingen `declare -A`, `readarray`/`mapfile`, `|&`) — macOS-default er 3.2.
|
||||||
|
|
||||||
|
## Context-budget
|
||||||
|
|
||||||
|
- **Laste en hel katalog** (`references/`, `references/ai-security/`). Navngi spesifikke filer. Hele kataloger sprenger budsjettet for nedstrøms-arbeid.
|
||||||
|
- **Bruke `general-purpose` + "les agentfilen X"** i stedet for en registrert `subagent_type`. Det dobler kostnaden og hopper over agent-definisjonens egen verktøy-/modell-konfig.
|
||||||
|
- **Preloade "i tilfelle".** Max-3-filer-per-invokasjon. Trenger du en fjerde, les den når behovet oppstår.
|
||||||
|
- **Parallell agent-spawning uten grunn.** Sekvensiell er default; parallell krever begrunnelse (uavhengige oppgaver, ikke "raskere").
|
||||||
|
- **Plugin-`CLAUDE.md` som prosa-essay.** Under 100 linjer, tabell-basert. Lang = ignorert (samme dynamikk som Cursor-regler).
|
||||||
|
|
||||||
|
## Manifest & struktur
|
||||||
|
|
||||||
|
- **`plugin.json` uten `auto_discover`** (eller med komponenter både auto-discovered *og* manuelt deklarert). Hold det konsistent — auto-discovery for commands/agents/skills/hooks.
|
||||||
|
- **Feil filnavn-mønster.** Agenter: `descriptive-name-agent.md`. Commands: `command.md`. Skills: `skill-name/SKILL.md`. Avvik = komponenten oppdages ikke.
|
||||||
|
- **Skill-`description` som bare sier hva, ikke når.** Triggering avhenger av at description-en beskriver *aktiveringssituasjonen*. "Does X" trigges ikke; "Use when the user asks to X / mentions Y" trigges.
|
||||||
|
- **Agent-`description` uten when-to-use.** Samme: agenten velges på description-en. Inkluder konkrete triggere / eksempler.
|
||||||
|
|
||||||
|
## Prosess
|
||||||
|
|
||||||
|
- **Oppdatere `CLAUDE.md` i en separat commit etterpå.** Samme commit som endringen — ny agent + agent-tabell, ny command + command-tabell, ny hook + hook-oversikt.
|
||||||
|
- **Glemme versjonssync.** Versjonsbump? Oppdater package.json/`plugin.json`, README-badges, CHANGELOG, konstanter — alle i samme commit.
|
||||||
|
- **Skrive kode i andre repos / utvide scope etter godkjent plan** uten eksplisitt klarsignal.
|
||||||
23
domain-packs/claude-code-plugin/pack.json
Normal file
23
domain-packs/claude-code-plugin/pack.json
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"schema": "domain-pack/v1",
|
||||||
|
"name": "claude-code-plugin",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"domain": "Claude Code-plugin-utvikling (commands / agents / skills / hooks / MCP)",
|
||||||
|
"description": "Domene-kunnskap for å bygge Claude Code-plugins: manifest- og frontmatter-regler, navnekonvensjoner, hooks-format, context-budget-disiplin, plugin-validator-pass.",
|
||||||
|
"phases": [1, 3, 5, 6, 7],
|
||||||
|
"verified": {
|
||||||
|
"date": "2026-05-12",
|
||||||
|
"against": "ktg-privat CLAUDE.md + .claude/rules/{plugin-convention,hook-format}.md (intern konvensjon); Anthropic plugin-dev-skills (struktur/commands/agents/skills/hooks)",
|
||||||
|
"note": "Ekstrahert fra eksisterende ktg-privat-konvensjoner. Påstander om Claude Code-plattformen (hooks-API, ${CLAUDE_PLUGIN_ROOT}, auto-discovery) bør re-verifiseres mot offisiell Claude Code-dokumentasjon ved neste oppdatering — ikke gjort uttømmende i S6 (pakken er en STUB utover de fire core-filene)."
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"conventions.md": "core",
|
||||||
|
"gotchas.md": "core",
|
||||||
|
"checklist.md": "core",
|
||||||
|
"glossary.md": "supplementary",
|
||||||
|
"patterns/README.md": "supplementary",
|
||||||
|
"scaffold/README.md": "supplementary",
|
||||||
|
"examples/README.md": "supplementary"
|
||||||
|
},
|
||||||
|
"status": "stub — pack.json + conventions.md + gotchas.md + checklist.md + glossary.md ferdige; patterns/scaffold/examples er stubs (forfattes senere). Ikke konsumert av Akashic-prototypen."
|
||||||
|
}
|
||||||
13
domain-packs/claude-code-plugin/patterns/README.md
Normal file
13
domain-packs/claude-code-plugin/patterns/README.md
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!-- domain-pack: claude-code-plugin · component: patterns · supplementary · STUB -->
|
||||||
|
|
||||||
|
# patterns/ — STUB (forfattes senere)
|
||||||
|
|
||||||
|
`claude-code-plugin`-pakken er en stub utover de fire core-filene (`pack.json`, `conventions.md`, `gotchas.md`, `checklist.md`) + `glossary.md`. Planlagte pattern-filer (kilde: ktg-privat-plugins + Anthropic `plugin-dev`-skills):
|
||||||
|
|
||||||
|
- `command-router.md` — hovedrouter-command som dispatcher til sub-commands (`/plugin` → `/plugin:build`, `/plugin:status`, …).
|
||||||
|
- `agent-definition.md` — hvordan skrive en agent-`description` som faktisk trigger; verktøy-/modell-valg per agent.
|
||||||
|
- `skill-progressive-disclosure.md` — kompakt SKILL.md + `references/`-struktur; når noe hører i SKILL.md vs en referanse-fil.
|
||||||
|
- `three-layer-architecture.md` — orkestrator/agent/knowledge-lag-mønsteret fra `kiur`; max-3-regel i praksis.
|
||||||
|
- `hook-mjs.md` — self-contained `.mjs`-hook-script: input-parsing (stdin JSON), exit-koder, `${CLAUDE_PLUGIN_ROOT}`.
|
||||||
|
|
||||||
|
Hver fil ≤500 ord. Forfatt ved behov — destiller fra `plugin-dev:plugin-structure`, `plugin-dev:command-development`, `plugin-dev:agent-development`, `plugin-dev:skill-development`, `plugin-dev:hook-development` + eksisterende ktg-privat-plugins (`kiur`, `harness`, `vegnormalene`).
|
||||||
15
domain-packs/claude-code-plugin/scaffold/README.md
Normal file
15
domain-packs/claude-code-plugin/scaffold/README.md
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
<!-- domain-pack: claude-code-plugin · component: scaffold · supplementary · STUB -->
|
||||||
|
|
||||||
|
# scaffold/ — STUB (forfattes senere)
|
||||||
|
|
||||||
|
Planlagte fil-templater som materialiseres inn i en ny plugin:
|
||||||
|
|
||||||
|
- `plugin.json` — manifest-skjelett (`name`, `version`, `description`, `auto_discover: true`).
|
||||||
|
- `hooks.json` — tomt hook-skjelett (objekt med event-nøkler, kommentert eksempel).
|
||||||
|
- `command.md` — command-frontmatter-skjelett.
|
||||||
|
- `agent.md` — agent-frontmatter-skjelett (med when-to-use-eksempel-blokk).
|
||||||
|
- `SKILL.md` — skill-skjelett med progressive-disclosure-struktur.
|
||||||
|
- `CLAUDE.md` — plugin-CLAUDE.md-skjelett med alle påkrevde seksjoner (< 100 linjer, tabell-basert).
|
||||||
|
- `plugin-tree/` — full katalog-skjelett (`.claude-plugin/`, `commands/`, `agents/`, `skills/`, `hooks/scripts/`, `README.md`).
|
||||||
|
|
||||||
|
Forfatt ved behov. Hold templates minimale — de skal kompletteres per plugin, ikke kopieres ordrett.
|
||||||
45
domain-packs/ios-app/checklist-accessibility.md
Normal file
45
domain-packs/ios-app/checklist-accessibility.md
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
<!-- domain-pack: ios-app · component: checklists · core -->
|
||||||
|
<!-- verified 2026-05-12 against W3C WCAG 2.2 (W3C Recommendation 2023-10-05). -->
|
||||||
|
|
||||||
|
# iOS-app — tilgjengelighet sjekkliste (WCAG 2.2 AA)
|
||||||
|
|
||||||
|
WCAG 2.2 ble W3C Recommendation 2023-10-05. Den la til 9 nye suksesskriterier vs 2.1 og fjernet 4.1.1 Parsing (obsolet). Denne sjekklisten dekker AA-nivå. Sub-sjekkliste av `checklist.md`. ([W3C — What's New in WCAG 2.2](https://www.w3.org/WAI/standards-guidelines/wcag/new-in-22/))
|
||||||
|
|
||||||
|
> WCAG er skrevet for web, men kriteriene mapper godt til native iOS via UIKit/SwiftUI Accessibility (VoiceOver, Dynamic Type, kontrast, fokus-orden). Der et kriterium er web-spesifikt, bruk dets *intensjon*.
|
||||||
|
|
||||||
|
## Nye i WCAG 2.2 — Level AA (de 4 som faktisk er nye krav på AA)
|
||||||
|
|
||||||
|
- [ ] **2.4.11 Focus Not Obscured (Minimum) [AA, ny]** — når et element får tastatur-/fokus, er det ikke fullstendig skjult av annet innhold (sticky headers, overlays, tastatur). iOS: pass på at fokusert felt scrolles synlig over tastaturet.
|
||||||
|
- [ ] **2.5.7 Dragging Movements [AA, ny]** — all funksjonalitet som krever dra-bevegelse har et enkelt-peker-alternativ uten dra (f.eks. knapper i tillegg til drag-to-reorder), med mindre dra er essensielt.
|
||||||
|
- [ ] **2.5.8 Target Size (Minimum) [AA, ny]** — interaktive mål er minst 24×24 CSS-px (eller har tilstrekkelig avstand). iOS HIG anbefaler 44×44 pt — følg HIG, så er dette dekket.
|
||||||
|
- [ ] **3.3.8 Accessible Authentication (Minimum) [AA, ny]** — ingen kognitiv funksjonstest (huske passord, løse puslespill, transkribere) som eneste vei gjennom et autentiserings-steg; tillat lim-inn, passord-managers, Sign in with Apple/passkeys, e-post-/SMS-kode. (Relevant kun hvis appen har auth.)
|
||||||
|
|
||||||
|
> Også nye i 2.2, men Level A (ta med hvis du sikter A som baseline): **3.2.6 Consistent Help [A]** — hjelpe-mekanismer i konsistent rekkefølge; **3.3.7 Redundant Entry [A]** — ikke be om samme info to ganger i samme prosess uten å auto-fylle.
|
||||||
|
> Level AAA (utenfor AA-kravet): 2.4.12 Focus Not Obscured (Enhanced), 2.4.13 Focus Appearance, 3.3.9 Accessible Authentication (Enhanced).
|
||||||
|
|
||||||
|
## Bærende WCAG 2.0/2.1 AA-kriterier (videreført — sjekk alltid)
|
||||||
|
|
||||||
|
- [ ] **1.1.1 Non-text Content [A]** — alle ikoner/bilder/knapper har `accessibilityLabel`; dekorative er `accessibilityHidden`.
|
||||||
|
- [ ] **1.3.1 Info and Relationships [A]** — overskrifter/grupper/lister eksponert via accessibility traits; skjemafelt har labels.
|
||||||
|
- [ ] **1.4.3 Contrast (Minimum) [AA]** — tekst ≥ 4.5:1 (stor tekst ≥ 3:1) mot bakgrunn — **også over Liquid Glass-materialer** (translucens kan senke effektiv kontrast; test mot reelle bakgrunner).
|
||||||
|
- [ ] **1.4.11 Non-text Contrast [AA]** — UI-komponenter og grafiske grenser ≥ 3:1.
|
||||||
|
- [ ] **1.4.4 Resize Text [AA] / 1.4.10 Reflow [AA]** — støtt Dynamic Type opp til største størrelse uten avkutting/horisontal scroll; bruk `.dynamicTypeSize` / skalérbare fonter, ikke faste px.
|
||||||
|
- [ ] **1.4.13 Content on Hover or Focus [AA]** — popovers/tooltips er dismissible, hoverbare, persistente.
|
||||||
|
- [ ] **2.1.1 Keyboard [A]** — full funksjon med ekstern tastatur / Full Keyboard Access; ingen fokus-felle (2.1.2).
|
||||||
|
- [ ] **2.4.3 Focus Order [A] / 2.4.7 Focus Visible [AA]** — logisk fokus-orden; synlig fokus-indikator.
|
||||||
|
- [ ] **2.4.6 Headings and Labels [AA]** — beskrivende overskrifter og labels.
|
||||||
|
- [ ] **2.5.3 Label in Name [A]** — synlig tekst på en kontroll er del av dens accessibility-navn.
|
||||||
|
- [ ] **3.1.1 Language of Page [A]** — app-språk satt korrekt (lokalisering).
|
||||||
|
- [ ] **3.2.3 Consistent Navigation [AA] / 3.2.4 Consistent Identification [AA]** — navigasjon og ikon-betydning konsistent på tvers av skjermer.
|
||||||
|
- [ ] **3.3.1 Error Identification [A] / 3.3.3 Error Suggestion [AA]** — feil beskrives i tekst, ikke bare farge; forslag til retting der mulig.
|
||||||
|
- [ ] **4.1.2 Name, Role, Value [A]** — custom-kontroller eksponerer korrekt rolle/verdi til VoiceOver (`accessibilityTraits`, `accessibilityValue`).
|
||||||
|
- [ ] **4.1.3 Status Messages [AA]** — dynamiske statusoppdateringer annonseres (`UIAccessibility.post(notification: .announcement)` / SwiftUI `accessibilityElement` + live region-ekvivalent).
|
||||||
|
- [ ] **2.3.1 Three Flashes [A]** — ingen blink > 3 Hz; respekter Reduce Motion.
|
||||||
|
|
||||||
|
## iOS-spesifikk røyktest
|
||||||
|
|
||||||
|
- [ ] Naviger hele appen med **VoiceOver** — alt er nåbart, navngitt, i logisk rekkefølge.
|
||||||
|
- [ ] **Dynamic Type** på største størrelse — ingen avkutting, ingen overlapp.
|
||||||
|
- [ ] **Reduce Motion / Reduce Transparency** respektert (særlig viktig med Liquid Glass).
|
||||||
|
- [ ] **Increase Contrast** og dark mode — kontrast holder.
|
||||||
|
- [ ] Fargen er aldri eneste informasjonsbærer.
|
||||||
43
domain-packs/ios-app/checklist-security-privacy.md
Normal file
43
domain-packs/ios-app/checklist-security-privacy.md
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
<!-- domain-pack: ios-app · component: checklists · core -->
|
||||||
|
<!-- verified 2026-05-12 against OWASP MASVS 2.1.0 + Apple privacy-manifest / App Privacy docs. -->
|
||||||
|
|
||||||
|
# iOS-app — sikkerhet & personvern sjekkliste
|
||||||
|
|
||||||
|
OWASP MASVS 2.1.0 (utgitt 2024-01-18) + `PrivacyInfo.xcprivacy` + App Privacy Details. Sub-sjekkliste av `checklist.md`. MASVS definerer *hva* som skal verifiseres; MASTG/MASWE definerer *hvordan* man tester. ([OWASP MASVS](https://mas.owasp.org/MASVS/))
|
||||||
|
|
||||||
|
## OWASP MASVS 2.1 — 8 kontroll-grupper
|
||||||
|
|
||||||
|
Velg de relevante; en all-local-app uten auth/nett trenger få. Ikke-relevante grupper merkes `N/A` med én linjes begrunnelse i `pack-overrides.md`.
|
||||||
|
|
||||||
|
- [ ] **MASVS-STORAGE** — sensitiv data i Keychain (ikke `UserDefaults`/`plist`/klartekst-fil); ingen sensitiv data i logger/backups/snapshots; cache ryddes ved behov.
|
||||||
|
- [ ] **MASVS-CRYPTO** — kun moderne algoritmer; nøkler i Keychain/Secure Enclave; ingen hardkodede nøkler; tilfeldighet fra `SecRandomCopyBytes`/`CryptoKit`.
|
||||||
|
- [ ] **MASVS-AUTH** — hvis appen har auth: sikker sesjonshåndtering, biometri som beleilighet ikke eneste faktor, riktig logout/timeout.
|
||||||
|
- [ ] **MASVS-NETWORK** — TLS på all trafikk (ATS aktiv, ingen ubegrunnede unntak); sertifikat-validering ikke deaktivert; vurder pinning hvis trusselsbildet krever det.
|
||||||
|
- [ ] **MASVS-PLATFORM** — minimale entitlements/capabilities; trygg IPC (App Groups, URL schemes, universal links validert); ingen sensitiv data i `pasteboard`/skjermbilder uten grunn; deep links validerer input.
|
||||||
|
- [ ] **MASVS-CODE** — oppdaterte dependencies (kjente CVE-er sjekket); inputvalidering på alt eksternt (deep links, fildelt innhold, push-payloads); ingen debug-kode/test-endepunkter i release.
|
||||||
|
- [ ] **MASVS-RESILIENCE** — *kun hvis appen håndterer høyverdi-data*: anti-tampering/jailbreak-deteksjon, obfuskering. For en vanlig konsument-app: vanligvis `N/A`.
|
||||||
|
- [ ] **MASVS-PRIVACY** *(ny i 2.1.0)* — minimer datainnsamling; vær transparent (purpose-strings, onboarding-forklaring, App Privacy Details); gi brukerkontroll (slett data, trekk samtykke); ingen tracking uten ATT.
|
||||||
|
|
||||||
|
## `PrivacyInfo.xcprivacy` — påkrevd siden 2024-05-01
|
||||||
|
|
||||||
|
Mal: `scaffold/PrivacyInfo.xcprivacy`. ([Apple — Privacy manifest files](https://developer.apple.com/documentation/bundleresources/privacy-manifest-files))
|
||||||
|
|
||||||
|
- [ ] `NSPrivacyTracking` (Bool) — `false` med mindre appen faktisk tracker på tvers av apper/nettsteder.
|
||||||
|
- [ ] `NSPrivacyTrackingDomains` (Array) — domener brukt til tracking (tom hvis `NSPrivacyTracking = false`).
|
||||||
|
- [ ] `NSPrivacyCollectedDataTypes` (Array) — hver innsamlet datatype med `NSPrivacyCollectedDataTypeLinked`, `...Tracking`, og `NSPrivacyCollectedDataTypePurposes`. Tom hvis ingenting samles.
|
||||||
|
- [ ] `NSPrivacyAccessedAPITypes` (Array) — **required-reason-API-kategorier** appen bruker, med tillatt reason-kode. Kategorier inkl.: file timestamp APIs, system boot time APIs, disk space APIs, active keyboard APIs, user defaults APIs (m.fl.). Manglende deklarasjon = App Store-avvisning (Guideline 5.3.4). ([Apple — Required reason API](https://developer.apple.com/documentation/bundleresources/describing-use-of-required-reason-api))
|
||||||
|
- [ ] **Tredjeparts-SDK-er:** hver må levere sin egen `PrivacyInfo.xcprivacy` (og signatur for noen). Verifiser — ellers blir det din avvisning.
|
||||||
|
|
||||||
|
## App Privacy Details ("nutrition label") — App Store Connect
|
||||||
|
|
||||||
|
Må stemme med faktisk databehandling i appen *og* alle SDK-er. ([Apple — App Privacy Details](https://developer.apple.com/app-store/app-privacy-details/))
|
||||||
|
|
||||||
|
- [ ] For hver relevant kategori (Contact Info, Health & Fitness, Financial Info, Location [Precise/Coarse], Sensitive Info, Contacts, User Content, Browsing/Search History, Identifiers, Purchases, Usage Data, Diagnostics, Surroundings, Body, Other): angitt **om** den samles, **formål** (App Functionality / Analytics / Product Personalization / Advertising / Other), og **om linket til identitet** + **om brukt til tracking**.
|
||||||
|
- [ ] "Data Not Collected" valgt hvis — og bare hvis — verken appen eller noen SDK samler noe. (Den enkleste posisjonen, og verifiserbar.)
|
||||||
|
- [ ] Personvern-policy-URL satt hvis noe samles.
|
||||||
|
|
||||||
|
## Permission-transparens (GDPR + App Review-forventning)
|
||||||
|
|
||||||
|
- [ ] Hver permission (location, notifikasjoner, …) forklart på en onboarding/forklarings-skjerm *før* system-prompten.
|
||||||
|
- [ ] App fungerer i degradert-men-nyttig modus hvis permission nektes (ingen dead-end).
|
||||||
|
- [ ] Ingen tredjeparts-AI-/analytics-deling uten at det er deklarert og (der relevant) samtykket.
|
||||||
58
domain-packs/ios-app/checklist.md
Normal file
58
domain-packs/ios-app/checklist.md
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
<!-- domain-pack: ios-app · component: checklists · core -->
|
||||||
|
<!-- verified 2026-05-12 against Apple App Store Connect / Review Guidelines / Upcoming Requirements. -->
|
||||||
|
|
||||||
|
# iOS-app — sjekklister (index + App Store-submission)
|
||||||
|
|
||||||
|
Fase-exit-kriterier. **Dette er komponenten som bærer det fase 5 ellers ville gjenoppfunnet** (friksjon #7). En `[skip]`-merket linje må begrunnes i `00-context/pack-overrides.md`.
|
||||||
|
|
||||||
|
**Sub-sjekklister (lastes uavhengig):**
|
||||||
|
- `checklist-security-privacy.md` — OWASP MASVS 2.1 (8 kontroll-grupper) + `PrivacyInfo.xcprivacy`-mal + App Privacy Details "nutrition label".
|
||||||
|
- `checklist-accessibility.md` — WCAG 2.2 AA inkl. de 4 nye 2.2-AA-kriteriene.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## A. App Store Connect — metadata før innsending
|
||||||
|
|
||||||
|
- [ ] App-navn, undertittel, beskrivelse, nøkkelord, support-URL satt.
|
||||||
|
- [ ] **Skjermbilder** i påkrevd basestørrelse: 1320×2868 px (6,9″ iPhone) + 2064×2752 px (13″ iPad hvis universal). Flat PNG/JPG, RGB, **ingen alfakanal**. Apple skalerer ned for mindre enheter. ([App Store Connect — Screenshot specifications](https://developer.apple.com/help/app-store-connect/reference/app-information/screenshot-specifications/))
|
||||||
|
- [ ] **Alders-rating:** revidert spørreskjema (4+/9+/12+/13+/16+/18+) fullført. ([Apple — Age rating update](https://developer.apple.com/news/?id=ks775ehf))
|
||||||
|
- [ ] **Eksport-compliance:** krypteringsbruk besvart (`ITSAppUsesNonExemptEncryption` i Info.plist *eller* svar i App Store Connect). Standard-HTTPS via system-API regnes normalt som unntatt — men spørsmålet **må** besvares.
|
||||||
|
- [ ] **Content rights:** erklæring om appen inneholder/viser tredjeparts-innhold du har rett til.
|
||||||
|
- [ ] **App Privacy Details** ("nutrition label") utfylt og stemmer med faktisk databehandling — inkl. alle SDK-er. Se `checklist-security-privacy.md` § App Privacy Details.
|
||||||
|
- [ ] **`PrivacyInfo.xcprivacy`** i bygget, korrekt utfylt (påkrevd siden 2024-05-01). Mal: `scaffold/PrivacyInfo.xcprivacy`. Se `checklist-security-privacy.md`.
|
||||||
|
- [ ] Bygget med **påkrevd SDK** (iOS 26-SDK / Xcode 26+, krav siden 2026-04-28).
|
||||||
|
- [ ] Versjon + build-nummer økt; release-notater skrevet.
|
||||||
|
|
||||||
|
## B. Info.plist & entitlements
|
||||||
|
|
||||||
|
- [ ] **`NSUsageDescription` for hver beskyttet ressurs appen bruker** (location, kamera, mikrofon, foto, kontakter, kalender, Bluetooth, Face ID, …). Inventar-mal: `scaffold/NSUsageDescription-inventory.md`. (Notifikasjoner: ingen nøkkel — men forklar i onboarding.)
|
||||||
|
- [ ] Capabilities matcher faktisk bruk (App Groups, Push, Live Activities `NSSupportsLiveActivities`, …) — ingen ubrukte.
|
||||||
|
- [ ] `NSAppTransportSecurity`: ingen `NSAllowsArbitraryLoads` uten begrunnelse; per-domene-unntak dokumentert.
|
||||||
|
- [ ] Hvis tracking: `NSUserTrackingUsageDescription` + ATT-prompt implementert.
|
||||||
|
|
||||||
|
## C. App Store Review Guidelines — vanlige avvisnings-triggere
|
||||||
|
|
||||||
|
- [ ] **4.2 Minimum functionality** — appen gjør noe meningsfullt nativt; ikke ren web-wrapper, ikke for tynn.
|
||||||
|
- [ ] **1.2 / 2.3 Metadata** — skjermbilder viser faktisk UI; beskrivelse stemmer; ingen villedende påstander.
|
||||||
|
- [ ] **2.1 Completeness** — ingen krasj, ingen ødelagte lenker, ingen placeholder-innhold; alle URL-er i metadata fungerer.
|
||||||
|
- [ ] **5.1.1 Data collection** — purpose-strings dekker all permission-bruk; ber ikke om mer data enn nødvendig.
|
||||||
|
- [ ] **5.1.2 Data use & sharing** — tredjeparts-deling (inkl. ekstern AI) deklarert i App Privacy Details.
|
||||||
|
- [ ] **3.1.1 In-App Purchase** — digitale varer som låses opp etter installasjon går via IAP (engangs paid-up-front-app er greit).
|
||||||
|
- [ ] **4.0 Design** — ikke copycat / generisk template.
|
||||||
|
- [ ] Demo-konto / instruksjoner i "App Review Information" hvis appen krever login eller spesielt oppsett.
|
||||||
|
[Kilde: [App Store Review Guidelines](https://developer.apple.com/app-store/review/guidelines/)]
|
||||||
|
|
||||||
|
## D. Region-spesifikke krav (hvis du distribuerer der)
|
||||||
|
|
||||||
|
- [ ] **EU — DSA trader-status:** verifisert kontaktinfo i App Store Connect (DSA art. 30–31). Uten det fjernes appen fra EU App Store. ([Apple — DSA requirement](https://developer.apple.com/news/upcoming-requirements/?id=02172025a))
|
||||||
|
- [ ] **Kina — ICP-filing:** ICP-filing-nummer fra MIIT i App Store Connect. Krever kinesisk juridisk enhet + Kina-hostet server.
|
||||||
|
- [ ] **Sør-Korea — GRAC:** spill må ha GRAC-rating; loot-box-sannsynlighet opplyst (Game Industry Promotion Act). Apple mapper globale ratinger automatisk.
|
||||||
|
- [ ] Andre regioner: sjekk om appens innhold/funksjon utløser lokale krav.
|
||||||
|
|
||||||
|
## E. Pre-submission røyktest
|
||||||
|
|
||||||
|
- [ ] Ren install på fysisk enhet (ikke bare simulator); permission-flows fungerer og degraderer nådig ved nektelse.
|
||||||
|
- [ ] Onboarding forklarer hver permission *før* prompten.
|
||||||
|
- [ ] Widget / Live Activity / Lock Screen-features fungerer eller er trygt fraværende.
|
||||||
|
- [ ] Dark mode, Dynamic Type (største størrelse), VoiceOver — grunnleggende gjennomgang. Detaljer: `checklist-accessibility.md`.
|
||||||
|
- [ ] `checklist-security-privacy.md` gjennomgått; `checklist-accessibility.md` gjennomgått.
|
||||||
38
domain-packs/ios-app/conventions.md
Normal file
38
domain-packs/ios-app/conventions.md
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
<!-- domain-pack: ios-app · component: conventions · core -->
|
||||||
|
<!-- verified 2026-05-12 against iOS 26 / HIG WWDC2025 / sources inline. Update verified.date in pack.json on change. -->
|
||||||
|
|
||||||
|
# iOS-app — konvensjoner
|
||||||
|
|
||||||
|
Ikke-forhandlbare beslutninger for *alle* iOS-apper i denne pipelinen. Avvik krever en eksplisitt `00-context/pack-overrides.md`-oppføring med begrunnelse.
|
||||||
|
|
||||||
|
## Plattform & deployment
|
||||||
|
|
||||||
|
- **Bygg med gjeldende påkrevd SDK.** Apple krever bygg med iOS 26-SDK (Xcode 26+) for App Store-innsending siden 2026-04-28. SDK-versjon ≠ deployment target. ([Apple — Upcoming Requirements](https://developer.apple.com/news/upcoming-requirements/))
|
||||||
|
- **Deployment-target-baseline: iOS 17 eller iOS 18.** iOS 17 dekker >95 % aktive enheter og låser opp SwiftData, interaktive widgets, WidgetKit-forbedringer. Velg iOS 18 kun hvis en feature krever det. Per-app-valg → dokumenter i `pack-overrides.md`. **iOS 19–25 finnes ikke** — Apple gikk fra iOS 18 rett til iOS 26 (år-basert navn, WWDC 2025); neste store versjon er iOS 27 (WWDC juni 2026, lansering høst 2026). ([Apple Newsroom WWDC25](https://www.apple.com/newsroom/2025/06/apple-introduces-a-delightful-and-elegant-new-software-design/))
|
||||||
|
- **iOS-version-spesifikke API-er må ikke degradere eldre brukere** i lanseringsvinduet — gate bak `if #available`, ha fallback.
|
||||||
|
|
||||||
|
## Design — HIG & Liquid Glass
|
||||||
|
|
||||||
|
- **Følg Apple Human Interface Guidelines.** Standard-navigasjon (`NavigationStack`, `TabView`), system-kontroller, Dynamic Type, dark mode, safe areas — ikke gjenoppfinn.
|
||||||
|
- **Liquid Glass er gjeldende designspråk** (introdusert iOS 26, WWDC 2025 — første store omdesign siden iOS 7). SwiftUI: `.glassEffect()`, `GlassEffectContainer`, `.interactive`. Adopter via standard-komponenter først; bruk `glassEffect` på custom-views bevisst, ikke overalt. ([HIG: Applying Liquid Glass](https://developer.apple.com/documentation/SwiftUI/Applying-Liquid-Glass-to-custom-views), [WWDC25 219 "Meet Liquid Glass"](https://developer.apple.com/videos/play/wwdc2025/219/)) `[delvis verifisert — API-navn bekreftet mot Apple-docs; konkret bruk er prosjekt-skjønn]`
|
||||||
|
|
||||||
|
## Swift / SwiftUI
|
||||||
|
|
||||||
|
- **SwiftUI som default UI-lag** for nye apper. UIKit kun ved konkret behov (custom drawing, modne kontroller uten SwiftUI-ekvivalent).
|
||||||
|
- **SwiftData som default persistens** (iOS 17+) — ikke Core Data for nye apper. ([SwiftData docs](https://developer.apple.com/documentation/swiftdata)) Se `patterns/offline-first-swiftdata.md`.
|
||||||
|
- **Concurrency:** `async/await` + structured concurrency; ikke completion-handler-pyramider i ny kode.
|
||||||
|
- **Arkitektur — MVVM som default:** SwiftUI-`View` + `@Observable`-ViewModel. Vurder **TCA (The Composable Architecture)** kun når app-state er kompleks nok til å rettferdiggjøre en reducer-modell (mange sammenvevde sidefeffekter, tung testbarhet-krav, team som allerede kan TCA). For en liten app: MVVM. Begrunn TCA-valg i en fase-3-ADR.
|
||||||
|
- **Ingen unødvendige tredjeparts-deps.** Hver dependency er en privacy-manifest-forpliktelse (SDK-er må levere egen `PrivacyInfo.xcprivacy`) og en App Review-risiko.
|
||||||
|
|
||||||
|
## Guardrails — regler du ikke avviker fra uten god grunn
|
||||||
|
|
||||||
|
- **`NSUsageDescription` for hver beskyttet ressurs appen bruker.** Manglende purpose-string = appen termineres ved permission-request *og* App Store-avvisning (Guideline 5.1.1). Notifications krever *ingen* Info.plist-nøkkel; Core Location, kamera, mikrofon, foto, kontakter, kalender m.fl. krever det. Se `scaffold/NSUsageDescription-inventory.md`.
|
||||||
|
- **`PrivacyInfo.xcprivacy` påkrevd** for App Store-innsending siden 2024-05-01: deklarer tracking, tracking-domener, innsamlede datatyper, og **required-reason-API-kategorier**. Manglende required-reason-deklarasjon = avvisning (Guideline 5.3.4). Mal: `scaffold/PrivacyInfo.xcprivacy`. ([Apple — Privacy manifest files](https://developer.apple.com/documentation/bundleresources/privacy-manifest-files))
|
||||||
|
- **App Privacy Details ("nutrition label")** i App Store Connect må stemme med faktisk databehandling. "Vi samler ingenting" er gyldig — men da må alle SDK-er også være rene.
|
||||||
|
- **ATS på.** HTTPS for all utgående trafikk; `NSAppTransportSecurity`-unntak (`NSAllowsArbitraryLoads`, `NSExceptionDomains`) krever begrunnelse ved review. Se `gotchas.md`.
|
||||||
|
- **GDPR / personvern:** forklar lokasjon/notifikasjons-tillatelser *før* de etterspørres (egen onboarding-skjerm); minimer datainnsamling; ingen tracking uten ATT-prompt (`NSUserTrackingUsageDescription` + `AppTrackingTransparency`). All-local er den enkleste compliance-posisjonen.
|
||||||
|
- **App Store Review Guidelines:** ingen "minimum functionality"-fellen (4.2 — web-wrapper / for tynn app), nøyaktig metadata (1.2), digitale varer via IAP (3.1.1). Full submission-sjekkliste: `checklist.md`.
|
||||||
|
|
||||||
|
## core / supplementary
|
||||||
|
|
||||||
|
`pack.json` → `components` er den autoritative merkingen. `00-context/domain-pack-ios-app.md`-snapshotet inkluderer `core`-filene sammenslått; `supplementary` (patterns, scaffold, examples, glossary) lastes on-demand fra `domain-packs/ios-app/`.
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
<!-- domain-pack: ios-app · component: examples · supplementary -->
|
||||||
|
<!-- Eksempel-feature-brief i Voyage Handover-1 strict-mode-format (jf. phase-design-draft.md § Fase 7).
|
||||||
|
Avledet fra en Akashic-feature ("lokale notifikasjoner når et soltidsvindu åpner"). Illustrerende — ikke en
|
||||||
|
ekte handover. Unntatt domain-pack-lengde-grensen (referanse-materiale, ikke instruksjon).
|
||||||
|
Brukes av fase 6/7-brief-generatoren som "slik ser en god iOS-feature-brief ut". -->
|
||||||
|
|
||||||
|
---
|
||||||
|
# --- Voyage-påkrevde (Handover 1, brief_version 2.0) ---
|
||||||
|
type: trekbrief
|
||||||
|
brief_version: "2.0"
|
||||||
|
created: 2026-06-01
|
||||||
|
task: "Lokale notifikasjoner som varsler brukeren når hvert av de tre daglige soltidsvinduene åpner, av/på per vindu, Focus-bevisst"
|
||||||
|
slug: notification-on-window-open
|
||||||
|
project_dir: .claude/projects/2026-06-01-notification-on-window-open/
|
||||||
|
research_topics: 0
|
||||||
|
research_status: complete
|
||||||
|
brief_quality: complete
|
||||||
|
source: manual
|
||||||
|
|
||||||
|
# --- app-creator-interne (Voyage ignorerer / strippes ved handover) ---
|
||||||
|
brief_type: feature
|
||||||
|
phase: 7
|
||||||
|
parent_app: akashic-intelligence
|
||||||
|
parent_feature: F-002
|
||||||
|
domain_pack: "ios-app@0.1.0"
|
||||||
|
revision: 0
|
||||||
|
length_words: 480
|
||||||
|
voyage_run_dir: null
|
||||||
|
voyage_run_status: null
|
||||||
|
---
|
||||||
|
|
||||||
|
# Task: Lokale notifikasjoner når et soltidsvindu åpner
|
||||||
|
|
||||||
|
> Generert av app-creator fase 7 på 2026-06-01 fra akashic-intelligence feature F-002.
|
||||||
|
|
||||||
|
## Intent
|
||||||
|
|
||||||
|
Praksisen Akashic støtter krever at brukeren bukker innenfor tre tidsvinduer som flytter seg med soltidene der brukeren er. Det definerende problemet er at det er lett å glemme — uten en påminnelse i tide forsvinner vanen. Denne featuren leverer den primære eksterne forsterkningen: én notifikasjon når hvert vindu åpner, slik at brukeren kan handle der og da. Den henger sammen med, men er separat fra, den visuelle in-app-klokka (F-003) — notifikasjonen er for når appen *ikke* er åpen.
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Når et soltidsvindu åpner, mottar brukeren én lokal notifikasjon (med mindre vinduet er slått av eller allerede markert fullført den dagen). Notifikasjonen kan trykkes for å åpne appen direkte til markeringssjermen for det vinduet. Brukeren kan slå hver av de tre notifikasjonene av/på uavhengig i innstillinger. Notifikasjonene respekterer brukerens Focus-modus. Tidene re-beregnes og re-planlegges når appen kommer i forgrunnen og posisjonen har endret seg vesentlig (delt logikk med F-001). Ingen notifikasjon fyrer på feil tidspunkt etter en lokasjons- eller dato-endring.
|
||||||
|
|
||||||
|
## Non-Goals
|
||||||
|
|
||||||
|
- Push-notifikasjoner / server (appen er all-local, ingen backend).
|
||||||
|
- Snooze, gjentatte påminnelser innenfor samme vindu, eller "du glemte i går"-varsler.
|
||||||
|
- Notifikasjons-handlinger utover "åpne appen" (in-notification "marker gjort" vurderes i en senere feature, ikke her).
|
||||||
|
- Konfigurerbar tekst / lyd per notifikasjon (standard system-lyd, fast tekst i v1).
|
||||||
|
- Time Sensitive / Critical interruption-nivå (krever Apple-entitlement; bruk standard `.active` i v1).
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
|
||||||
|
- Ingen nye tredjeparts-deps (app-invariant).
|
||||||
|
- All in-app- og notifikasjons-tekst skal være forsiktig med effekt-claims — speil kildens framing, hevd ingenting (app-brief constraint-signal, [enforce]).
|
||||||
|
- Permission-transparens: notifikasjons-tillatelsen forklares på en onboarding-skjerm *før* `requestAuthorization` (GDPR + App Review-forventning, [enforce]).
|
||||||
|
- Maks ~64 ventende lokale notifikasjoner per app (iOS-grense) — planlegg rullerende (f.eks. neste N dager), ikke et helt år.
|
||||||
|
|
||||||
|
## Preferences
|
||||||
|
|
||||||
|
- `UNUserNotificationCenter` + `UNCalendarNotificationTrigger`; re-planlegging ved `scenePhase == .active` (jf. domain-pack `patterns/local-notifications.md` og `patterns/current-location-regeneration.md`).
|
||||||
|
- Del soltids-/vindu-beregningen med F-001 og F-003 — ikke dupliser logikken.
|
||||||
|
- MVVM, SwiftUI; interruption-nivå `.active`.
|
||||||
|
|
||||||
|
## Non-Functional Requirements
|
||||||
|
|
||||||
|
- Re-planlegging ved app-foreground fullfører på < 100 ms (synkron del); ingen merkbar UI-stall.
|
||||||
|
- Appen krasjer ikke og viser ingen dead-end hvis notifikasjons-tillatelse er nektet — degraderer til in-app-klokka (F-003) med en CTA for å aktivere varsler.
|
||||||
|
- Ingen sensitiv data i notifikasjons-payload (det er ingen — men prinsippet står).
|
||||||
|
|
||||||
|
## Success Criteria
|
||||||
|
|
||||||
|
- Given notifikasjons-tillatelse gitt og alle tre vinduer på, When et vindu åpner mens appen er i bakgrunnen, Then leveres nøyaktig én notifikasjon for det vinduet, og trykk åpner markeringssjermen for det vinduet.
|
||||||
|
- Given et vindu er slått av ELLER allerede markert fullført i dag, When vinduet åpner, Then leveres ingen notifikasjon for det vinduet.
|
||||||
|
- Given brukeren flytter seg vesentlig (eller krysser midnatt), When appen kommer i forgrunnen, Then er ventende notifikasjoner re-planlagt mot de nye soltidene, og ingen utdatert notifikasjon gjenstår.
|
||||||
|
- Given notifikasjons-tillatelse er nektet, When brukeren åpner appen, Then vises in-app-klokka og en CTA for å aktivere varsler — ingen krasj, ingen tom skjerm.
|
||||||
|
- Alle eksisterende tester passerer: `xcodebuild test -scheme Akashic` exit 0.
|
||||||
|
- Ingen nye Swift Package-dependencies i `Package.resolved`.
|
||||||
|
|
||||||
|
## Research Plan
|
||||||
|
|
||||||
|
No external research needed — the codebase and this brief contain sufficient context for planning. (Soltids-beregning og vindu-modell etableres av F-001, som er en avhengighet; se context.md.)
|
||||||
|
|
||||||
|
## Open Questions / Assumptions
|
||||||
|
|
||||||
|
- [ANTAKELSE] F-001 (soltids-/vindu-beregning) er ferdig og eksponerer en stabil API for "neste vindu-åpningstider" — denne featuren bygger på den. Hvis F-001 ikke er klar, blokkér.
|
||||||
|
- [ANTAKELSE] Standard `.active`-interruption-nivå er godt nok i v1. Hvis bruker-feedback senere tilsier at varslene drukner i Focus, vurder time-sensitive-entitlement (egen feature).
|
||||||
|
|
||||||
|
## How to continue
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/trekplan --project .claude/projects/2026-06-01-notification-on-window-open/
|
||||||
|
/trekexecute --project .claude/projects/2026-06-01-notification-on-window-open/
|
||||||
|
```
|
||||||
58
domain-packs/ios-app/glossary.md
Normal file
58
domain-packs/ios-app/glossary.md
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
<!-- domain-pack: ios-app · component: glossary · supplementary -->
|
||||||
|
<!-- Lastes selektivt (fase 1 ved behov, ved oppslag). verified 2026-05-12. -->
|
||||||
|
|
||||||
|
# iOS-app — glossar
|
||||||
|
|
||||||
|
**ATT (App Tracking Transparency)** — rammeverk + system-prompt som kreves før en app kan tracke brukeren på tvers av apper/nettsteder (f.eks. lese IDFA). Krever `NSUserTrackingUsageDescription`. Uten samtykke returnerer IDFA bare nuller.
|
||||||
|
|
||||||
|
**ATS (App Transport Security)** — iOS-policy som krever HTTPS for all utgående trafikk by default. Unntak via `NSAppTransportSecurity`-dict i Info.plist; brede unntak (`NSAllowsArbitraryLoads`) krever begrunnelse ved App Review.
|
||||||
|
|
||||||
|
**App Group** — delt container (`group.<bundle-id>`) som lar en app og dens extensions (widget, Live Activity) dele filer / `UserDefaults` / en SwiftData-store.
|
||||||
|
|
||||||
|
**App Privacy Details** — "nutrition label" på App Store-produktsiden. Utvikler deklarerer i App Store Connect hvilke datatyper appen (og dens SDK-er) samler, til hvilket formål, og om linket til identitet / brukt til tracking.
|
||||||
|
|
||||||
|
**App Review** — Apples manuelle + automatiske gjennomgang før en app/oppdatering publiseres. Styres av App Store Review Guidelines.
|
||||||
|
|
||||||
|
**App Store Connect (ASC)** — Apples webportal for app-metadata, bygg-opplasting, TestFlight, priser, personvern-deklarasjoner, innsending.
|
||||||
|
|
||||||
|
**Capabilities / entitlements** — opt-in-funksjoner (Push, App Groups, HealthKit, Sign in with Apple, Live Activities, …) som aktiveres i Xcode og signeres inn i appen. App Review sjekker at capabilities matcher faktisk bruk.
|
||||||
|
|
||||||
|
**Core Location / CLLocationManager** — iOS-API for posisjon. Krever `NSLocationWhenInUseUsageDescription` (eller `...AlwaysAndWhenInUse...`).
|
||||||
|
|
||||||
|
**Deployment target** — laveste iOS-versjon appen kjører på. Distinkt fra **base SDK** (versjonen appen *bygges mot*; Apple krever bygg med en bestemt minimums-SDK for innsending).
|
||||||
|
|
||||||
|
**DSA trader status** — under EUs Digital Services Act må app-distributører oppgi verifisert kontaktinfo i App Store Connect; ellers fjernes appen fra EU App Store.
|
||||||
|
|
||||||
|
**Dynamic Island** — det interaktive området rundt front-kameraet på iPhone 14 Pro+ / standard på iPhone 15+; vert for Live Activities.
|
||||||
|
|
||||||
|
**Dynamic Type** — iOS-funksjon for brukervalgt tekststørrelse; apper skal skalere uten avkutting (WCAG 1.4.4 / 1.4.10).
|
||||||
|
|
||||||
|
**GRAC** — Korea Game Rating and Administration Committee; spill distribuert i Sør-Korea trenger GRAC-rating.
|
||||||
|
|
||||||
|
**HIG (Human Interface Guidelines)** — Apples designretningslinjer. Gjeldende designspråk: **Liquid Glass** (iOS 26, WWDC 2025).
|
||||||
|
|
||||||
|
**ICP filing** — kinesisk myndighets-registrering (MIIT) som kreves for apper i App Store i Kina; forutsetter kinesisk juridisk enhet + Kina-hostet server.
|
||||||
|
|
||||||
|
**IDFA (Identifier for Advertisers)** — annonse-identifikator; tilgang krever ATT-samtykke.
|
||||||
|
|
||||||
|
**Interruption level** — hvor påtrengende en notifikasjon er: `.passive`, `.active`, `.timeSensitive` (krever entitlement), `.critical` (krever Apple-godkjent entitlement). Bestemmer hvordan Focus-modus behandler den.
|
||||||
|
|
||||||
|
**Liquid Glass** — Apples translucente, refraktive designspråk introdusert iOS 26 (WWDC 2025); SwiftUI: `.glassEffect()`, `GlassEffectContainer`, `.interactive`.
|
||||||
|
|
||||||
|
**Live Activities / ActivityKit** — sanntids-oppdaterte visninger på låseskjerm + Dynamic Island (iOS 16.1+). Krever `NSSupportsLiveActivities = YES` i hoved-app-ens Info.plist.
|
||||||
|
|
||||||
|
**MASVS / MASTG / MASWE** — OWASP Mobile Application Security Verification Standard (hva som skal verifiseres; v2.1.0 har 8 kontroll-grupper) / Testing Guide (hvordan teste) / Weakness Enumeration (svakheter).
|
||||||
|
|
||||||
|
**Privacy manifest (`PrivacyInfo.xcprivacy`)** — plist-fil som deklarerer tracking, tracking-domener, innsamlede datatyper og **required-reason-API-kategorier**. Påkrevd for App Store-innsending siden 2024-05-01.
|
||||||
|
|
||||||
|
**Required-reason API** — Apple-API-er (file timestamps, system boot time, disk space, active keyboards, user defaults, m.fl.) som krever en deklarert tillatt grunn i privacy-manifestet.
|
||||||
|
|
||||||
|
**SwiftData** — Apples Swift-native persistens-rammeverk (iOS 17+); etterfølger til Core Data for nye apper. `@Model`, `ModelContainer`, `@Query`.
|
||||||
|
|
||||||
|
**TCA (The Composable Architecture)** — tredjeparts SwiftUI-arkitektur basert på reducers/effects; vurderes når app-state er kompleks nok til å rettferdiggjøre det.
|
||||||
|
|
||||||
|
**TestFlight** — Apples beta-distribusjonstjeneste (intern + ekstern testere) via App Store Connect.
|
||||||
|
|
||||||
|
**UNUserNotificationCenter** — iOS-API for lokale og push-notifikasjoner; `requestAuthorization`, `UNNotificationRequest`, `UNCalendarNotificationTrigger`. Lokale notifikasjoner krever ingen Info.plist-nøkkel.
|
||||||
|
|
||||||
|
**WidgetKit** — rammeverk for hjemskjerm-/låseskjerm-widgets og Live Activity-UI; timeline-basert oppdatering med begrenset refresh-budsjett.
|
||||||
38
domain-packs/ios-app/gotchas.md
Normal file
38
domain-packs/ios-app/gotchas.md
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
<!-- domain-pack: ios-app · component: gotchas · core -->
|
||||||
|
<!-- verified 2026-05-12 against Apple Developer docs + App Store Review Guidelines. -->
|
||||||
|
|
||||||
|
# iOS-app — gotchas ("ikke gjør dette")
|
||||||
|
|
||||||
|
Ting som ser riktige ut men ikke er det. Hver av disse har avvist en app eller krasjet en bygging.
|
||||||
|
|
||||||
|
## App Store-innsending
|
||||||
|
|
||||||
|
- **Manglende `NSUsageDescription` for en beskyttet ressurs.** Appen termineres *umiddelbart* (ingen dialog) når permission etterspørres, og innsendingen avvises (Guideline 5.1.1). Gjelder Core Location, kamera, mikrofon, foto-bibliotek, kontakter, kalender, Bluetooth, Face ID m.fl. **Gjelder IKKE notifikasjoner** — `UNUserNotificationCenter.requestAuthorization` trenger ingen Info.plist-nøkkel.
|
||||||
|
- **Manglende eller ufullstendig `PrivacyInfo.xcprivacy`.** Påkrevd siden 2024-05-01. Spesielt: ikke-deklarerte **required-reason-API-er** (file-timestamp, system-boot-time, disk-space, active-keyboard, user-defaults m.fl.) → avvisning (Guideline 5.3.4). Tredjeparts-SDK-er må levere *sin egen* privacy-manifest — sjekk dem.
|
||||||
|
- **`NSAllowsArbitraryLoads = true` uten begrunnelse.** App Review krever forklaring på brede ATS-unntak; "vi trengte det" holder ikke. Bruk `NSExceptionDomains` per-domene i stedet, og bare hvis nødvendig.
|
||||||
|
- **"Minimum functionality" (Guideline 4.2).** En ren web-wrapper, en app som er for tynn, eller en app som "ikke gjør nok native" avvises. En liten fokusert app er greit *hvis* den gjør noe meningsfullt nativt.
|
||||||
|
- **Unøyaktig metadata / villedende skjermbilder (Guideline 1.2 / 2.3).** Skjermbilder må vise faktisk UI. Beskrivelse må stemme med funksjonalitet.
|
||||||
|
- **Digitale varer utenfor IAP (Guideline 3.1.1).** Engangs-betalt app (paid-up-front) er greit; men låser appen opp digitalt innhold *etter* installasjon mot betaling, skal det gå via In-App Purchase.
|
||||||
|
- **Tredjeparts-AI / data-deling ikke deklarert (Guideline 5.1.2).** Sender appen brukerdata til en ekstern AI-tjeneste, må det fram i App Privacy Details — stricter håndhevet siden 2025.
|
||||||
|
- **Alders-spørreskjemaet ikke fullført.** Det reviderte alders-rating-systemet (4+/9+/12+/13+/16+/18+) krevde fullført spørreskjema innen 2026-01-31; nye innsendinger må ha det utfylt.
|
||||||
|
- **Glemt region-krav** (hvis du distribuerer der): EU DSA trader-status (verifisert kontaktinfo, ellers fjernes appen fra EU App Store); Kina ICP-filing-nummer (krever kinesisk juridisk enhet + server); Sør-Korea GRAC-rating for spill. Se `checklist.md`.
|
||||||
|
- **Eksport-compliance ikke besvart.** Bruk av kryptering (inkl. HTTPS via standard-API-er regnes vanligvis som unntatt, men spørsmålet *må* besvares) — `ITSAppUsesNonExemptEncryption` i Info.plist eller svar i App Store Connect.
|
||||||
|
|
||||||
|
## SwiftUI / SwiftData / extensions
|
||||||
|
|
||||||
|
- **Anta ikke sanntids-synk mellom app- og widget-prosess.** App Group-delt store er kilden, men oppdateringstiming er strammere på iOS 17 enn iOS 18+. Trigg `WidgetCenter.reloadTimelines` eksplisitt.
|
||||||
|
- **Glem ikke `NSSupportsLiveActivities = YES`** i *hoved-app-ens* Info.plist (ikke widget-extension-ens). Uten den fungerer ikke Live Activities — og det feiler stille.
|
||||||
|
- **Hopp ikke over SwiftData-migrasjonsplan.** En uplanlagt `@Model`-endring etter lansering kan tvinge destruktiv migrasjon (brukeren mister data).
|
||||||
|
- **Overskrid ikke extension-minnebudsjettet** (≈30 MB-klassen) i widget/Live-Activity-kode — store containere/tunge beregninger der crasher extension.
|
||||||
|
- **Bruk `if #available` for nyere API-er** — ellers krasjer appen på enheter med eldre deployment target.
|
||||||
|
|
||||||
|
## Lokasjon & permission
|
||||||
|
|
||||||
|
- **Be ikke om "Always"-lokasjon** når "When In Use" holder — review-friksjon og brukermistillit; Settings → Privacy avslører det.
|
||||||
|
- **Be ikke om permission ved første launch** uten kontekst — forklar på en onboarding-skjerm først (review forventer det; bedre conversion).
|
||||||
|
- **Etterlat ikke en tom/dead-end-skjerm** når permission nektes — ha en fallback (siste kjente posisjon / manuell input / degradert modus).
|
||||||
|
|
||||||
|
## Generelt
|
||||||
|
|
||||||
|
- **`iOS 19` finnes ikke.** Apple gikk fra iOS 18 til iOS 26 (WWDC 2025). Refererer en spec/brief "iOS 19", er det en feil — mener sannsynligvis iOS 26 (gjeldende) eller iOS 27 (høst 2026).
|
||||||
|
- **`UserDefaults` er ikke et hemmelig-lager.** Sensitiv data → Keychain (MASVS-STORAGE). Se `checklist-security-privacy.md`.
|
||||||
29
domain-packs/ios-app/pack.json
Normal file
29
domain-packs/ios-app/pack.json
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"schema": "domain-pack/v1",
|
||||||
|
"name": "ios-app",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"domain": "iOS-app-utvikling (Swift/SwiftUI, App Store-distribusjon)",
|
||||||
|
"description": "Domene-kunnskap for iOS-app-utvikling: HIG/Liquid Glass, Swift/SwiftUI-konvensjoner, offline-first-mønstre, App Store-submission, MASVS 2.1, WCAG 2.2 AA, privacy manifest.",
|
||||||
|
"phases": [1, 3, 4, 5, 6, 7],
|
||||||
|
"verified": {
|
||||||
|
"date": "2026-05-12",
|
||||||
|
"against": "iOS 26 (gjeldende SDK; build-krav siden 2026-04-28), HIG / Liquid Glass (WWDC 2025), deployment-target-baseline iOS 17–18, OWASP MASVS 2.1.0 (2024-01-18), WCAG 2.2 AA (W3C Rec 2023-10-05)",
|
||||||
|
"note": "Kildebelegg: Apple Developer (developer.apple.com), W3C WAI (w3.org/WAI), OWASP MAS (mas.owasp.org). Se conventions.md / checklist*.md for per-påstand-referanser. iOS 19–25 finnes ikke — Apple gikk fra iOS 18 til iOS 26 (år-basert navn) på WWDC 2025."
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"conventions.md": "core",
|
||||||
|
"gotchas.md": "core",
|
||||||
|
"checklist.md": "core",
|
||||||
|
"checklist-security-privacy.md": "core",
|
||||||
|
"checklist-accessibility.md": "core",
|
||||||
|
"glossary.md": "supplementary",
|
||||||
|
"patterns/offline-first-swiftdata.md": "supplementary",
|
||||||
|
"patterns/local-notifications.md": "supplementary",
|
||||||
|
"patterns/widget-live-activities-shared-model.md": "supplementary",
|
||||||
|
"patterns/current-location-regeneration.md": "supplementary",
|
||||||
|
"scaffold/PrivacyInfo.xcprivacy": "supplementary",
|
||||||
|
"scaffold/NSUsageDescription-inventory.md": "supplementary",
|
||||||
|
"scaffold/app-store-connect-metadata.md": "supplementary",
|
||||||
|
"examples/feature-brief-local-notification-window.md": "supplementary"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
<!-- domain-pack: ios-app · component: patterns · supplementary -->
|
||||||
|
<!-- verified 2026-05-12 against Core Location / CLLocationManager docs. -->
|
||||||
|
|
||||||
|
# Pattern: current-location-basert beregning med regenerering & fallback
|
||||||
|
|
||||||
|
**Når:** appen beregner noe som avhenger av hvor brukeren er *nå* (soltider, tidssoner, lokale data) og må holde det oppdatert når brukeren flytter seg — uten å lagre lokasjonshistorikk.
|
||||||
|
|
||||||
|
## Form
|
||||||
|
|
||||||
|
- **Be om "When In Use"**, ikke "Always", med mindre bakgrunns-oppdatering er strengt nødvendig. Nøkkel: `NSLocationWhenInUseUsageDescription` (Always: `NSLocationAlwaysAndWhenInUseUsageDescription`). Forklar hvorfor på onboarding *før* prompten.
|
||||||
|
- **Hent posisjon ved app-foreground** (`scenePhase == .active`): én `requestLocation()` (engangs) eller kort `startUpdatingLocation()` til en god fix, så stopp. Ikke kontinuerlig sporing.
|
||||||
|
- **Regenerer avledede verdier** ved hver fix der posisjonen har endret seg vesentlig (terskel, f.eks. >tens of km, eller tidssone-bytte): re-kjør beregningen, re-planlegg avhengige lokale notifikasjoner (se `patterns/local-notifications.md`), oppdater widget-timeline.
|
||||||
|
- **Cache siste kjente posisjon** (kun den ene verdien, ikke en logg) for bruk når en fersk fix ikke er tilgjengelig.
|
||||||
|
|
||||||
|
## Fallback-stige (når GPS mangler / permission nektet)
|
||||||
|
|
||||||
|
1. **Siste kjente posisjon** (cachet) — bruk den, vis at den er stale.
|
||||||
|
2. **Manuell input** — la brukeren sette/velge sted (by, eller kart-pin) hvis appen er meningsløs uten posisjon.
|
||||||
|
3. **Degradert modus** — vis hva som er mulig uten posisjon (generisk innhold), med tydelig CTA for å gi tilgang / sette sted.
|
||||||
|
4. **Aldri krasj, aldri tom skjerm** uten forklaring. En app som bare viser "Location required" og ikke noe annet risikerer Guideline 4.2 / dårlig review.
|
||||||
|
|
||||||
|
## Personvern
|
||||||
|
|
||||||
|
- Posisjon brukes til beregning og forkastes — ikke lagret som historikk, ikke sendt noe sted. Reflekter dette i App Privacy Details (Location → App Functionality, *ikke* linket til identitet, ingen tracking).
|
||||||
|
- Ingen `PrivacyInfo.xcprivacy`-required-reason for Core Location i seg selv, men *vær konsekvent* med nutrition-label-erklæringen.
|
||||||
|
|
||||||
|
## Fallgruver
|
||||||
|
|
||||||
|
- **Ikke** be om "Always" for noe "When In Use" dekker — review-friksjon + brukermistillit.
|
||||||
|
- **Ikke** poll lokasjon i bakgrunnen "for sikkerhets skyld" — batteridrenering, og synlig i Settings → Privacy.
|
||||||
|
- **Ikke** anta at en fix kommer raskt — ha en timeout og fallback-sti.
|
||||||
|
- **Husk** tidssone: en lokasjonsendring kan også endre tidssonen; beregninger som bruker lokal tid må re-deriveres.
|
||||||
|
|
||||||
|
## App-brief-signal
|
||||||
|
|
||||||
|
"Lokasjons-bevisst", "current location", "regenererer ved app-foreground", "fallback ved nektet permission", "soltider / lokale tider".
|
||||||
34
domain-packs/ios-app/patterns/local-notifications.md
Normal file
34
domain-packs/ios-app/patterns/local-notifications.md
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
<!-- domain-pack: ios-app · component: patterns · supplementary -->
|
||||||
|
<!-- verified 2026-05-12 against UNUserNotificationCenter docs. -->
|
||||||
|
|
||||||
|
# Pattern: lokale notifikasjoner (UNUserNotificationCenter)
|
||||||
|
|
||||||
|
**Når:** appen må varsle brukeren om hendelser den selv vet om (tidsvinduer, påminnelser, milepæler) — uten server, uten push.
|
||||||
|
|
||||||
|
## Form
|
||||||
|
|
||||||
|
- **Autorisasjon ved kjøretid:** `UNUserNotificationCenter.shared().requestAuthorization(options: [.alert, .sound, .badge])`. **Ingen Info.plist-nøkkel kreves** for standard lokale notifikasjoner. ([Apple — UNUserNotificationCenter](https://developer.apple.com/documentation/usernotifications/unusernotificationcenter))
|
||||||
|
- **Be om autorisasjon i kontekst** — ikke ved første launch. Forklar hvorfor på en onboarding-skjerm *før* prompten (App Store Review forventer dette; GDPR-vennlig).
|
||||||
|
- **Planlegging:** `UNNotificationRequest` med `UNCalendarNotificationTrigger` (klokkeslett) eller `UNTimeIntervalNotificationTrigger`. iOS-grense: ~64 ventende lokale notifikasjoner per app — planlegg rullerende, ikke alt på en gang.
|
||||||
|
- **Re-planlegg ved app-foreground** hvis tidene avhenger av tilstand som endrer seg (f.eks. lokasjons-avledede tider — se `patterns/current-location-regeneration.md`): fjern utdaterte (`removePendingNotificationRequests`) og planlegg nye.
|
||||||
|
|
||||||
|
## Interruption levels & Focus
|
||||||
|
|
||||||
|
- `UNNotificationInterruptionLevel`: `.passive`, `.active` (default), `.timeSensitive`, `.critical`.
|
||||||
|
- **Focus mode respekterer nivåene:** `.timeSensitive` kan bryte gjennom de fleste Focus-filtre — krever entitlement (`com.apple.developer.usernotifications.time-sensitive`). `.critical` omgår mute/DND — krever Apple-godkjent entitlement, gis sjelden. For en vanlig app: `.active` eller `.timeSensitive` (med entitlement) hvis varselet er reelt tidskritisk.
|
||||||
|
- Ingen App Store-entitlement kreves for å *planlegge* standard lokale notifikasjoner — kun for time-sensitive/critical-nivåene.
|
||||||
|
|
||||||
|
## Handling av tap
|
||||||
|
|
||||||
|
- `UNUserNotificationCenterDelegate` — `didReceive response` for å reagere på trykk (deep-link til riktig skjerm), `willPresent` for visning mens appen er i forgrunnen.
|
||||||
|
- Hvis et trykk skal endre tilstand ("marker gjort"): bruk `UNNotificationAction` for in-notification-handling der mulig, ellers åpne appen til riktig kontekst.
|
||||||
|
|
||||||
|
## Fallgruver
|
||||||
|
|
||||||
|
- **Ikke** anta autorisasjon — sjekk `getNotificationSettings` og degrader nådig (in-app-klokke/varsler) hvis nektet.
|
||||||
|
- **Ikke** spam — én varsel per hendelse, av/på per kategori.
|
||||||
|
- **Ikke** glem å re-planlegge når underliggende data endres; gamle notifikasjoner som fyrer på feil tid er en synlig bug.
|
||||||
|
|
||||||
|
## App-brief-signal
|
||||||
|
|
||||||
|
"Påminn brukeren", "varsel når X", "respekterer Focus mode", "av/på per varseltype".
|
||||||
33
domain-packs/ios-app/patterns/offline-first-swiftdata.md
Normal file
33
domain-packs/ios-app/patterns/offline-first-swiftdata.md
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
<!-- domain-pack: ios-app · component: patterns · supplementary -->
|
||||||
|
<!-- verified 2026-05-12 against SwiftData docs (iOS 17+). -->
|
||||||
|
|
||||||
|
# Pattern: offline-first med SwiftData
|
||||||
|
|
||||||
|
**Når:** appen eier sine data lokalt, ingen backend (eller backend kun som sync-tillegg). Den enkleste personvern-posisjonen og det riktige valget for små single-purpose-apper.
|
||||||
|
|
||||||
|
## Form
|
||||||
|
|
||||||
|
- **`@Model`-klasser** definerer skjemaet. Ingen `NSManagedObject`, ingen `.xcdatamodeld`.
|
||||||
|
- **`ModelContainer`** opprettes ved app-start; `ModelContext` injiseres i view-treet via `.modelContainer(...)`.
|
||||||
|
- **`@Query`** i views for reaktiv henting; muter via `modelContext.insert/delete` + (auto)`save`.
|
||||||
|
- **Migrasjoner:** `SchemaMigrationPlan` med versjonerte `VersionedSchema`-er. Planlegg fra dag 1 — skjemaet *vil* endre seg.
|
||||||
|
|
||||||
|
## Offline-first-disiplin
|
||||||
|
|
||||||
|
- All lesning/skriving går mot lokal store; ingen view venter på nett.
|
||||||
|
- Hvis sync legges til senere: lokal store er sannheten, sync er en bakgrunnsoppgave som reconciler — ikke omvendt. Konflikt-strategi (last-write-wins / per-felt-merge) er en arkitektur-beslutning (fase 3-ADR).
|
||||||
|
- Backup: SwiftData-store ligger i app-containeren og dekkes av iCloud-enhets-backup automatisk. Eksplisitt iCloud-sync krever CloudKit-integrasjon (`ModelConfiguration(... , cloudKitDatabase: .automatic)`) — en bevisst tilleggsbeslutning, ikke default.
|
||||||
|
|
||||||
|
## Deling med widget / Live Activity
|
||||||
|
|
||||||
|
Store må ligge i en **App Group**-container for å være synlig for extensions. Se `patterns/widget-live-activities-shared-model.md` — dette pattern-et og det henger sammen for enhver app med widgets.
|
||||||
|
|
||||||
|
## Fallgruver
|
||||||
|
|
||||||
|
- **Ikke** anta at endringer i app-prosessen er øyeblikkelig synlige i widget-prosessen — refresh-timing er mer pålitelig på iOS 18+ enn iOS 17. ([Hacking with Swift — SwiftData i widgets](https://www.hackingwithswift.com/quick-start/swiftdata/how-to-access-a-swiftdata-container-from-widgets))
|
||||||
|
- **Ikke** behold en stor `ModelContainer` i minne i en widget-extension uten grunn — extension-minnebudsjettet er stramt.
|
||||||
|
- **Ikke** hopp over migrasjonsplanen "fordi appen er liten" — en uplanlagt skjemaendring etter lansering kan kreve destruktiv migrasjon.
|
||||||
|
|
||||||
|
## App-brief-signal som trigger dette pattern-et
|
||||||
|
|
||||||
|
"Ingen backend / all data lokal", "fungerer offline", "personvern-bevarende", "én bruker, egen enhet".
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
<!-- domain-pack: ios-app · component: patterns · supplementary -->
|
||||||
|
<!-- verified 2026-05-12 against WidgetKit / ActivityKit docs (Live Activities iOS 16.1+). -->
|
||||||
|
|
||||||
|
# Pattern: app + widget + Live Activity deler én datamodell
|
||||||
|
|
||||||
|
**Når:** funksjonalitet vises på hjemskjerm-widget, låseskjerm og/eller Dynamic Island — som *presentasjonslag på samme kjerne-data*, ikke fire uavhengige delsystemer.
|
||||||
|
|
||||||
|
## Arkitektur-prinsipp
|
||||||
|
|
||||||
|
Modeller én gang. App, widget-extension og Live Activity leser **samme delte tilstand** via en **App Group**-container. Widgeten og Live Activity-en eier *ikke* egen kopi av forretningslogikken — de rendrer et snapshot.
|
||||||
|
|
||||||
|
## Mekanikk
|
||||||
|
|
||||||
|
- **App Group:** legg til App Group-capability (`group.<bundle-id>`) på *både* app-target og widget-extension-target.
|
||||||
|
- **Delt SwiftData-store:** `ModelConfiguration(... , groupContainer: .identifier("group.<bundle-id>"))` → samme `ModelContainer` i begge targets. Widgeten legger `.modelContainer(...)` på sin `WidgetConfiguration`. ([Hacking with Swift — SwiftData i widgets](https://www.hackingwithswift.com/quick-start/swiftdata/how-to-access-a-swiftdata-container-from-widgets)) Alternativ for enkle verdier: delt `UserDefaults(suiteName:)`.
|
||||||
|
- **Widget-refresh:** `WidgetCenter.shared.reloadTimelines(ofKind:)` fra appen når data endres; ellers timeline-baserte oppdateringer. Vær konservativ — WidgetKit-refresh-budsjettet er begrenset.
|
||||||
|
- **Live Activities (iOS 16.1+):** ActivityKit + en WidgetKit-extension. Krever `NSSupportsLiveActivities = YES` i **hoved-app-ens** Info.plist (ikke extension-ens). Vises på låseskjerm + Dynamic Island (Dynamic Island: iPhone 14 Pro+ / standard på iPhone 15+; eldre enheter får bare låseskjerm-presentasjonen). `ActivityAttributes` definerer statisk + dynamisk innhold; oppdater via `activity.update(...)`, avslutt via `activity.end(...)`. ([Live Activities — GitHub iOS16-Live-Activities](https://github.com/1998code/iOS16-Live-Activities))
|
||||||
|
- **Opt-in:** Live Activities / Lock Screen-features bør være noe brukeren slår på, ikke noe som dukker opp uoppfordret.
|
||||||
|
|
||||||
|
## Fallgruver
|
||||||
|
|
||||||
|
- **Ikke** dupliser forretningslogikk inn i extension — beregn i appen / et delt framework, del bare resultatet.
|
||||||
|
- **Ikke** anta sanntids-synk app↔extension; oppdateringstiming er strammere på iOS 17 enn iOS 18+.
|
||||||
|
- **Ikke** overskrid extension-minnebudsjettet (≈30 MB-klassen) — hold widget/Live-Activity-koden lett.
|
||||||
|
- **Glem ikke** `NSSupportsLiveActivities` — uten den fungerer ikke Live Activities, og det feiler stille.
|
||||||
|
|
||||||
|
## App-brief-signal
|
||||||
|
|
||||||
|
"Widget på hjemskjerm", "Live Activities / låseskjerm-countdown", "samme kjerne-datamodell", "Dynamic Island".
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
<!-- domain-pack: ios-app · component: scaffold -->
|
||||||
|
<!-- Template: fyll ut for hver app. verified 2026-05-12 against Apple Info.plist key docs. -->
|
||||||
|
|
||||||
|
# `NSUsageDescription`-inventar — {app-slug}
|
||||||
|
|
||||||
|
For *hver* beskyttet ressurs appen bruker: en Info.plist purpose-string. **Manglende = appen termineres ved permission-request + App Store-avvisning (Guideline 5.1.1).** Strengen skal forklare *hvorfor appen trenger det*, kort og konkret — ikke "Appen trenger lokasjon".
|
||||||
|
|
||||||
|
| Ressurs | Info.plist-nøkkel | Brukes? | Purpose-string (vises i system-prompt) |
|
||||||
|
|---------|-------------------|---------|----------------------------------------|
|
||||||
|
| Lokasjon (når i bruk) | `NSLocationWhenInUseUsageDescription` | ☐ | "{f.eks.: Brukes for å beregne dine lokale soltider. Posisjonen forlater aldri enheten.}" |
|
||||||
|
| Lokasjon (alltid) | `NSLocationAlwaysAndWhenInUseUsageDescription` | ☐ | "{kun hvis bakgrunns-lokasjon er strengt nødvendig — ellers la stå tom}" |
|
||||||
|
| Kamera | `NSCameraUsageDescription` | ☐ | "{...}" |
|
||||||
|
| Mikrofon | `NSMicrophoneUsageDescription` | ☐ | "{...}" |
|
||||||
|
| Foto-bibliotek (les) | `NSPhotoLibraryUsageDescription` | ☐ | "{...}" |
|
||||||
|
| Foto-bibliotek (skriv) | `NSPhotoLibraryAddUsageDescription` | ☐ | "{...}" |
|
||||||
|
| Kontakter | `NSContactsUsageDescription` | ☐ | "{...}" |
|
||||||
|
| Kalender | `NSCalendarsUsageDescription` | ☐ | "{...}" |
|
||||||
|
| Påminnelser | `NSRemindersUsageDescription` | ☐ | "{...}" |
|
||||||
|
| Bluetooth | `NSBluetoothAlwaysUsageDescription` | ☐ | "{...}" |
|
||||||
|
| Face ID | `NSFaceIDUsageDescription` | ☐ | "{...}" |
|
||||||
|
| HealthKit (les/del) | `NSHealthShareUsageDescription` / `NSHealthUpdateUsageDescription` | ☐ | "{...}" |
|
||||||
|
| Motion & fitness | `NSMotionUsageDescription` | ☐ | "{...}" |
|
||||||
|
| Lokalt nettverk | `NSLocalNetworkUsageDescription` | ☐ | "{...}" |
|
||||||
|
| Tracking (IDFA) | `NSUserTrackingUsageDescription` | ☐ | "{kun hvis appen faktisk tracker — krever også ATT-prompt}" |
|
||||||
|
|
||||||
|
**Notifikasjoner:** trenger **ingen** Info.plist-nøkkel. Men forklar hvorfor på en onboarding-skjerm *før* `UNUserNotificationCenter.requestAuthorization(...)`-kallet — App Review forventer det, og conversion blir bedre.
|
||||||
|
|
||||||
|
**Andre Info.plist-felter knyttet til submission:**
|
||||||
|
- `ITSAppUsesNonExemptEncryption` — `false` hvis appen kun bruker standard-HTTPS via system-API (vanligvis unntatt). Ellers besvar eksport-compliance i App Store Connect.
|
||||||
|
- `NSSupportsLiveActivities` — `YES` i hoved-app-ens Info.plist hvis appen bruker Live Activities.
|
||||||
|
- `UIBackgroundModes` — kun moduser appen faktisk bruker (review sjekker dette).
|
||||||
|
|
||||||
|
Etter utfylling: kryss av i `checklist.md` § B.
|
||||||
65
domain-packs/ios-app/scaffold/PrivacyInfo.xcprivacy
Normal file
65
domain-packs/ios-app/scaffold/PrivacyInfo.xcprivacy
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
Template: PrivacyInfo.xcprivacy — Apple Privacy Manifest
|
||||||
|
domain-pack: ios-app · component: scaffold
|
||||||
|
Påkrevd for App Store-innsending siden 2024-05-01.
|
||||||
|
Dette eksempelet er for en ALL-LOCAL-app som ikke tracker, ikke samler data,
|
||||||
|
og kun bruker UserDefaults (en required-reason-API). Tilpass per app:
|
||||||
|
- NSPrivacyTracking: true KUN hvis appen tracker på tvers av apper/nettsteder
|
||||||
|
- NSPrivacyTrackingDomains: liste over tracking-domener (tom ellers)
|
||||||
|
- NSPrivacyCollectedDataTypes: én dict per innsamlet datatype (tom hvis ingenting)
|
||||||
|
- NSPrivacyAccessedAPITypes: én dict per required-reason-API-kategori appen bruker,
|
||||||
|
med tillatt reason-kode (se Apple-docs for kategorier + koder)
|
||||||
|
Hver tredjeparts-SDK må levere SIN EGEN PrivacyInfo.xcprivacy — verifiser.
|
||||||
|
Docs: https://developer.apple.com/documentation/bundleresources/privacy-manifest-files
|
||||||
|
https://developer.apple.com/documentation/bundleresources/describing-use-of-required-reason-api
|
||||||
|
-->
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>NSPrivacyTracking</key>
|
||||||
|
<false/>
|
||||||
|
|
||||||
|
<key>NSPrivacyTrackingDomains</key>
|
||||||
|
<array/>
|
||||||
|
|
||||||
|
<key>NSPrivacyCollectedDataTypes</key>
|
||||||
|
<array/>
|
||||||
|
<!-- Eksempel-oppføring hvis appen f.eks. samler grov lokasjon for app-funksjonalitet,
|
||||||
|
ikke linket til identitet, ikke for tracking:
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>NSPrivacyCollectedDataType</key>
|
||||||
|
<string>NSPrivacyCollectedDataTypeCoarseLocation</string>
|
||||||
|
<key>NSPrivacyCollectedDataTypeLinked</key>
|
||||||
|
<false/>
|
||||||
|
<key>NSPrivacyCollectedDataTypeTracking</key>
|
||||||
|
<false/>
|
||||||
|
<key>NSPrivacyCollectedDataTypePurposes</key>
|
||||||
|
<array>
|
||||||
|
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<key>NSPrivacyAccessedAPITypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>NSPrivacyAccessedAPIType</key>
|
||||||
|
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
|
||||||
|
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||||
|
<array>
|
||||||
|
<!-- CA92.1 = access info from same app, per documentation -->
|
||||||
|
<string>CA92.1</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
<!-- Legg til flere kategorier ved behov, f.eks.:
|
||||||
|
NSPrivacyAccessedAPICategoryFileTimestamp (reasons: C617.1, 3B52.1, 0A2A.1, ...)
|
||||||
|
NSPrivacyAccessedAPICategorySystemBootTime (reasons: 35F9.1, 8FFB.1, 3D61.1)
|
||||||
|
NSPrivacyAccessedAPICategoryDiskSpace (reasons: E174.1, 85F4.1, 7D9E.1, B728.1)
|
||||||
|
NSPrivacyAccessedAPICategoryActiveKeyboards(reasons: 3EC4.1, 54BD.1)
|
||||||
|
-->
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
62
domain-packs/ios-app/scaffold/app-store-connect-metadata.md
Normal file
62
domain-packs/ios-app/scaffold/app-store-connect-metadata.md
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
<!-- domain-pack: ios-app · component: scaffold -->
|
||||||
|
<!-- Template: fyll ut per app. verified 2026-05-12 against App Store Connect reference. -->
|
||||||
|
|
||||||
|
# App Store Connect-metadata — {app-slug}
|
||||||
|
|
||||||
|
Samle alt som må inn i App Store Connect før innsending. Kryss av mot `checklist.md` § A.
|
||||||
|
|
||||||
|
## App-informasjon
|
||||||
|
|
||||||
|
- **App-navn:** {≤30 tegn}
|
||||||
|
- **Undertittel:** {≤30 tegn}
|
||||||
|
- **Bundle ID:** {com.example.app}
|
||||||
|
- **Primær kategori / sekundær:** {…}
|
||||||
|
- **Aldersrating:** fullført revidert spørreskjema → resultat: {4+ / 9+ / 12+ / 13+ / 16+ / 18+}
|
||||||
|
- **Support-URL:** {https://…}
|
||||||
|
- **Marketing-URL** (valgfri): {…}
|
||||||
|
- **Personvern-policy-URL:** {påkrevd hvis noe data samles; for all-local kan en kort side som sier "ingen data samles" holde}
|
||||||
|
- **Copyright:** {© ÅÅÅÅ Navn}
|
||||||
|
|
||||||
|
## Beskrivelse & nøkkelord
|
||||||
|
|
||||||
|
- **Beskrivelse:** {≤4000 tegn — må stemme med faktisk funksjonalitet, ingen påstander appen ikke kan stå inne for}
|
||||||
|
- **Nøkkelord:** {≤100 tegn, komma-separert}
|
||||||
|
- **Promotional text** (valgfri, kan endres uten review): {≤170 tegn}
|
||||||
|
- **Hva er nytt (release-notater):** {per versjon}
|
||||||
|
|
||||||
|
## Skjermbilder & forhåndsvisning
|
||||||
|
|
||||||
|
- **6,9″ iPhone:** 1320×2868 px — {N stk, 1–10}
|
||||||
|
- **13″ iPad** (hvis universal): 2064×2752 px — {N stk}
|
||||||
|
- Format: flat PNG/JPG, RGB, **ingen alfakanal**. Må vise faktisk UI (Guideline 2.3).
|
||||||
|
- **App preview** (valgfri video): {15–30 s, per enhetsstørrelse}
|
||||||
|
|
||||||
|
## Personvern (App Privacy Details)
|
||||||
|
|
||||||
|
- **Data Not Collected?** {ja / nei} — hvis nei, fyll ut per kategori (se `checklist-security-privacy.md`).
|
||||||
|
- For hver innsamlet kategori: formål + linket til identitet? + brukt til tracking?
|
||||||
|
- **`PrivacyInfo.xcprivacy`** i bygget? {ja — se `scaffold/PrivacyInfo.xcprivacy`}
|
||||||
|
|
||||||
|
## Compliance
|
||||||
|
|
||||||
|
- **Eksport-compliance:** `ITSAppUsesNonExemptEncryption` = {false hvis kun standard-HTTPS, ellers besvar i ASC}
|
||||||
|
- **Content rights:** appen inneholder/bruker tredjeparts-innhold jeg har rett til? {ja/nei + grunnlag}
|
||||||
|
- **Tredjeparts-innhold-disclaimere** (hvis relevant): {f.eks. "ikke affiliert med X" i beskrivelsen}
|
||||||
|
|
||||||
|
## Region-spesifikt (kun markeder du distribuerer i)
|
||||||
|
|
||||||
|
- **EU — DSA trader-status:** verifisert kontaktinfo i ASC? {ja/nei}
|
||||||
|
- **Kina — ICP-filing-nummer:** {nummer / N/A — ikke distribuert i Kina}
|
||||||
|
- **Sør-Korea — GRAC** (kun spill): {rating / N/A}
|
||||||
|
|
||||||
|
## App Review-informasjon
|
||||||
|
|
||||||
|
- **Demo-konto:** {brukernavn/passord hvis login kreves, ellers N/A}
|
||||||
|
- **Notater til review:** {spesielt oppsett, hvordan teste tidsavhengige features, kontaktinfo}
|
||||||
|
- **Kontakt:** {navn, e-post, telefon}
|
||||||
|
|
||||||
|
## Pris & tilgjengelighet
|
||||||
|
|
||||||
|
- **Prismodell:** {gratis / engangs-betalt — pris-tier / freemium}
|
||||||
|
- **Land/regioner:** {alle / utvalg}
|
||||||
|
- **Utgivelse:** {manuell / automatisk ved godkjenning / planlagt dato}
|
||||||
|
|
@ -159,3 +159,28 @@ Eventuelt: aksepter at operatør gir kvaliteter, og gjør AI-foreslått-features
|
||||||
Ingen ny design-friksjon. S5 var en ren revisjons-/spec-skrivings-sesjon mot research-brief-mandatet — ingen reell pipeline-kjøring som kunne avsløre nye gap. Prosess-merknad: revisjonen av `phase-design-draft.md` ble stor (førsteutkast ~900 linjer → andreutkast tilsvarende), men holdt seg innenfor token-budsjett ved å skrives som ett `Write`-kall etter at all kontekst var lest. Neste reelle friksjons-belegg kommer når Akashic kjøres videre (fase 2+) i S8+.
|
Ingen ny design-friksjon. S5 var en ren revisjons-/spec-skrivings-sesjon mot research-brief-mandatet — ingen reell pipeline-kjøring som kunne avsløre nye gap. Prosess-merknad: revisjonen av `phase-design-draft.md` ble stor (førsteutkast ~900 linjer → andreutkast tilsvarende), men holdt seg innenfor token-budsjett ved å skrives som ett `Write`-kall etter at all kontekst var lest. Neste reelle friksjons-belegg kommer når Akashic kjøres videre (fase 2+) i S8+.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## #9: Prototype-data (Akashic `01-app-brief.md`) refererer en iOS-versjon som ikke finnes ("iOS 19")
|
||||||
|
|
||||||
|
**Fase:** fase 1 (Akashic-brief), oppdaget i fase-arbeid utenfor Akashic (S6 domain-pack-forfatting + verifisering)
|
||||||
|
**Type:** prototype-data-friksjon (ikke en design-flaw i app-creator selv, men en konkret demonstrasjon av hvorfor Verifiseringsplikten + fase-1-research-tema-uthenting trengs)
|
||||||
|
**Observert:** 2026-05-12 (S6) — under verifisering av `ios-app`-pakkens `pack.json` `verified`-felt mot offisielle Apple-kilder
|
||||||
|
|
||||||
|
**Beskrivelse:** Akashic `01-app-brief.md` § Plattform sier "Min-versjon: iOS 18 (gjeldende per mai 2026). Oppdateres til iOS 19 etter at den lanseres høst 2026". Verifisering mot Apple Newsroom / Apple Developer: **iOS 19 finnes ikke.** Apple gikk på WWDC juni 2025 fra iOS 18 rett til **iOS 26** (år-basert navn), med "Liquid Glass" som nytt designspråk; iOS 26 ble lansert september 2025. I mai 2026 er iOS 26 gjeldende versjon; neste store versjon er iOS 27 (WWDC juni 2026, lansering høst 2026). Briefen ble skrevet i S1 uten å verifisere iOS-navne-endringen — et lite, men konkret eksempel på at en udokumentert/feilhusket plattform-faktum sniker seg inn i en brief hvis den ikke verifiseres.
|
||||||
|
|
||||||
|
**Hva S6 gjorde med det:** `ios-app/pack.json` `verified.against` reflekterer den verifiserte tilstanden (iOS 26 / HIG-Liquid Glass WWDC 2025 / deployment-baseline iOS 17–18 / MASVS 2.1.0 / WCAG 2.2 AA). `domain-pack-spec.md` § D7 fikk en korreksjons-note. `ios-app/conventions.md` og `gotchas.md` sier eksplisitt at "iOS 19 finnes ikke" og at en spec/brief som refererer den er feil. **Selve Akashic-briefen rettes i S7** (revision 0→1 uansett — operatør har sagt det som mangler skal fylles inn da; iOS-versjons-korreksjonen er en del av det).
|
||||||
|
|
||||||
|
**Lærdom for app-creator-designet:** fase 1-malen bør ha plattform-versjons-felter merket som verifiserings-pliktige (datert "verifisert mot {kilde} {dato}"), og domain-pack `conventions.md` er det rette stedet for "gjeldende plattform-versjon"-fakta — slik at app-briefen arver dem fra pakken i stedet for å gjette. Allerede delvis dekket av at `phase-design-draft.md` § Fase 1 har trekbrief-disiplinen "research-tema-uthenting" og `[ANTAKELSE]`-markører, og at `ios-app`-pakken nå bærer iOS-versjons-policyen. Ingen ny revisjon av `phase-design-draft.md` nødvendig — men verdt å huske at domain-pack-`conventions.md` skal være kilden for slike fakta, ikke per-app-briefen.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Ny friksjon oppstått i S6
|
||||||
|
|
||||||
|
Én ny prototype-data-friksjon: #9 (over). Ingen ny *design*-friksjon i selve pipeline-designet — S6 var forfatter-arbeid (domain-packs), ikke pipeline-kjøring.
|
||||||
|
|
||||||
|
Mindre prosess-/spec-merknader fra forfatter-arbeidet (ikke nummererte friksjons-poeng — bare ting verdt å notere):
|
||||||
|
- **`checklist.md` sprenger lengde-grensen for `ios-app`.** App Store-submission + MASVS 2.1 (8 grupper) + WCAG 2.2 AA + privacy-manifest-mal + App Privacy Details får ikke plass på én skjerm. Løst som `domain-pack-spec.md` § D2 forutser: splittet i `checklist.md` (App Store-submission + index) + `checklist-security-privacy.md` + `checklist-accessibility.md`, hver lastbar uavhengig, hver med egen `components`-oppføring. Bekrefter at split-konvensjonen i § D2 var nødvendig, ikke teoretisk.
|
||||||
|
- **`pack.json` trengte et `components`-felt.** D3-skjemaet (S5) hadde ikke en maskinlesbar core/supplementary-merking; D2 sa "merkes i toppen av hver fil eller sentralt". S6 valgte sentralt (`components`-map i `pack.json`) fordi en snapshot-generator da kan lese det direkte. `domain-pack-spec.md` § D3/D4 oppdatert. Liten spec-gap fylt under forfatter-arbeidet — akkurat den typen ting forfatting av en referanse-implementasjon skal avsløre.
|
||||||
|
- **Verifiserings-asymmetri pakkene imellom.** `ios-app` er verifisert mot offisielle eksterne kilder (Apple/W3C/OWASP). `claude-code-plugin` er ekstrahert fra interne ktg-konvensjoner og er en stub — plattform-detaljene der (hooks-API, `${CLAUDE_PLUGIN_ROOT}`, auto-discovery) er *ikke* uttømmende verifisert mot offisiell Claude Code-dokumentasjon. Markert eksplisitt i pakkens `pack.json` `verified.note` og i `domain-pack-spec.md` § Kilder. Ikke et problem (pakken er ikke i bruk av Akashic), men ærlig om status.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue