| name | community-metrics |
| description | Create new community metrics by adding enum values, recording functions, wiring, backfill migrations, and API integration. Use when adding new community metrics, creating metrics, or tracking community activity. Use when this capability is needed. |
| metadata | {"author":"6529-collections"} |
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.yaml in /community-metrics endpoint
- 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)
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.ts in createDrop()
- Wave participation:
waves.api.service.ts in multiple methods
- Ratings:
ratings.api.service.ts in rating submission methods
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 {
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,
);
}
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.sql
migrations/TIMESTAMP-backfill-metric-name-metric.down.sql
In the .up.sql file, write SQL to backfill historical data. Common pattern:
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() {
}
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:
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 {
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:
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.yaml in project root
Example: Adding "Comments Created" Metric
- Enum: Add
COMMENTS_CREATED to MetricRollupHourMetric
- Recorder:
async recordCommentCreated() { await this.recordMetric(MetricRollupHourMetric.COMMENTS_CREATED); }
- Wiring: Call in
comments.api.service.ts after comment creation
- Backfill: Aggregate from
comments table grouped by hour
- OpenAPI: Add
comments_created: integer to response
- Service: SUM all
COMMENTS_CREATED values
Next Steps
- Use
AskUserQuestion to 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.