agentsclimarketplace

Coding standards

Skill chawkitariq/fidely/.claude/skills/coding-standards

Standards de codage à appliquer sur tout code écrit ou modifié dans Fidely. Déclencher quand : écriture ou revue de TypeScript/Vue, création de composable (useDB, useClient), ajout de fonction dans utils/, revue de types (Card, ClientData, CardFormData), JSDoc manquant. Mots-clés : TypeScript strict, any, import type, JSDoc, @param, @returns, <script setup>, defineProps, defineEmits, computed, uuidv7, zod, eslint, interface Card, interface ClientData.From its SKILL.md

Install
npx -y skills add chawkitariq/fidely --skill coding-standards

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

10.5 KB, ~2.7k tokens by cl100k_base, as published. Nobody here has run it

Skill : Standards de codage Fidely

Ces règles s'appliquent à tout code écrit ou modifié, sans exception.

Ressources disponibles


1. TypeScript

  • strict: true activé via les configs auto-générées de Nuxt
  • Zéro any implicite ou explicite — typer toutes les interfaces
  • Exporter les interfaces depuis les composables qui les définissent :
    // app/composables/useDB.ts — interfaces réelles du projet
    export interface Card {
      id: string           // UUID v7
      title: string
      reward_points: number
      reward: string
      created_at: number   // timestamp ms
    }
    
    export interface ClientData {
      cards: Record<string, number>  // cardId → points
      last_seen: number              // timestamp ms
    }
    
  • Utiliser import type { ... } pour les imports de types seuls
  • Typer explicitement les retours de fonctions async :
    async function getAllCards(): Promise<Card[]> { ... }
    async function updatePoints(clientId: string, cardId: string, delta: number): Promise<number> { ... }
    async function addCard(data: Omit<Card, 'id' | 'created_at'>): Promise<Card> { ... }
    

2. ESLint & formatage

  • Pas de virgule finale (commaDangle: 'never')
  • Accolades style 1tbs (braceStyle: '1tbs')
  • Indentation 2 espaces (.editorconfig)
  • Pas de point-virgule superflu (defaults Nuxt ESLint)
  • Vérification obligatoire avant commit :
    pnpm lint       # 0 warning
    pnpm typecheck  # 0 erreur
    

3. Langue du code — anglais obligatoire

Tout le code est écrit en anglais, sans exception.

ÉlémentLangue
Noms de variables, fonctions, interfaces✅ Anglais
Commentaires inline (// ...)✅ Anglais
JSDoc (/** ... */)✅ Anglais
Messages d'erreur lancés par throw✅ Anglais
Textes UI affichés à l'utilisateur (labels, toasts, placeholders)🇫🇷 Français
// ❌ Ne pas faire
/** Retourne tous les points du client pour cette carte */
const current = client.cards[cardId] ?? 0 // points actuels

// ✅ Correct
/** Returns the client's current points for a given card. */
const current = client.cards[cardId] ?? 0 // current point balance

4. JSDoc — obligatoire

Toute fonction publique, composable, et interface exportée doit avoir un JSDoc. JSDoc rédigé en anglais (voir section 3).

Fonctions et composables

/**
 * Opens the `fidely` IndexedDB database (version 2) and returns the instance.
 * Creates the `cards`, `clients`, and `config` object stores if needed.
 * Result is cached — multiple calls return the same promise.
 *
 * @returns Promise resolved with the IDBDatabase instance
 */
async function openDB(): Promise<IDBDatabase> { ... }

/**
 * Adds or removes points for a client on a given card.
 * Implicitly creates the client if they don't exist yet.
 * Guarantees the balance never drops below 0 (Math.max).
 *
 * @param clientId - Client UUID (stored in IndexedDB config store)
 * @param cardId   - Loyalty card UUID
 * @param delta    - Points to add (positive) or remove (negative)
 * @returns New point balance for this client/card pair
 */
async function updatePoints(clientId: string, cardId: string, delta: number): Promise<number> { ... }

/**
 * Redeems a reward by deducting `rewardPoints` from the client's balance.
 * Preserves any surplus (e.g. 8 pts, threshold 6 → 2 pts remaining).
 *
 * @param clientId     - Client UUID
 * @param cardId       - Loyalty card UUID
 * @param rewardPoints - Points to deduct (= card.reward_points)
 * @returns Remaining balance after deduction
 * @throws Error 'Not enough points' if balance < rewardPoints
 */
async function consumeReward(clientId: string, cardId: string, rewardPoints: number): Promise<number> { ... }

Interfaces et types exportés

/**
 * Loyalty card created by a merchant.
 * Persisted in IndexedDB object store `cards` (keyPath: 'id').
 */
export interface Card {
  /** UUID v7 generated by uuidv7() */
  id: string
  /** Display name of the card (e.g. "Café du Coin") */
  title: string
  /** Number of points required to unlock the reward */
  reward_points: number
  /** Reward description (e.g. "1 café offert") */
  reward: string
  /** Creation timestamp in milliseconds */
  created_at: number
}

/**
 * Client loyalty data across all cards.
 * Persisted in IndexedDB object store `clients` (key = clientId UUID).
 */
export interface ClientData {
  /** Map of cardId → accumulated points */
  cards: Record<string, number>
  /** Last update timestamp in ms */
  last_seen: number
}

Composables

/**
 * Main composable for all Fidely IndexedDB operations.
 * Single entry point — never call `indexedDB` directly from a page or component.
 *
 * Object stores: `cards` (loyalty cards), `clients` (points per client),
 * `config` (app settings, including client_id).
 *
 * @example
 * const { getAllCards, addCard, updatePoints } = useDB()
 * const cards = await getAllCards()
 */
export function useDB() { ... }

/**
 * Manages the unique client identifier (stable UUID, generated once).
 * Stored in IndexedDB object store `config` under the key `client_id`.
 *
 * @example
 * const { getOrCreateClientId } = useClient()
 * const id = await getOrCreateClientId() // same value on every call
 */
export function useClient() { ... }

Règles JSDoc

ÉlémentJSDoc requis
Fonction exportée depuis un composable✅ Oui
Interface / type exporté✅ Oui
Composable lui-même (export function useXxx)✅ Oui
Fonction interne locale non exportée > 10 lignes✅ Oui
Fonction utilitaire dans utils/✅ Oui
Getter/computed trivial (computed(() => props.id))❌ Non
Handler inline évident (function closeModal())❌ Non

5. Structure d'un composable

/**
 * [Description du composable et de sa responsabilité]
 *
 * @example
 * const { items, loadItems } = useFeature()
 */
export function useFeature() {
  const items = ref<Item[]>([])

  /**
   * Charge les items depuis IndexedDB.
   * Ne fait rien côté serveur (SSR guard).
   */
  async function loadItems(): Promise<void> {
    if (import.meta.server) return   // guard SSR obligatoire si browser API
    // logique
  }

  return { items, loadItems }
}

Règles :

  • Nom : useXxx en camelCase — auto-importé par Nuxt
  • Exporter les interfaces utilisées par plusieurs fichiers depuis le composable
  • Guard SSR : if (import.meta.server) return avant tout appel à indexedDB, localStorage, document, window
  • Pas de side-effects au niveau module (pas de fetch ou indexedDB.open() au top-level)
  • useDB() est le seul point d'entrée pour IndexedDB

6. Structure d'un composant Vue

Ordre obligatoire dans <script setup lang="ts"> :

<script setup lang="ts">
// 1. imports de types uniquement
import type { Card } from '~/composables/useDB'

// 2. props — générics, jamais options object
const props = defineProps<{
  card: Card
  loading?: boolean
}>()

// 3. emits — tuple syntax
const emit = defineEmits<{
  saved: [card: Card]
  cancelled: []
}>()

// 4. composables Nuxt (auto-importés)
const toast = useToast()

// 5. state local
const isOpen = ref(false)

// 6. computed — jamais de logique dans le template
const label = computed(() => props.loading ? 'Chargement…' : 'Enregistrer')

// 7. fonctions (async avec try/catch + feedback toast)
async function handleSave(): Promise<void> {
  // logique
}
</script>

Règles :

  • <script setup lang="ts"> toujours en premier, avant <template>
  • Props optionnelles avec ? — valeur par défaut dans un computed ou ??
  • Jamais defineProps avec l'objet options (style Vue 2)
  • Jamais de logique conditionnelle complexe dans {{ }} — utiliser computed
  • Emits en camelCase côté émission, kebab-case dans le parent (@points-changed)

7. UUID — utiliser uuidv7 exclusivement

// app/utils/uuid.ts — helper du projet
import { uuidv7 } from 'uuidv7'

export function generateUUID(): string {
  return uuidv7()
}
// ❌ Ne pas utiliser crypto.randomUUID()
const id = crypto.randomUUID()

// ✅ Utiliser generateUUID() du projet
const { generateUUID } = await import('~/utils/uuid')
const id = generateUUID()

Pourquoi uuidv7 ? UUID v7 sont triés chronologiquement → meilleure indexation IndexedDB et débogage facilité.


8. Auto-imports Nuxt — ne jamais importer manuellement

// ❌ Inutile
import { ref, computed, onMounted } from 'vue'
import { useRoute, navigateTo } from '#app'

// ✅ Correct — juste utiliser directement
const route = useRoute()
const count = ref(0)

Auto-importés : ref, computed, reactive, watch, watchEffect, onMounted, onBeforeUnmount, useRoute, useRouter, navigateTo, useToast, useHead, useSeoMeta, et tous les composables/utils du dossier app/


9. Checklist avant de marquer une tâche ✅

pnpm typecheck   # 0 erreur TypeScript
pnpm lint        # 0 warning ESLint
pnpm vitest run  # 0 test en échec
[ ] Code et JSDoc rédigés en anglais (textes UI en français)
[ ] Aucun `any` explicite ou implicite
[ ] JSDoc présent sur toutes les fonctions/interfaces exportées
[ ] Guards SSR en place sur toutes les browser APIs
[ ] Retours de fonctions async explicitement typés
[ ] Ordre des blocs dans <script setup> respecté
[ ] Props/emits avec générics (pas options object)
[ ] Jamais de logique dans {{ }} — utiliser computed
[ ] uuidv7() utilisé via generateUUID() — pas crypto.randomUUID()

Confirmation en fin de tâche

Après application de ces standards, confirmer :

coding-standards appliqués

  • TypeScript : [0 any / types vérifiés]
  • JSDoc : [fonctions/interfaces documentées]
  • ESLint : [pnpm lint → 0 warning]
  • Structure Vue : [ordre des blocs respecté]

What ships with it: 2 files

9.4 KB alongside SKILL.md

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.