### 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!
```