Skip to main content

Shared Packages

reptidex’s simplified frontend architecture uses 2 core shared packages that promote code reuse, consistency, and maintainability across all 4 applications.

Package Architecture

Simplified Structure

packages/
├── @reptidex/ui/         # Complete design system and UI components
└── @reptidex/core/       # Business logic, utilities, and API layer

Package Management

  • Package Manager: pnpm with workspace support
  • Versioning: Semantic versioning with automated releases
  • Publishing: Internal registry with scoped packages
  • Dependencies: Shared dependencies hoisted to monorepo root
  • Build System: Turborepo for optimized builds and caching

Core Packages

@reptidex/ui

Purpose: Comprehensive design system and component library
Package Type: UI Components & Design System
Dependencies: Material UI, Tailwind CSS, React
Bundle Size: ~150KB gzipped
Applications: All 4 frontend applications
Key Components:

Base Components

  • Material UI theme customization
  • Button, Input, Card, Modal variants
  • Form components with validation
  • Loading states and skeletons
  • Navigation and layout components

reptidex Components

  • AnimalCard with lineage display
  • MorphBadge with genetics info
  • PedigreeTree visualization
  • BreedingPairCard components
  • MarketplaceListing cards

Charts & Visualizations

  • Growth tracking charts
  • Breeding calendar components
  • Sales analytics dashboards
  • Genetic probability calculators
  • Interactive pedigree trees

Design System

  • Consistent typography scale
  • reptidex brand color palette
  • Responsive breakpoint system
  • Dark/light theme support
  • Accessibility compliance (WCAG 2.1)
Component Example:
import { AnimalCard, MorphBadge, Button } from '@reptidex/ui';

export const AnimalListing = ({ animal }) => (
  <AnimalCard
    animal={animal}
    showPedigree
    actions={
      <>
        <MorphBadge morphs={animal.morphs} />
        <Button variant="primary" size="lg">
          View Details
        </Button>
      </>
    }
  />
);
Theme Configuration:
import { createTheme } from '@reptidex/ui/theme';

const theme = createTheme({
  palette: {
    primary: {
      main: '#2E7D32', 
      light: '#60AD5E',
      dark: '#1B5E20'
    },
    secondary: {
      main: '#8D6E63', 
      light: '#BCAAA4',
      dark: '#5D4037'
    }
  },
  typography: {
    fontFamily: 'Inter, system-ui, sans-serif',
    h1: { fontSize: '2.5rem', fontWeight: 600 },
    body1: { fontSize: '1rem', lineHeight: 1.6 }
  }
});

@reptidex/core

Purpose: Business logic, API integration, and shared utilities
Package Type: Business Logic & API Layer
Dependencies: React Query, Zod, date-fns
Bundle Size: ~80KB gzipped
Applications: All 4 frontend applications
Key Features:

API Integration

  • Type-safe API clients for all 6 services
  • React Query hooks with caching
  • Error handling and retry logic
  • Real-time subscriptions via WebSocket
  • Mock data for development

Business Logic

  • Genetic calculation utilities
  • Breeding program validation
  • Price calculation algorithms
  • Lineage tracking logic
  • Morph combination rules

Authentication

  • JWT token management
  • Role-based access control
  • Session handling utilities
  • Protected route components
  • Permission validation

Data Validation

  • Zod schemas for all data types
  • Form validation utilities
  • API response validation
  • Type-safe error handling
  • Input sanitization
API Client Example:
import { useAnimals, useBreeder, animalsAPI } from '@reptidex/core';

// React Query hook with caching
const AnimalsList = () => {
  const { data: animals, isLoading, error } = useAnimals({
    filters: { 
      species: 'python-regius',
      available: true,
      organization: user.organizationId
    },
    pagination: { page: 1, limit: 20 }
  });

  if (isLoading) return <AnimalsSkeleton />;
  if (error) return <ErrorMessage error={error} />;

  return (
    <div>
      {animals.data.map(animal => (
        <AnimalCard key={animal.id} animal={animal} />
      ))}
    </div>
  );
};

// Direct API access
const createAnimal = async (animalData: CreateAnimalRequest) => {
  try {
    const animal = await animalsAPI.create(animalData);
    return { success: true, data: animal };
  } catch (error) {
    return { success: false, error: error.message };
  }
};
Business Logic Example:
import { calculateGeneticProbability, validateBreedingPair } from '@reptidex/core';

// Genetic probability calculation
const BreedingCalculator = ({ sire, dam }) => {
  const probabilities = calculateGeneticProbability({
    sire: sire.genetics,
    dam: dam.genetics,
    targetMorphs: ['pied', 'banana']
  });

  return (
    <div>
      <h3>Expected Offspring</h3>
      {probabilities.map(prob => (
        <div key={prob.phenotype}>
          {prob.phenotype}: {prob.probability}% chance
        </div>
      ))}
    </div>
  );
};

// Breeding pair validation
const validatePair = validateBreedingPair(sire, dam);
if (!validatePair.valid) {
  console.error('Invalid breeding pair:', validatePair.errors);
}
Authentication Utilities:
import { useAuth, ProtectedRoute } from '@reptidex/core';

const BreederDashboard = () => {
  const { user, isAuthenticated, hasRole } = useAuth();
  
  if (!isAuthenticated) return <LoginForm />;
  if (!hasRole('breeder')) return <AccessDenied />;

  return <BreederWorkspace user={user} />;
};

// Protected route wrapper
export const BreederRoute = ({ children }) => (
  <ProtectedRoute requiredRoles={['breeder']}>
    {children}
  </ProtectedRoute>
);

Development Workflow

Package Development

# Install all dependencies
pnpm install

# Build both packages
pnpm build

# Run tests for all packages
pnpm test

# Develop specific package with hot reload
pnpm --filter @reptidex/ui dev
pnpm --filter @reptidex/core dev

# Add dependency to specific package
pnpm --filter @reptidex/ui add @mui/material
pnpm --filter @reptidex/core add react-query

Version Management

# Create changeset for version bump
pnpm changeset

# Version packages based on changesets
pnpm changeset version

# Publish packages to registry
pnpm changeset publish

# Check current versions
pnpm list --depth=0

Cross-Application Development

# Link packages for local development
pnpm --filter web-public add @reptidex/ui@workspace:*
pnpm --filter web-breeder add @reptidex/core@workspace:*

# Build packages and applications together
pnpm build --filter=@reptidex/ui --filter=web-public

# Run application with package watching
pnpm dev --parallel

Package Dependencies

Dependency Graph

External Dependencies

@reptidex/ui Dependencies:
  • @radix-ui/react-* ^1.0.0 - Headless UI primitives
  • class-variance-authority ^0.7.0 - CVA for component variants
  • clsx ^2.0.0 - Conditional className utility
  • tailwind-merge ^2.0.0 - Tailwind class merging
  • tailwindcss ^3.4.0 - Utility-first CSS framework
  • lucide-react ^0.400.0 - Icon library
@reptidex/core Dependencies:
  • @tanstack/react-query ^5.0.0 - Data fetching and caching
  • zustand ^4.4.0 - State management
  • zod ^3.22.0 - Schema validation
  • date-fns ^3.0.0 - Date manipulation utilities
  • axios ^1.6.0 - HTTP client

Peer Dependencies

Both packages require:
  • react ^18.2.0
  • react-dom ^18.2.0
  • typescript ^5.2.0

Build Configuration

Turborepo Configuration

{
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    },
    "test": {
      "dependsOn": ["build"],
      "outputs": ["coverage/**"]
    }
  }
}

TypeScript Configuration

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "declaration": true,
    "declarationMap": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "skipLibCheck": true,
    "jsx": "react-jsx"
  },
  "include": ["src/**/*"],
  "exclude": ["dist", "node_modules", "**/*.test.*"]
}

Package Export Configuration

{
  "name": "@reptidex/ui",
  "version": "1.0.0",
  "type": "module",
  "main": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/index.js",
      "types": "./dist/index.d.ts"
    },
    "./theme": {
      "import": "./dist/theme/index.js", 
      "types": "./dist/theme/index.d.ts"
    },
    "./components/*": {
      "import": "./dist/components/*/index.js",
      "types": "./dist/components/*/index.d.ts"
    }
  },
  "peerDependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  }
}

Testing Strategy

Unit Testing

// @reptidex/ui component testing
import { render, screen } from '@testing-library/react';
import { AnimalCard } from '../AnimalCard';
import { mockAnimal } from '../../__mocks__/animal';

describe('AnimalCard', () => {
  it('renders animal information correctly', () => {
    render(<AnimalCard animal={mockAnimal} />);
    
    expect(screen.getByText(mockAnimal.name)).toBeInTheDocument();
    expect(screen.getByText(mockAnimal.species)).toBeInTheDocument();
    expect(screen.getByRole('img', { name: /animal photo/i })).toBeInTheDocument();
  });

  it('displays morph badges when provided', () => {
    const animalWithMorphs = { ...mockAnimal, morphs: ['pied', 'banana'] };
    render(<AnimalCard animal={animalWithMorphs} />);
    
    expect(screen.getByText('pied')).toBeInTheDocument();
    expect(screen.getByText('banana')).toBeInTheDocument();
  });
});
// @reptidex/core business logic testing  
import { calculateGeneticProbability } from '../genetics';
import { mockSire, mockDam } from '../../__mocks__/animals';

describe('calculateGeneticProbability', () => {
  it('calculates correct probabilities for simple recessive', () => {
    const result = calculateGeneticProbability({
      sire: { pied: 'het' },
      dam: { pied: 'het' },
      targetMorphs: ['pied']
    });

    expect(result).toEqual([
      { phenotype: 'normal', probability: 75 },
      { phenotype: 'pied', probability: 25 }
    ]);
  });
});

Integration Testing

// Cross-package integration tests
import { render, screen, waitFor } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { AnimalsList } from '@reptidex/ui';
import { useAnimals } from '@reptidex/core';

const TestWrapper = ({ children }) => {
  const queryClient = new QueryClient({
    defaultOptions: { queries: { retry: false } }
  });
  
  return (
    <QueryClientProvider client={queryClient}>
      {children}
    </QueryClientProvider>
  );
};

describe('UI and Core Integration', () => {
  it('renders animals list with API data', async () => {
    render(
      <TestWrapper>
        <AnimalsList organizationId="test-org-123" />
      </TestWrapper>
    );

    await waitFor(() => {
      expect(screen.getByText('Loading animals...')).toBeInTheDocument();
    });

    await waitFor(() => {
      expect(screen.getByText('Test Ball Python')).toBeInTheDocument();
    });
  });
});

Performance Optimization

Bundle Optimization

  • Tree Shaking: Dead code elimination for both packages
  • Code Splitting: Lazy loading for heavy components
  • Bundle Analysis: Regular monitoring of package sizes
  • Peer Dependencies: Avoiding duplicate React/Material UI bundles

Build Performance

{
  "scripts": {
    "build": "turbo build --filter=@reptidex/ui --filter=@reptidex/core",
    "build:ui": "tsup src/index.ts --format esm,cjs --dts --clean",
    "build:core": "tsup src/index.ts --format esm,cjs --dts --clean",
    "dev": "turbo dev --parallel",
    "test": "turbo test --parallel"
  }
}

Runtime Performance

  • Component Memoization: React.memo for expensive components
  • Query Optimization: Efficient React Query cache management
  • Virtual Scrolling: Large lists in Animal browsing
  • Image Optimization: Lazy loading and WebP conversion

Documentation & Storybook

Interactive Documentation

// Storybook stories for @reptidex/ui
export default {
  title: 'Components/AnimalCard',
  component: AnimalCard,
  parameters: {
    docs: {
      description: {
        component: 'Displays animal information with optional pedigree and actions'
      }
    }
  }
};

export const Default = {
  args: {
    animal: mockAnimal,
    showPedigree: false,
    actions: <Button>View Details</Button>
  }
};

export const WithPedigree = {
  args: {
    animal: mockAnimalWithPedigree,
    showPedigree: true
  }
};

API Documentation

// Auto-generated TypeScript documentation
/**
 * Hook for fetching animals with filtering and pagination
 * @param options - Query options including filters and pagination
 * @returns React Query result with animals data
 */
export function useAnimals(options: UseAnimalsOptions): UseQueryResult<AnimalsResponse> {
  return useQuery({
    queryKey: ['animals', options],
    queryFn: () => animalsAPI.getAnimals(options),
    staleTime: 5 * 60 * 1000, // 5 minutes
    cacheTime: 10 * 60 * 1000 // 10 minutes
  });
}

Future Roadmap

Short-term Enhancements (Q1 2025)

  • Design Tokens: Centralized design system tokens for consistency
  • Advanced Animations: Sophisticated motion design for interactions
  • Mobile Optimization: Enhanced mobile component variants
  • Accessibility Audit: WCAG 2.1 AA compliance verification

Medium-term Goals (Q2-Q3 2025)

  • Micro Frontends: Module Federation for independent deployments
  • Native Components: React Native component library for mobile apps
  • GraphQL Integration: Type-safe GraphQL client and code generation
  • Advanced Caching: Sophisticated caching strategies with Redis

Long-term Vision (Q4 2025+)

  • Plugin Architecture: Extensible package system for third-party integrations
  • AI Components: AI-powered components for genetic predictions
  • Internationalization: Built-in i18n support for global expansion
  • Performance Monitoring: Runtime performance tracking and optimization

The simplified 2-package architecture provides all necessary functionality while maintaining clean separation of concerns and optimal performance across all reptidex applications.