### Run All Scenarios (Linux/Mac) Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/k6-tests/sanity/CHECKLIST.md Execute all sanity tests on Linux or macOS. Ensure k6 is installed and environment variables are set. ```bash # Linux/Mac chmod +x k6-tests/sanity/run-all.sh export BASE_URL=http://localhost:5000 export SEED_OUTPUT_DIR=./seed-output ./k6-tests/sanity/run-all.sh ``` -------------------------------- ### Run All Scenarios (Windows PowerShell) Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/k6-tests/sanity/CHECKLIST.md Execute all sanity tests on Windows using PowerShell. Ensure k6 is installed and parameters are provided. ```powershell # Windows PowerShell ."/k6-tests/sanity/run-all.ps1" -BaseUrl http://localhost:5000 -SeedDir ./seed-output ``` -------------------------------- ### Audit Log Entry Example Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/docs/admin_phase_5.md An example of an audit log entry for data export actions. It includes the action type and relevant notes about the export. ```text ActionType: ExportData Notes: "Exported 1,234 Users records in CSV format" ``` -------------------------------- ### Complete Post Selection Flow Example Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/Docs/seed-pipeline/POST-SELECTION-VISUAL-FLOW.md Illustrates the step-by-step process of generating a user's post feed, from initial query to final response. It shows candidate post generation, privacy and age filtering, score calculation, and pagination. ```text USER PROFILE: user_123 FOLLOWING: 13 people REQUEST: GET /api/posts/feed?page=1&pageSize=20 ┌─────────────────────────────────────────────────┐ │ QUERY: 500 most recent posts from │ │ - user_123's own posts (5) │ │ - 13 followees' posts (150 posts) │ │ - Total: 150 candidates │ └─────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────┐ │ FILTER 1: Privacy Check │ │ ✅ Public posts: 120 │ │ ✅ Followers posts (user follows): 18 │ │ ❌ Private posts (skip): 12 │ │ → Remaining: 138 posts │ └─────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────┐ │ FILTER 2: Age Check (< 30 days) │ │ ✅ < 30 days: 120 posts │ │ ❌ > 30 days: 18 posts (removed) │ │ → Remaining: 120 posts │ └─────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────┐ │ SCORE CALCULATION (for 120 posts) │ │ Post 1: Score 87.54 ⭐ RANK #1 │ │ Post 2: Score 65.20 ⭐ RANK #2 │ │ Post 3: Score 54.30 ⭐ RANK #3 │ │ ... │ │ Post 20: Score 12.40 ⭐ RANK #20 │ │ Post 21: Score 11.90 │ │ Post 22: Score 10.20 │ │ ... │ └─────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────┐ │ PAGINATE (page=1, pageSize=20) │ │ Take posts 1-20 from ranking │ └─────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────┐ │ RESPONSE │ │ { │ │ "items": [ Post, Post, ... ], // 20 posts │ │ "page": 1, │ │ "pageSize": 20, │ │ "totalCount": 120 │ │ } └─────────────────────────────────────────────────┘ ``` -------------------------------- ### Recharts Growth Chart Example Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/docs/admin_phase_3.md Example of using Recharts to render a line chart for growth data. Requires 'GrowthChartResponse' type and data transformation. ```tsx import { LineChart, Line, XAxis, YAxis, Tooltip, Legend, ResponsiveContainer } from 'recharts'; function GrowthChart({ data }: { data: GrowthChartResponse }) { // Transform data for Recharts const chartData = data.users.map((point, index) => ({ date: new Date(point.date).toLocaleDateString(), users: point.count, posts: data.posts[index]?.count ?? 0, reports: data.reports[index]?.count ?? 0, })); return ( ); } ``` -------------------------------- ### Score Calculation Example: Post A Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/Docs/seed-pipeline/POST-SELECTION-VISUAL-FLOW.md Demonstrates the calculation of a trending score for a post with high recent engagement. This example highlights how engagement, decay, and velocity contribute to a high final score. ```text Interactions: 15 likes, 5 comments, 0 shares Engagement = 1.0 + (15 × 1.0) + (5 × 3.0) + (0 × 5.0) + (0 × 0.2) = 1.0 + 15 + 15 + 0 + 0 = 31.0 Age: 2 hours Decay = e^(-0.1 × 2) = e^(-0.2) ≈ 0.819 Recent: 5 interactions in last 1 hour Velocity = 5.0 interactions/hour Boost = 1 + (0.5 × 5.0) = 3.5x FINAL SCORE = 31.0 × 0.819 × 3.5 = 88.47 ⭐⭐⭐⭐⭐ TOP RANK! ``` -------------------------------- ### API Error Response Example Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/docs/admin_phase_2.md Example of a structured error response from the API for a 'not found' scenario. This format can be used for other API errors. ```json { code: "AUDIT_LOG_NOT_FOUND", message: "Audit log not found." } ``` -------------------------------- ### Run Sanity Tests in CI/CD Pipeline Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/k6-tests/sanity/IMPLEMENTATION_SUMMARY.md Integrate K6 sanity tests into a CI/CD workflow. This example shows a 'run' step in a GitHub Actions workflow, setting the BASE_URL and executing the Bash runner script. ```yaml - name: Run Sanity Tests run: | export BASE_URL=http://localhost:5000 ./k6-tests/sanity/run-all.sh ``` -------------------------------- ### Score Calculation Example: Post B Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/Docs/seed-pipeline/POST-SELECTION-VISUAL-FLOW.md Illustrates the trending score calculation for a post with low engagement and no recent activity. This example shows how decay and lack of velocity result in a low final score. ```text Interactions: 3 likes, 1 comment, 0 shares Engagement = 1.0 + (3 × 1.0) + (1 × 3.0) = 7.0 Age: 20 hours Decay = e^(-0.1 × 20) = e^(-2.0) ≈ 0.135 Recent: 0 interactions in last 1 hour Velocity = 0 Boost = 1 + 0 = 1.0 FINAL SCORE = 7.0 × 0.135 × 1.0 = 0.945 (very low, buried in feed) ``` -------------------------------- ### Current Feed Fetching Flow Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/Docs/seed-pipeline/FEED-SCROLLING-LIMITATIONS.md Illustrates the current method of fetching posts for the feed, which always starts from the beginning (skip: 0) and takes a fixed number of candidates (TrendingCandidateLimit). This is a key part of the scrolling limitation. ```csharp var (candidates, _) = await _uow.Posts.GetFeedPagedAsync( currentUserId, skip: 0, // ⚠️ ALWAYS ZERO! take: TrendingCandidateLimit // ⚠️ ALWAYS 500! ); ``` -------------------------------- ### Database Query for Feed Candidates Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/Docs/seed-pipeline/FEED-SCROLLING-LIMITATIONS.md Illustrates the SQL query executed by GetFeedPagedAsync. It shows the 'OFFSET skip (0)' and 'LIMIT take (500)' clauses, emphasizing that the query always starts from the beginning and is capped at 500 records. ```text GetFeedPagedAsync(userId, skip=0, take=500) ├─────────────────────────────────────────────────────────┤ │ SELECT * FROM Posts WHERE │ (ProfileId = userId OR user follows author) │ AND NOT deleted AND NOT archived │ ORDER BY CreatedAt DESC │ OFFSET skip (0) ← Always from top! │ LIMIT take (500) ← Max 500 posts └─────────────────────────────────────────────────────────┘ ``` -------------------------------- ### Filter Validation Logic Examples Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/docs/admin_phase_2.md Illustrates common validation checks for filters. Includes checking date ranges and ensuring page numbers are within valid bounds. ```typescript // Invalid date range if (fromDate && toDate && new Date(fromDate) > new Date(toDate)) { // Show error: "From date must be before to date" } // Page out of range if (page > totalPages) { // Redirect to last page } ``` -------------------------------- ### Option 1: Dynamic Candidate Pool Implementation Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/Docs/seed-pipeline/FEED-SCROLLING-LIMITATIONS.md Demonstrates how to modify the `GetFeedAsync` method to incorporate a new `offset` parameter for dynamic candidate fetching, allowing for a truly paginated candidate pool. ```csharp public async Task> GetFeedAsync( Guid currentUserId, int page, int pageSize, int offset = 0) // ← New parameter { var candidateSkip = offset; var (candidates, total) = await _uow.Posts.GetFeedPagedAsync( currentUserId, skip: candidateSkip, // ← Dynamic! take: TrendingCandidateLimit ); // Rest is same... var skip = (page - 1) * pageSize; // ... } ``` -------------------------------- ### Bash Script for Running All K6 Scenarios Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/k6-tests/sanity/CHECKLIST.md This script sets environment variables, creates a results directory, and iterates through five scenarios, generating JSON output and a pass/fail summary. It is designed for Bash/Linux/Mac environments and returns proper exit codes. ```bash #!/bin/bash # Exit immediately if a command exits with a non-zero status. set -e # Define base directory and results directory BASE_DIR="$(cd "$(dirname "$0")" && pwd)/.." RESULTS_DIR="$BASE_DIR/results" # Create results directory if it doesn't exist rm -rf "$RESULTS_DIR" mkdir -p "$RESULTS_DIR" # Load environment variables from .env file if it exists if [ -f "$BASE_DIR/.env" ]; then export $(grep -v '^#' "$BASE_DIR/.env" | xargs) fi # Define scenarios and their corresponding files SCENARIOS=( "scenario-1-reaction-like-unlike-loop.js" "scenario-2-auth-login-logout-relogin.js" "scenario-3-feed-refresh-repeat.js" "scenario-4-search-related-fallback.js" "scenario-5-share-unshare.js" ) TOTAL_SCENARIOS=${#SCENARIOS[@]} PASSED_COUNT=0 FAILED_COUNT=0 echo "Starting K6 Sanity Test Suite..." # Loop through each scenario for i in "${!SCENARIOS[@]}"; do SCENARIO_FILE="${SCENARIOS[$i]}" SCENARIO_NAME="$(basename "$SCENARIO_FILE" .js)" SCENARIO_PATH="$BASE_DIR/$SCENARIO_FILE" OUTPUT_FILE="$RESULTS_DIR/$SCENARIO_NAME.json" echo "--------------------------------------------------" echo "Running scenario $((i + 1))/$TOTAL_SCENARIOS: $SCENARIO_NAME" echo "--------------------------------------------------" # Execute K6 test for the current scenario k6 run --out json=$OUTPUT_FILE "$SCENARIO_PATH" # Check the exit code of the k6 run command if [ $? -eq 0 ]; then echo "✅ Scenario $SCENARIO_NAME passed." PASSED_COUNT=$((PASSED_COUNT + 1)) else echo "❌ Scenario $SCENARIO_NAME failed." FAILED_COUNT=$((FAILED_COUNT + 1)) fi done echo "==================================================" echo "K6 Sanity Test Suite Summary:" echo "Total Scenarios: $TOTAL_SCENARIOS" echo "Passed: $PASSED_COUNT" echo "Failed: $FAILED_COUNT" echo "==================================================" # Exit with a non-zero status code if any scenario failed if [ $FAILED_COUNT -gt 0 ]; then exit 1 else exit 0 fi ``` -------------------------------- ### Weight Calculation for Post Selection Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/Docs/seed-pipeline/POST-SELECTION-VISUAL-FLOW.md Demonstrates the calculation of weights and probabilities for selecting hot versus normal posts, considering the distribution of interactions. This calculation clarifies the practical probability of picking a hot post. ```csharp weights[i] = post in hotPosts ? 7.0 : 1.0; totalWeight = sum of all weights = (800 × 7) + (9,200 × 1) = 5,600 + 9,200 = 14,800 probability(pick hot post) = 5,600 / 14,800 = 37.84% ← Practical ratio (NOT 77.8% because many interactions spread) ``` -------------------------------- ### Get Dashboard Stats Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/docs/admin_phase_3.md Retrieves overall dashboard statistics for administrators. ```APIDOC ## GET /api/admin/analytics ### Description Retrieves overall dashboard statistics for administrators. ### Method GET ### Endpoint /api/admin/analytics ### Response #### Success Response (200) - **data** (DashboardStatsResponse) - The dashboard statistics response object. ``` -------------------------------- ### Get Post Privacy Distribution Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/docs/admin_phase_3.md Retrieves the distribution of posts by their privacy level. ```APIDOC ## GET /api/admin/analytics/charts/post-privacy ### Description Retrieves the distribution of posts by their privacy level. ### Method GET ### Endpoint /api/admin/analytics/charts/post-privacy ### Response #### Success Response (200) - **privacyLevels** (LabeledDataPoint[]) - An array of objects, each representing a privacy level and its count/percentage. - **totalPosts** (number) - The total number of posts. ``` -------------------------------- ### PowerShell Script for Running All K6 Scenarios Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/k6-tests/sanity/CHECKLIST.md This script accepts parameters, sets environment variables, creates a results directory, and iterates through five scenarios, generating JSON output with colored output and a pass/fail summary. It is designed for PowerShell/Windows environments and returns proper exit codes. ```powershell # Define base directory and results directory $BASE_DIR = "$(cd "$(dirname "$($MyInvocation.MyCommand.Path)")" && pwd)/.." $RESULTS_DIR = "Join-Path $BASE_DIR results" # Create results directory if it doesn't exist if (Test-Path $RESULTS_DIR) { Remove-Item $RESULTS_DIR -Recurse -Force } New-Item -ItemType Directory -Path $RESULTS_DIR | Out-Null # Load environment variables from .env file if it exists $envFile = "Join-Path $BASE_DIR .env" if (Test-Path $envFile) { $envVars = Get-Content $envFile | Where-Object { $_ -notmatch '^#' -and $_ -match '=' } foreach ($line in $envVars) { $key, $value = $line.Split('=', 2) $env:($key) = $value } } # Define scenarios and their corresponding files $SCENARIOS = @( "scenario-1-reaction-like-unlike-loop.js", "scenario-2-auth-login-logout-relogin.js", "scenario-3-feed-refresh-repeat.js", "scenario-4-search-related-fallback.js", "scenario-5-share-unshare.js" ) $TOTAL_SCENARIOS = $SCENARIOS.Count $PASSED_COUNT = 0 $FAILED_COUNT = 0 # Define colors for output $Color = @{ Green = "\[0;32m" Red = "\[0;31m" Yellow = "\[0;33m" Blue = "\[0;34m" Reset = "\[0m" } # Function to write colored output function Write-Color { param( [string]$Text, [string]$ColorName ) Write-Host "$($Color[$ColorName])$Text$($Color.Reset)" } Write-Host "Starting K6 Sanity Test Suite..." # Loop through each scenario for ($i = 0; $i -lt $TOTAL_SCENARIOS; $i++) { $SCENARIO_FILE = $SCENARIOS[$i] $SCENARIO_NAME = [System.IO.Path]::GetFileNameWithoutExtension($SCENARIO_FILE) $SCENARIO_PATH = "Join-Path $BASE_DIR $SCENARIO_FILE" $OUTPUT_FILE = "Join-Path $RESULTS_DIR $SCENARIO_NAME.json" Write-Host "--------------------------------------------------" Write-Color "Running scenario $($i + 1)/$TOTAL_SCENARIOS: $SCENARIO_NAME" "Blue" Write-Host "--------------------------------------------------" # Execute K6 test for the current scenario # Using Start-Process to capture exit code $process = Start-Process -FilePath "k6" -ArgumentList "run --out json=$OUTPUT_FILE `"$SCENARIO_PATH`"" -Wait -PassThru -NoNewWindow # Check the exit code of the k6 run command if ($process.ExitCode -eq 0) { Write-Color "✅ Scenario $SCENARIO_NAME passed." "Green" $PASSED_COUNT++ } else { Write-Color "❌ Scenario $SCENARIO_NAME failed." "Red" $FAILED_COUNT++ } } Write-Host "==================================================" Write-Color "K6 Sanity Test Suite Summary:" "Yellow" Write-Host "Total Scenarios: $TOTAL_SCENARIOS" Write-Color "Passed: $PASSED_COUNT" "Green" Write-Color "Failed: $FAILED_COUNT" "Red" Write-Host "==================================================" # Exit with a non-zero status code if any scenario failed if ($FAILED_COUNT -gt 0) { exit 1 } else { exit 0 } ``` -------------------------------- ### Initial Feed Fetch Configuration Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/Docs/seed-pipeline/FEED-SCROLLING-LIMIT-EXPLAINED.md Shows the hardcoded skip and take values used for fetching feed posts, limiting the initial retrieval to 500 items. ```text GetFeedAsync: skip: 0 take: 500 For ALL pages, you fetch the SAME 500 posts from DB. Then paginate those 500 in-memory. If you have 1000 posts in your feed: Page 1-25 ✅ Shows posts 1-500 Page 26+ ❌ Shows posts 501-1000 ``` -------------------------------- ### Get Period Comparison Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/docs/admin_phase_3.md Compares statistics between two periods to show growth trends. ```APIDOC ## GET /api/admin/analytics/comparison ### Description Compares statistics between two periods to show growth trends. ### Method GET ### Endpoint /api/admin/analytics/comparison ### Parameters #### Query Parameters - **fromDate** (string) - Optional - The start date for the current period (ISO 8601 format). - **toDate** (string) - Optional - The end date for the current period (ISO 8601 format). ### Response #### Success Response (200) - **currentPeriod** (PeriodStats) - Statistics for the current period. - **previousPeriod** (PeriodStats) - Statistics for the previous period. - **growth** (GrowthComparison) - The calculated growth percentages between the periods. ``` -------------------------------- ### Get User Role Distribution Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/docs/admin_phase_3.md Retrieves the distribution of users across different roles. ```APIDOC ## GET /api/admin/analytics/charts/user-roles ### Description Retrieves the distribution of users across different roles. ### Method GET ### Endpoint /api/admin/analytics/charts/user-roles ### Response #### Success Response (200) - **roles** (LabeledDataPoint[]) - An array of objects, each representing a role and its count/percentage. - **totalUsers** (number) - The total number of users. ``` -------------------------------- ### Run Single K6 Sanity Test Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/k6-tests/sanity/IMPLEMENTATION_SUMMARY.md Execute a single K6 sanity test scenario. Ensure the BASE_URL and SEED_OUTPUT_DIR environment variables are set correctly. ```bash export BASE_URL=http://localhost:5000 export SEED_OUTPUT_DIR=./seed-output k6 run \ --env BASE_URL=$BASE_URL \ --env SEED_OUTPUT_DIR=$SEED_OUTPUT_DIR \ k6-tests/sanity/scenario-1-reaction-like-unlike-loop.js ``` -------------------------------- ### Run All K6 Sanity Tests (Bash) Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/k6-tests/sanity/IMPLEMENTATION_SUMMARY.md Execute all K6 sanity tests using the provided Bash script. Make the script executable before running. ```bash chmod +x k6-tests/sanity/run-all.sh ./k6-tests/sanity/run-all.sh ``` -------------------------------- ### Get Top Users Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/docs/admin_phase_3.md Retrieves a list of top users based on their activity or engagement metrics. ```APIDOC ## GET /api/admin/analytics/top-users ### Description Retrieves a list of top users based on their activity or engagement metrics. ### Method GET ### Endpoint /api/admin/analytics/top-users ### Parameters #### Query Parameters - **limit** (number) - Optional - The maximum number of top users to return. Defaults to 10. ### Response #### Success Response (200) - **(TopUserDto[])** - An array of top user objects. ``` -------------------------------- ### Run All Scenarios (Bash) Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/k6-tests/sanity/IMPLEMENTATION_SUMMARY.md Executes all sanity test scenarios using a bash script. It sets environment variables, loops through scenarios, generates reports, and displays a summary. ```bash # Usage ./k6-tests/sanity/run-all.sh # Features: # - Sets environment variables # - Loops through all scenarios # - Generates JSON reports # - Shows pass/fail summary ``` -------------------------------- ### Get Report Status Distribution Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/docs/admin_phase_3.md Retrieves the distribution of reports by their status (pending, resolved, rejected). ```APIDOC ## GET /api/admin/analytics/charts/report-status ### Description Retrieves the distribution of reports by their status (pending, resolved, rejected). ### Method GET ### Endpoint /api/admin/analytics/charts/report-status ### Response #### Success Response (200) - **pending** (number) - The count of pending reports. - **resolved** (number) - The count of resolved reports. - **rejected** (number) - The count of rejected reports. - **totalReports** (number) - The total number of reports. ``` -------------------------------- ### Data Flow Diagram Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/Docs/seed-pipeline/FEED-SCROLLING-LIMIT-EXPLAINED.md Visualizes the data flow from the database to memory, showing how fetching a fixed 500 posts limits visibility and causes pagination failures beyond page 25. ```text ┌──────────────────────────────┐ │ DB: User's Feed (1000 posts) │ │ Post #1000 (newest) │ │ Post #999 │ │ ... │ │ Post #501 │ │ Post #500 │ │ Post #499 (oldest visible) │ │ Post #498 (not fetched) │ │ ... │ │ Post #1 (oldest) │ └──────────────────────────────┘ GetFeedPagedAsync skip=0, take=500 ┌──────────────────────────────┐ │ Memory: 500 Posts │ │ [Post 1000-501] │ │ Scored + Sorted │ └──────────────────────────────┘ Paginate in-memory ┌──────────────────────────────┐ │ Page 1: [1-20] ✅ │ │ Page 2: [21-40] ✅ │ │ ... │ │ Page 25: [481-500] ✅ │ │ Page 26: [] ❌ │ │ (Posts 501-1000 hidden!) │ └──────────────────────────────┘ ``` -------------------------------- ### Get User Status Distribution Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/docs/admin_phase_3.md Retrieves the distribution of users by their status (active, banned, inactive). ```APIDOC ## GET /api/admin/analytics/charts/user-status ### Description Retrieves the distribution of users by their status (active, banned, inactive). ### Method GET ### Endpoint /api/admin/analytics/charts/user-status ### Response #### Success Response (200) - **activeUsers** (number) - The count of active users. - **bannedUsers** (number) - The count of banned users. - **inactiveUsers** (number) - The count of inactive users. - **totalUsers** (number) - The total number of users. ``` -------------------------------- ### PostRepository.cs - GetFeedPagedAsync Implementation Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/Docs/seed-pipeline/FEED-SCROLLING-LIMIT-EXPLAINED.md The repository's GetFeedPagedAsync method correctly implements skip and take for database-level pagination, but these parameters are not utilized by the service layer. ```csharp public async Task<(IEnumerable Items, int Total)> GetFeedPagedAsync(Guid profileId, int skip, int take) { var baseQuery = _dbSet .Where(p => /* privacy */ && !archived && !deleted) .OrderByDescending(p => p.CreatedAt); var total = await baseQuery.CountAsync(); var items = await baseQuery .Skip(skip) // .Take(take) // .ToListAsync(); return (items, total); } ``` -------------------------------- ### Get Top Posts Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/docs/admin_phase_3.md Retrieves a list of top posts based on engagement metrics like reactions and comments. ```APIDOC ## GET /api/admin/analytics/top-posts ### Description Retrieves a list of top posts based on engagement metrics like reactions and comments. ### Method GET ### Endpoint /api/admin/analytics/top-posts ### Parameters #### Query Parameters - **limit** (number) - Optional - The maximum number of top posts to return. Defaults to 10. ### Response #### Success Response (200) - **(TopPostDto[])** - An array of top post objects. ``` -------------------------------- ### GET /api/admin/health/detailed Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/docs/admin_phase_1.md Performs a full health check of the system, combining overall status with detailed system metrics. ```APIDOC ## GET /api/admin/health/detailed ### Description Performs a full health check of the system, combining overall status with detailed system metrics. ### Method GET ### Endpoint /api/admin/health/detailed ### Headers - **Authorization** (string) - Required - Bearer token for admin authentication ### Response #### Success Response (200 OK) - **overallStatus** (string) - The overall health status of the system ('Healthy', 'Degraded', 'Unhealthy') - **timestamp** (string) - ISO 8601 timestamp of the health check - **totalCheckDurationMs** (number) - Total time taken for all health checks in milliseconds - **metrics** (object) - Detailed system metrics - **memory** (object) - **workingSetMB** (number) - **privateMemoryMB** (number) - **gcMemoryMB** (number) - **cpu** (object) - **usagePercent** (number) - **process** (object) - **threadCount** (number) - **handleCount** (number) - **uptimeSeconds** (number) - **uptimeFormatted** (string) - **garbageCollection** (object) - **gen0Collections** (number) - **gen1Collections** (number) - **gen2Collections** (number) - **timestamp** (string) - ISO 8601 timestamp of the metrics retrieval - **services** (array) - Health status of individual services - **name** (string) - **status** (string) - **message** (string | null) - **responseTimeMs** (number) - **data** (object | null) - **database** (object) - Health status of the database connection - **status** (string) - **message** (string | null) - **responseTimeMs** (number) ### Response Example ```json { "overallStatus": "Healthy", "timestamp": "2024-01-15T10:30:00.000Z", "totalCheckDurationMs": 55.5, "metrics": { "memory": { "workingSetMB": 180.32, "privateMemoryMB": 195.45, "gcMemoryMB": 125.45 }, "cpu": { "usagePercent": 12.5 }, "process": { "threadCount": 45, "handleCount": 320, "uptimeSeconds": 86400, "uptimeFormatted": "1d 0h 0m" }, "garbageCollection": { "gen0Collections": 45, "gen1Collections": 12, "gen2Collections": 3 }, "timestamp": "2024-01-15T10:30:00.000Z" }, "services": [ { "name": "memory", "status": "Healthy", "message": "Memory usage is normal: 125.45MB", "responseTimeMs": 1, "data": { "AllocatedMB": 125.45, "WorkingSetMB": 180.32 } } ], "database": { "status": "Healthy", "message": "Database connection is healthy (15ms)", "responseTimeMs": 15 } } ``` ``` -------------------------------- ### Request Flow for Page 25 Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/Docs/seed-pipeline/FEED-SCROLLING-LIMIT-EXPLAINED.md Demonstrates that even for page 25, the same initial 500 posts are fetched, and in-memory pagination still works as the offset is within the fetched limit. ```text REQUEST #2: GET /api/posts/feed?page=25&pageSize=20 GetFeedPagedAsync(userId, skip=0, take=500) DB: Returns SAME [Post 1000-500] Filter + Score in memory Paginate: skip=480, take=20 RETURN: [Post 520-501] ✅ Still works (within 500) ``` -------------------------------- ### GET /api/admin/health/metrics Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/docs/admin_phase_1.md Retrieves detailed system metrics including CPU, Memory, Garbage Collection, and Process information. ```APIDOC ## GET /api/admin/health/metrics ### Description Retrieves detailed system metrics including CPU, Memory, Garbage Collection, and Process information. ### Method GET ### Endpoint /api/admin/health/metrics ### Headers - **Authorization** (string) - Required - Bearer token for admin authentication ### Response #### Success Response (200 OK) - **memory** (object) - Memory usage details - **workingSetMB** (number) - **privateMemoryMB** (number) - **gcMemoryMB** (number) - **cpu** (object) - CPU usage details - **usagePercent** (number) - **process** (object) - Process information - **threadCount** (number) - **handleCount** (number) - **uptimeSeconds** (number) - **uptimeFormatted** (string) - **garbageCollection** (object) - Garbage collection statistics - **gen0Collections** (number) - **gen1Collections** (number) - **gen2Collections** (number) - **timestamp** (string) - ISO 8601 timestamp of the metrics retrieval ### Response Example ```json { "memory": { "workingSetMB": 180.32, "privateMemoryMB": 195.45, "gcMemoryMB": 125.45 }, "cpu": { "usagePercent": 12.5 }, "process": { "threadCount": 45, "handleCount": 320, "uptimeSeconds": 86400, "uptimeFormatted": "1d 0h 0m" }, "garbageCollection": { "gen0Collections": 45, "gen1Collections": 12, "gen2Collections": 3 }, "timestamp": "2024-01-15T10:30:00.000Z" } ``` ``` -------------------------------- ### Request Flow for Page 1 Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/Docs/seed-pipeline/FEED-SCROLLING-LIMIT-EXPLAINED.md Illustrates the successful retrieval and pagination of posts for the first page, fetching the initial 500 most recent posts. ```text REQUEST #1: GET /api/posts/feed?page=1&pageSize=20 GetFeedPagedAsync(userId, skip=0, take=500) DB: SELECT * FROM Posts WHERE (owner=userId OR follow) ORDER BY CreatedAt DESC LIMIT 500 Returns: [Post 1000-500] Filter + Score in memory Paginate: skip=0, take=20 RETURN: [Post 1000-981] ✅ Works! ``` -------------------------------- ### Run Smoke Tests with k6 Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/k6-tests/smoke/README.md Command to execute a specific smoke test file using the k6 tool. Replace the placeholder with the actual test file name. ```bash k6 run ``` -------------------------------- ### Get Content Activity Chart Data Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/docs/admin_phase_3.md Retrieves time series data for posts, comments, and reactions over a specified period and interval. ```APIDOC ## GET /api/admin/analytics/charts/content-activity ### Description Retrieves time series data for posts, comments, and reactions over a specified period and interval. ### Method GET ### Endpoint /api/admin/analytics/charts/content-activity ### Parameters #### Query Parameters - **fromDate** (string) - Optional - The start date for the data range (ISO 8601 format). - **toDate** (string) - Optional - The end date for the data range (ISO 8601 format). - **interval** (ChartInterval) - Optional - The interval for the data aggregation ('day', 'week', or 'month'). ### Response #### Success Response (200) - **posts** (TimeSeriesDataPoint[]) - Time series data for posts. - **comments** (TimeSeriesDataPoint[]) - Time series data for comments. - **reactions** (TimeSeriesDataPoint[]) - Time series data for reactions. - **fromDate** (string) - The start date of the returned data. - **toDate** (string) - The end date of the returned data. - **interval** (ChartInterval) - The interval used for the data. ``` -------------------------------- ### Seed Pipeline: Weighted Post Selection Logic Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/Docs/seed-pipeline/POST-SELECTION-VISUAL-FLOW.md Illustrates the logic for selecting posts based on a weighted random approach, differentiating between hot and normal posts. This is used to generate engagement data for test posts. ```text Input: 10,000 Posts │ ├─ Step 1: BuildHotPostSet │ ├─ Calculate: 10,000 × 0.08 = 800 hot posts │ ├─ Method: StableSeed.FromString($"hot:{PostId}") │ └─ Result: Consistent 800 hot posts │ ├─ Step 2: PickPostWeighted (Loop to create engagement) │ ├─ For each new reaction/comment/repost: │ │ ├─ Generate random [0-9]: │ │ │ ├─ [0-7) → Hot post (77.8% chance) │ │ │ └─ [7-9) → Normal post (22.2% chance) │ │ └─ Create interaction on selected post │ │ │ └─ Create 80,000-120,000 reactions │ Create 15,000-30,000 comments │ Create 1,000-2,000 reposts │ └─ Result: Realistic engagement distribution ``` -------------------------------- ### Get Growth Chart Data Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/docs/admin_phase_3.md Retrieves time series data for user, post, and report growth over a specified period and interval. ```APIDOC ## GET /api/admin/analytics/charts/growth ### Description Retrieves time series data for user, post, and report growth over a specified period and interval. ### Method GET ### Endpoint /api/admin/analytics/charts/growth ### Parameters #### Query Parameters - **fromDate** (string) - Optional - The start date for the data range (ISO 8601 format). - **toDate** (string) - Optional - The end date for the data range (ISO 8601 format). - **interval** (ChartInterval) - Optional - The interval for the data aggregation ('day', 'week', or 'month'). ### Response #### Success Response (200) - **users** (TimeSeriesDataPoint[]) - Time series data for user growth. - **posts** (TimeSeriesDataPoint[]) - Time series data for post growth. - **reports** (TimeSeriesDataPoint[]) - Time series data for report growth. - **fromDate** (string) - The start date of the returned data. - **toDate** (string) - The end date of the returned data. - **interval** (ChartInterval) - The interval used for the data. ``` -------------------------------- ### Run Sanity Tests Before Deployment (Bash) Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/k6-tests/sanity/IMPLEMENTATION_SUMMARY.md Execute the full K6 sanity test suite using the Bash runner script. This is typically done before deploying changes. ```bash ./k6-tests/sanity/run-all.sh ``` -------------------------------- ### Run All K6 Sanity Tests (PowerShell) Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/k6-tests/sanity/IMPLEMENTATION_SUMMARY.md Execute all K6 sanity tests using the provided PowerShell script. This command allows specifying the BaseUrl and optionally showing a summary. ```powershell . /k6-tests/sanity/run-all.ps1 -BaseUrl http://localhost:5000 -ShowSummary ``` -------------------------------- ### Get User Activity Chart Data Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/docs/admin_phase_3.md Retrieves time series data for new, active, and banned users over a specified period and interval. ```APIDOC ## GET /api/admin/analytics/charts/user-activity ### Description Retrieves time series data for new, active, and banned users over a specified period and interval. ### Method GET ### Endpoint /api/admin/analytics/charts/user-activity ### Parameters #### Query Parameters - **fromDate** (string) - Optional - The start date for the data range (ISO 8601 format). - **toDate** (string) - Optional - The end date for the data range (ISO 8601 format). - **interval** (ChartInterval) - Optional - The interval for the data aggregation ('day', 'week', or 'month'). ### Response #### Success Response (200) - **newUsers** (TimeSeriesDataPoint[]) - Time series data for new users. - **activeUsers** (TimeSeriesDataPoint[]) - Time series data for active users. - **bannedUsers** (TimeSeriesDataPoint[]) - Time series data for banned users. - **fromDate** (string) - The start date of the returned data. - **toDate** (string) - The end date of the returned data. - **interval** (ChartInterval) - The interval used for the data. ``` -------------------------------- ### System Metrics Response Structure Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/docs/admin_phase_1.md This JSON object represents the response from the GET /api/admin/health/metrics endpoint, detailing CPU, memory, garbage collection, and process information. ```json { "memory": { "workingSetMB": 180.32, "privateMemoryMB": 195.45, "gcMemoryMB": 125.45 }, "cpu": { "usagePercent": 12.5 }, "process": { "threadCount": 45, "handleCount": 320, "uptimeSeconds": 86400, "uptimeFormatted": "1d 0h 0m" }, "garbageCollection": { "gen0Collections": 45, "gen1Collections": 12, "gen2Collections": 3 }, "timestamp": "2024-01-15T10:30:00.000Z" } ``` -------------------------------- ### Post Feed Ranking Pipeline Overview Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/Docs/seed-pipeline/POST-SELECTION-VISUAL-FLOW.md Illustrates the sequence of operations for retrieving and ranking posts for a user's feed, from initial database query to final response mapping. ```text User Request: GET /api/posts/feed?page=1&pageSize=20 │ ├─ Step 1: GetFeedPagedAsync (Query) │ ├─ SELECT TOP 500 FROM Posts WHERE: │ │ ├─ (ProfileId = @userId │ │ │ OR EXISTS Follows WHERE FollowerId=@userId │ │ │ AND FolloweeId=PostProfileId) │ │ ├─ AND DeletedDayExpiredAt IS NULL │ │ └─ AND IsArchived = 0 │ ├─ ORDER BY CreatedAt DESC │ └─ Result: ~100-300 candidates │ ├─ Step 2: Privacy Filter (In-Memory) │ ├─ For each candidate post: │ │ ├─ if post.Privacy == Public → PASS ✅ │ │ ├─ if post.Privacy == Followers │ │ │ └─ Check: CanFollowAsync(viewerId, postAuthorId)? │ │ │ ├─ YES → PASS ✅ │ │ │ └─ NO → SKIP ❌ │ │ └─ if post.Privacy == Private │ │ └─ Only author → PASS ✅ │ │ Others → SKIP ❌ │ └─ Result: ~80-250 valid posts │ ├─ Step 3: Age Filter (In-Memory) │ ├─ For each valid post: │ │ ├─ ageHours = (now - post.CreatedAt).TotalHours │ │ ├─ if ageHours < 720 (30 days) → PASS ✅ │ │ └─ if ageHours >= 720 → SKIP ❌ (too old) │ └─ Result: ~50-180 fresh valid posts │ ├─ Step 4: Compute TrendingScore for Each │ ├─ For each post: │ │ ├─ A. Calculate Engagement │ │ │ Engagement = 1.0 + │ │ │ (Likes × 1.0) + │ │ │ (Comments × 3.0) + │ │ │ (Shares × 5.0) + │ │ │ (Views × 0.2) │ │ │ │ │ ├─ B. Calculate Decay (age penalty) │ │ │ Decay = e^(-0.1 × ageHours) │ │ │ e.g., 24h old → e^(-2.4) ≈ 0.091 │ │ │ │ │ ├─ C. Calculate Velocity (momentum) │ │ │ RecentInteractions = interactions in last 1 hour │ │ │ Velocity = RecentInteractions / 1.0 (per hour) │ │ │ VelocityBoost = 1 + (0.5 × Velocity) │ │ │ e.g., 3 new likes in last hour → 1 + 0.5×3 = 2.5x │ │ │ │ │ └─ D. Final Score │ │ Score = Engagement × Decay × VelocityBoost │ │ │ └─ Result: Each post has numeric Score │ ├─ Step 5: Sort by Score (Descending) │ ├─ Order by Score DESC │ └─ Result: Posts ranked by relevance │ ├─ Step 6: Paginate │ ├─ Skip (page-1) × pageSize = (1-1) × 20 = 0 │ ├─ Take 20 items │ └─ Result: First 20 posts for feed │ └─ Step 7: Map to Response └─ Return PostResponse[] with metadata Output: { items: 20 posts, total: 145, page: 1, pageSize: 20 } ``` -------------------------------- ### Request Flow for Page 26 (Failure) Source: https://github.com/i-love-u-3000/favi-be/blob/main/Favi-BE/Favi-BE.API/Docs/seed-pipeline/FEED-SCROLLING-LIMIT-EXPLAINED.md Shows why page 26 returns empty results: the service still fetches only the initial 500 posts, and the in-memory pagination offset exceeds the available data. ```text REQUEST #3: GET /api/posts/feed?page=26&pageSize=20 GetFeedPagedAsync(userId, skip=0, take=500) DB: Returns SAME [Post 1000-500] Filter + Score in memory (still 500 max) Paginate: skip=500, take=20 RETURN: [] ❌ Empty! Can't access Post 500-1! ```