{"id":29023650,"url":"https://github.com/giveth/donation-agent-evaluator-service","last_synced_at":"2026-07-04T03:32:31.956Z","repository":{"id":298670191,"uuid":"988432787","full_name":"Giveth/donation-agent-evaluator-service","owner":"Giveth","description":null,"archived":false,"fork":false,"pushed_at":"2025-09-26T17:25:45.000Z","size":966,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-09-26T19:20:56.718Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Giveth.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-05-22T14:37:50.000Z","updated_at":"2025-09-26T17:25:48.000Z","dependencies_parsed_at":"2025-06-12T08:52:53.496Z","dependency_job_id":"c78be0e3-57f0-4d8a-b847-871f8529ca46","html_url":"https://github.com/Giveth/donation-agent-evaluator-service","commit_stats":null,"previous_names":["giveth/donation-agent-evaluator-service"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Giveth/donation-agent-evaluator-service","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Giveth%2Fdonation-agent-evaluator-service","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Giveth%2Fdonation-agent-evaluator-service/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Giveth%2Fdonation-agent-evaluator-service/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Giveth%2Fdonation-agent-evaluator-service/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Giveth","download_url":"https://codeload.github.com/Giveth/donation-agent-evaluator-service/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Giveth%2Fdonation-agent-evaluator-service/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35109210,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-04T02:00:05.987Z","response_time":113,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-26T03:36:57.839Z","updated_at":"2026-07-04T03:32:31.949Z","avatar_url":"https://github.com/Giveth.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Donation Agent Evaluator Service\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://giveth-brand-assets.s3.us-east-2.amazonaws.com/logos/giveth-logo-blue-text.png\" width=\"200\" alt=\"Giveth Logo\" /\u003e\n\u003c/p\u003e\n\nA NestJS-based microservice that evaluates charitable projects within \"Causes\" and assigns CauseScores (0-100) to determine fund distribution proportions for the Giveth platform.\n\n## Table of Contents\n\n- [Overview](#overview)\n- [Architecture](#architecture)\n- [API Endpoints](#api-endpoints)\n- [Database Schema](#database-schema)\n- [Scoring System](#scoring-system)\n- [Setup \u0026 Development](#setup--development)\n- [Background Services](#background-services)\n- [Integration Details](#integration-details)\n- [Monitoring \u0026 Health Checks](#monitoring--health-checks)\n- [Data Flow](#data-flow)\n- [Troubleshooting](#troubleshooting)\n\n## Overview\n\nThe Donation Agent Evaluator Service is a core component of Giveth's Causes feature. It provides:\n\n- **Objective Project Evaluation**: Uses multiple criteria to assess project quality and relevance\n- **Automated Fund Distribution**: Calculates scores that determine how donations are split among projects\n- **Social Media Integration**: Tracks project activity on Twitter and Farcaster\n- **LLM-Powered Assessment**: Uses Gemini 2.5 Flash for qualitative content evaluation\n- **Real-time Data Processing**: Maintains up-to-date project information through scheduled jobs\n\n### Key Features\n\n- 🎯 **Multi-criteria Scoring**: 8 weighted components totaling 100 points\n- 🤖 **AI-Powered Quality Assessment**: LLM evaluation of content quality and relevance\n- 📊 **Social Media Tracking**: Twitter and Farcaster activity monitoring\n- ⚡ **Asynchronous Processing**: Job-based evaluation system for scalability\n- 📈 **Comprehensive Monitoring**: Health checks and detailed logging\n- 🔄 **Automated Data Sync**: Regular project and social media data updates\n\n## Architecture\n\n### Core Modules\n\n```\n📦 Donation Agent Evaluator Service\n├── 🎯 EvaluationModule          # API endpoints and job orchestration\n├── 📊 DataFetchingModule        # Giveth backend integration\n├── 📱 SocialMediaModule         # Twitter/Farcaster data fetching\n├── 🤖 LLMIntegrationModule      # OpenRouter/Gemini integration\n├── ⚖️  ScoringModule            # Score calculation engine\n├── 💾 SocialMediaStorageModule  # Database entities and services\n├── ⏰ ScheduledJobsModule       # Background job processing\n└── 🏥 HealthModule              # Health checks and monitoring\n```\n\n### Technology Stack\n\n- **Framework**: NestJS (Node.js)\n- **Database**: PostgreSQL with TypeORM\n- **Cache**: NestJS Cache Manager\n- **Social Media**: Twitter Scraper, Farcaster APIs\n- **LLM**: OpenRouter API (Gemini 2.5 Flash)\n- **Queue**: Built-in job processing system\n- **Container**: Docker with multi-stage builds\n\n## API Endpoints\n\n### Core Evaluation Endpoints\n\n#### `POST /evaluate/cause`\n\nQueues evaluation of projects within a single cause.\n\n**Headers Required:**\n\n- `Content-Type: application/json`\n\n**Request Body (required):**\n\n```json\n{\n  \"cause\": {\n    \"id\": 123,\n    \"title\": \"Environmental Conservation\",\n    \"description\": \"Projects focused on environmental protection\",\n    \"categories\": [\n      {\n        \"category_name\": \"Climate Action\",\n        \"category_description\": \"Fighting climate change\",\n        \"maincategory_title\": \"Environment\",\n        \"maincategory_description\": \"Environmental initiatives\"\n      }\n    ]\n  },\n  \"projectIds\": [456, 789, 101112]\n}\n```\n\n**Field Requirements:**\n\n- `cause.id` (number, required): Cause ID\n- `cause.title` (string, required): Cause title\n- `cause.description` (string, required): Cause description\n- `cause.categories` (array, optional): Array of category objects\n  - `category_name` (string, required): Category name\n  - `category_description` (string, required): Category description\n  - `maincategory_title` (string, required): Main category title\n  - `maincategory_description` (string, required): Main category description\n- `projectIds` (number[], required): Array of project IDs to evaluate\n\n**Response:**\n\n```json\n{\n  \"jobId\": \"uuid-job-id\",\n  \"estimatedDuration\": \"2-3 minutes\"\n}\n```\n\n**Sample cURL Request:**\n\n```bash\ncurl -X POST https://staging.eval.ads.giveth.io/evaluate/cause \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"cause\": {\n      \"id\": 123,\n      \"title\": \"Environmental Conservation\",\n      \"description\": \"Projects focused on environmental protection\",\n      \"categories\": [\n        {\n          \"category_name\": \"Climate Action\",\n          \"category_description\": \"Fighting climate change\",\n          \"maincategory_title\": \"Environment\",\n          \"maincategory_description\": \"Environmental initiatives\"\n        }\n      ]\n    },\n    \"projectIds\": [456, 789, 101112]\n  }'\n```\n\n#### `POST /evaluate/causes`\n\nQueues evaluation of multiple causes in batch.\n\n**Headers Required:**\n\n- `Content-Type: application/json`\n\n**Request Body (required):**\n\n```json\n{\n  \"causes\": [\n    {\n      \"cause\": {\n        \"id\": 123,\n        \"title\": \"Environmental Conservation\",\n        \"description\": \"Projects focused on environmental protection\",\n        \"categories\": [\n          {\n            \"category_name\": \"Climate Action\",\n            \"category_description\": \"Fighting climate change\",\n            \"maincategory_title\": \"Environment\",\n            \"maincategory_description\": \"Environmental initiatives\"\n          }\n        ]\n      },\n      \"projectIds\": [456, 789]\n    },\n    {\n      \"cause\": {\n        \"id\": 124,\n        \"title\": \"Education Access\",\n        \"description\": \"Improving access to quality education\",\n        \"categories\": [\n          {\n            \"category_name\": \"Primary Education\",\n            \"category_description\": \"Elementary education access\",\n            \"maincategory_title\": \"Education\",\n            \"maincategory_description\": \"Educational development\"\n          }\n        ]\n      },\n      \"projectIds\": [101112, 131415]\n    }\n  ]\n}\n```\n\n**Field Requirements:**\n\n- `causes` (array, required): Array of cause evaluation requests\n- Each cause object follows the same structure as single cause evaluation:\n  - `cause.id` (number, required): Cause ID\n  - `cause.title` (string, required): Cause title\n  - `cause.description` (string, required): Cause description\n  - `cause.categories` (array, optional): Array of category objects with required fields\n  - `projectIds` (number[], required): Array of project IDs to evaluate\n\n**Sample cURL Request:**\n\n```bash\ncurl -X POST https://staging.eval.ads.giveth.io/evaluate/causes \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"causes\": [\n      {\n        \"cause\": {\n          \"id\": 123,\n          \"title\": \"Environmental Conservation\",\n          \"description\": \"Projects focused on environmental protection\",\n          \"categories\": [\n            {\n              \"category_name\": \"Climate Action\",\n              \"category_description\": \"Fighting climate change\",\n              \"maincategory_title\": \"Environment\",\n              \"maincategory_description\": \"Environmental initiatives\"\n            }\n          ]\n        },\n        \"projectIds\": [456, 789]\n      },\n      {\n        \"cause\": {\n          \"id\": 124,\n          \"title\": \"Education Access\",\n          \"description\": \"Improving access to quality education\"\n        },\n        \"projectIds\": [101112, 131415]\n      }\n    ]\n  }'\n```\n\n#### `GET /evaluate/jobs/:jobId`\n\nGets the status and results of an evaluation job.\n\n**Path Parameters:**\n\n- `jobId` (string, required): The UUID of the evaluation job\n\n**Response:**\n\n```json\n{\n  \"status\": \"completed\",\n  \"progress\": 100,\n  \"result\": {\n    \"cause\": {\n      \"id\": 123,\n      \"title\": \"Environmental Conservation\",\n      \"totalProjects\": 3,\n      \"averageScore\": 67.5\n    },\n    \"projects\": [\n      {\n        \"projectId\": 456,\n        \"title\": \"Ocean Cleanup Initiative\",\n        \"causeScore\": 85.2,\n        \"scoreBreakdown\": {\n          \"projectInfoQuality\": 8.5,\n          \"updateRecency\": 4.2,\n          \"socialMediaQuality\": 7.8,\n          \"socialMediaRecency\": 3.1,\n          \"socialMediaFrequency\": 4.5,\n          \"relevanceToCause\": 22.1,\n          \"evidenceOfImpact\": 20.5,\n          \"givPowerRank\": 14.5\n        }\n      }\n    ]\n  }\n}\n```\n\n**Status Values:**\n\n- `pending`: Job is queued but not started\n- `processing`: Job is currently running\n- `completed`: Job finished successfully\n- `failed`: Job encountered an error\n\n**Sample cURL Request:**\n\n```bash\ncurl https://staging.eval.ads.giveth.io/evaluate/jobs/550e8400-e29b-41d4-a716-446655440000\n```\n\n#### `GET /evaluate/evaluation-detailed`\n\nReturns detailed evaluation reports from CSV data.\n\n**Query Parameters:**\n\n- `causeIds` (optional): Comma-separated cause IDs to filter results (e.g., `?causeIds=123,124,125`)\n\n**Sample cURL Requests:**\n\n```bash\n# Get all evaluation data\ncurl https://staging.eval.ads.giveth.io/evaluate/evaluation-detailed\n\n# Get data for specific causes\ncurl \"https://staging.eval.ads.giveth.io/evaluate/evaluation-detailed?causeIds=123,124,125\"\n```\n\n### Admin Operations Endpoints\n\n#### `POST /admin/sync-projects`\n\nManually trigger project synchronization from Giveth backend.\n\n**Headers Required:**\n\n- None (no request body needed)\n\n**Response:**\n\n```json\n{\n  \"success\": true,\n  \"message\": \"Successfully synchronized 847 projects from 23 causes\",\n  \"data\": {\n    \"projectsProcessed\": 847,\n    \"causesProcessed\": 23,\n    \"processingTimeMs\": 45623,\n    \"errors\": 0,\n    \"correlationId\": \"uuid-correlation-id\"\n  },\n  \"timestamp\": \"2025-01-31T10:30:00Z\"\n}\n```\n\n**Sample cURL Request:**\n\n```bash\ncurl -X POST https://staging.eval.ads.giveth.io/admin/sync-projects\n```\n\n#### `POST /admin/fetch/:projectId`\n\nForce social media data fetch for a specific project.\n\n**Path Parameters:**\n\n- `projectId` (string, required): The project ID to fetch data for\n\n**Response:**\n\n```json\n{\n  \"success\": true,\n  \"message\": \"Successfully fetched social media data for project project-123\",\n  \"data\": {\n    \"projectId\": \"project-123\",\n    \"twitterFetch\": {\n      \"attempted\": true,\n      \"success\": true,\n      \"postsFound\": 15\n    },\n    \"farcasterFetch\": {\n      \"attempted\": true,\n      \"success\": true,\n      \"postsFound\": 8\n    },\n    \"correlationId\": \"uuid-correlation-id\"\n  },\n  \"timestamp\": \"2025-01-31T10:30:00Z\"\n}\n```\n\n**Sample cURL Request:**\n\n```bash\ncurl -X POST https://staging.eval.ads.giveth.io/admin/fetch/project-123\n```\n\n#### `GET /admin/stats`\n\nGet comprehensive system statistics.\n\n**Response:** Detailed system statistics including project counts, job statuses, and social media metrics.\n\n**Sample cURL Request:**\n\n```bash\ncurl https://staging.eval.ads.giveth.io/admin/stats\n```\n\n#### `GET /admin/cause-project-validation`\n\nValidate cause-project filtering behavior.\n\n**Response:** Validation results comparing GraphQL data with stored database data.\n\n**Sample cURL Request:**\n\n```bash\ncurl https://staging.eval.ads.giveth.io/admin/cause-project-validation\n```\n\n#### `GET /admin/social-posts`\n\nRetrieve stored social media posts for multiple projects.\n\n**Query Parameters (required):**\n\n- `projectIds` (string, required): Comma-separated project IDs (e.g., `project1,project2`)\n- `platform` (string, optional): Filter by platform (`twitter` or `farcaster`)\n- `limit` (number, optional): Posts per project (default: 10, max: 50)\n\n**Sample cURL Requests:**\n\n```bash\n# Get posts for multiple projects\ncurl \"https://staging.eval.ads.giveth.io/admin/social-posts?projectIds=project1,project2,project3\"\n\n# Get only Twitter posts with limit\ncurl \"https://staging.eval.ads.giveth.io/admin/social-posts?projectIds=project1,project2\u0026platform=twitter\u0026limit=5\"\n\n# Get Farcaster posts only\ncurl \"https://staging.eval.ads.giveth.io/admin/social-posts?projectIds=project1\u0026platform=farcaster\u0026limit=10\"\n```\n\n### Utility Endpoints\n\n#### `GET /`\n\nBasic service information.\n\n**Response:** Basic service status and information.\n\n**Sample cURL Request:**\n\n```bash\ncurl https://staging.eval.ads.giveth.io/\n```\n\n#### `GET /download`\n\nDownload evaluation results as CSV file.\n\n**Response:** CSV file download containing evaluation results.\n\n**Live URL**: https://staging.eval.ads.giveth.io/download/\n\n**Sample cURL Request:**\n\n```bash\n# Download CSV file\ncurl -O https://staging.eval.ads.giveth.io/download\n\n# Or save with specific filename\ncurl https://staging.eval.ads.giveth.io/download -o evaluation-results.csv\n```\n\n## Database Schema\n\n### Core Entities\n\n#### ProjectSocialAccount\n\nStores project metadata and social media handles.\n\n```sql\nCREATE TABLE project_social_accounts (\n  id UUID PRIMARY KEY,\n  project_id VARCHAR UNIQUE NOT NULL,\n  title VARCHAR(255) NOT NULL,\n  slug VARCHAR(255) NOT NULL,\n  description TEXT,\n  project_status VARCHAR(100) NOT NULL,\n  giv_power_rank INTEGER,\n  last_update_date TIMESTAMP,\n  last_update_content TEXT,\n  last_update_title VARCHAR(500),\n  x_url VARCHAR,\n  farcaster_url VARCHAR,\n  last_x_fetch TIMESTAMP,\n  last_farcaster_fetch TIMESTAMP,\n  latest_x_post_timestamp TIMESTAMP,\n  latest_farcaster_post_timestamp TIMESTAMP,\n  metadata JSONB,\n  created_at TIMESTAMP DEFAULT NOW(),\n  updated_at TIMESTAMP DEFAULT NOW()\n);\n```\n\n#### StoredSocialPost\n\nStores social media posts from Twitter and Farcaster.\n\n```sql\nCREATE TABLE stored_social_posts (\n  id UUID PRIMARY KEY,\n  post_id VARCHAR NOT NULL,\n  content TEXT NOT NULL,\n  url VARCHAR,\n  post_timestamp TIMESTAMP NOT NULL,\n  fetched_at TIMESTAMP NOT NULL,\n  metadata JSONB,\n  project_account_id UUID NOT NULL,\n  created_at TIMESTAMP DEFAULT NOW(),\n  FOREIGN KEY (project_account_id) REFERENCES project_social_accounts(id) ON DELETE CASCADE,\n  UNIQUE(post_id, project_account_id)\n);\n```\n\n#### ScheduledJob\n\nManages background job processing.\n\n```sql\nCREATE TABLE scheduled_jobs (\n  id UUID PRIMARY KEY,\n  project_id VARCHAR NOT NULL,\n  job_type job_type_enum NOT NULL,\n  scheduled_for TIMESTAMP NOT NULL,\n  status job_status_enum DEFAULT 'pending',\n  processed_at TIMESTAMP,\n  error TEXT,\n  attempts INTEGER DEFAULT 0,\n  metadata JSONB,\n  created_at TIMESTAMP DEFAULT NOW(),\n  updated_at TIMESTAMP DEFAULT NOW()\n);\n```\n\n### Entity Relationships\n\n```mermaid\nerDiagram\n    ProjectSocialAccount ||--o{ StoredSocialPost : \"has many\"\n    ProjectSocialAccount {\n        string id PK\n        string projectId UK\n        string title\n        string slug\n        text description\n        string projectStatus\n        int givPowerRank\n        timestamp lastUpdateDate\n        text lastUpdateContent\n        string xUrl\n        string farcasterUrl\n        timestamp lastXFetch\n        timestamp lastFarcasterFetch\n        jsonb metadata\n    }\n    StoredSocialPost {\n        string id PK\n        string postId\n        text content\n        string url\n        timestamp postTimestamp\n        timestamp fetchedAt\n        jsonb metadata\n        string projectAccountId FK\n    }\n    ScheduledJob {\n        string id PK\n        string projectId\n        enum jobType\n        timestamp scheduledFor\n        enum status\n        timestamp processedAt\n        text error\n        int attempts\n        jsonb metadata\n    }\n```\n\n## Scoring System\n\nThe CauseScore is calculated using a weighted rubric totaling 100 points:\n\n### Scoring Components\n\n| Component                                   | Weight | Type           | Description                                                |\n| ------------------------------------------- | ------ | -------------- | ---------------------------------------------------------- |\n| **Project Information Quality**             | 10%    | LLM-assessed   | Quality of project title, description, and updates         |\n| **Update Recency**                          | 5%     | Calculated     | How recently the project was updated                       |\n| **Social Media Content Quality**            | 10%    | LLM-assessed   | Quality of social media posts (Twitter 50%, Farcaster 50%) |\n| **Social Media Posting Recency**            | 5%     | Calculated     | How recently social media was posted                       |\n| **Social Media Posting Frequency**          | 5%     | Calculated     | Frequency of social media activity                         |\n| **Relevance to Cause**                      | 25%    | LLM-assessed   | How well the project aligns with the cause theme (Social Media 50%, Project Data 50%) |\n| **Evidence of Social/Environmental Impact** | 25%    | LLM-assessed   | Evidence of real-world impact                              |\n| **GIVpower Rank**                           | 15%    | From Giveth DB | Community-driven ranking metric                            |\n\n### Scoring Algorithm\n\n```typescript\n// Weighted score calculation\nconst causeScore =\n  projectInfoQuality * 0.1 +\n  updateRecency * 0.05 +\n  socialMediaQuality * 0.1 +\n  socialMediaRecency * 0.05 +\n  socialMediaFrequency * 0.05 +\n  relevanceToCause * 0.25 +\n  evidenceOfImpact * 0.25 +\n  givPowerRank * 0.15;\n```\n\n### LLM Assessment Criteria\n\nThe service uses structured prompts to ensure consistent LLM evaluations:\n\n- **Quality Assessment**: Evaluates content clarity, completeness, and professionalism\n- **Relevance Assessment**: Measures alignment with cause theme using a 50/50 split between social media content and project data\n- **Impact Assessment**: Looks for concrete evidence of social/environmental benefits\n\n#### Relevance Scoring Methodology\n\nThe **Relevance to Cause** component (25% of total score) uses a simplified, two-component assessment:\n\n- **Social Media Relevance (50%)**: Combined evaluation of all Twitter and Farcaster posts for cause alignment\n- **Project Relevance (50%)**: Assessment of project title, description, latest update title, and latest update content for cause alignment\n\n**Scoring Rubric:**\n- **80-100**: Exceptional alignment - directly supports cause mission with clear evidence\n- **60-79**: Strong alignment - closely matches cause goals with good evidence  \n- **40-59**: Moderate alignment - some connection but not perfectly aligned\n- **20-39**: Weak alignment - minimal connection or poor quality\n- **0-19**: No meaningful alignment - unrelated or very poor quality\n\nThis approach ensures projects aren't unfairly penalized for limited social media presence while maintaining rigorous relevance standards.\n\n## Setup \u0026 Development\n\n### Prerequisites\n\n- Node.js 18+\n- PostgreSQL 13+\n- Docker (optional)\n- npm or yarn\n\n### Environment Variables\n\nCreate a `.env` file based on `.env.example`:\n\n```bash\n# Core Configuration\nNODE_ENV=development\nPORT=3000\n\n# Database Configuration\nPOSTGRES_HOST=localhost\nPOSTGRES_PORT=5432\nPOSTGRES_USER=your_user\nPOSTGRES_PASSWORD=your_password\nPOSTGRES_DB=donation_evaluator\nDATABASE_URL=postgresql://user:pass@localhost:5432/donation_evaluator\n\n# Cache Settings\nCACHE_TTL_SOCIAL_MEDIA=21600  # 6 hours in seconds\n\n# Twitter Authentication (Method 1: Cookies)\nTWITTER_COOKIES='[{\"name\":\"auth_token\",\"value\":\"...\"}]'\n\n# Twitter Authentication (Method 2: Credentials - Account 1)\nTWITTER_USERNAME=your_username\nTWITTER_PASSWORD=your_password\nTWITTER_EMAIL=your_email\n\n# Twitter Authentication (Method 2: Credentials - Account 2)\nTWITTER_USERNAME_2=your_username_2\nTWITTER_PASSWORD_2=your_password_2\nTWITTER_EMAIL_2=your_email_2\n\n# Twitter Rate Limiting\nTWITTER_MIN_DELAY_MS=3000\nTWITTER_MAX_DELAY_MS=8000\nTWITTER_MAX_RETRIES=3\nTWITTER_BASE_RETRY_DELAY_MS=5000\n\n# Farcaster Integration (FREE - No API Keys Required)\n# Uses FName Registry and Warpcast APIs\n\n# LLM Integration (OpenRouter)\nOPENROUTER_API_KEY=your_openrouter_key\nLLM_MODEL=google/gemini-2.5-flash\n\n# Giveth Backend Integration\nGIVETH_API_BASE_URL=https://api.giveth.io\nGIVETH_API_KEY=your_giveth_key\n\n# Scoring Weight Configuration (Optional)\nSCORING_WEIGHT_PROJECT_INFO_QUALITY=10\nSCORING_WEIGHT_UPDATE_RECENCY=5\nSCORING_WEIGHT_SOCIAL_MEDIA_QUALITY=10\nSCORING_WEIGHT_SOCIAL_MEDIA_RECENCY=5\nSCORING_WEIGHT_SOCIAL_MEDIA_FREQUENCY=5\nSCORING_WEIGHT_RELEVANCE_TO_CAUSE=25\nSCORING_WEIGHT_EVIDENCE_OF_IMPACT=25\nSCORING_WEIGHT_GIVPOWER_RANK=15\n```\n\n### Installation \u0026 Running\n\n```bash\n# Install dependencies\nnpm install\n\n# Run database migrations\nnpm run migration:run\n\n# Development mode (with hot reload)\nnpm run start:dev\n\n# Debug mode\nnpm run start:debug\n\n# Production build\nnpm run build\nnpm run start:prod\n```\n\n### Code Quality Commands\n\n**IMPORTANT: Always run these after making code changes:**\n\n```bash\n# Check linting and formatting\nnpm run code:check\n\n# Fix linting and formatting issues\nnpm run code:fix\n\n# Individual checks\nnpm run lint:check\nnpm run format:check\n```\n\n### Testing\n\n```bash\n# Unit tests\nnpm run test\n\n# Tests with coverage\nnpm run test:cov\n\n# End-to-end tests\nnpm run test:e2e\n\n# Test specific services\nnpx ts-node test-twitter-elonmusk.ts\nnpx ts-node run-farcaster-test.ts\n```\n\n### Docker Setup\n\n```bash\n# Development\ndocker-compose up -d\n\n# Staging\ndocker-compose -f docker-compose-staging.yml up -d\n\n# Production\ndocker-compose -f docker-compose-production.yml up -d\n```\n\n## Background Services\n\n### Scheduled Job Types\n\nThe service runs several background jobs to maintain data freshness:\n\n#### Project Sync Jobs\n\n- **Frequency**: Every 6 hours\n- **Purpose**: Sync project metadata from Giveth backend\n- **Batch Size**: 15 projects per batch\n- **Concurrency**: 3 parallel jobs\n\n#### Twitter Fetch Jobs\n\n- **Frequency**: Hourly distribution\n- **Rate Limiting**: 3-8 second delays between requests\n- **Features**:\n  - Dual authentication strategy (cookies + credentials)\n  - Automatic account fallback\n  - Incremental fetching to avoid duplicates\n  - Cookie persistence for session management\n\n#### Farcaster Fetch Jobs\n\n- **Frequency**: Hourly distribution\n- **Rate Limiting**: 2-3 second delays between requests\n- **Features**:\n  - FName Registry integration for username resolution\n  - Username transfer handling\n  - Intelligent caching (24h for FIDs, 1h for casts)\n  - Completely FREE (no API keys required)\n\n### Job Processing Flow\n\n```mermaid\ngraph TD\n    A[Cron Scheduler] --\u003e B[Job Queue]\n    B --\u003e C{Job Type}\n    C --\u003e|PROJECT_SYNC| D[Project Sync Processor]\n    C --\u003e|TWEET_FETCH| E[Twitter Fetch Processor]\n    C --\u003e|FARCASTER_FETCH| F[Farcaster Fetch Processor]\n    D --\u003e G[Update ProjectSocialAccount]\n    E --\u003e H[Store Social Posts]\n    F --\u003e H\n    H --\u003e I[Update Cache]\n    G --\u003e I\n```\n\n### Error Handling \u0026 Retry Logic\n\n- **Exponential Backoff**: Failed jobs retry with increasing delays\n- **Max Attempts**: Up to 3 retry attempts per job\n- **Graceful Degradation**: Missing social media data assigns 0 scores rather than failing evaluation\n- **Correlation IDs**: All operations include tracking IDs for debugging\n\n## Integration Details\n\n### Giveth GraphQL API Integration\n\nThe service integrates with Giveth's Impact Graph API for:\n\n- **Cause Data**: Fetching cause details and project relationships\n- **Project Metadata**: Getting project information, updates, and GIVpower rankings\n- **Bulk Updates**: Sending evaluation results back to Impact Graph\n\n**Key GraphQL Operations:**\n\n- `getCauseDetails`: Fetch cause information and associated projects\n- `getProjectDetails`: Get detailed project information\n- `bulkUpdateCauseProjectEvaluation`: Submit evaluation results\n\n### Social Media APIs\n\n#### Twitter Integration\n\n- **Library**: `@the-convocation/twitter-scraper`\n- **Authentication**: Dual strategy (cookies + password)\n- **Rate Limiting**: 3-8 second delays with exponential backoff\n- **Features**: Batch processing, automatic fallback, session persistence\n\n#### Farcaster Integration\n\n- **APIs**: FName Registry (username resolution) + Warpcast (cast fetching)\n- **Cost**: Completely FREE - no API keys required\n- **Features**: Transfer handling, intelligent caching, incremental updates\n\n### LLM Integration\n\n- **Provider**: OpenRouter API\n- **Model**: Gemini 2.5 Flash (fast, cost-effective)\n- **Use Cases**:\n  - Project information quality assessment\n  - Social media content quality evaluation\n  - Relevance to cause determination\n  - Evidence of impact analysis\n\n**Prompt Engineering**:\n\n- Structured prompts stored in `/src/modules/llm-integration/prompts/`\n- Consistent scoring instructions (0-10 scale)\n- Clear evaluation criteria for each component\n\n## Monitoring \u0026 Logging\n\n### Logging \u0026 Correlation\n\n- **Structured Logging**: JSON format with correlation IDs\n- **Log Levels**: Error, Warn, Log, Debug, Verbose\n- **Correlation IDs**: UUID tracking for request flows\n- **Performance Metrics**: Response times and processing duration\n\n### System Statistics\n\nAccess via `GET /admin/stats`:\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"sync\": {\n      \"totalProjects\": 1247,\n      \"projectsWithX\": 892,\n      \"projectsWithFarcaster\": 456,\n      \"lastSyncTime\": \"2025-01-31T08:00:00Z\"\n    },\n    \"jobs\": {\n      \"pending\": 23,\n      \"processing\": 5,\n      \"completed\": 15678,\n      \"failed\": 12,\n      \"byJobType\": {\n        \"tweet_fetch\": 8921,\n        \"farcaster_fetch\": 6234,\n        \"project_sync\": 523\n      }\n    },\n    \"socialMedia\": {\n      \"totalPosts\": 45623,\n      \"twitterPosts\": 28934,\n      \"farcasterPosts\": 16689,\n      \"postsLast24Hours\": 1234,\n      \"postsLast7Days\": 8765\n    }\n  }\n}\n```\n\n## Data Flow\n\n### High-Level Architecture\n\n```mermaid\ngraph TD\n    %% External Systems\n    IG[Impact Graph API\u003cbr/\u003eGraphQL]\n    SOCIAL[Social Media APIs\u003cbr/\u003eTwitter + Farcaster]\n    OR[OpenRouter API\u003cbr/\u003eGemini 2.5 Flash]\n\n    %% Our System\n    API[Evaluation API\u003cbr/\u003eEndpoints]\n    CRON[Scheduled Jobs\u003cbr/\u003eBackground Processing]\n    DB[(PostgreSQL Database\u003cbr/\u003eProject Data + Social Posts)]\n    CACHE[(Cache Layer\u003cbr/\u003e6h TTL)]\n\n    %% Processing\n    EVAL[Evaluation Engine\u003cbr/\u003eScore Calculation]\n    LLM[LLM Processing\u003cbr/\u003eQuality Assessment]\n\n    %% Data Flows\n    CRON --\u003e|Fetch Projects\u003cbr/\u003eEvery 6h| IG\n    CRON --\u003e|Fetch Social Posts\u003cbr/\u003eHourly| SOCIAL\n    IG --\u003e DB\n    SOCIAL --\u003e DB\n\n    API --\u003e|Evaluation Request| EVAL\n    EVAL --\u003e DB\n    EVAL --\u003e LLM\n    LLM --\u003e OR\n    EVAL --\u003e CACHE\n    EVAL --\u003e|Results| API\n    API --\u003e|Update Scores| IG\n```\n\n### Detailed Data Processing Flow\n\n```mermaid\nsequenceDiagram\n    participant Client\n    participant API\n    participant Queue\n    participant Worker\n    participant DB\n    participant LLM\n    participant Cache\n\n    Client-\u003e\u003eAPI: POST /evaluate/cause\n    API-\u003e\u003eQueue: Add evaluation job\n    API-\u003e\u003eClient: Return job ID\n\n    Queue-\u003e\u003eWorker: Process evaluation job\n    Worker-\u003e\u003eDB: Fetch project data\n    Worker-\u003e\u003eDB: Fetch social posts\n    Worker-\u003e\u003eCache: Check cached scores\n\n    alt Cache miss\n        Worker-\u003e\u003eLLM: Assess content quality\n        Worker-\u003e\u003eLLM: Evaluate relevance\n        Worker-\u003e\u003eLLM: Check impact evidence\n        LLM-\u003e\u003eWorker: Return assessments\n        Worker-\u003e\u003eCache: Store results\n    end\n\n    Worker-\u003e\u003eWorker: Calculate final scores\n    Worker-\u003e\u003eDB: Log evaluation results\n    Worker-\u003e\u003eQueue: Mark job complete\n\n    Client-\u003e\u003eAPI: GET /evaluate/jobs/:id\n    API-\u003e\u003eClient: Return results\n```\n\n## Troubleshooting\n\n### Common Issues\n\n#### 1. Twitter Authentication Failures\n\n**Symptoms**: `TwitterService` throws authentication errors\n**Solutions**:\n\n- Check cookie validity in `twitter_cookies.json`\n- Verify username/password credentials\n- Ensure both accounts are configured for fallback\n- Check rate limiting delays\n\n#### 2. Farcaster Username Resolution Issues\n\n**Symptoms**: Cannot resolve Farcaster usernames to FIDs\n**Solutions**:\n\n- Verify username format (no @ prefix)\n- Check FName Registry API availability\n- Clear username cache if transfers occurred\n- Validate username ownership changes\n\n#### 3. LLM Assessment Failures\n\n**Symptoms**: Scoring fails with LLM errors\n**Solutions**:\n\n- Verify OpenRouter API key\n- Check model availability (`google/gemini-2.5-flash`)\n- Review prompt formatting\n- Monitor rate limits and quotas\n\n#### 4. Database Connection Issues\n\n**Symptoms**: Health checks fail for database\n**Solutions**:\n\n- Verify PostgreSQL connection parameters\n- Check SSL configuration for production\n- Ensure migrations are up to date\n- Monitor connection pool status\n\n#### 5. Job Processing Delays\n\n**Symptoms**: Background jobs not processing timely\n**Solutions**:\n\n- Check job queue statistics via `/admin/stats`\n- Monitor job failure rates\n- Verify cron job scheduling\n- Review rate limiting configurations\n\n### Debug Commands\n\n```bash\n# Manual project sync\ncurl -X POST https://staging.eval.ads.giveth.io/admin/sync-projects\n\n# Get system statistics\ncurl https://staging.eval.ads.giveth.io/admin/stats\n\n# Get social posts for projects\ncurl \"https://staging.eval.ads.giveth.io/admin/social-posts?projectIds=project1,project2\u0026limit=5\"\n\n# Force social media fetch for a project\ncurl -X POST https://staging.eval.ads.giveth.io/admin/fetch/PROJECT_ID\n\n# Get evaluation detailed report\ncurl https://staging.eval.ads.giveth.io/evaluate/evaluation-detailed\n\n# Check job status\ncurl https://staging.eval.ads.giveth.io/evaluate/jobs/JOB_ID\n```\n\n### Performance Optimization\n\n1. **Database Indexing**: Ensure proper indexes on frequently queried columns\n2. **Cache Tuning**: Adjust TTL values based on data freshness requirements\n3. **Rate Limiting**: Balance API limits with processing speed\n4. **Batch Processing**: Use batch operations for bulk data operations\n5. **Connection Pooling**: Monitor and tune database connection pools\n\n---\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch\n3. Run code quality checks: `npm run code:check`\n4. Submit a pull request with comprehensive tests\n\n## License\n\nThis project is licensed under the MIT License - see the LICENSE file for details.\n\n## Support\n\nFor questions and support:\n\n- Create an issue in the repository\n- Contact the Giveth development team\n- Review the existing documentation in `/docs/`\n\n---\n\n_Built with ❤️ for the Giveth community_\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgiveth%2Fdonation-agent-evaluator-service","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgiveth%2Fdonation-agent-evaluator-service","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgiveth%2Fdonation-agent-evaluator-service/lists"}