Claude Code Plugins

Community-maintained marketplace

Feedback

data-architecture

@omerakben/omer-akben
1
0

Single source of truth patterns, facts.ts structure, type safety, and data helper functions. Use when working with project data or adding new facts.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name data-architecture
description Single source of truth patterns, facts.ts structure, type safety, and data helper functions. Use when working with project data or adding new facts.

Data Architecture Skill

Overview

This project uses a single source of truth pattern for all data. All personal information, project details, and configuration data is centralized in typed data files.

Core Principle: Single Source of Truth

Rule: Never hardcode personal data. Always reference data files.

// ❌ WRONG - Hardcoded data
const email = "me@omerakben.com";
const name = "Omer Akben";

// ✅ CORRECT - Reference data file
import { facts } from "@/data/facts";
const email = facts.contact.email;
const name = facts.personal.name;
```typescript

## Data File Structure

### Primary Data Files

```typescript
src/data/
├── facts.ts          # Personal info, skills, experience
├── projects.ts       # Project catalog with metadata
└── ...               # Other data files

src/config/
└── assistantFaq.ts   # FAQ and intent libraries
```typescript

## facts.ts Architecture

**Location:** `src/data/facts.ts`

### Structure Overview

```typescript
export const facts = {
  personal: {
    name: string;
    title: string;
    location: LocationInfo;
    bio: string;
    tagline: string;
  },

  contact: {
    email: string;
    phone: string;
    github: string;
    linkedin: string;
    calendly: string;
  },

  professional: {
    experience: Experience[];
    education: Education[];
    skills: Skill[];
    certifications: Certification[];
    workAuthorization: WorkAuthorization; // Added 2025-11-02
  },

  preferences: {
    timezone: string;
    availability: string;
  }
};
```typescript

### Type Definitions

```typescript
interface LocationInfo {
  city: string;
  state: string;
  country: string;
  timezone: string;
}

interface Experience {
  id: string;
  company: string;
  position: string;
  startDate: string;
  endDate: string | 'Present';
  description: string;
  technologies: string[];
  achievements: string[];
}

interface Skill {
  id: string;
  name: string;
  category: SkillCategory;
  level: SkillLevel;
  yearsOfExperience: number;
}

interface WorkAuthorization {
  status: string;
  officialTitle: string;
  sponsorshipRequired: boolean;
  employmentRestrictions: boolean;
  eligibleEmployers: string;
  proofDocument: string;
  summary: string;
}
```typescript

### Work Authorization Data

**Added:** November 2, 2025
**Location:** `facts.professional.workAuthorization`

```typescript
workAuthorization: {
  status: "U.S. Permanent Resident (Green Card)",
  officialTitle: "Lawful Permanent Resident (LPR)",
  sponsorshipRequired: false,
  employmentRestrictions: false,
  eligibleEmployers: "Any U.S. employer",
  proofDocument: "Form I-551 (Permanent Resident Card)",
  summary: "Authorized to work for any U.S. employer without restrictions or sponsorship requirements."
}
```typescript

**Usage:** AI agent references this when answering recruiter questions

## projects.ts Architecture

**Location:** `src/data/projects.ts`

### Structure

```typescript
export interface Project {
  id: string;
  slug: string;
  title: string;
  tagline: string;
  description: string;
  longDescription: string;
  technologies: Technology[];
  category: ProjectCategory;
  featured: boolean;
  showcase: boolean;
  liveUrl?: string;
  githubUrl?: string;
  imageUrl: string;
  metrics?: ProjectMetrics;
  testimonials?: Testimonial[];
}

export const projects: Project[] = [
  // Array of all projects
];
```typescript

### Helper Functions

```typescript
// Get projects by category
export function getProjectsByCategory(category: ProjectCategory): Project[] {
  return projects.filter(p => p.category === category);
}

// Get featured projects
export function getFeaturedProjects(): Project[] {
  return projects.filter(p => p.featured);
}

// Get project by slug
export function getProjectBySlug(slug: string): Project | undefined {
  return projects.find(p => p.slug === slug);
}

// Get all technologies used
export function getAllTechnologies(): Technology[] {
  const techSet = new Set<Technology>();
  projects.forEach(p => p.technologies.forEach(t => techSet.add(t)));
  return Array.from(techSet);
}
```typescript

### Usage Pattern

```typescript
import { projects, getFeaturedProjects, getProjectBySlug } from "@/data/projects";

// In component
const featured = getFeaturedProjects();
const project = getProjectBySlug(params.slug);
```typescript

## Type Safety Patterns

### 1. Const Assertions

```typescript
export const SKILL_CATEGORIES = [
  'Frontend',
  'Backend',
  'DevOps',
  'AI/ML',
] as const;

export type SkillCategory = typeof SKILL_CATEGORIES[number];
// Type is: 'Frontend' | 'Backend' | 'DevOps' | 'AI/ML'
```typescript

### Benefits

- Autocomplete in IDE
- Type checking
- Single source for both runtime and types

### 2. Branded Types

```typescript
type ProjectId = string & { readonly __brand: 'ProjectId' };
type UserId = string & { readonly __brand: 'UserId' };

// Prevents mixing up IDs
function getProject(id: ProjectId) { /* ... */ }
function getUser(id: UserId) { /* ... */ }

// TypeScript error: types are incompatible
const projectId: ProjectId = 'proj_123' as ProjectId;
const userId: UserId = 'user_456' as UserId;
getProject(userId); // ❌ Error!
```typescript

### 3. Discriminated Unions

```typescript
type Education =
  | { type: 'degree'; university: string; degree: string; major: string; }
  | { type: 'bootcamp'; program: string; completion: string; }
  | { type: 'certification'; name: string; issuer: string; };

function formatEducation(edu: Education): string {
  switch (edu.type) {
    case 'degree':
      return `${edu.degree} in ${edu.major} from ${edu.university}`;
    case 'bootcamp':
      return `${edu.program}`;
    case 'certification':
      return `${edu.name} by ${edu.issuer}`;
  }
}
```typescript

## Zod Validation Integration

### Schema Definitions

**Location:** `src/lib/agent-tools/schemas.ts`

```typescript
import { z } from 'zod';

export const ContactSchema = z.object({
  name: z.string().min(1),
  email: z.string().email(),
  company: z.string().optional(),
  message: z.string().min(10),
});

export type Contact = z.infer<typeof ContactSchema>;
```typescript

### Runtime Validation

```typescript
// API route handler
export async function POST(request: Request) {
  const body = await request.json();

  // Validate with Zod
  const result = ContactSchema.safeParse(body);

  if (!result.success) {
    return Response.json({
      success: false,
      error: result.error.format(),
    }, { status: 400 });
  }

  // Type-safe data access
  const { name, email, company, message } = result.data;
  // ...
}
```typescript

### Benefits of Zod

- Runtime validation
- Type inference from schemas
- Detailed error messages
- Parse, transform, and validate in one step

## AI Agent Data Integration

### Knowledge Base

**Location:** `src/lib/agent-knowledge-base.ts`

The AI agent consumes data from facts.ts:

```typescript
import { facts } from '@/data/facts';

export const agentKnowledgeBase = `
# Core Identity
Name: ${facts.personal.name}
Title: ${facts.personal.title}
Location: ${facts.personal.location.city}, ${facts.personal.location.state}

# Work Authorization
Status: ${facts.professional.workAuthorization.status}
Sponsorship Required: ${facts.professional.workAuthorization.sponsorshipRequired}

# Skills
${facts.professional.skills.map(s => `- ${s.name} (${s.level})`).join('\n')}

# Contact
Email: ${facts.contact.email}
LinkedIn: ${facts.contact.linkedin}
`;
```typescript

### Benefits

- Single source ensures consistency
- Updates to facts.ts automatically flow to AI
- No hardcoded data in agent prompts

### Tool Implementations

AI agent tools reference data files:

```typescript
// src/app/api/tools/get-contact/route.ts
import { facts } from '@/data/facts';

export async function POST() {
  return Response.json({
    success: true,
    data: {
      email: facts.contact.email,
      linkedin: facts.contact.linkedin,
      github: facts.contact.github,
      calendly: facts.contact.calendly,
    }
  });
}
```typescript

## Adding New Data

### Step 1: Update Type Definition

```typescript
// src/data/facts.ts
interface Facts {
  personal: PersonalInfo;
  contact: ContactInfo;
  professional: ProfessionalInfo;
  newSection: NewSectionType; // Add new section
}
```typescript

### Step 2: Add Data

```typescript
export const facts: Facts = {
  // ... existing data
  newSection: {
    field1: 'value1',
    field2: 'value2',
  }
};
```typescript

### Step 3: Update AI Knowledge Base

```typescript
// src/lib/agent-knowledge-base.ts
export const agentKnowledgeBase = `
...existing content...

# New Section
${facts.newSection.field1}
${facts.newSection.field2}
`;
```typescript

### Step 4: Add Tests

```typescript
// src/data/facts.test.ts
describe('facts.newSection', () => {
  it('should have required fields', () => {
    expect(facts.newSection.field1).toBeDefined();
    expect(facts.newSection.field2).toBeDefined();
  });
});
```typescript

## Data Validation Patterns

### 1. Email Validation

```typescript
import { z } from 'zod';

const EmailSchema = z.string()
  .email('Invalid email format')
  .toLowerCase()
  .trim();

// Usage
const email = EmailSchema.parse('USER@EXAMPLE.COM');
// Result: 'user@example.com'
```typescript

### 2. URL Validation

```typescript
const UrlSchema = z.string()
  .url('Invalid URL format')
  .refine(url => url.startsWith('https://'), {
    message: 'URL must use HTTPS'
  });
```typescript

### 3. Date Validation

```typescript
const DateSchema = z.string()
  .regex(/^\d{4}-\d{2}-\d{2}$/, 'Date must be YYYY-MM-DD')
  .refine(date => !isNaN(Date.parse(date)), {
    message: 'Invalid date'
  });
```typescript

### 4. Enum Validation

```typescript
const SkillLevelSchema = z.enum([
  'Beginner',
  'Intermediate',
  'Advanced',
  'Expert'
]);

type SkillLevel = z.infer<typeof SkillLevelSchema>;
```typescript

## Helper Function Patterns

### 1. Filter Helpers

```typescript
// Get items by property
export function getByCategory<T extends { category: string }>(
  items: T[],
  category: string
): T[] {
  return items.filter(item => item.category === category);
}

// Get items by multiple criteria
export function getByFilters<T>(
  items: T[],
  filters: Partial<T>
): T[] {
  return items.filter(item => {
    return Object.entries(filters).every(([key, value]) => {
      return item[key as keyof T] === value;
    });
  });
}
```typescript

### 2. Sort Helpers

```typescript
// Sort by date
export function sortByDate<T extends { date: string }>(
  items: T[],
  order: 'asc' | 'desc' = 'desc'
): T[] {
  return [...items].sort((a, b) => {
    const dateA = new Date(a.date).getTime();
    const dateB = new Date(b.date).getTime();
    return order === 'asc' ? dateA - dateB : dateB - dateA;
  });
}

// Sort by property
export function sortBy<T, K extends keyof T>(
  items: T[],
  key: K,
  order: 'asc' | 'desc' = 'asc'
): T[] {
  return [...items].sort((a, b) => {
    if (a[key] < b[key]) return order === 'asc' ? -1 : 1;
    if (a[key] > b[key]) return order === 'asc' ? 1 : -1;
    return 0;
  });
}
```typescript

### 3. Transform Helpers

```typescript
// Group by property
export function groupBy<T, K extends keyof T>(
  items: T[],
  key: K
): Record<string, T[]> {
  return items.reduce((acc, item) => {
    const groupKey = String(item[key]);
    if (!acc[groupKey]) acc[groupKey] = [];
    acc[groupKey].push(item);
    return acc;
  }, {} as Record<string, T[]>);
}

// Map to lookup object
export function toMap<T extends { id: string }>(
  items: T[]
): Record<string, T> {
  return items.reduce((acc, item) => {
    acc[item.id] = item;
    return acc;
  }, {} as Record<string, T>);
}
```typescript

## Testing Data Integrity

### Unit Tests

```typescript
// src/data/facts.test.ts
import { facts } from './facts';

describe('facts.ts data integrity', () => {
  it('should have valid email', () => {
    expect(facts.contact.email).toMatch(/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/);
  });

  it('should have all required skills', () => {
    expect(facts.professional.skills.length).toBeGreaterThan(0);
    facts.professional.skills.forEach(skill => {
      expect(skill.name).toBeTruthy();
      expect(skill.category).toBeTruthy();
      expect(skill.level).toBeTruthy();
    });
  });

  it('should have valid work authorization', () => {
    const { workAuthorization } = facts.professional;
    expect(workAuthorization.status).toBeTruthy();
    expect(typeof workAuthorization.sponsorshipRequired).toBe('boolean');
    expect(typeof workAuthorization.employmentRestrictions).toBe('boolean');
  });
});
```typescript

### Zod Schema Tests

```typescript
import { ContactSchema } from './schemas';

describe('ContactSchema validation', () => {
  it('should accept valid contact', () => {
    const valid = {
      name: 'John Doe',
      email: 'john@example.com',
      message: 'Hello, this is a test message.',
    };

    const result = ContactSchema.safeParse(valid);
    expect(result.success).toBe(true);
  });

  it('should reject invalid email', () => {
    const invalid = {
      name: 'John Doe',
      email: 'not-an-email',
      message: 'Hello, world',
    };

    const result = ContactSchema.safeParse(invalid);
    expect(result.success).toBe(false);
  });
});
```typescript

## Common Mistakes

### Mistake 1: Hardcoding Data

```typescript
// ❌ WRONG
function Header() {
  return <h1>Omer Akben - AI Engineer</h1>;
}

// ✅ CORRECT
import { facts } from '@/data/facts';

function Header() {
  return <h1>{facts.personal.name} - {facts.personal.title}</h1>;
}
```typescript

### Mistake 2: Inconsistent Data Format

```typescript
// ❌ WRONG - Different date formats
{
  startDate: '2024-01-01',
  endDate: 'January 2024',
}

// ✅ CORRECT - Consistent ISO format
{
  startDate: '2024-01-01',
  endDate: '2024-01-31',
}
```typescript

### Mistake 3: No Validation

```typescript
// ❌ WRONG - Assumes data is valid
const user = JSON.parse(request.body);
saveUser(user);

// ✅ CORRECT - Validate first
const result = UserSchema.safeParse(JSON.parse(request.body));
if (result.success) {
  saveUser(result.data);
}
```typescript

## Data Update Checklist

When adding or updating data:

- [ ] Update type definitions first
- [ ] Add/modify data in facts.ts or projects.ts
- [ ] Update AI knowledge base if needed
- [ ] Add helper functions if beneficial
- [ ] Write unit tests for new data
- [ ] Verify AI agent responses still accurate
- [ ] Check that related tools still work
- [ ] Update documentation if structure changed

## Quick Reference

```typescript
// Import data
import { facts } from '@/data/facts';
import { projects, getProjectBySlug } from '@/data/projects';

// Access data
const email = facts.contact.email;
const name = facts.personal.name;
const project = getProjectBySlug('portfolio');

// Validate with Zod
const result = Schema.safeParse(data);
if (result.success) {
  // Use result.data
}

// Helper pattern
export function getFiltered<T>(items: T[], predicate: (item: T) => boolean): T[] {
  return items.filter(predicate);
}
```typescript

## Related Files

- `src/data/facts.ts` - Single source of truth for personal data
- `src/data/projects.ts` - Project catalog with helpers
- `src/lib/agent-knowledge-base.ts` - AI agent data integration
- `src/lib/agent-tools/schemas.ts` - Zod validation schemas
- `src/config/assistantFaq.ts` - FAQ and intent libraries