Creating New Community Metrics
This skill guides you through the complete process of creating a new community metric in the 6529 SEIZE Backend.
Overview
Community metrics track various activities and statistics. Creating a new metric involves six steps:
- Add enum value to
MetricRollupHourMetric - Create recording function in
MetricsRecorder - Wire up the recorder in relevant code locations
- Create backfill migration for historical data
- Add field to
openapi.yamlin/community-metricsendpoint - Wire up metric field in
CommunityMetricsService.getCommunityMetricsSummary
Required Information
Before implementing, gather these details using AskUserQuestion:
1. Metric Name
- What should the metric be called?
- Use UPPER_SNAKE_CASE for the enum value
- Example:
DROPS_CREATED,WAVE_PARTICIPATIONS,RATINGS_GIVEN
2. Recording Function Arguments
- What parameters does the recording function need?
- Common patterns:
- Simple counter:
recordMetric(metric: MetricRollupHourMetric) - With entity ID:
recordMetric(metric: MetricRollupHourMetric, entityId: string) - With amount:
recordMetric(metric: MetricRollupHourMetric, amount: number) - With identity:
recordMetric(metric: MetricRollupHourMetric, identityId: string)
- Simple counter:
3. Recording Locations
- Where in the codebase should this metric be recorded?
- Consider:
- Which API endpoints create/modify the tracked activity?
- Which background loops process related data?
- Which services handle the business logic?
- Examples:
- Drop creation:
drops.api.service.tsincreateDrop() - Wave participation:
waves.api.service.tsin multiple methods - Ratings:
ratings.api.service.tsin rating submission methods
- Drop creation:
4. Summary Aggregation Strategy
- How should the metric be aggregated in
getCommunityMetricsSummary? - Options:
- Sum: Total count across all time (e.g., total drops created)
- Count: Number of distinct occurrences
- Average: Mean value over time
- Latest: Most recent value
- Custom: Complex calculation requiring joins or subqueries
Implementation Steps
Step 1: Add Enum Value
Find MetricRollupHourMetric (likely in src/entities/ or src/enums/) and add the new metric:
export enum MetricRollupHourMetric {
// ... existing metrics
NEW_METRIC_NAME = 'NEW_METRIC_NAME'
}
Step 2: Create Recording Function
In MetricsRecorder class (find with Glob or Grep), add a method to record the metric:
async recordNewMetricName(args: any): Promise<void> {
await this.recordMetric(
MetricRollupHourMetric.NEW_METRIC_NAME,
// additional arguments as needed
);
}
Step 3: Wire Up Recording
In the identified locations, call the recording function:
await this.metricsRecorder.recordNewMetricName(args);
Important: Ensure MetricsRecorder is available in the service. Check constructor for dependency injection.
Step 4: Create Backfill Migration
Run the migration command:
npm run migrate:new backfill-metric-name-metric
This creates two files:
migrations/TIMESTAMP-backfill-metric-name-metric.up.sqlmigrations/TIMESTAMP-backfill-metric-name-metric.down.sql
In the .up.sql file, write SQL to backfill historical data. Common pattern:
-- Insert historical metric data
INSERT INTO metric_rollup_hour (metric, hour, value, created_at)
SELECT
'NEW_METRIC_NAME' as metric,
DATE_FORMAT(created_at, '%Y-%m-%d %H:00:00') as hour,
COUNT(*) as value,
NOW() as created_at
FROM relevant_table
WHERE created_at IS NOT NULL
GROUP BY DATE_FORMAT(created_at, '%Y-%m-%d %H:00:00')
ON DUPLICATE KEY UPDATE
value = VALUES(value);
Delete the .down.sql file and update the .js migration file to do nothing in the down migration:
async down() {
// Do nothing - we don't rollback metric backfills
}
Step 5: Update OpenAPI Schema
Find /community-metrics endpoint in openapi.yaml and add the new field to the response schema:
CommunityMetricsSummary:
type: object
properties:
# ... existing metrics
new_metric_name:
type: integer
description: Description of what this metric represents
After editing, regenerate types:
cd src/api-serverless && npm run restructure-openapi && npm run generate
Step 6: Wire Up in CommunityMetricsService
Find CommunityMetricsService.getCommunityMetricsSummary and add the metric aggregation based on the chosen strategy:
For Sum Strategy:
const newMetricName = await this.db.execute<{total: number}>(
`SELECT COALESCE(SUM(value), 0) as total
FROM metric_rollup_hour
WHERE metric = :metric`,
{ metric: MetricRollupHourMetric.NEW_METRIC_NAME }
);
return {
// ... existing metrics
new_metric_name: newMetricName[0]?.total ?? 0
};
For Custom Strategy: Implement the specific SQL query needed for the aggregation logic.
Verification Checklist
After implementation, verify:
- Enum value added to
MetricRollupHourMetric - Recording function created in
MetricsRecorder - Recording function called in all identified locations
- Backfill migration created and SQL written
- OpenAPI schema updated with new field
- Types regenerated (
npm run restructure-openapi && npm run generate) - Aggregation logic added to
getCommunityMetricsSummary - Tests pass (
npm test) - Code builds (
npm run build)
Common Patterns
Pattern: Simple Activity Counter
- Use For: Counting occurrences (drops created, votes cast)
- Arguments: Just the metric enum
- Aggregation: SUM of all values
Pattern: Identity-Specific Metric
- Use For: Tracking per-user activity
- Arguments: Metric enum + identity ID
- Aggregation: SUM or COUNT with GROUP BY identity
Pattern: Weighted Metric
- Use For: Metrics with varying values (reputation changes, token amounts)
- Arguments: Metric enum + amount
- Aggregation: SUM of amounts
Files to Locate
Use these search patterns to find relevant files:
MetricRollupHourMetric:Grep "enum MetricRollupHourMetric"MetricsRecorder:Glob "**/*MetricsRecorder*"CommunityMetricsService:Glob "**/CommunityMetricsService*"- Migration files: Check
migrations/directory - OpenAPI:
openapi.yamlin project root
Example: Adding "Comments Created" Metric
- Enum: Add
COMMENTS_CREATEDtoMetricRollupHourMetric - Recorder:
async recordCommentCreated() { await this.recordMetric(MetricRollupHourMetric.COMMENTS_CREATED); } - Wiring: Call in
comments.api.service.tsafter comment creation - Backfill: Aggregate from
commentstable grouped by hour - OpenAPI: Add
comments_created: integerto response - Service: SUM all
COMMENTS_CREATEDvalues
Next Steps
- Use
AskUserQuestionto gather the four required pieces of information - Search the codebase to locate the necessary files
- Implement each step in order
- Run tests and build to verify
- Create migration and test backfill locally if possible
Converted and distributed by TomeVault — claim your Tome and manage your conversions.