agentsclimarketplace

Algolia reference architecture

Skill jeremylongshore/claude-code-plugins-plus-skills/plugins/saas-packs/algolia-pack/skills/algolia-reference-architecture

425 plugins, 2,810 skills, 200 agents for Claude Code. Open-source marketplace at tonsofskills.com with the ccpi CLI package manager.

Install
npx -y skills add jeremylongshore/claude-code-plugins-plus-skills --skill algolia-reference-architecture

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

What its author says it does

Copied from the file, not written here

'Implement Algolia reference architecture: index design, multi-index strategy,

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

9.9 KB, as published. Nobody here has run it

Algolia Reference Architecture

Overview

Production-ready architecture for Algolia-powered search. Covers index design, data pipeline from source to Algolia, service layer patterns, and frontend integration.

Architecture Overview

┌──────────────────────────────────────────────────────────────┐
│                      Frontend                                 │
│  InstantSearch.js / React InstantSearch                       │
│  Uses: liteClient (search-only key)                          │
│  Sends: search-insights events (clicks, conversions)          │
└───────────────────────┬──────────────────────────────────────┘
                        │ Search + Events
                        ▼
┌──────────────────────────────────────────────────────────────┐
│                   Algolia Cloud                               │
│  ┌─────────┐  ┌──────────────┐  ┌─────────────┐             │
│  │ Search   │  │ Analytics    │  │ Recommend   │             │
│  │ Engine   │  │ + Insights   │  │ (ML-based)  │             │
│  └─────────┘  └──────────────┘  └─────────────┘             │
└───────────────────────▲──────────────────────────────────────┘
                        │ Indexing (admin key)
                        │
┌──────────────────────────────────────────────────────────────┐
│                    Backend Service                            │
│  ┌────────────┐  ┌──────────────┐  ┌─────────────────┐      │
│  │ Search     │  │ Indexing     │  │ Settings        │      │
│  │ Service    │  │ Pipeline     │  │ Manager         │      │
│  └────────────┘  └──────┬───────┘  └─────────────────┘      │
│                         │                                     │
│  ┌──────────────────────▼────────────────────────────┐       │
│  │              Source Database                        │       │
│  │  PostgreSQL / MongoDB / CMS / External API          │       │
│  └────────────────────────────────────────────────────┘       │
└──────────────────────────────────────────────────────────────┘

Project Structure

src/
├── algolia/
│   ├── client.ts           # Singleton client (see algolia-sdk-patterns)
│   ├── indices.ts          # Index name constants + environment prefixing
│   ├── settings/
│   │   ├── products.ts     # Products index settings
│   │   ├── articles.ts     # Articles index settings
│   │   └── apply.ts        # Script to apply all settings
│   └── transforms/
│       ├── product.ts      # DB record → Algolia record transformer
│       └── article.ts      # DB record → Algolia record transformer
├── services/
│   ├── search.ts           # Search service (wraps Algolia client)
│   └── indexing.ts         # Indexing pipeline (DB → transform → Algolia)
├── api/
│   ├── search.ts           # Search endpoint (returns Algolia results)
│   └── reindex.ts          # Admin endpoint to trigger reindex
└── jobs/
    └── sync-algolia.ts     # Cron job for periodic full sync

Index Design Patterns

Pattern 1: One Index Per Entity Type

// src/algolia/indices.ts
const ENV = process.env.NODE_ENV === 'production' ? '' : `${process.env.NODE_ENV}_`;

export const INDICES = {
  products:  `${ENV}products`,
  articles:  `${ENV}articles`,
  faq:       `${ENV}faq`,
  users:     `${ENV}users`,     // Internal search only (never expose to frontend)
} as const;

export type IndexName = typeof INDICES[keyof typeof INDICES];

Pattern 2: Record Transformer (Source → Algolia)

// src/algolia/transforms/product.ts
import type { Product } from '../db/types';

interface AlgoliaProduct {
  objectID: string;
  name: string;
  description: string;
  category: string;
  brand: string;
  price: number;
  rating: number;
  review_count: number;
  in_stock: boolean;
  image_url: string;
  _tags: string[];        // Algolia convention: filterable tags
}

export function transformProduct(product: Product): AlgoliaProduct {
  return {
    objectID: product.id,
    name: product.name,
    description: product.description?.substring(0, 5000) || '',  // Truncate
    category: product.category.name,
    brand: product.brand.name,
    price: product.price / 100,                  // Cents → dollars
    rating: product.avgRating,
    review_count: product.reviewCount,
    in_stock: product.inventory > 0,
    image_url: product.images[0]?.url || '',
    _tags: [
      product.category.slug,
      ...(product.isFeatured ? ['featured'] : []),
      ...(product.isNew ? ['new-arrival'] : []),
    ],
  };
}

Pattern 3: Settings as Code

// src/algolia/settings/products.ts
import type { IndexSettings } from 'algoliasearch';

export const productSettings: IndexSettings = {
  searchableAttributes: [
    'name',
    'brand',
    'category',
    'unordered(description)',
  ],
  attributesForFaceting: [
    'searchable(brand)',
    'category',
    'filterOnly(price)',
    'filterOnly(in_stock)',
    '_tags',
  ],
  customRanking: ['desc(review_count)', 'desc(rating)'],
  attributesToRetrieve: ['name', 'brand', 'price', 'image_url', 'category', 'rating'],
  attributesToHighlight: ['name', 'description'],
  attributesToSnippet: ['description:30'],
  unretrievableAttributes: ['_tags'],
  distinct: 1,
  attributeForDistinct: 'product_group_id',
  replicas: [
    'virtual(products_price_asc)',
    'virtual(products_price_desc)',
    'virtual(products_newest)',
  ],
};

// src/algolia/settings/apply.ts
import { getClient } from '../client';
import { INDICES } from '../indices';
import { productSettings } from './products';

async function applyAllSettings() {
  const client = getClient();
  await client.setSettings({ indexName: INDICES.products, indexSettings: productSettings });
  console.log('All Algolia settings applied');
}

Pattern 4: Search Service Layer

// src/services/search.ts
import { getClient } from '../algolia/client';
import { INDICES } from '../algolia/indices';
import { ApiError } from 'algoliasearch';

export class SearchService {
  private client = getClient();

  async searchProducts(params: {
    query: string;
    filters?: string;
    facetFilters?: string[][];
    page?: number;
    hitsPerPage?: number;
  }) {
    try {
      return await this.client.searchSingleIndex({
        indexName: INDICES.products,
        searchParams: {
          query: params.query,
          filters: params.filters,
          facetFilters: params.facetFilters,
          page: params.page ?? 0,
          hitsPerPage: params.hitsPerPage ?? 20,
          facets: ['category', 'brand'],
          clickAnalytics: true,
        },
      });
    } catch (error) {
      if (error instanceof ApiError && error.status === 404) {
        return { hits: [], nbHits: 0, nbPages: 0, page: 0 };
      }
      throw error;
    }
  }

  async federatedSearch(query: string) {
    const { results } = await this.client.search({
      requests: [
        { indexName: INDICES.products, query, hitsPerPage: 5 },
        { indexName: INDICES.articles, query, hitsPerPage: 3 },
        { indexName: INDICES.faq, query, hitsPerPage: 3 },
      ],
    });
    return results;
  }
}

Error Handling

IssueCauseSolution
Circular dependencyService imports client imports serviceUse lazy initialization
Config driftDashboard edits not in codeApply settings from code in CI
Transform errorsDB schema changeAdd validation in transformer
Index name typoHardcoded stringsUse INDICES constants

Resources

Next Steps

For multi-environment setup, see algolia-multi-env-setup.

Keep looking

Skills are one crate of 328,083. 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.