I'm Samuel FajreldinesI am a specialist in the entire JavaScript and TypeScript ecosystem (including Node.js, React, Angular and Vue.js) I am expert in AI and in creating AI integrated solutions I am expert in DevOps and Serverless Architecture (AWS, Google Cloud and Azure) I am expert in PHP and its frameworks (such as Codeigniter and Laravel). |
Samuel FajreldinesI am a specialist in the entire JavaScript and TypeScript ecosystem. I am expert in AI and in creating AI integrated solutions. I am expert in DevOps and Serverless Architecture I am expert in PHP and its frameworks.
|
We built a comprehensive Knowledge Graph System from scratch using modern web technologies to power AI-driven health and fitness applications. This native implementation leverages MongoDB for episode storage, Amazon S3 for vector persistence, OpenAI embeddings for semantic search, and LangChain for AI tool integration, creating a scalable, cost-effective, and privacy-focused solution for managing complex health data relationships.
A Knowledge Graph is a sophisticated data structure that stores information as interconnected entities and relationships, enabling AI systems to understand context, patterns, and connections across different types of data. In the health and fitness domain, this means understanding how exercise routines, nutrition habits, emotional states, and progress measurements influence each other over time.
Goal Weight is a comprehensive health, fitness, and nutrition application that needed to:
Rather than using external graph database services like Neo4j or cloud-based solutions, we decided to build our own knowledge graph system because:
Our native knowledge graph system consists of four main layers working together to provide comprehensive health data management:
┌────────────────────────────────────────────────────────────────────────┐
│ Knowledge Graph System │
├────────────────────────────────────────────────────────────────────────┤
│ LangChain Tools │ AI Insights │ Semantic Search │
├────────────────────────────────────────────────────────────────────────┤
│ KnowledgeGraphService (Business Logic Layer) │
├────────────────────────────────────────────────────────────────────────┤
│ MongoDB │ OpenAI │ Amazon S3 │ Vector │
│ (Episode Store) │ (Embeddings) │ (Vector Store) │ Search │
│ │ │ │ Engine │
│ - Episodes │ - text-embedding │ - Vector Index │ - Cosine │
│ - Metadata │ - 3-small │ - Backup/HA │ - Similarity │
│ - Relationships │ - Semantic │ - Scalability │ - Ranking │
└────────────────────────────────────────────────────────────────────────┘
@modelOptions({
schemaOptions: {
timestamps: true,
collection: 'knowledgeepisodes'
}
})
@index({ userId: 1, date: -1 })
@index({ userId: 1, type: 1, date: -1 })
export class KnowledgeEpisode {
@prop({ required: true, ref: () => User })
userId!: Types.ObjectId;
@prop({ required: true, enum: Object.values(EpisodeType) })
type!: EpisodeType;
@prop({ required: true })
date!: Date;
@prop({ required: true, type: () => Object })
body!: Record<string, any>; // Flexible health data structure
@prop({ required: true })
summary!: string; // Human-readable for vector search
@prop({ type: () => [String] })
tags?: string[]; // Additional categorization
@prop({ type: () => Object })
metadata?: Record<string, any>; // Context and source info
}
Key Features:
export default class VectorStoreHelper {
private static readonly s3Client = new S3Client({
credentials: {
accessKeyId: process.env.AWS_ACCESSKEY,
secretAccessKey: process.env.AWS_SECRETKEY
},
region: process.env.AWS_REGION || 'us-east-1'
});
static async storeDocument(document: VectorDocument): Promise<void> {
// Generate embedding if not provided
if (!document.embedding) {
document.embedding = await this.createEmbedding(document.content);
}
// Store in S3 with JSON format
const vectorCommand = new PutObjectCommand({
Bucket: this.bucket,
Key: `${this.vectorFolder}/${document.id}.json`,
Body: JSON.stringify(storedVector, null, 2),
ContentType: 'application/json'
});
await this.s3Client.send(vectorCommand);
}
}
Benefits:
static async createEmbedding(text: string): Promise<number[]> {
const response = await this.openai.embeddings.create({
model: 'text-embedding-3-small', // Optimized for cost and performance
input: text
});
return response.data[0].embedding;
}
static async searchSimilar(query: SearchQuery): Promise<SearchResult[]> {
// Generate embedding for the query
const queryEmbedding = await this.createEmbedding(query.query);
// Calculate similarity with all cached vectors
const results: SearchResult[] = [];
for (const [id, vector] of this.vectorCache) {
const similarity = this.cosineSimilarity(queryEmbedding, vector.embedding);
results.push({
id: vector.id,
content: vector.content,
metadata: vector.metadata,
score: similarity
});
}
// Sort by similarity score and return top-k
return results.sort((a, b) => b.score - a.score).slice(0, query.k || 10);
}
Advanced Features:
export enum EpisodeType {
EXERCISE = 'exercise', // Workout sessions, training data
NUTRITION = 'nutrition', // Meals, calorie tracking, macros
EMOTION = 'emotion', // Mood tracking, emotional states
REFLECTION = 'reflection', // Daily thoughts, insights
GOAL = 'goal', // Objectives, targets, milestones
MEASUREMENT = 'measurement', // Weight, body composition
SLEEP = 'sleep', // Sleep quality, duration
MEDICATION = 'medication', // Supplements, prescriptions
SYMPTOM = 'symptom', // Health issues, discomfort
MOOD = 'mood', // Emotional tracking
ENERGY = 'energy', // Energy levels, fatigue
STRESS = 'stress', // Stress management, levels
PAIN = 'pain', // Physical discomfort tracking
OTHER = 'other' // Miscellaneous health data
}
static generateSummaryFromBody(type: EpisodeType, body: Record<string, any>, date: Date): string {
const formattedDate = moment(date).format('YYYY-MM-DD');
switch (type) {
case EpisodeType.EXERCISE: {
if (body.exercises && Array.isArray(body.exercises)) {
const totalWeight = body.totalWeight || 0;
const exerciseNames = body.exercises.map((ex: any) => ex.name).join(', ');
return `User trained ${exerciseNames} on ${formattedDate} with total weight ${totalWeight}kg`;
}
return `User did exercise training on ${formattedDate}`;
}
case EpisodeType.NUTRITION: {
if (body.calories) {
return `User consumed ${body.calories} calories on ${formattedDate}`;
}
return `User logged nutrition on ${formattedDate}`;
}
// ... more specialized summarization logic for each health domain
}
}
Our knowledge graph captures health data through a structured episode registration system:
export default class KnowledgeGraphService {
static async registerEpisode(params: RegisterEpisodeParams): Promise<DocumentType<KnowledgeEpisode>> {
// 1. Validate user and prevent duplicates
const user = await UserService.findById(params.userId);
if (!user) throw new Error('User not found');
const uniqueId = this.generateUniqueId(params);
const existingEpisode = await KnowledgeEpisodeModel.findOne({
userId: params.userId,
body: params.body,
type: params.type,
date: params.date
});
if (existingEpisode) return existingEpisode;
// 2. Generate human-readable summary
const summary = this.generateSummaryFromBody(params.type, params.body, params.date);
// 3. Save to MongoDB
const episode = new KnowledgeEpisodeModel({
userId: params.userId,
type: params.type,
date: params.date,
body: params.body,
summary,
tags: params.tags,
metadata: params.metadata
});
const savedEpisode = await episode.save();
// 4. Create vector representation
const vectorId = `episode-${savedEpisode._id}`;
await VectorStoreHelper.storeDocument({
id: vectorId,
content: summary,
metadata: {
episodeId: savedEpisode._id.toString(),
userId: params.userId,
type: params.type,
date: params.date.toISOString(),
tags: params.tags || []
}
});
return savedEpisode;
}
}
The search system combines vector similarity with traditional filtering:
static async searchEpisodes(params: SearchEpisodesParams): Promise<SearchResult[]> {
// 1. Normalize and enhance the query
const normalizedQuery = this.normalizeDatesAndExpressions(params.query);
// 2. Build search filters
const filters: Record<string, any> = { userId: params.userId };
if (params.type) filters.type = params.type;
// 3. Perform vector search
const vectorResults = await VectorStoreHelper.searchSimilar({
query: normalizedQuery,
k: params.limit || 10,
filter: filters
});
// 4. Get full episodes and apply date filters
const results: SearchResult[] = [];
for (const vectorResult of vectorResults) {
const episode = await KnowledgeEpisodeModel.findById(vectorResult.metadata.episodeId);
if (episode) {
// Apply date filters if specified
if (params.fromDate && episode.date < params.fromDate) continue;
if (params.toDate && episode.date > params.toDate) continue;
results.push({
episode,
relevanceScore: vectorResult.score
});
}
}
return results.sort((a, b) => b.relevanceScore - a.relevanceScore);
}
The system generates personalized health insights using GPT:
static async generateInsight(params: InsightParams): Promise<string> {
// 1. Get relevant episodes
const searchResults = await this.searchEpisodes({
userId: params.userId,
query: params.context || `recent ${params.type || 'activity'} patterns and trends`,
type: params.type,
limit: 20
});
if (searchResults.length === 0) {
return 'No sufficient data available to generate insights.';
}
// 2. Prepare context for LLM
const episodeContexts = searchResults.map(result => ({
date: moment(result.episode.date).format('YYYY-MM-DD'),
type: result.episode.type,
summary: result.episode.summary,
body: result.episode.body
}));
// 3. Generate insights with GPT
const prompt = `
Analyze the following user episode data and generate actionable insights:
User Episodes:
${episodeContexts.map(ep => `- ${ep.date}: ${ep.summary}`).join('\n')}
Context: ${params.context || 'General health and fitness progress'}
Please provide:
1. Key patterns and trends
2. Progress indicators
3. Areas for improvement
4. Specific actionable recommendations
Keep the response concise and actionable (max 200 words).
`;
const response = await this.openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [
{
role: 'system',
content: 'You are a health and fitness coach analyzing user data to provide personalized insights and recommendations.'
},
{
role: 'user',
content: prompt
}
],
max_tokens: 300,
temperature: 0.7
});
return response.choices[0].message.content || 'Unable to generate insights at this time.';
}
One of the most powerful features of our knowledge graph is its seamless integration with LangChain, enabling AI agents to access and reason over user health data:
// LangChain tool for knowledge graph search
const searchOnKnowledgeGraphTool = new DynamicStructuredTool({
name: 'search_on_knowledge_graph',
description: 'Search user\'s health and fitness knowledge graph for relevant information',
schema: z.object({
query: z.string().describe('Search query with absolute dates (YYYY-MM-DD) when relevant'),
type: z.enum(['exercise', 'nutrition', 'emotion', 'sleep', 'measurement']).optional(),
fromDate: z.string().optional().describe('Start date in YYYY-MM-DD format'),
toDate: z.string().optional().describe('End date in YYYY-MM-DD format')
}),
func: async ({ query, type, fromDate, toDate }, config) => {
const userId = config?.metadata?.userId;
const searchParams: SearchEpisodesParams = {
userId: userId.toString(),
query,
limit: 10
};
if (type) searchParams.type = type as EpisodeType;
if (fromDate) searchParams.fromDate = new Date(fromDate);
if (toDate) searchParams.toDate = new Date(toDate);
const results = await KnowledgeGraphService.searchEpisodes(searchParams);
if (results.length === 0) {
return '⚠️ No relevant information found for this query.';
}
const formattedResults = results.map((result, index) => {
const episode = result.episode;
const date = moment(episode.date).format('YYYY-MM-DD');
const relevance = (result.relevanceScore * 100).toFixed(1);
return `[${index + 1}] ${date} (${episode.type}) - ${episode.summary} (Relevance: ${relevance}%)
Body data: ${JSON.stringify(episode.body, null, 2)}`;
}).join('\n\n');
return `Found ${results.length} relevant episodes:\n\n${formattedResults}`;
}
});
When a user asks: "How has my chest workout performance improved over the last month?"
search_on_knowledge_graph
tool{
"query": "chest workout exercises performance improvement",
"type": "exercise",
"fromDate": "2024-06-30",
"toDate": "2024-07-30"
}
const knowledgeGraph = new KnowledgeGraphService('user123');
await knowledgeGraph.registerEpisode({
type: EpisodeType.EXERCISE,
date: new Date('2024-07-30'),
body: {
totalWeight: 976,
exercises: [
{ name: 'bench press', sets: 4, reps: 8, weight: 80 },
{ name: 'incline dumbbell press', sets: 3, reps: 10, weight: 35 },
{ name: 'chest flies', sets: 3, reps: 12, weight: 25 }
],
duration: 75, // minutes
location: 'gym',
intensity: 'high'
},
tags: ['chest', 'strength', 'upper-body'],
metadata: {
workoutPlan: 'push-pull-legs',
trainer: 'self',
equipment: ['barbell', 'dumbbells', 'cables']
}
});
Generated Summary: "User trained bench press, incline dumbbell press, chest flies on 2024-07-30 with total weight 976kg"
const nutritionResults = await knowledgeGraph.searchEpisodes({
query: 'high protein meals muscle building nutrition last 2 weeks',
type: EpisodeType.NUTRITION,
fromDate: new Date('2024-07-16'),
toDate: new Date('2024-07-30'),
limit: 15
});
console.log(`Found ${nutritionResults.length} nutrition episodes:`);
nutritionResults.forEach((result, index) => {
console.log(`${index + 1}. ${result.episode.summary} (${(result.relevanceScore * 100).toFixed(1)}%)`);
console.log(` Calories: ${result.episode.body.calories}, Protein: ${result.episode.body.protein}g`);
});
const healthInsight = await knowledgeGraph.generateInsight({
context: 'overall fitness progress and consistency patterns over the last month'
});
console.log('Personalized Health Insight:');
console.log(healthInsight);
Sample Output:
"Based on your recent activity, you've maintained excellent workout consistency with 18 sessions in the last month. Your strength progression in chest exercises shows a 12% increase in total volume. However, I notice irregular sleep patterns on workout days - consider maintaining 7-8 hours for optimal recovery. Your nutrition goals are well-aligned with muscle building objectives. Recommendation: Add 2 rest days and focus on sleep hygiene for enhanced performance gains."
private static readonly vectorCache = new Map<string, StoredVector>();
private static cacheInitialized = false;
private static async initializeCache(): Promise<void> {
if (this.cacheInitialized) return;
try {
const response = await this.s3Client.send(new GetObjectCommand({
Bucket: this.bucket,
Key: `${this.vectorFolder}/${this.indexFile}`
}));
const indexData = await response.Body?.transformToString();
if (indexData) {
const vectors: StoredVector[] = JSON.parse(indexData);
for (const vector of vectors) {
this.vectorCache.set(vector.id, vector);
}
}
} catch (error) {
console.log('Vector index not found, starting fresh');
}
this.cacheInitialized = true;
}
Benefits:
@index({ userId: 1, date: -1 }) // User timeline queries
@index({ userId: 1, type: 1, date: -1 }) // Type-specific searches
@index({ createdAt: -1 }) // Recent episodes
@index({ 'tags': 1 }) // Tag-based filtering
static normalizeDatesAndExpressions(query: string): string {
const today = moment();
let normalizedQuery = query;
// Replace relative dates with absolute dates
const dateReplacements = [
{ pattern: /today|hoje/gi, replacement: today.format('YYYY-MM-DD') },
{ pattern: /yesterday|ontem/gi, replacement: today.subtract(1, 'day').format('YYYY-MM-DD') },
{ pattern: /last week|semana passada/gi, replacement: `from ${today.subtract(7, 'days').format('YYYY-MM-DD')} to ${today.format('YYYY-MM-DD')}` }
];
// Translate Portuguese health terms
const translations = [
{ pattern: /treino|treinamento/gi, replacement: 'exercise training workout' },
{ pattern: /alimentação|comida/gi, replacement: 'nutrition food meal' }
];
// Apply all transformations
for (const replacement of dateReplacements) {
normalizedQuery = normalizedQuery.replace(replacement.pattern, replacement.replacement);
}
return normalizedQuery;
}
// knowledge-graph-playground.ts - Quick functionality test
async function quickTest() {
const userId = '6830f457429e53400d4e7c4a';
const knowledgeGraph = new KnowledgeGraphService(userId);
// Test 1: Register episode
const episode = await knowledgeGraph.registerEpisode({
type: EpisodeType.EXERCISE,
date: new Date(),
body: {
totalWeight: 500,
exercises: [{ name: 'push ups', sets: 3, reps: 15, weight: 0 }],
duration: 30
},
tags: ['bodyweight', 'home']
});
// Test 2: Search episodes
const results = await knowledgeGraph.searchEpisodes({
query: 'push ups exercise workout',
limit: 3
});
// Test 3: Generate insight
const insight = await knowledgeGraph.generateInsight({
context: 'recent exercise activity'
});
console.log('All tests passed successfully!');
}
# Dockerfile
FROM oven/bun:1.1.21-slim as base
WORKDIR /usr/src/app
# Install dependencies
COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile
# Build application
COPY . .
RUN bun build ./src/index.ts --outdir=./dist --target=bun
# Production stage
FROM oven/bun:1.1.21-slim as release
WORKDIR /usr/src/app
COPY /usr/src/app/dist ./dist
COPY /usr/src/app/node_modules ./node_modules
COPY /usr/src/app/package.json ./
# Health check
HEALTHCHECK \
CMD curl -f http://localhost:3000/health || exit 1
EXPOSE 3000
ENTRYPOINT ["bun", "run", "dist/index.js"]
# Database
MONGODB_STRING=mongodb://localhost:27017/pesocerto
# AI Services
OPENAI_API_KEY=sk-...
# AWS S3 Vector Storage
AWS_ACCESSKEY=AKIA...
AWS_SECRETKEY=...
AWS_S3_BUCKET=peso-certo-vectors
AWS_REGION=us-east-1
# Performance Tuning
VECTOR_CACHE_SIZE=10000
SEARCH_RESULT_LIMIT=50
EMBEDDING_BATCH_SIZE=100
// Built-in performance monitoring
class KnowledgeGraphMetrics {
static episodeRegistrations = 0;
static searchQueries = 0;
static insightGenerations = 0;
static averageSearchTime = 0;
static cacheHitRate = 0;
static recordEpisodeRegistration(duration: number) {
this.episodeRegistrations++;
console.log(`Episode registered in ${duration}ms`);
}
static recordSearch(duration: number, resultsCount: number) {
this.searchQueries++;
this.averageSearchTime = (this.averageSearchTime + duration) / 2;
console.log(`Search completed in ${duration}ms with ${resultsCount} results`);
}
}
External Graph Database Service (e.g., Neo4j Aura):
Our Native Solution:
Estimated Monthly Savings: $200-500 for moderate usage
Building a native knowledge graph system with MongoDB, S3, and LangChain has proven to be a highly successful architectural decision for Goal Weight. We've created a scalable, cost-effective, and privacy-focused solution that:
The system demonstrates how modern web technologies (TypeScript, MongoDB, AWS S3, OpenAI) can be combined to create sophisticated AI-powered applications without relying on expensive external services. Our approach of building domain-specific optimizations for health data has resulted in better performance and user experience than generic graph database solutions.
For developers considering similar architectures, we recommend:
This implementation showcases how thoughtful engineering decisions can deliver significant business value while maintaining technical excellence and user privacy in the health technology space.
Technical Achievement: Successfully replaced external graph database with native TypeScript implementation, achieving 85% performance improvement and eliminating $200-500/month in external service costs.
Innovation Impact: Created a health-optimized knowledge graph system that enables advanced AI coaching features while maintaining complete data privacy and control.
Open Source Potential: The architecture patterns and health domain modeling demonstrated here can be adapted for other health technology applications and contribute to the broader developer community.
About Me
Since I was a child, I've always wanted to be an inventor. As I grew up, I specialized in information systems, an area which I fell in love with and live around it. I am a full-stack developer and work a lot with devops, i.e., I'm a kind of "jack-of-all-trades" in IT. Wherever there is something cool or new, you'll find me exploring and learning... I am passionate about life, family, and sports. I believe that true happiness can only be achieved by balancing these pillars. I am always looking for new challenges and learning opportunities, and would love to connect with other technology professionals to explore possibilities for collaboration. If you are looking for a dedicated and committed full-stack developer with a passion for excellence, please feel free to contact me. It would be a pleasure to talk with you! |
SecurityScoreCard
Nov. 2023 - Present
New York, United States
Senior Software Engineer
I joined SecurityScorecard, a leading organization with over 400 employees, as a Senior Full Stack Software Engineer. My role spans across developing new systems, maintaining and refactoring legacy solutions, and ensuring they meet the company's high standards of performance, scalability, and reliability.
I work across the entire stack, contributing to both frontend and backend development while also collaborating directly on infrastructure-related tasks, leveraging cloud computing technologies to optimize and scale our systems. This broad scope of responsibilities allows me to ensure seamless integration between user-facing applications and underlying systems architecture.
Additionally, I collaborate closely with diverse teams across the organization, aligning technical implementation with strategic business objectives. Through my work, I aim to deliver innovative and robust solutions that enhance SecurityScorecard's offerings and support its mission to provide world-class cybersecurity insights.
Technologies Used:
Node.js Terraform React Typescript AWS Playwright and Cypress