Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions packages/codegraph/data/skill/shopify-apps/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
---
name: shopify-apps
description: Sviluppo di app Shopify embedded nell'admin — Polaris, App Bridge, Admin GraphQL API, session token, webhook, billing, extension. ATTIVARE SEMPRE quando l'utente menziona "app Shopify", "app embedded", "Polaris", "App Bridge", "shopify app init", "shopify app dev", "shopify app deploy", "shopify.app.toml", "access scope", "OAuth Shopify", "session token", "Admin API", "admin GraphQL", "authenticate.admin", "app extension", "admin action", "admin block", "webhook Shopify", "billing API", "Built for Shopify", "App Store Shopify", "custom app", "app proxy", "s-page", "s-section", "polaris web components". Attivare anche senza queste parole quando la richiesta descrive uno strumento per il merchant dentro il pannello Shopify - "una schermata nell'admin per gestire X", "un pannello dove il cliente configura Y", "sincronizzare ordini Shopify col gestionale", "automatizzare qualcosa lato backoffice". NON è la skill per la vetrina - quella è shopify-storefront o shopify-themes.
---

# App Shopify embedded

Un'app embedded vive in un iframe dentro l'admin Shopify (**App Home**), parla con l'admin via **App Bridge** e usa i componenti **Polaris** per sembrare parte di Shopify e non un corpo estraneo.

Questa è la superficie del *merchant*, non del cliente finale. Se la richiesta riguarda quello che vede chi compra, sei nella skill sbagliata.

---

## Attenzione: Polaris è cambiato

Il modello attuale usa **Polaris web components**, non i vecchi componenti React di `@shopify/polaris`:

```jsx
export default function App() {
return (
<s-page heading="La mia app">
<s-section heading="Benvenuto">
<s-paragraph>Contenuto della pagina.</s-paragraph>
</s-section>
</s-page>
);
}
```

Sono standard Web Components: funzionano in React, Vue o vanilla JS come un `<button>` qualsiasi. Si caricano da `cdn.shopify.com/shopifycloud/polaris.js` (sempre l'ultima versione) e i tipi TypeScript arrivano da `@shopify/polaris-types`, da tenere allineato con `@latest`.

Stessa cosa per App Bridge: si carica da `cdn.shopify.com/shopifycloud/app-bridge.js`, espone la variabile globale `shopify`, e i tipi stanno in `@shopify/app-bridge-types`.

**Perché è importante saperlo:** buona parte del materiale in circolazione (e la memoria di qualsiasi modello addestrato prima) descrive lo stack precedente a componenti React con `<AppProvider>`, `@shopify/app-bridge-react` v3 e provider annidati. Se stai per scrivere quel codice, fermati e verifica com'è impostato il progetto.

---

## Scaffold

```bash
shopify app init # scegli "Build a React Router app"
cd my-app
shopify app dev # crea il tunnel e apre l'app nel dev store
```

Il template include App Bridge, Polaris e la gestione dell'autenticazione. Non ricostruire a mano ciò che il template già fa: l'auth di un'app embedded è il punto in cui l'improvvisazione si paga di più.

---

## Autenticazione

**Session token, mai cookie.** L'app frontend ottiene un JWT di durata brevissima da App Bridge e lo manda al proprio backend, che lo verifica con il secret condiviso.

```js
const token = await shopify.idToken();
await fetch('/api/sync-products', {
method: 'POST',
headers: {Authorization: `Bearer ${token}`},
});
```

I token vanno richiesti a ogni chiamata: hanno vita di circa un minuto e non si mettono in cache. Gli approcci basati su cookie falliscono negli iframe in modi che in locale non si vedono.

Nel template React Router, le route protette passano da `authenticate.admin(request)` prima di leggere qualsiasi dato del merchant.

**Direct API access.** Con la configurazione giusta, il frontend può chiamare l'Admin GraphQL API direttamente: App Bridge autentica la richiesta.

```js
const response = await fetch('shopify:admin/api/graphql.json', {
method: 'POST',
body: JSON.stringify({query: `query { products(first: 10) { edges { node { id title } } } }`}),
});
```

Va abilitato nel `shopify.app.toml`:

```toml
[access_scopes]
scopes = "read_products,write_products"

[access.admin]
embedded_app_direct_api_access = true
direct_api_mode = "online"
```

`online` lega il token alla sessione utente; `offline` persiste ed è quello che serve ai job di background.

---

## Struttura di lavoro

1. **Configura** `shopify.app.toml`: scope minimi necessari, URL, webhook, direct API access
2. **Costruisci le pagine** con Polaris web components; per gli elementi che stanno *fuori* dall'iframe (title bar, menu di navigazione) usa i componenti App Bridge
3. **Leggi e scrivi dati** via Admin GraphQL — dal backend con il token, o dal frontend con direct API access
4. **Reagisci agli eventi** con i webhook (HMAC verificato, handler idempotenti e veloci)
5. **Estendi altre superfici** con le extension (admin action, admin block, theme app extension, checkout UI extension, Functions)
6. **Testa** su dev store: installazione, disinstallazione, sessione di ritorno, scope mancanti, stati di billing, webhook, errori API

Dettagli su Polaris, App Bridge e pattern di pagina: `references/polaris-e-app-bridge.md`.
Admin API, webhook, billing, OAuth e deploy: `references/admin-api-e-deploy.md`.

---

## Come rispondere

**Verifica lo stack prima di scrivere.** Web components o React legacy? Template React Router o Remix? È la stessa disciplina della skill storefront, per la stessa ragione.

**Non improvvisare l'autenticazione.** Se ti trovi a scrivere logica di sessione con i cookie in un'app embedded, il progetto sta prendendo la strada sbagliata.

**Scope minimi.** Ogni permesso in più è attrito all'installazione e una domanda in più in review.

**Usa Polaris salvo motivo esplicito.** Un'app che non somiglia all'admin viene percepita come meno affidabile e disinstallata prima. Questo è l'unico contesto Shopify in cui "non fare design originale" è il consiglio giusto — l'opposto di quanto vale per una vetrina.

**Distingui custom app e app pubblica.** Un'app per un solo merchant non passa dalla review e non ha bisogno dei requisiti Built for Shopify. Una da App Store sì, e vanno considerati fin dal preventivo.

---

## File di riferimento

- `references/polaris-e-app-bridge.md` — web components, API di App Bridge, pattern di pagina, extension UI
- `references/admin-api-e-deploy.md` — Admin GraphQL, webhook, billing, hosting, deploy, Built for Shopify

## Skill collegate

- **`shopify-core`** — scelta dell'architettura, API e autenticazione, livello condiviso
- **`shopify-functions`** — le Functions sono extension di un'app: se la richiesta tocca il checkout, si lavora lì
- **`shopify-themes`** — per le theme app extension, cioè il modo corretto di portare la funzionalità dell'app dentro la vetrina
- **`shopify-storefront`** — se il merchant ha una vetrina headless che consuma i dati gestiti dall'app
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# Admin API, webhook, billing e deploy

## Indice
- [Admin GraphQL API](#admin-graphql-api)
- [Rate limit e query costose](#rate-limit-e-query-costose)
- [Bulk operations](#bulk-operations)
- [Webhook](#webhook)
- [Billing](#billing)
- [OAuth e installazione](#oauth-e-installazione)
- [Hosting e deploy](#hosting-e-deploy)
- [Built for Shopify e review](#built-for-shopify-e-review)
- [Checklist prima del lancio](#checklist-prima-del-lancio)

---

## Admin GraphQL API

Accesso completo ai dati del merchant: prodotti, ordini, clienti, inventario, fulfillment, metafield.

- Versione API dichiarata esplicitamente e aggiornata ogni trimestre
- Le mutation restituiscono `userErrors`: **vanno sempre controllati**, un 200 non significa che l'operazione sia riuscita
- Le query costano in base alla complessità, non al numero di chiamate

Codegen: mantenere i tipi GraphQL generati evita l'intera classe di bug da campo rinominato o rimosso in una nuova versione API.

---

## Rate limit e query costose

Modello a punti con leaky bucket: ogni query ha un costo calcolato sui campi richiesti, le mutation costano di più. La risposta include il costo effettivo e i punti residui — vale la pena leggerli e non ignorarli.

Quando si sbatte sui limiti:

1. Riduci i campi richiesti — molte query chiedono tre volte i dati che usano
2. Backoff esponenziale sui `THROTTLED`
3. Paginazione a pagine più piccole
4. Per i volumi grandi, bulk operations

Parallelizzare di più peggiora la situazione: il bucket è per app e per shop.

---

## Bulk operations

Per esportare o importare grandi quantità di dati (interi cataloghi, storici ordini) l'API sincrona non è la strada: si usa una bulk operation, che gira asincrona e produce un file JSONL da scaricare.

Pattern: avvii l'operazione → ricevi un ID → controlli lo stato (o ascolti il webhook) → scarichi e processi il file. Più lento a partire, incomparabilmente più affidabile su volumi grandi.

---

## Webhook

Sottoscrizioni dichiarate nel `shopify.app.toml` o create via API.

Regole non negoziabili:

- **Verifica HMAC** prima di fidarti del payload — senza, chiunque può inviarti eventi falsi
- **Idempotenza**: lo stesso evento può arrivare più volte; usa l'ID evento per deduplicare
- **Risposta rapida**: 2xx subito, elaborazione in coda. Gli handler lenti vengono considerati falliti e ritentati, generando duplicati
- **Webhook GDPR obbligatori** per le app pubbliche: richiesta dati cliente, cancellazione dati cliente, cancellazione dati shop
- **`app/uninstalled`**: pulizia dei dati e dello stato di billing

Un webhook non gestito o costantemente in errore può portare Shopify a sospendere le consegne.

---

## Billing

Modelli disponibili: abbonamento ricorrente, prova gratuita, pricing gestito da Shopify, consumo.

Pattern che funziona nel template React Router: il controllo dello stato di billing sta nel loader del layout dell'app, e chi non ha un piano attivo viene rediretto alla pagina di selezione. Così nessuna route protetta è raggiungibile senza piano, senza duplicare il controllo ovunque.

Da testare esplicitamente: prova scaduta, upgrade, downgrade, pagamento fallito, disinstallazione con abbonamento attivo. Sono gli stati in cui le app perdono soldi silenziosamente.

---

## OAuth e installazione

Il flusso lo gestisce il template, ma vale sapere cosa succede: il merchant approva gli scope → l'app riceve il codice → lo scambia per un access token → salva la sessione.

Punti di attenzione:

- **Aggiungere scope dopo il lancio** richiede riapprovazione dai merchant già installati
- **Reinstallazione**: l'app deve gestire il caso di uno shop che si reinstalla con dati residui
- **Sessioni persistenti**: vanno in un database, non in memoria — con più istanze in esecuzione, la memoria non è condivisa

---

## Hosting e deploy

L'app gira su un hosting tuo: Fly.io, Render, Google Cloud Run e simili.

```bash
shopify app deploy # sincronizza configurazione ed extension con Shopify
```

Attenzione alla distinzione: `deploy` della CLI sincronizza **configurazione ed extension** verso Shopify, non pubblica il codice del tuo server. Quello va deployato sul tuo hosting con il tuo processo. Sono due passaggi, ed è una fonte ricorrente di "ho deployato ma non vedo le modifiche".

Requisiti pratici dell'hosting: HTTPS, latenza bassa verso i merchant, database persistente per sessioni e dati, e capacità di reggere i picchi di webhook (un import massivo del merchant genera migliaia di eventi).

---

## Built for Shopify e review

Per le app pubbliche sull'App Store esistono requisiti di qualità: performance, uso di Polaris e App Bridge, gestione dell'installazione, privacy, supporto. Rispettarli dà visibilità nell'App Store.

Non riguardano le custom app per un singolo merchant — ma buona parte sono comunque buone pratiche.

---

## Checklist prima del lancio

- [ ] Scope minimi e giustificati
- [ ] HMAC verificato su tutti i webhook
- [ ] Webhook GDPR implementati e testati
- [ ] `app/uninstalled` che pulisce davvero i dati
- [ ] Stati di billing testati end-to-end
- [ ] Sessioni persistite in database
- [ ] Gestione dei `userErrors` su ogni mutation
- [ ] Rate limit gestiti con backoff
- [ ] Nessun token o secret nei log
- [ ] Versione API dichiarata e piano di aggiornamento trimestrale
- [ ] Testato su dev store: installazione, reinstallazione, disinstallazione, scope mancanti
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Polaris, App Bridge e UI dell'app

> Verifica sempre com'è impostato il progetto: lo stack a web components è quello attuale, ma molte app in produzione usano ancora i componenti React di `@shopify/polaris`. Non mescolare i due modelli nello stesso progetto senza una ragione.

## Indice
- [Polaris web components](#polaris-web-components)
- [App Bridge](#app-bridge)
- [Componenti App Bridge fuori dall'iframe](#componenti-app-bridge-fuori-dalliframe)
- [Pattern di pagina](#pattern-di-pagina)
- [Extension UI](#extension-ui)
- [Errori ricorrenti](#errori-ricorrenti)

---

## Polaris web components

Standard Web Components: si usano come elementi HTML nativi, in qualunque framework.

```jsx
<s-page heading="Ordini da sincronizzare">
<s-section heading="In coda">
<s-paragraph>3 ordini in attesa di sincronizzazione.</s-paragraph>
</s-section>
</s-page>
```

- Caricamento da `cdn.shopify.com/shopifycloud/polaris.js` — sempre l'ultima versione
- Tipi TypeScript: `@shopify/polaris-types`, da tenere a `@latest` per restare allineati al CDN
- Sono inclusi nelle app scaffoldate con la CLI: non vanno aggiunti a mano

Puoi anche costruire UI custom con qualsiasi framework, ma pesa la scelta: i componenti Polaris danno accessibilità, coerenza con l'admin e conformità agli standard Built for Shopify senza lavoro aggiuntivo. Un'app che sembra estranea all'admin viene disinstallata prima.

Conseguenza pratica del CDN "sempre ultima versione": non hai un lockfile per la UI. Vale la pena verificare l'app dopo aggiornamenti importanti di Polaris, e tenere i tipi allineati per accorgersi dei cambiamenti in fase di build.

---

## App Bridge

La variabile globale `shopify` espone le API per parlare con l'admin. Nessuna configurazione di autenticazione: l'app gira già dentro una sessione autenticata.

Cose che si fanno con App Bridge:

- **Session token** per autenticare il proprio backend: `await shopify.idToken()`
- **Resource picker** per far selezionare prodotti, collezioni o varianti al merchant
- **Toast e modali** per il feedback
- **Navigazione e deep link** verso altre parti dell'admin
- **Direct API access** all'Admin GraphQL via `fetch('shopify:admin/api/graphql.json')`

Tipi TypeScript: `@shopify/app-bridge-types`, anche questo allineato a `@latest`.

---

## Componenti App Bridge fuori dall'iframe

Title bar e menu di navigazione vivono **fuori** dall'iframe dell'app, nell'admin vero e proprio:

```jsx
import {TitleBar, NavMenu} from '@shopify/app-bridge-react';

export default function App() {
return (
<>
<TitleBar title="Dettaglio prodotto" subtitle="SKU: ABC-123" />
<NavMenu>
<a href="/">Home</a>
<a href="/products">Prodotti</a>
<a href="/settings">Impostazioni</a>
</NavMenu>
</>
);
}
```

È ciò che fa sembrare l'app parte dell'admin invece di una pagina web incastrata dentro una cornice.

---

## Pattern di pagina

Shopify pubblica template per i pattern ricorrenti — landing page dell'app, pagina impostazioni, tabelle dati, empty state, flussi di setup — allineati agli standard **Built for Shopify**. Prima di progettare una schermata da zero, guarda se il pattern esiste già: risparmia lavoro e allinea l'app ai criteri di review.

Principi che valgono comunque:

- **Empty state con azione**, non una pagina vuota: il primo accesso è il momento in cui si perde il merchant
- **Impostazioni raggruppate** per intento, non per struttura del database
- **Feedback immediato** su ogni azione (toast), e stati di caricamento espliciti
- **Errori che dicono cosa fare**, non solo cosa è andato storto
- Linguaggio del merchant, non del sistema: "sincronizza ordini", non "esegui job di reconciliation"

---

## Extension UI

L'app può estendere altre superfici oltre ad App Home:

| Extension | Dove appare |
|---|---|
| **Admin action** | Azione contestuale su prodotti, ordini, clienti |
| **Admin block** | Riquadro dentro le pagine di dettaglio dell'admin |
| **Theme app extension** | Blocchi inseribili nella vetrina dal theme editor |
| **Checkout UI extension** | Elementi nel checkout (con vincoli di piano) |
| **Customer account extension** | Aree cliente |
| **Functions** | Logica di checkout — vedi skill `shopify-functions` |

La **theme app extension** merita attenzione particolare: è il modo corretto di aggiungere funzionalità a un tema senza modificarne i file. Il merchant inserisce il blocco dal theme editor, e l'aggiornamento del tema non cancella nulla. Se stai per proporre modifiche dirette a un tema per una funzionalità ricorrente, valuta prima questa strada.

---

## Errori ricorrenti

**Auth improvvisata.** Cookie negli iframe: funziona in locale, si rompe da un merchant. Session token, sempre.

**Token trattati come validi solo perché presenti.** La verifica va fatta lato server a ogni richiesta.

**Redirect che perdono i parametri.** L'app perde il contesto embedded e finisce in uno stato incoerente.

**UI custom dove bastava Polaris.** Costa tempo, peggiora l'accessibilità e complica la review.

**Provider annidati copiati da tutorial vecchi.** Se il progetto usa i web components, quel codice non serve e crea conflitti.

**Chiamate Admin API dal client senza direct API access.** O si abilita nella configurazione, o si passa dal backend: non ci sono scorciatoie.
Loading
Loading