claude-code-arcane 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/README.md +5 -2
- package/agents/ecommerce/ecommerce-architect.md +60 -0
- package/agents/engineering/dotnet-engineer.md +78 -0
- package/docs/SKILLS-CATALOG.md +45 -3
- package/docs/USER-GUIDE.md +2 -2
- package/package.json +1 -1
- package/profiles/backend-dotnet.yaml +54 -0
- package/profiles/ecommerce.yaml +48 -0
- package/profiles/job-hunt.yaml +35 -0
- package/profiles/unity-design.yaml +1 -0
- package/profiles/unity-dev.yaml +1 -0
- package/rules/dotnet-code.md +64 -0
- package/skills/cart-checkout/SKILL.md +85 -0
- package/skills/cart-checkout/references/checkout-flow-spec.md +50 -0
- package/skills/cold-outreach/SKILL.md +65 -0
- package/skills/cold-outreach/references/recruiter-playbook.md +65 -0
- package/skills/commerce-analytics/SKILL.md +85 -0
- package/skills/commerce-analytics/references/ga4-ecommerce-events.md +63 -0
- package/skills/commerce-analytics/scripts/ga4_ecommerce_validate.py +134 -0
- package/skills/commerce-data-model/SKILL.md +84 -0
- package/skills/commerce-data-model/references/data-model-spec.md +79 -0
- package/skills/cover-letter/SKILL.md +66 -0
- package/skills/cv-ats-export/SKILL.md +64 -0
- package/skills/cv-ats-export/scripts/cv_export.py +306 -0
- package/skills/cv-tailor/SKILL.md +70 -0
- package/skills/cv-tailor/references/ats-keywords.md +46 -0
- package/skills/dotnet-architecture/SKILL.md +66 -0
- package/skills/dotnet-architecture/references/anti-patterns.md +12 -0
- package/skills/dotnet-architecture/references/checklist.md +19 -0
- package/skills/dotnet-architecture/references/patterns.md +118 -0
- package/skills/dotnet-architecture/references/project-structure.md +78 -0
- package/skills/dotnet-best-practices/SKILL.md +76 -0
- package/skills/dotnet-best-practices/references/api-design.md +75 -0
- package/skills/dotnet-best-practices/references/architecture.md +62 -0
- package/skills/dotnet-best-practices/references/async.md +62 -0
- package/skills/dotnet-best-practices/references/database.md +69 -0
- package/skills/dotnet-best-practices/references/dependency-injection.md +73 -0
- package/skills/dotnet-best-practices/references/devops.md +76 -0
- package/skills/dotnet-best-practices/references/error-handling.md +72 -0
- package/skills/dotnet-best-practices/references/performance.md +63 -0
- package/skills/dotnet-best-practices/references/security.md +73 -0
- package/skills/dotnet-best-practices/references/testing.md +76 -0
- package/skills/dotnet-scaffold/SKILL.md +99 -0
- package/skills/install-mcp/SKILL.md +107 -0
- package/skills/install-mcp/references/manual-setup.md +92 -0
- package/skills/interview-prep/SKILL.md +69 -0
- package/skills/interview-prep/references/star-framework.md +42 -0
- package/skills/inventory-stock/SKILL.md +86 -0
- package/skills/inventory-stock/scripts/restock_forecast.py +173 -0
- package/skills/job-hunt/SKILL.md +92 -0
- package/skills/job-hunt/references/templates/Aplicacion.md +48 -0
- package/skills/job-hunt/references/templates/CV Custom.md +53 -0
- package/skills/job-hunt/references/templates/Contacto.md +30 -0
- package/skills/job-hunt/references/templates/Dashboard.md +45 -0
- package/skills/job-hunt/references/templates/Empresa.md +36 -0
- package/skills/job-hunt/references/templates/Entrevista.md +44 -0
- package/skills/job-hunt/references/templates/Perfil.md +38 -0
- package/skills/job-search/SKILL.md +83 -0
- package/skills/job-search/references/scoring-rubric.md +43 -0
- package/skills/linkedin-optimize/SKILL.md +79 -0
- package/skills/master-profile/SKILL.md +69 -0
- package/skills/merchant-feed/SKILL.md +85 -0
- package/skills/merchant-feed/references/feed-attribute-map.md +47 -0
- package/skills/merchant-feed/scripts/feed_validate.py +140 -0
- package/skills/network-map/SKILL.md +61 -0
- package/skills/network-map/scripts/network_map.py +109 -0
- package/skills/order-lifecycle/SKILL.md +86 -0
- package/skills/order-lifecycle/references/order-state-machine.md +53 -0
- package/skills/payments-architecture/SKILL.md +80 -0
- package/skills/personal-brand/SKILL.md +54 -0
- package/skills/personal-brand/references/post-pillars.md +66 -0
- package/skills/portfolio-site/SKILL.md +59 -0
- package/skills/product-listing/SKILL.md +84 -0
- package/skills/promotions-discounts/SKILL.md +80 -0
- package/skills/shipping-tax/SKILL.md +85 -0
- package/skills/storefront-architecture/SKILL.md +80 -0
- package/skills/subscription-billing/SKILL.md +81 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Checkout Flow — Step-by-Step Spec
|
|
2
|
+
|
|
3
|
+
A platform-agnostic reference for a correct, conversion-optimized checkout. Adapt step granularity to your catalog (digital/low-SKU can collapse steps).
|
|
4
|
+
|
|
5
|
+
## Steps, Fields & Validation
|
|
6
|
+
|
|
7
|
+
| Step | Fields | Validation / behavior |
|
|
8
|
+
|------|--------|-----------------------|
|
|
9
|
+
| **Cart** | line items, qty, totals | Editable qty; re-price + re-check stock server-side on load |
|
|
10
|
+
| **Identity** | email (required), login/guest | Collect email first; offer guest checkout prominently |
|
|
11
|
+
| **Shipping address** | name, address, country, postal | Inline validation; address autocomplete if available |
|
|
12
|
+
| **Shipping method** | method options + rates | Recompute on address change; show ETA + cost |
|
|
13
|
+
| **Payment** | payment method | Tokenized/hosted fields; idempotency key generated here |
|
|
14
|
+
| **Review** | full summary | Final total incl. tax/shipping/discounts before pay button |
|
|
15
|
+
| **Confirmation** | order number | Show + email receipt; clear cart; fire `purchase` event |
|
|
16
|
+
|
|
17
|
+
## Server-Side Re-Validation (before charge)
|
|
18
|
+
Always recompute, never trust the client:
|
|
19
|
+
1. Item availability (reserve with TTL)
|
|
20
|
+
2. Prices (current catalog prices, not cart-stored)
|
|
21
|
+
3. Promotions (re-evaluate eligibility + caps)
|
|
22
|
+
4. Shipping + tax (against final address)
|
|
23
|
+
5. Final total → only then create the payment intent
|
|
24
|
+
|
|
25
|
+
## Error Handling
|
|
26
|
+
- Never clear entered fields on a validation error.
|
|
27
|
+
- Show errors inline next to the field, plus a summary.
|
|
28
|
+
- Payment decline → keep the order in a recoverable state; let the shopper retry without re-entering everything.
|
|
29
|
+
- Stock lost during checkout → tell the shopper exactly which line and offer alternatives.
|
|
30
|
+
|
|
31
|
+
## Address Validation
|
|
32
|
+
- Normalize country to ISO code; postal format per country.
|
|
33
|
+
- Soft-validate (suggest correction) rather than hard-block where possible.
|
|
34
|
+
|
|
35
|
+
## Abandoned-Cart Triggers
|
|
36
|
+
| Touch | Timing | Content |
|
|
37
|
+
|-------|--------|---------|
|
|
38
|
+
| 1 | ~1h | "You left these" + cart contents |
|
|
39
|
+
| 2 | ~24h | Objection handling, reviews, support offer |
|
|
40
|
+
| 3 | ~72h | Incentive (only if margin allows) |
|
|
41
|
+
|
|
42
|
+
Suppress all touches once `purchase` fires. Respect consent + frequency caps.
|
|
43
|
+
|
|
44
|
+
## Verdict: READY when
|
|
45
|
+
- [ ] Guest checkout works end-to-end
|
|
46
|
+
- [ ] Email captured before payment
|
|
47
|
+
- [ ] All totals recomputed server-side pre-charge
|
|
48
|
+
- [ ] Payment is idempotent (no double-charge on retry/double-click)
|
|
49
|
+
- [ ] Entered data survives validation errors
|
|
50
|
+
- [ ] `purchase` event fires once with transaction id
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cold-outreach
|
|
3
|
+
description: "Write cold LinkedIn/email messages from a job-seeker to recruiters, hiring managers and referrals — plus post-application follow-up sequences that get replies. For B2B sales outreach use cold-email instead. Triggers: mensaje en frio recruiter, escribirle a un reclutador, follow up postulacion, networking message, pedir referido, contactar hiring manager."
|
|
4
|
+
argument-hint: "[contact-note | recruiter + company]"
|
|
5
|
+
category: "career"
|
|
6
|
+
user-invocable: true
|
|
7
|
+
allowed-tools: Read, Glob, Grep, Write, Edit, WebFetch
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Cold Outreach — Job-seeker → Recruiter / Hiring Manager
|
|
11
|
+
|
|
12
|
+
Escribís mensajes en frío de un **candidato** a recruiters, hiring managers y referidos, y secuencias de **follow-up** post-aplicación que reciben respuesta. Esto NO es venta B2B (para eso está `/cold-email`) — el ángulo es conseguir una conversación o un referido, sin sonar a spam ni a desesperación.
|
|
13
|
+
|
|
14
|
+
## Cuándo usar cada variante
|
|
15
|
+
|
|
16
|
+
| Situación | Mensaje |
|
|
17
|
+
|-----------|---------|
|
|
18
|
+
| Recruiter posteó un rol | Mensaje corto con fit + interés explícito |
|
|
19
|
+
| Hiring manager / futuro lead | Mensaje de valor: qué resolvés que a su equipo le importa |
|
|
20
|
+
| Pedir un referido a alguien de la empresa | Cálido, bajo compromiso, fácil de decir que sí |
|
|
21
|
+
| Networking sin rol abierto | Curiosidad genuina + algo en común, sin pedir nada todavía |
|
|
22
|
+
| Follow-up post-aplicación | Recordatorio con valor, no "¿alguna novedad?" |
|
|
23
|
+
|
|
24
|
+
## Principios
|
|
25
|
+
|
|
26
|
+
- **Personalizá la primera línea.** Algo real de esa persona/empresa/rol. Si sirve para 100 personas, no sirve para ninguna.
|
|
27
|
+
- **Corto.** LinkedIn: 50–125 palabras. La connection note: <300 caracteres.
|
|
28
|
+
- **Una pregunta / un CTA.** Bajá la fricción de responder.
|
|
29
|
+
- **Vos resolvés algo para ellos**, no "estoy buscando trabajo, ¿me ayudás?". El foco es el valor que aportás al equipo.
|
|
30
|
+
- **Sin paredes de texto, sin CV adjunto en el primer toque** (salvo que lo pidan).
|
|
31
|
+
- **Respetá el "no".** Un follow-up, máximo dos. Nunca insistir agresivo.
|
|
32
|
+
|
|
33
|
+
## Estructura de un primer mensaje
|
|
34
|
+
|
|
35
|
+
1. **Gancho personal** (1 línea): por qué *a esta persona*.
|
|
36
|
+
2. **Quién sos + fit** (1–2 líneas): rol + el logro más relevante para ellos.
|
|
37
|
+
3. **CTA suave** (1 línea): ¿15 min para charlar? / ¿abierto a una intro? / dejé mi aplicación, encantado de dar contexto.
|
|
38
|
+
|
|
39
|
+
## Secuencia de follow-up post-aplicación
|
|
40
|
+
|
|
41
|
+
- **Día 0** — aplicación enviada (+ mensaje al recruiter/hiring manager si tenés el contacto).
|
|
42
|
+
- **Día 4–5** — follow-up 1: reafirmá interés + agregá *algo nuevo* (un proyecto relevante, una idea sobre su producto). No "¿novedades?".
|
|
43
|
+
- **Día 10–12** — follow-up 2 (último): breve, profesional, dejá la puerta abierta. Si no hay respuesta, cerrás el loop con dignidad.
|
|
44
|
+
|
|
45
|
+
Cada follow-up debe tener un **gancho propio** y leerse solo, sin depender de los anteriores.
|
|
46
|
+
|
|
47
|
+
## Proceso
|
|
48
|
+
|
|
49
|
+
1. Leer la nota de `05-Contactos/` (o crearla) y la de `04-Empresas/`.
|
|
50
|
+
2. Investigar a la persona (rol, equipo, algo reciente) — WebFetch del perfil público si hay URL.
|
|
51
|
+
3. Elegir variante + canal.
|
|
52
|
+
4. Draftear mensaje + 1 variante de apertura.
|
|
53
|
+
5. Registrar en `05-Contactos/` (historial de interacciones) y planificar el follow-up.
|
|
54
|
+
|
|
55
|
+
> Nota: Claude no accede a tu LinkedIn ni envía mensajes — redacta para que vos copies/pegues y registres la interacción.
|
|
56
|
+
|
|
57
|
+
## Idioma
|
|
58
|
+
|
|
59
|
+
Espejá el idioma de la persona/empresa. Inglés por default para roles internacionales.
|
|
60
|
+
|
|
61
|
+
Ver `references/recruiter-playbook.md` para plantillas por situación y la psicología de por qué responden.
|
|
62
|
+
|
|
63
|
+
## Handoff
|
|
64
|
+
|
|
65
|
+
Pedí aprobación (approval) antes de escribir en `05-Contactos/`. Cuando el mensaje está READY para copiar/pegar y el follow-up agendado, prepará la conversación con `/interview-prep` si hay respuesta.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Recruiter / Hiring Manager Playbook
|
|
2
|
+
|
|
3
|
+
Plantillas y psicología para outreach de candidato. Adaptá siempre la primera línea — las plantillas son esqueleto, no copy-paste.
|
|
4
|
+
|
|
5
|
+
## Por qué responden (y por qué no)
|
|
6
|
+
|
|
7
|
+
Responden cuando: el mensaje es corto, claro sobre el fit, fácil de responder, y se nota que es para *ellos*. No responden cuando: es genérico, largo, pide demasiado de entrada, o suena desesperado. El recruiter recibe decenas por día — el filtro es "¿esto me ahorra trabajo o me lo agrega?".
|
|
8
|
+
|
|
9
|
+
## Plantillas
|
|
10
|
+
|
|
11
|
+
### 1. Recruiter que posteó un rol
|
|
12
|
+
```
|
|
13
|
+
Hola {nombre}, vi que están buscando {rol} en {empresa}.
|
|
14
|
+
Soy {rol/seniority} con {logro relevante en 1 línea, con número}.
|
|
15
|
+
Me interesa especialmente {algo real del rol/empresa}.
|
|
16
|
+
¿Te sirve si te paso mi CV o coordinamos 15 min?
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### 2. Hiring manager / futuro lead (mensaje de valor)
|
|
20
|
+
```
|
|
21
|
+
Hola {nombre}, sigo {producto/equipo de la empresa} y me llamó {detalle específico}.
|
|
22
|
+
Vengo de {contexto}: {logro mapeado a lo que su equipo necesita}.
|
|
23
|
+
Apliqué a {rol}; si te viene bien, encantado de darte contexto en una charla corta.
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### 3. Pedir un referido (a alguien del equipo)
|
|
27
|
+
```
|
|
28
|
+
Hola {nombre}, vi que trabajás en {empresa} como {rol}.
|
|
29
|
+
Estoy aplicando a {rol} ahí y me encantaría tu perspectiva sobre el equipo.
|
|
30
|
+
Si te parece y te hace sentido, ¿estarías abierto a referirme? Sin problema si no.
|
|
31
|
+
Te dejo mi perfil para que veas si encaja: {link}.
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 4. Connection note (<300 chars)
|
|
35
|
+
```
|
|
36
|
+
Hola {nombre}, me interesa mucho {empresa/área}. Vengo de {1 cosa}.
|
|
37
|
+
Me encantaría conectar y, si surge, charlar sobre {rol/equipo}.
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 5. Follow-up 1 (día 4–5) — con valor nuevo
|
|
41
|
+
```
|
|
42
|
+
Hola {nombre}, te escribo para reafirmar mi interés en {rol}.
|
|
43
|
+
Sumo un dato: {proyecto/idea relevante para su producto}.
|
|
44
|
+
Quedo a disposición para lo que necesiten del proceso.
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 6. Follow-up 2 (día 10–12) — cierre digno
|
|
48
|
+
```
|
|
49
|
+
Hola {nombre}, entiendo que están con mucho.
|
|
50
|
+
Dejo la puerta abierta por si avanza {rol}; me encantaría sumar.
|
|
51
|
+
¡Gracias por el tiempo!
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Reglas de cadencia
|
|
55
|
+
|
|
56
|
+
- Máximo 2 follow-ups. Después, soltar.
|
|
57
|
+
- Cada follow-up agrega algo (no "¿novedades?").
|
|
58
|
+
- Espaciar 4–5 días. Nunca el mismo día ni días consecutivos.
|
|
59
|
+
- Registrar cada toque en la nota de `05-Contactos/`.
|
|
60
|
+
|
|
61
|
+
## Tono
|
|
62
|
+
|
|
63
|
+
- Cálido y profesional, nunca servil ni agresivo.
|
|
64
|
+
- Confiado: estás ofreciendo valor, no mendigando.
|
|
65
|
+
- Humano: escribí como hablás, sin jerga corporativa vacía.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: commerce-analytics
|
|
3
|
+
description: "Define and audit e-commerce analytics — conversion rate, AOV, CLV, cohort/funnel metrics, and the standard GA4 ecommerce event spec (view_item, add_to_cart, begin_checkout, purchase). Includes a dataLayer event validator. Triggers: defining commerce KPIs, instrumenting GA4 ecommerce events, auditing tracking."
|
|
4
|
+
argument-hint: "[kpis | events | audit]"
|
|
5
|
+
category: "ecommerce"
|
|
6
|
+
user-invocable: true
|
|
7
|
+
allowed-tools: Read, Glob, Grep, Bash
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Commerce Analytics
|
|
11
|
+
|
|
12
|
+
You cannot optimize what you mis-measure. Define the KPIs that actually move a store and instrument the standard ecommerce event spec correctly — platform-agnostic, with a validator for GA4 dataLayer events.
|
|
13
|
+
|
|
14
|
+
## Before Starting
|
|
15
|
+
|
|
16
|
+
Gather: current tracking (GA4/GTM/other), business model (one-time vs subscription), key conversion actions, and goal (define KPIs, design/instrument events, or audit existing tracking).
|
|
17
|
+
|
|
18
|
+
## How This Skill Works
|
|
19
|
+
|
|
20
|
+
| Mode | Trigger | Output |
|
|
21
|
+
|------|---------|--------|
|
|
22
|
+
| **KPIs** | `kpis` | KPI framework + dashboard spec |
|
|
23
|
+
| **Events** | `events` | Ecommerce event taxonomy + dataLayer spec |
|
|
24
|
+
| **Audit** | `audit` | Tracking gap + data-quality review |
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Phase 1 — Core KPIs
|
|
29
|
+
|
|
30
|
+
| Metric | Formula | Watch for |
|
|
31
|
+
|--------|---------|-----------|
|
|
32
|
+
| **Conversion rate** | orders / sessions | Segment by device/channel |
|
|
33
|
+
| **AOV** | revenue / orders | Moves with promos/bundles |
|
|
34
|
+
| **CLV** | avg order value × frequency × lifespan | The number that justifies CAC |
|
|
35
|
+
| **Cart abandonment** | 1 − (checkouts / carts) | Diagnoses checkout friction |
|
|
36
|
+
| **Repeat rate** | repeat customers / total | Retention health |
|
|
37
|
+
| **Sell-through** | units sold / units received | Feeds `inventory-stock` forecasts |
|
|
38
|
+
|
|
39
|
+
**Rule:** Pair every acquisition metric with a margin metric — revenue growth on negative contribution margin is a trap.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Phase 2 — The Ecommerce Event Spec
|
|
44
|
+
|
|
45
|
+
The standard GA4 ecommerce funnel events, each carrying `currency` + an `items[]` array:
|
|
46
|
+
|
|
47
|
+
`view_item_list → view_item → add_to_cart → begin_checkout → add_shipping_info → add_payment_info → purchase` (plus `remove_from_cart`, `refund`).
|
|
48
|
+
|
|
49
|
+
Each `items[]` entry: `item_id`, `item_name`, `price`, `quantity` (+ optional `item_brand`, `item_category`, `item_variant`). `purchase` also needs `transaction_id` and `value`.
|
|
50
|
+
|
|
51
|
+
Validate a captured dataLayer against this spec:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
python skills/commerce-analytics/scripts/ga4_ecommerce_validate.py # demo events
|
|
55
|
+
python skills/commerce-analytics/scripts/ga4_ecommerce_validate.py events.json
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
It reports PASS/FAIL per event with the missing required fields. For the full taxonomy and parameter reference, see [references/ga4-ecommerce-events.md](references/ga4-ecommerce-events.md).
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Phase 3 — Audit & Data Quality
|
|
63
|
+
|
|
64
|
+
Common faults: missing `transaction_id` (duplicate purchases), `value` excluding/including tax inconsistently, `items[]` absent on purchase, double-firing (GTM + hardcoded). Cross-check store revenue vs GA4 revenue — variance > 5% means a tracking bug.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Output Artifacts
|
|
69
|
+
|
|
70
|
+
| Request | Output |
|
|
71
|
+
|---------|--------|
|
|
72
|
+
| KPIs | KPI framework + dashboard layout |
|
|
73
|
+
| Events | Event taxonomy + dataLayer spec |
|
|
74
|
+
| Audit | Gap analysis + data-quality scorecard |
|
|
75
|
+
|
|
76
|
+
Commerce tracking is **COMPLIANT** when the full funnel fires with valid `items[]` and `currency`, `purchase` carries a unique `transaction_id`, revenue reconciles within 5%, and KPIs pair growth with margin.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Related Skills
|
|
81
|
+
|
|
82
|
+
- **analytics-tracking**: general GA4/GTM setup this builds on for SaaS-style funnels.
|
|
83
|
+
- **inventory-stock**: sell-through metrics feed restock forecasting.
|
|
84
|
+
- **commerce-data-model**: item taxonomy maps to `items[]` parameters.
|
|
85
|
+
- **ab-test-setup** / **campaign-analytics**: experimentation and campaign measurement.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# GA4 Ecommerce Event Taxonomy & Parameter Reference
|
|
2
|
+
|
|
3
|
+
The standard funnel. Fire these with a consistent `items[]` shape so reports, funnels, and audiences work. The `ga4_ecommerce_validate.py` script checks a captured dataLayer against this spec.
|
|
4
|
+
|
|
5
|
+
## The funnel
|
|
6
|
+
```
|
|
7
|
+
view_item_list → view_item → add_to_cart → view_cart → begin_checkout
|
|
8
|
+
→ add_shipping_info → add_payment_info → purchase
|
|
9
|
+
```
|
|
10
|
+
Plus: `select_item`, `remove_from_cart`, `refund`.
|
|
11
|
+
|
|
12
|
+
## Required parameters per event
|
|
13
|
+
| Event | Required (beyond items[]) |
|
|
14
|
+
|-------|---------------------------|
|
|
15
|
+
| view_item | currency |
|
|
16
|
+
| add_to_cart / remove_from_cart / view_cart | currency |
|
|
17
|
+
| begin_checkout | currency |
|
|
18
|
+
| add_shipping_info | currency |
|
|
19
|
+
| add_payment_info | currency |
|
|
20
|
+
| purchase | currency, value, transaction_id |
|
|
21
|
+
| refund | currency, transaction_id |
|
|
22
|
+
| view_item_list / select_item | (item_list_id / item_list_name recommended) |
|
|
23
|
+
|
|
24
|
+
## items[] object
|
|
25
|
+
| Field | Req? | Notes |
|
|
26
|
+
|-------|------|-------|
|
|
27
|
+
| item_id | yes | Map to SKU |
|
|
28
|
+
| item_name | yes | Product/variant name |
|
|
29
|
+
| price | recommended | Unit price (number) |
|
|
30
|
+
| quantity | recommended | Defaults to 1 |
|
|
31
|
+
| item_brand | optional | |
|
|
32
|
+
| item_category | optional | Up to item_category5 |
|
|
33
|
+
| item_variant | optional | e.g. "Red / M" |
|
|
34
|
+
| discount | optional | Per-unit discount |
|
|
35
|
+
| index | optional | Position in list |
|
|
36
|
+
|
|
37
|
+
## Worked example — purchase
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"event": "purchase",
|
|
41
|
+
"ecommerce": {
|
|
42
|
+
"currency": "USD",
|
|
43
|
+
"value": 42.00,
|
|
44
|
+
"transaction_id": "T-1001",
|
|
45
|
+
"tax": 3.50,
|
|
46
|
+
"shipping": 5.00,
|
|
47
|
+
"items": [
|
|
48
|
+
{ "item_id": "ACME-TEE-RED-M", "item_name": "Acme Cotton Tee",
|
|
49
|
+
"item_variant": "Red / M", "price": 21.00, "quantity": 2 }
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Common faults (audit checklist)
|
|
56
|
+
- [ ] `purchase` missing `transaction_id` → duplicate purchases on refresh
|
|
57
|
+
- [ ] `value` inconsistent about tax/shipping inclusion (pick one, document it)
|
|
58
|
+
- [ ] `items[]` absent or empty on funnel events
|
|
59
|
+
- [ ] Double-firing (GTM tag + hardcoded gtag)
|
|
60
|
+
- [ ] Currency missing → revenue not attributed
|
|
61
|
+
- [ ] Store revenue vs GA4 revenue variance > 5% → tracking bug
|
|
62
|
+
|
|
63
|
+
Verdict: **COMPLIANT** when the full funnel fires with valid `items[]` + `currency`, `purchase` has a unique `transaction_id`, and revenue reconciles within 5%.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ga4_ecommerce_validate.py — Validate a captured dataLayer against the GA4
|
|
3
|
+
standard ecommerce event spec.
|
|
4
|
+
|
|
5
|
+
Checks each event for: a known ecommerce event name, required top-level
|
|
6
|
+
parameters (currency/value/transaction_id where applicable), a non-empty
|
|
7
|
+
items[] array, and required per-item fields. No external dependencies.
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
python ga4_ecommerce_validate.py # built-in demo events
|
|
11
|
+
python ga4_ecommerce_validate.py events.json # your captured dataLayer
|
|
12
|
+
|
|
13
|
+
Input JSON: either a single event object or an array of event objects, each:
|
|
14
|
+
{"event": "purchase", "ecommerce": {"currency": "USD", "value": 42.0,
|
|
15
|
+
"transaction_id": "T123", "items": [{"item_id": "SKU1",
|
|
16
|
+
"item_name": "Tee", "price": 21.0, "quantity": 2}, ...]}}
|
|
17
|
+
|
|
18
|
+
Some setups put params at the top level instead of under "ecommerce"; both
|
|
19
|
+
shapes are accepted.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
import json
|
|
23
|
+
import sys
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# event name -> required top-level (ecommerce) params beyond items[]
|
|
27
|
+
EVENT_REQS = {
|
|
28
|
+
"view_item_list": [],
|
|
29
|
+
"view_item": ["currency"],
|
|
30
|
+
"select_item": [],
|
|
31
|
+
"add_to_cart": ["currency"],
|
|
32
|
+
"remove_from_cart": ["currency"],
|
|
33
|
+
"view_cart": ["currency"],
|
|
34
|
+
"begin_checkout": ["currency"],
|
|
35
|
+
"add_shipping_info": ["currency"],
|
|
36
|
+
"add_payment_info": ["currency"],
|
|
37
|
+
"purchase": ["currency", "value", "transaction_id"],
|
|
38
|
+
"refund": ["currency", "transaction_id"],
|
|
39
|
+
}
|
|
40
|
+
EVENTS_REQUIRING_ITEMS = set(EVENT_REQS) - {"refund"}
|
|
41
|
+
ITEM_REQUIRED = ["item_id", "item_name"] # GA4 needs id or name; we require both for quality
|
|
42
|
+
ITEM_RECOMMENDED = ["price", "quantity"]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
DEMO_EVENTS = [
|
|
46
|
+
{"event": "view_item", "ecommerce": {"currency": "USD",
|
|
47
|
+
"items": [{"item_id": "ACME-TEE", "item_name": "Acme Tee", "price": 21.0}]}},
|
|
48
|
+
{"event": "add_to_cart", "ecommerce": {"currency": "USD",
|
|
49
|
+
"items": [{"item_id": "ACME-TEE", "item_name": "Acme Tee", "price": 21.0, "quantity": 2}]}},
|
|
50
|
+
{"event": "purchase", "ecommerce": {"currency": "USD", "value": 42.0, "transaction_id": "T-1001",
|
|
51
|
+
"items": [{"item_id": "ACME-TEE", "item_name": "Acme Tee", "price": 21.0, "quantity": 2}]}},
|
|
52
|
+
# intentionally broken: missing transaction_id + value, item missing name
|
|
53
|
+
{"event": "purchase", "ecommerce": {"currency": "USD",
|
|
54
|
+
"items": [{"item_id": "ACME-MUG", "price": 9.0}]}},
|
|
55
|
+
{"event": "add_to_cart", "ecommerce": { # missing currency + empty items
|
|
56
|
+
"items": []}},
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def get_ecom(event):
|
|
61
|
+
"""Return the param dict — under 'ecommerce' or at the top level."""
|
|
62
|
+
if isinstance(event.get("ecommerce"), dict):
|
|
63
|
+
return event["ecommerce"]
|
|
64
|
+
return {k: v for k, v in event.items() if k != "event"}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def validate_event(event, idx):
|
|
68
|
+
errors = []
|
|
69
|
+
name = event.get("event")
|
|
70
|
+
if not name:
|
|
71
|
+
return [f"event[{idx}]: missing 'event' name"], None
|
|
72
|
+
if name not in EVENT_REQS:
|
|
73
|
+
return [f"event[{idx}] '{name}': not a recognized GA4 ecommerce event"], name
|
|
74
|
+
|
|
75
|
+
ecom = get_ecom(event)
|
|
76
|
+
|
|
77
|
+
for param in EVENT_REQS[name]:
|
|
78
|
+
if param not in ecom or ecom[param] in (None, ""):
|
|
79
|
+
errors.append(f"missing required param '{param}'")
|
|
80
|
+
|
|
81
|
+
if name in EVENTS_REQUIRING_ITEMS:
|
|
82
|
+
items = ecom.get("items")
|
|
83
|
+
if not isinstance(items, list) or not items:
|
|
84
|
+
errors.append("missing or empty 'items[]'")
|
|
85
|
+
else:
|
|
86
|
+
for i, it in enumerate(items):
|
|
87
|
+
missing = [f for f in ITEM_REQUIRED if not it.get(f)]
|
|
88
|
+
if missing:
|
|
89
|
+
errors.append(f"items[{i}]: missing {', '.join(missing)}")
|
|
90
|
+
rec_missing = [f for f in ITEM_RECOMMENDED if it.get(f) in (None, "")]
|
|
91
|
+
if rec_missing:
|
|
92
|
+
errors.append(f"items[{i}]: (recommended) missing {', '.join(rec_missing)}")
|
|
93
|
+
return errors, name
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def main():
|
|
97
|
+
if len(sys.argv) > 1:
|
|
98
|
+
path = sys.argv[1]
|
|
99
|
+
try:
|
|
100
|
+
with open(path, encoding="utf-8") as f:
|
|
101
|
+
data = json.load(f)
|
|
102
|
+
except (OSError, json.JSONDecodeError) as e:
|
|
103
|
+
print(f"[ERROR] cannot read {path}: {e}")
|
|
104
|
+
sys.exit(1)
|
|
105
|
+
else:
|
|
106
|
+
print("[INFO] No JSON given - using built-in demo events.\n")
|
|
107
|
+
data = DEMO_EVENTS
|
|
108
|
+
|
|
109
|
+
events = data if isinstance(data, list) else [data]
|
|
110
|
+
|
|
111
|
+
total_fail = 0
|
|
112
|
+
for idx, event in enumerate(events):
|
|
113
|
+
errors, name = validate_event(event, idx)
|
|
114
|
+
hard = [e for e in errors if "(recommended)" not in e]
|
|
115
|
+
if hard:
|
|
116
|
+
total_fail += 1
|
|
117
|
+
print(f"FAIL [{idx}] {name or '?'}")
|
|
118
|
+
for e in errors:
|
|
119
|
+
print(f" - {e}")
|
|
120
|
+
else:
|
|
121
|
+
warn = [e for e in errors if "(recommended)" in e]
|
|
122
|
+
print(f"PASS [{idx}] {name}")
|
|
123
|
+
for w in warn:
|
|
124
|
+
print(f" ~ {w}")
|
|
125
|
+
|
|
126
|
+
print()
|
|
127
|
+
passed = len(events) - total_fail
|
|
128
|
+
verdict = "COMPLIANT" if total_fail == 0 else "NON-COMPLIANT"
|
|
129
|
+
print(f"{verdict}: {passed}/{len(events)} events passed.")
|
|
130
|
+
sys.exit(0 if total_fail == 0 else 1)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
if __name__ == "__main__":
|
|
134
|
+
main()
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: commerce-data-model
|
|
3
|
+
description: "Design and audit the core e-commerce domain model — products, variants, SKUs, options, collections, attributes, taxonomy, faceted search and pagination. Language- and platform-agnostic. Triggers: modeling a catalog, reviewing an existing product schema, designing filtering/search."
|
|
4
|
+
argument-hint: "[model | audit | taxonomy]"
|
|
5
|
+
category: "ecommerce"
|
|
6
|
+
user-invocable: true
|
|
7
|
+
allowed-tools: Read, Glob, Grep, Write, Edit
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Commerce Data Model
|
|
11
|
+
|
|
12
|
+
Design the backbone of any storefront: a product catalog model that survives variants, bundles, localization, and faceted search — independent of language, framework, or database.
|
|
13
|
+
|
|
14
|
+
> **Note:** This skill may create or modify files in your project (a model spec or schema doc). It will ask before writing.
|
|
15
|
+
|
|
16
|
+
## Before Starting
|
|
17
|
+
|
|
18
|
+
Gather: business context (physical/digital/services, single vs multi-vendor, B2C/B2B), scale (SKU count, variant explosion, locales/currencies), and goal (model from scratch, audit an existing schema, or design taxonomy + filtering).
|
|
19
|
+
|
|
20
|
+
## How This Skill Works
|
|
21
|
+
|
|
22
|
+
| Mode | Trigger | Output |
|
|
23
|
+
|------|---------|--------|
|
|
24
|
+
| **Model** | `model` | Entity model spec: Product, Variant, SKU, Option, Collection, Attribute |
|
|
25
|
+
| **Audit** | `audit` | Gap analysis of an existing schema against commerce best practices |
|
|
26
|
+
| **Taxonomy** | `taxonomy` | Category tree, attribute schema, faceted-search and pagination design |
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Phase 1 — Core Entities
|
|
31
|
+
|
|
32
|
+
The canonical separation that prevents 90% of catalog pain:
|
|
33
|
+
|
|
34
|
+
| Entity | Is | Is NOT | Key fields |
|
|
35
|
+
|--------|----|--------|-----------|
|
|
36
|
+
| **Product** | The marketing/SEO unit ("Acme Tee") | A buyable thing | title, description, slug, status, brand |
|
|
37
|
+
| **Variant** | A buyable combination ("Tee / Red / M") | A category | option values, price, weight, barcode |
|
|
38
|
+
| **SKU** | The stock-keeping identifier | A variant's price | code, variant_id |
|
|
39
|
+
| **Option** | An axis of variation (Color, Size) | A value | name, position |
|
|
40
|
+
| **Collection** | A merchandising grouping | A taxonomy node | title, rules (manual/automatic) |
|
|
41
|
+
|
|
42
|
+
**Rule:** Price, inventory, and barcode live on the **Variant**, never the Product. A product with no options still has exactly one variant.
|
|
43
|
+
|
|
44
|
+
For the full field-level spec, identifiers (GTIN/MPN), bundles/kits, and digital vs physical modeling, see [references/data-model-spec.md](references/data-model-spec.md).
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Phase 2 — Attributes & Taxonomy
|
|
49
|
+
|
|
50
|
+
- **Taxonomy** (category tree): hierarchical, navigational, one primary path per product. Stable URLs.
|
|
51
|
+
- **Collections**: many-to-many merchandising overlays (manual or rule-based). A product lives in one category branch but many collections.
|
|
52
|
+
- **Attributes**: typed key-values (`material: cotton`, `sleeve: short`). Drive facets. Define a controlled vocabulary — free-text attributes break filtering.
|
|
53
|
+
|
|
54
|
+
**Attribute typing:** `text | enum | number | boolean | measurement`. Enums must reference a value list. Measurements carry a unit.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Phase 3 — Faceted Search & Pagination
|
|
59
|
+
|
|
60
|
+
- Facets come from `enum`/`boolean`/`measurement` attributes, not free text.
|
|
61
|
+
- Multi-select within a facet = OR; across facets = AND.
|
|
62
|
+
- Always show counts; never show zero-result facet values.
|
|
63
|
+
- **Pagination:** prefer cursor/keyset over offset for deep catalogs (offset degrades and double-counts under writes). Cap page size.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Output Artifacts
|
|
68
|
+
|
|
69
|
+
| Request | Output |
|
|
70
|
+
|---------|--------|
|
|
71
|
+
| Model from scratch | Entity spec + ER sketch + identifier strategy |
|
|
72
|
+
| Audit schema | Verdict per entity: COMPLIANT / CONCERNS, with fixes |
|
|
73
|
+
| Design taxonomy | Category tree + attribute schema + facet plan |
|
|
74
|
+
|
|
75
|
+
A schema is **COMPLIANT** when price/inventory sit on variants, every product has ≥1 variant, attributes are typed against vocabularies, and URLs are stable.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Related Skills
|
|
80
|
+
|
|
81
|
+
- **storefront-architecture**: consumes this model to design PLP/PDP pages. Next step after modeling.
|
|
82
|
+
- **merchant-feed**: maps these entities to Google/Meta feed attributes.
|
|
83
|
+
- **inventory-stock**: owns stock levels that hang off the SKU/variant.
|
|
84
|
+
- **order-lifecycle**: references variants as order line items.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Commerce Data Model — Field-Level Spec & Worked Example
|
|
2
|
+
|
|
3
|
+
A language- and database-agnostic reference for the core catalog entities. Use it as the template for a model spec.
|
|
4
|
+
|
|
5
|
+
## Entities & Fields
|
|
6
|
+
|
|
7
|
+
### Product (marketing/SEO unit)
|
|
8
|
+
| Field | Type | Notes |
|
|
9
|
+
|-------|------|-------|
|
|
10
|
+
| id | id | Internal key |
|
|
11
|
+
| title | text | Display name |
|
|
12
|
+
| slug | text | Stable URL segment, unique |
|
|
13
|
+
| description | rich text | Long copy |
|
|
14
|
+
| brand | text | Brand/manufacturer |
|
|
15
|
+
| status | enum | draft / active / archived |
|
|
16
|
+
| options | Option[] | Axes of variation (0..n) |
|
|
17
|
+
| variants | Variant[] | ≥1 always |
|
|
18
|
+
| collections | Collection[] | Many-to-many |
|
|
19
|
+
| primary_category | Category | One navigational path |
|
|
20
|
+
| attributes | Attribute[] | Typed key-values |
|
|
21
|
+
|
|
22
|
+
### Variant (buyable unit)
|
|
23
|
+
| Field | Type | Notes |
|
|
24
|
+
|-------|------|-------|
|
|
25
|
+
| id | id | |
|
|
26
|
+
| sku | text | Stock-keeping code, unique |
|
|
27
|
+
| option_values | map | e.g. {Color: Red, Size: M} |
|
|
28
|
+
| price | integer (minor units) | Never a float |
|
|
29
|
+
| compare_at_price | integer | For showing discounts |
|
|
30
|
+
| barcode | text | GTIN/UPC/EAN |
|
|
31
|
+
| weight / dimensions | number + unit | For shipping/carrier rates |
|
|
32
|
+
| requires_shipping | bool | False for digital |
|
|
33
|
+
|
|
34
|
+
### Option / Option Value
|
|
35
|
+
`Option { name, position }` → `OptionValue { option_id, value, position }`. Example: Option "Size" → values S, M, L.
|
|
36
|
+
|
|
37
|
+
### Collection (merchandising)
|
|
38
|
+
`Collection { title, slug, type: manual|automatic, rules? }`. Automatic collections select by attribute rules (e.g. `tag = summer`).
|
|
39
|
+
|
|
40
|
+
### Attribute (faceting)
|
|
41
|
+
`Attribute { key, type: text|enum|number|boolean|measurement, value, unit? }`. Enum attributes reference a controlled value list.
|
|
42
|
+
|
|
43
|
+
## Identifiers
|
|
44
|
+
- **SKU** — your internal stock identifier (required, unique).
|
|
45
|
+
- **GTIN** (UPC/EAN/ISBN) — global trade identifier; required for marketplaces/feeds where one exists.
|
|
46
|
+
- **MPN** — manufacturer part number; fallback when no GTIN.
|
|
47
|
+
|
|
48
|
+
## Bundles / Kits
|
|
49
|
+
Model as a Product whose variant references component variants with quantities. Decide inventory rule: track by components (decrement each) vs by kit (own stock).
|
|
50
|
+
|
|
51
|
+
## Worked Example — "Acme Tee"
|
|
52
|
+
|
|
53
|
+
```yaml
|
|
54
|
+
product:
|
|
55
|
+
title: "Acme Cotton Tee"
|
|
56
|
+
slug: "acme-cotton-tee"
|
|
57
|
+
brand: "Acme"
|
|
58
|
+
status: active
|
|
59
|
+
options:
|
|
60
|
+
- { name: Color, values: [Red, Blue] }
|
|
61
|
+
- { name: Size, values: [S, M, L] }
|
|
62
|
+
attributes:
|
|
63
|
+
- { key: material, type: enum, value: cotton }
|
|
64
|
+
- { key: sleeve, type: enum, value: short }
|
|
65
|
+
variants:
|
|
66
|
+
- sku: ACME-TEE-RED-M
|
|
67
|
+
option_values: { Color: Red, Size: M }
|
|
68
|
+
price: 2100 # 21.00 in minor units
|
|
69
|
+
barcode: "0123456789012"
|
|
70
|
+
weight: { value: 180, unit: g }
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Checklist (verdict: COMPLIANT when all true)
|
|
74
|
+
- [ ] Price + inventory + barcode live on the variant, not the product
|
|
75
|
+
- [ ] Every product has ≥1 variant (even with no options)
|
|
76
|
+
- [ ] Attributes are typed and enums reference a vocabulary
|
|
77
|
+
- [ ] Primary category is single; collections are many-to-many
|
|
78
|
+
- [ ] Money stored as integer minor units
|
|
79
|
+
- [ ] Slugs/URLs stable and unique
|