Skip to content

Upgrade staging#181

Merged
elliotBraem merged 8 commits intomainfrom
staging
Jun 20, 2025
Merged

Upgrade staging#181
elliotBraem merged 8 commits intomainfrom
staging

Conversation

@elliotBraem
Copy link
Collaborator

@elliotBraem elliotBraem commented Jun 20, 2025

  • moderation can have platform_username or near account id
  • activity clean up
  • delete tests
  • curated by and approver for

Summary by CodeRabbit

  • New Features

    • Enhanced activity and moderation APIs with richer metadata, improved validation, and standardized response formats.
    • Expanded moderation history details, including moderator identity type and action source.
    • Added new activity type for content rejection.
    • Introduced new API query options for detailed user activity filtering and leaderboard parameters.
    • Added method to fetch moderations by NEAR account in moderation service.
  • Bug Fixes

    • Improved error handling and response consistency across activity and moderation endpoints.
  • Refactor

    • Unified and modernized API data schemas and types for activities, moderation, and feeds.
    • Streamlined user identification and authentication logic in activity endpoints.
    • Updated database schema to support new moderation fields and indexes.
    • Replaced raw SQL queries with structured query builder usage for leaderboard and activity stats.
    • Refactored API client hooks to align with updated backend API contracts and conditional fetching.
    • Consolidated upsert logic for user stats in database repository.
  • Chores

    • Removed legacy and redundant validation/type definitions.
    • Deleted all backend test files and related test utilities.
    • Cleaned up obsolete scripts and documentation.
    • Removed deprecated test seed data and configuration files.

@vercel
Copy link

vercel bot commented Jun 20, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
curatedotfun-app (staging) 🛑 Canceled (Inspect) Jun 20, 2025 9:54pm
1 Skipped Deployment
Name Status Preview Comments Updated (UTC)
curatedotfun-app ⬜️ Skipped (Inspect) Jun 20, 2025 9:54pm

@coderabbitai
Copy link

coderabbitai bot commented Jun 20, 2025

Walkthrough

This change set implements a comprehensive refactor and redesign of the activity, moderation, and submission APIs and their related data schemas. It transitions validation and typing to a new shared types package, updates database schemas (especially moderation history), and removes all backend test code and related seed/config files. The update also streamlines internal logic, enhances type safety, and standardizes API responses.

Changes

Files / Groups Change Summary
apps/api/src/routes/api/activity.ts, apps/api/src/routes/api/submission.ts Refactored route handlers to use new shared types and schemas, improved validation, error handling, and response formatting; updated moderation history mapping.
apps/api/src/services/activity.service.ts, apps/api/src/services/moderation.service.ts,
apps/api/src/services/submission.service.ts
Refactored service logic for new moderation and activity types, improved typing, added new moderation fetch logic, updated method signatures, and error handling.
apps/api/package.json Removed the "test" script entry.
apps/api/src/validation/activity.validation.ts Deleted file; validation schemas and types for activities and stats now moved to shared types package.
apps/api/test/... (all files and subfolders) Deleted all test suites, helpers, seed scripts, configs, and test data utilities.
apps/app/src/lib/api/activity.ts Refactored API hooks to use new types, schemas, and improved conditional query logic.
packages/shared-db/migrations/0015_ambiguous_the_watchers.sql,
meta/0015_snapshot.json,
meta/_journal.json
Migrated moderation history schema: renamed columns, added moderator/source fields, updated indexes and constraints, and added migration metadata.
packages/shared-db/src/repositories/activity.repository.ts,
moderation.repository.ts,
submission.repository.ts
Updated repository logic and typings for new moderation history structure and improved error handling; added new moderation fetch methods.
packages/shared-db/src/schema/activity.ts,
schema/moderation.ts
Added/updated Zod schemas and types for activity/moderation tables, new enums, and relations.
packages/shared-db/src/validators.ts Removed all activity, userStats, and feedUserStats schemas and types (now in schema files).
packages/types/src/api/activity.ts,
api/common.ts,
api/moderation.ts
Added new API schemas/types for activities, moderation, feeds, query options, and responses using Zod.
packages/types/src/domain/submission.ts Updated moderationHistory property to use new ModerationAction type; removed old interface.
packages/types/src/dtos/activity.dto.ts Deleted old DTO schemas/types for activity APIs.
packages/types/src/index.ts Changed export from old DTOs to new API activity schemas.
apps/api/src/utils/service-provider.ts Added initialization and registration of new ActivityService with required repositories and services.
apps/app/src/components/profile/overview/ApproverFor.tsx, CuratorFor.tsx Simplified Item components to accept FeedInfo data; added error handling and updated rendering logic.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant API_Route
    participant Service
    participant Repository
    participant TypesPkg

    Client->>API_Route: Request (e.g., GET /api/activity/user/:accountId)
    API_Route->>TypesPkg: Validate params/query with Zod schemas
    API_Route->>Service: Call getUserActivities(accountId, options)
    Service->>Repository: Fetch user, activities, moderation history
    Repository-->>Service: Return typed and validated data
    Service->>TypesPkg: Parse/validate results with shared schemas
    Service-->>API_Route: Return standardized response object
    API_Route->>TypesPkg: Wrap response in ActivityListResponseSchema
    API_Route-->>Client: JSON response { statusCode, success, data }
Loading

Possibly related PRs

  • PotLock/curatedotfun#171: Modifies submission API moderation history mapping similarly, updating fields and response structure.
  • PotLock/curatedotfun#118: Refactors backend database access to repository pattern, related to this PR's repository and service layer changes.

Poem

In the warren, code hops anew,
Old tests and seeds bid adieu.
Moderators named, their sources clear,
Activity flows—now crystal here!
With Zod and types, the fields align,
The schema’s fresh, the docs divine.
🐇✨ Hooray for a backend, robust and fine!

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
packages/shared-db/src/repositories/submission.repository.ts (1)

372-379: Fix formatting issue in pagination object.

While the logic is correct, there's a Prettier formatting failure that needs to be addressed. The pagination object formatting should be standardized.

#!/bin/bash
# Description: Fix formatting issues in the file
# Expected: Clean formatting after running prettier

npx prettier --write packages/shared-db/src/repositories/submission.repository.ts
apps/api/src/routes/api/activity.ts (1)

46-76: Consider extracting error handling into a helper function.

The error handling pattern is repeated multiple times throughout the file with similar logic for parsing ActivityServiceError vs validation errors vs generic errors.

Consider creating a helper function to reduce duplication:

+function handleActivityError(error: unknown, operation: string) {
+  if (error instanceof ActivityServiceError) {
+    return {
+      schema: ApiErrorResponseSchema.parse({
+        statusCode: error.statusCode as ContentfulStatusCode,
+        success: false,
+        error: { message: error.message },
+      }),
+      statusCode: error.statusCode as ContentfulStatusCode,
+    };
+  }
+  
+  const isValidationError = error instanceof Error && error.name === "ValidationError";
+  const message = isValidationError ? "Invalid query parameters" : `Failed to ${operation}`;
+  const statusCode = isValidationError ? 400 : 500;
+  
+  return {
+    schema: ApiErrorResponseSchema.parse({
+      statusCode,
+      success: false,
+      error: { message },
+    }),
+    statusCode,
+  };
+}
apps/app/src/lib/api/activity.ts (1)

40-71: Comprehensive query parameter support with minor optimization opportunity

The enhanced useUserActivity hook now supports rich filtering options. The parameter building logic is thorough and handles all the query options from GetUserActivitiesApiQuery.

Consider extracting the parameter building logic into a helper function for better readability:

+function buildUserActivityParams(options?: Partial<GetUserActivitiesApiQuery>): string {
+  const params = new URLSearchParams();
+  
+  if (options?.types)
+    params.append(
+      "types",
+      Array.isArray(options.types) ? options.types.join(",") : options.types,
+    );
+  if (options?.feed_id) params.append("feed_id", options.feed_id);
+  if (options?.from_date) params.append("from_date", options.from_date);
+  if (options?.to_date) params.append("to_date", options.to_date);
+  if (options?.limit) params.append("limit", options.limit.toString());
+  if (options?.offset) params.append("offset", options.offset.toString());
+  if (options?.sortBy) params.append("sortBy", options.sortBy);
+  if (options?.sortOrder) params.append("sortOrder", options.sortOrder);
+
+  return params.toString();
+}

 export function useUserActivity(
   userId: string | number,
   options?: Partial<GetUserActivitiesApiQuery>,
 ) {
-  const params = new URLSearchParams();
-
-  if (options?.types)
-    params.append(
-      "types",
-      Array.isArray(options.types) ? options.types.join(",") : options.types,
-    );
-  if (options?.feed_id) params.append("feed_id", options.feed_id);
-  if (options?.from_date) params.append("from_date", options.from_date);
-  if (options?.to_date) params.append("to_date", options.to_date);
-
-  if (options?.limit) params.append("limit", options.limit.toString());
-  if (options?.offset) params.append("offset", options.offset.toString());
-  if (options?.sortBy) params.append("sortBy", options.sortBy);
-  if (options?.sortOrder) params.append("sortOrder", options.sortOrder);
-
-  const queryString = params.toString();
+  const queryString = buildUserActivityParams(options);
   const path = `/activity/user/${userId}${queryString ? `?${queryString}` : ""}`;
apps/api/src/services/moderation.service.ts (1)

149-223: Improved variable naming and moderation source tracking

The changes to use moderatorNearId and moderatorAccountId for clarity are good. The addition of moderationSource logic properly distinguishes between super admin direct actions and UI-driven actions.

Consider making the platform determination more dynamic as noted in the TODO:

- const submissionPlatform = "twitter"; // TODO: dynamic, tied to source
+ const submissionPlatform = submission.platform || "twitter"; // Default to twitter for backward compatibility
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fbfd4c9 and b02e5c6.

📒 Files selected for processing (37)
  • apps/api/package.json (0 hunks)
  • apps/api/src/routes/api/activity.ts (13 hunks)
  • apps/api/src/routes/api/submission.ts (3 hunks)
  • apps/api/src/services/activity.service.ts (9 hunks)
  • apps/api/src/services/moderation.service.ts (11 hunks)
  • apps/api/src/services/submission.service.ts (0 hunks)
  • apps/api/src/validation/activity.validation.ts (0 hunks)
  • apps/api/test/README.md (0 hunks)
  • apps/api/test/component/approval-flow.test.ts (0 hunks)
  • apps/api/test/component/submission-flow.test.ts (0 hunks)
  • apps/api/test/curate.config.test.json (0 hunks)
  • apps/api/test/e2e/full-flow.test.ts (0 hunks)
  • apps/api/test/integration/database.test.ts (0 hunks)
  • apps/api/test/setup/seed-test.ts (0 hunks)
  • apps/api/test/setup/seed.sql (0 hunks)
  • apps/api/test/unit/sanitize.test.ts (0 hunks)
  • apps/api/test/unit/services/scheduler/scheduler.service.test.ts (0 hunks)
  • apps/api/test/utils/test-client.ts (0 hunks)
  • apps/api/test/utils/test-data.ts (0 hunks)
  • apps/api/test/utils/test-helpers.ts (0 hunks)
  • apps/api/test/utils/test-server.ts (0 hunks)
  • apps/app/src/lib/api/activity.ts (1 hunks)
  • packages/shared-db/migrations/0015_ambiguous_the_watchers.sql (1 hunks)
  • packages/shared-db/migrations/meta/0015_snapshot.json (1 hunks)
  • packages/shared-db/migrations/meta/_journal.json (1 hunks)
  • packages/shared-db/src/repositories/activity.repository.ts (2 hunks)
  • packages/shared-db/src/repositories/moderation.repository.ts (6 hunks)
  • packages/shared-db/src/repositories/submission.repository.ts (4 hunks)
  • packages/shared-db/src/schema/activity.ts (2 hunks)
  • packages/shared-db/src/schema/moderation.ts (4 hunks)
  • packages/shared-db/src/validators.ts (0 hunks)
  • packages/types/src/api/activity.ts (1 hunks)
  • packages/types/src/api/common.ts (1 hunks)
  • packages/types/src/api/moderation.ts (2 hunks)
  • packages/types/src/domain/submission.ts (3 hunks)
  • packages/types/src/dtos/activity.dto.ts (0 hunks)
  • packages/types/src/index.ts (1 hunks)
💤 Files with no reviewable changes (19)
  • apps/api/package.json
  • apps/api/src/services/submission.service.ts
  • apps/api/test/setup/seed-test.ts
  • apps/api/test/utils/test-client.ts
  • apps/api/test/utils/test-server.ts
  • apps/api/test/component/submission-flow.test.ts
  • apps/api/test/README.md
  • apps/api/test/unit/sanitize.test.ts
  • apps/api/test/setup/seed.sql
  • packages/shared-db/src/validators.ts
  • apps/api/test/curate.config.test.json
  • apps/api/test/utils/test-helpers.ts
  • apps/api/test/integration/database.test.ts
  • apps/api/test/unit/services/scheduler/scheduler.service.test.ts
  • apps/api/test/component/approval-flow.test.ts
  • apps/api/test/e2e/full-flow.test.ts
  • apps/api/src/validation/activity.validation.ts
  • apps/api/test/utils/test-data.ts
  • packages/types/src/dtos/activity.dto.ts
🧰 Additional context used
🪛 GitHub Actions: CI
packages/shared-db/src/repositories/submission.repository.ts

[error] 1-1: Prettier formatting check failed. Run 'prettier --write' to fix code style issues.

packages/shared-db/src/repositories/activity.repository.ts

[error] 1-1: Prettier formatting check failed. Run 'prettier --write' to fix code style issues.

🔇 Additional comments (48)
packages/shared-db/migrations/meta/_journal.json (1)

110-116: LGTM! Migration journal entry is properly formatted.

The new migration entry follows the expected format and corresponds to the moderation history schema changes mentioned in the AI summary.

packages/types/src/index.ts (1)

4-4: ```shell
#!/bin/bash
set -e

Re-verify that no files still import from the old DTO path in .ts and .tsx sources

rg "dtos/activity.dto" --glob ".ts" --glob ".tsx"


</details>
<details>
<summary>packages/shared-db/src/repositories/activity.repository.ts (2)</summary>

`3-11`: **Good practice: Separating type-only imports from runtime imports.**

The separation of type-only imports (`ActivityType`, `InsertActivity`, `UpdateFeedUserStats`, `UpdateUserStats`) from runtime value imports (`activityTypeZodEnum`) improves clarity and potentially helps with tree-shaking.

---

`757-764`: **Fix formatting issues to resolve pipeline failure.**

The formatting changes look fine functionally, but there's a Prettier formatting check failure in the pipeline that needs to be addressed.


```shell
#!/bin/bash
# Description: Check and fix Prettier formatting issues
# Expected: No formatting errors after running prettier --write

# Check current formatting
npx prettier --check packages/shared-db/src/repositories/activity.repository.ts

# Show what prettier would change
npx prettier packages/shared-db/src/repositories/activity.repository.ts
packages/shared-db/src/repositories/submission.repository.ts (1)

124-133: LGTM! Consistent update to moderation history mapping.

The changes correctly update the moderation history mapping from the old structure (tweetId, adminId) to the new enriched structure (submissionId, moderatorAccountId, moderatorAccountIdType, source). The pattern is consistently applied across all three methods.

Also applies to: 201-210, 325-334

packages/types/src/domain/submission.ts (2)

1-1: Good practice: Consolidating moderation types.

Importing ModerationAction from the shared API module instead of maintaining a local Moderation interface promotes type consistency and reduces duplication across the codebase.


32-32: ```shell
#!/bin/bash

Locate any local Moderation type/interface in the types package

rg -n "export (type|interface) Moderation" packages/types/src

Dump the ModerationActionSchema definition to review its fields

rg -n -A20 "export const ModerationActionSchema" packages/types/src/api/moderation.ts


</details>
<details>
<summary>packages/shared-db/migrations/0015_ambiguous_the_watchers.sql (4)</summary>

`1-3`: **Verify column renaming order and constraint handling.**

The migration renames columns before dropping constraints, which is correct. However, ensure that the constraint drop on line 3 references the original column name before the rename.

---

`26-27`: **Ensure data integrity before setting NOT NULL constraints.**

Setting columns to NOT NULL after data population is correct. The migration populates both new columns for all existing records, so this should be safe.

---

`29-31`: **Verify foreign key and index recreation.**

The new foreign key constraint correctly references the renamed column `submission_id` and maintains cascade deletion. The indexes are properly recreated with updated column names.

---

`15-24`: ```shell
#!/bin/bash
# Locate the creation of the moderation_history table and any FK on submission_id
echo "=== moderation_history table definition ==="
rg -n 'create table "moderation_history"' -A 20 packages/shared-db/migrations

echo
echo "=== FOREIGN KEY constraints involving submission_id ==="
rg -n 'foreign key.*submission_id' -A 5 packages/shared-db/migrations
apps/api/src/routes/api/submission.ts (4)

88-101: Excellent expansion of moderation history mapping.

The mapping correctly includes all new fields from the updated moderation schema:

  • moderatorAccountId, moderatorAccountIdType, source (new fields)
  • Proper date formatting with ISO strings
  • Safe handling of optional updatedAt field

The addition of null safety with (rs.moderationHistory ?? []) is a good defensive programming practice.


102-102: Good defensive programming with null safety.

Adding (rs.feeds ?? []) prevents potential runtime errors when feeds is null or undefined.


175-188: Consistent mapping implementation across endpoints.

The single submission endpoint uses identical mapping logic to the list endpoint, ensuring API consistency.


256-269: Feed-specific endpoint maintains consistency.

The feed submissions endpoint also implements the same expanded moderation history mapping, maintaining consistent API responses across all submission endpoints.

packages/types/src/api/common.ts (2)

46-60: Well-designed query options schema with proper validation.

The QueryOptionsSchema implementation is excellent:

  • String-to-number transformation handles HTTP query parameters correctly
  • Proper validation with min/max constraints
  • Optional parameters allow flexible API usage
  • Enum validation for sortOrder prevents invalid values

62-74: Comprehensive pagination schema design.

The PaginatedDataSchema provides a robust foundation for paginated API responses:

  • Generic item schema allows reuse across different data types
  • Includes all necessary pagination metadata
  • Optional convenience fields (totalPages, hasNextPage, hasPrevPage) enhance client-side experience
packages/types/src/api/moderation.ts (3)

12-21: Well-defined enums for moderation metadata.

The new enums are comprehensive and align with the PR objectives:

  • ModeratorAccountIdTypeEnum supports both "near" and "platform_username" as required
  • ModerationSourceEnum covers various moderation sources including UI, platform comments, auto-approval, and admin actions

These enums provide clear type safety and validation for moderation workflows.


27-29: Schema correctly updated to match database changes.

The ModerationActionSchema properly replaces adminId with the new moderation fields:

  • moderatorAccountId (string) - the identifier value
  • moderatorAccountIdType (enum) - specifies whether it's a NEAR account or platform username
  • source (enum) - tracks how the moderation action was initiated

This matches the database migration exactly.


46-46: Consistent schema updates for request types.

The CreateModerationRequestSchema is properly updated to use moderatorAccountId instead of adminId, maintaining consistency across the API contract.

packages/shared-db/migrations/meta/0015_snapshot.json (2)

1264-1403: Database schema snapshot correctly reflects migration changes.

The moderation_history table schema properly shows:

  • Column renames: submission_id (line 1274-1279) and moderator_account_id (line 1286-1291)
  • New columns: moderator_account_id_type (line 1292-1297) and source (line 1298-1303)
  • Updated indexes: moderation_history_submission_idx and moderation_history_moderator_account_idx
  • Correct foreign key: moderation_history_submission_id_submissions_tweet_id_fk

The schema snapshot accurately captures the migration results.


1405-1428: Enums properly defined in schema.

The database enums are correctly defined:

  • activity_type includes all expected activity types
  • submission_status maintains the standard pending/approved/rejected values
  • plugin_type covers all plugin categories

These align with the application type definitions.

apps/api/src/routes/api/activity.ts (3)

8-19: LGTM: Good refactoring to use shared types.

The transition from local validation schemas to the centralized @curatedotfun/types package improves consistency and type safety across the codebase.


179-184: Good change: Standardized NEAR account ID parameters.

The update from generic user ID to explicit NEAR account ID in the path parameter improves API clarity and aligns with the system's account model.


124-126: Verify authentication middleware sets accountId correctly.

The code assumes c.get("accountId") is always properly set by authentication middleware. Ensure the middleware consistently populates this value for all authenticated routes.

#!/bin/bash
# Description: Verify authentication middleware sets accountId in context
# Expected: Find middleware that sets accountId in context

rg -A 10 -B 5 "\.set.*accountId" --type ts
packages/shared-db/src/repositories/moderation.repository.ts (3)

1-6: LGTM: Good addition of schema validation.

The import of selectModerationHistorySchema and the or/inArray operators enables proper validation and the new flexible querying capabilities.


40-40: Excellent: Consistent schema validation across all methods.

Adding schema parsing to all return values ensures data integrity and proper type validation throughout the moderation operations.

Also applies to: 66-68, 95-95, 126-126


136-185: Well-implemented: New method supports PR objective.

The getModerationsLinkedToNearAccount method effectively addresses the requirement to enable moderation queries by either platform username or NEAR account ID. The logic correctly handles:

  • Direct NEAR account ID matching
  • Platform username array matching (when provided)
  • Proper conditional query construction with or

One minor suggestion for clarity:

+  /**
+   * Retrieves all moderation entries linked to a specific NEAR account,
+   * either directly or through their connected platform usernames.
+   * @param nearAccountId The NEAR account ID.
+   * @param platformUsernameStrings An array of formatted platform username strings (e.g., ["twitter:userA", "mastodon:userB@social.com"]).
+   * @returns Promise<SelectModerationHistory[]> Array of moderation entries, empty if none found.
+   */
packages/shared-db/src/schema/moderation.ts (3)

13-27: Well-designed: Comprehensive enum definitions.

The new enums moderatorAccountIdTypeSchema and moderationSourceSchema provide good type safety and cover the expected use cases:

  • Account ID types: "near" and "platform_username"
  • Sources: UI, platform comments, auto-approval, and super admin actions

33-42: Consistent field updates align with PR objectives.

The replacement of tweetId with submissionId and adminId with moderatorAccountId, plus the addition of moderatorAccountIdType and source fields, properly supports the enhanced moderation capabilities.


74-81: Proper schema validation for new fields.

The insert and select schemas correctly validate the new enum fields, ensuring data integrity at the application level.

Also applies to: 93-96

packages/shared-db/src/schema/activity.ts (2)

26-26: Good addition: CONTENT_REJECTION activity type.

Adding "CONTENT_REJECTION" to the activity types properly supports tracking rejection actions in the moderation workflow.


129-161: Excellent: Comprehensive schema validation.

The addition of Zod insert/update/select schemas for all activity-related tables provides:

  • Runtime validation for database operations
  • Type safety with proper TypeScript inference
  • Consistent handling of auto-generated fields (id, timestamps)

This follows best practices for schema-driven development.

packages/types/src/api/activity.ts (3)

1-187: Excellent: Comprehensive API schema design.

This new file provides a well-structured foundation for activity-related API validation and typing:

  • Clear separation of concerns (enums, core schemas, request params, responses)
  • Proper date handling with preprocessing for ISO string conversion
  • Comprehensive validation for query parameters with transformation
  • Standardized response schemas for consistent API contracts

The design follows Zod best practices and provides strong type safety.


132-158: Robust query parameter transformation.

The transform function for GetUserActivitiesApiQuerySchema handles edge cases well:

  • Proper string splitting and trimming for activity types
  • Validation against allowed enum values
  • Graceful handling of empty or invalid types
  • Sensible defaults for pagination parameters

31-46: Good date handling with preprocessing.

The use of z.preprocess to handle both Date objects and ISO strings ensures flexibility while maintaining strict datetime validation in the final schema.

apps/app/src/lib/api/activity.ts (3)

1-11: LGTM: Clean import structure with shared types

The migration to @curatedotfun/types improves type consistency across the codebase and centralizes type definitions.


28-37: Good authentication integration

Properly integrates isSignedIn state to conditionally enable user-specific queries, preventing unnecessary API calls when unauthenticated.


73-95: Consistent authentication pattern across user-specific hooks

Both useMyCuratedFeeds and useMyApprovedFeeds follow the same authentication pattern, which is good for consistency.

apps/api/src/services/moderation.service.ts (4)

47-68: Good simplification of authorization return type

Changing from an object with { isAuthorized: boolean; adminIdForHistory: string } to a simple boolean makes the method easier to use and understand. The moderatorNearId is now tracked directly in the calling method.


218-226: Enhanced moderation data structure with proper metadata

The addition of moderatorAccountIdType: "near" and source: moderationSource fields provides better tracking of moderation actions. The rename from tweetId to submissionId is more generic and appropriate.


486-508: Solid implementation of moderation lookup by NEAR account

The new getModerationsByNearAccount method properly integrates connected accounts to find all moderation actions linked to a NEAR account. The error handling for connected accounts lookup is appropriate.


510-533: Good encapsulation of connected accounts logic

Making getConnectedAccounts private and renaming it from getConnectedAccountsForUser improves encapsulation and clarity.

apps/api/src/services/activity.service.ts (5)

32-46: Good dependency injection and logging setup

The addition of ModerationService and UserService dependencies enables the enhanced functionality, and the child logger provides proper service-scoped logging.


90-115: Excellent moderation integration with proper error handling

The integration of moderation data is well-implemented:

  • Uses a Map for efficient lookup by submission ID
  • Includes comprehensive error handling that logs failures without interrupting the main flow
  • Properly handles the case where moderation data might not be available

112-115: Consistent schema parsing pattern

The two-step parsing approach (selectActivitySchema.parse() followed by ActivitySchema.parse()) ensures data consistency and type safety throughout the transformation pipeline.


127-135: Good type safety improvements across leaderboard methods

The updates to use GetLeaderboardApiQuery and return properly typed UserRankingLeaderboardEntry[] improve type safety and API consistency.


274-294: Consistent typing pattern for feed-related methods

Both getFeedsCuratedByUser and getFeedsApprovedByUser now return properly typed FeedInfo[] arrays with schema parsing, maintaining consistency with the broader type safety improvements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🔭 Outside diff range comments (1)
packages/shared-db/src/repositories/activity.repository.ts (1)

214-214: Fix unsafe IN clause construction.

The current implementation directly interpolates the array into SQL, which could lead to SQL injection if the types array contains malicious input.

Use Drizzle's inArray operator for safe parameterization:

-conditions.push(sql`${schema.activities.type} IN ${options.types}`);
+conditions.push(inArray(schema.activities.type, options.types));

Don't forget to import inArray from drizzle-orm.

🧹 Nitpick comments (1)
packages/shared-db/src/repositories/leaderboard.repository.ts (1)

47-72: Extract date range calculation to shared utility.

The date range calculation logic is duplicated between this file and activity.repository.ts. Consider extracting this to a shared utility function to follow the DRY principle.

Create a shared utility:

// In packages/shared-db/src/utils/dateRange.ts
export function getStartDateForTimeRange(timeRange: string): Date | null {
  const now = new Date();
  
  switch (timeRange) {
    case "day":
    case "today":
      return new Date(
        Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())
      );
    case "week":
      const startDate = new Date(now);
      const dayOfWeek = startDate.getUTCDay();
      const diff = startDate.getUTCDate() - dayOfWeek;
      startDate.setUTCDate(diff);
      startDate.setUTCHours(0, 0, 0, 0);
      return startDate;
    case "month":
      return new Date(
        Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1)
      );
    case "year":
      return new Date(Date.UTC(now.getUTCFullYear(), 0, 1));
    default: // "all"
      return null;
  }
}

Then use it in both repositories:

import { getStartDateForTimeRange } from "../utils/dateRange";

// Replace the switch statement with:
const startDate = getStartDateForTimeRange(timeRange);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b02e5c6 and e03f9bb.

📒 Files selected for processing (8)
  • packages/shared-db/migrations/0016_ambitious_blazing_skull.sql (1 hunks)
  • packages/shared-db/migrations/meta/0016_snapshot.json (1 hunks)
  • packages/shared-db/migrations/meta/_journal.json (1 hunks)
  • packages/shared-db/src/repositories/activity.repository.ts (5 hunks)
  • packages/shared-db/src/repositories/leaderboard.repository.ts (2 hunks)
  • packages/shared-db/src/repositories/submission.repository.ts (3 hunks)
  • packages/shared-db/src/schema/activity.ts (4 hunks)
  • packages/shared-db/src/schema/users.ts (2 hunks)
✅ Files skipped from review due to trivial changes (3)
  • packages/shared-db/src/schema/users.ts
  • packages/shared-db/migrations/meta/0016_snapshot.json
  • packages/shared-db/migrations/0016_ambitious_blazing_skull.sql
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/shared-db/migrations/meta/_journal.json
  • packages/shared-db/src/repositories/submission.repository.ts
  • packages/shared-db/src/schema/activity.ts
🔇 Additional comments (5)
packages/shared-db/src/repositories/activity.repository.ts (4)

3-11: Good separation of type-only imports from value imports.

This improves code clarity and can help with tree-shaking in the build process.


72-122: Excellent refactor to atomic upsert operations.

The change from manual existence checks to INSERT ... ON CONFLICT DO UPDATE provides several benefits:

  • Eliminates race conditions in concurrent environments
  • Reduces database round trips from 2 to 1
  • Simplifies the code and improves maintainability
  • Ensures atomic operations for counter increments

133-192: Well-structured refactor using query builder CTEs.

The conversion from raw SQL to typed query builder improves:

  • Type safety with schema references
  • Maintainability through clearer structure
  • Readability with named CTEs

The ranking logic correctly uses ROW_NUMBER() window functions ordered by counts.


318-377: Clean refactor with improved type safety.

The conversion to query builder with CTEs provides better type safety while maintaining the original logic. The date filtering and aggregation calculations are correctly preserved.

packages/shared-db/src/repositories/leaderboard.repository.ts (1)

74-193: Verify date filtering behavior for moderation counts.

The refactor looks great with improved type safety and maintainability. However, I notice that the date filter is only applied to submissions.createdAt but not to moderation history records. This means approvals/rejections that happened outside the date range will be counted if they're for submissions within the range.

Is this intentional behavior (counting all moderation actions on submissions from the time period) or should moderation actions also be filtered by date?

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
apps/api/src/services/activity.service.ts (1)

77-83: Excellent! NotFoundError implementation addresses previous feedback.

The implementation properly throws a NotFoundError when the user is not found, which addresses the previous review comment and improves API consistency.

🧹 Nitpick comments (1)
apps/api/src/services/activity.service.ts (1)

112-115: Consider if double schema parsing is necessary.

The code applies both selectActivitySchema.parse() and ActivitySchema.parse() to each activity. This double parsing may be redundant unless there's a specific transformation needed between the database schema and API schema.

If the schemas are compatible, consider simplifying to:

-      return activities.map((activity) => {
-        const parsedActivity = selectActivitySchema.parse(activity);
-        return ActivitySchema.parse(parsedActivity);
-      });
+      return activities.map((activity) => 
+        ActivitySchema.parse(activity)
+      );
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e03f9bb and bf21834.

📒 Files selected for processing (1)
  • apps/api/src/services/activity.service.ts (9 hunks)
🔇 Additional comments (9)
apps/api/src/services/activity.service.ts (9)

16-33: LGTM! Well-structured import refactoring.

The import changes properly support the transition to the shared types package and new service dependencies for enhanced moderation integration.


41-46: LGTM! Constructor properly supports new service dependencies.

The addition of ModerationService and UserService dependencies and enhanced logger initialization align well with the service's expanded functionality.


128-132: LGTM! Improved type safety with GetLeaderboardApiQuery.

The parameter type refinement enhances API consistency and type safety.


256-262: LGTM! Proper schema parsing implementation.

The schema parsing with UserRankingLeaderboardEntrySchema.parse() ensures data validation and type safety.


170-170: LGTM! Consistent schema parsing for type safety.

The addition of selectUserStatsSchema.parse() maintains consistency with the service's validation pattern.


216-216: LGTM! Consistent schema parsing for type safety.

The addition of selectFeedUserStatsSchema.parse() maintains consistency with the service's validation pattern.


274-277: LGTM! Enhanced type safety with FeedInfo schema.

The return type change to FeedInfo[] with proper schema parsing improves API consistency and type safety.


289-293: LGTM! Enhanced type safety with FeedInfo schema.

The return type change to FeedInfo[] with proper schema parsing improves API consistency and type safety.


308-314: LGTM! Enhanced type safety with UserFeedRanks schema.

The return type change to UserFeedRanks with proper schema parsing improves API consistency and type safety.

Comment on lines +90 to +110
let detailedModerationsMap = new Map();

try {
const detailedModerations =
await this.moderationService.getModerationsByNearAccount(accountId);
detailedModerations.forEach((modAction) => {
if (modAction.submissionId) {
if (!detailedModerationsMap.has(modAction.submissionId)) {
detailedModerationsMap.set(modAction.submissionId, modAction);
}
}
});
} catch (modError) {
this.logger.error(
{
accountId,
error: modError,
},
"Failed to fetch detailed moderations for activity feed.",
);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Unused moderation data - consider integrating or removing.

The detailed moderation data is fetched and stored in detailedModerationsMap but is never used in the activity processing or return statement. This creates unnecessary overhead and potentially confusing code.

Consider either:

  1. Integrating the moderation data into the returned activities
  2. Removing the unused moderation fetching logic
-      let detailedModerationsMap = new Map();
-
-      try {
-        const detailedModerations =
-          await this.moderationService.getModerationsByNearAccount(accountId);
-        detailedModerations.forEach((modAction) => {
-          if (modAction.submissionId) {
-            if (!detailedModerationsMap.has(modAction.submissionId)) {
-              detailedModerationsMap.set(modAction.submissionId, modAction);
-            }
-          }
-        });
-      } catch (modError) {
-        this.logger.error(
-          {
-            accountId,
-            error: modError,
-          },
-          "Failed to fetch detailed moderations for activity feed.",
-        );
-      }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let detailedModerationsMap = new Map();
try {
const detailedModerations =
await this.moderationService.getModerationsByNearAccount(accountId);
detailedModerations.forEach((modAction) => {
if (modAction.submissionId) {
if (!detailedModerationsMap.has(modAction.submissionId)) {
detailedModerationsMap.set(modAction.submissionId, modAction);
}
}
});
} catch (modError) {
this.logger.error(
{
accountId,
error: modError,
},
"Failed to fetch detailed moderations for activity feed.",
);
}
// ... previous activity fetching logic above
// (Removed unused moderation fetching logic)
// ... continue processing activities below
🤖 Prompt for AI Agents
In apps/api/src/services/activity.service.ts around lines 90 to 110, the
detailedModerationsMap is populated but never used afterward, causing
unnecessary overhead. To fix this, either integrate the moderation data from
detailedModerationsMap into the activity processing or the return value where
relevant, or remove the entire try-catch block and related variables fetching
detailed moderation data if it is not needed.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
apps/app/src/components/profile/overview/CuratorFor.tsx (2)

16-18: Same commented code issue as ApproverFor.

Consider removing this commented code or converting to a proper TODO if the points feature is planned.


9-9: Same TODO comment as ApproverFor.

Consider addressing the default image fallback consistently across both components.

🧹 Nitpick comments (2)
apps/app/src/components/profile/overview/ApproverFor.tsx (2)

16-18: Remove commented code or track as proper TODO.

The commented-out points rendering appears to be dead code. Either remove it completely or convert it to a proper TODO comment if the feature is planned for future implementation.

-      {/* <h5 className="text-lg sm:text-xl font-[900] text-black shrink-0">
-        {(feed as any).points}
-      </h5> */}

9-9: Address the TODO comment.

The fallback image path suggests incomplete work. Consider using a more appropriate default image or tracking this as a proper issue.

Would you like me to help create a proper issue to track finding a better default image for feeds?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bf21834 and 26c2b29.

📒 Files selected for processing (5)
  • apps/api/src/utils/service-provider.ts (2 hunks)
  • apps/app/src/components/profile/overview/ApproverFor.tsx (2 hunks)
  • apps/app/src/components/profile/overview/CuratorFor.tsx (2 hunks)
  • packages/shared-db/src/repositories/activity.repository.ts (7 hunks)
  • packages/types/src/api/activity.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/shared-db/src/repositories/activity.repository.ts
  • packages/types/src/api/activity.ts
🔇 Additional comments (7)
apps/api/src/utils/service-provider.ts (2)

2-2: LGTM! Repository imports added correctly.

The new imports for ActivityRepository and LeaderboardRepository are properly added to support the ActivityService initialization.

Also applies to: 4-4


150-160: ActivityService initialization looks good.

The service is properly initialized with all required dependencies (repositories, services, database, logger) and follows the established pattern used by other services in this provider. The service registration ensures it's available for dependency injection throughout the application.

apps/app/src/components/profile/overview/ApproverFor.tsx (3)

1-1: Good type safety improvement.

Using FeedInfo from the shared types package improves type consistency across the application and aligns with the PR's goal of standardizing data schemas.


4-4: Component simplification improves maintainability.

The refactored Item component with a single data prop reduces complexity and prop drilling while maintaining type safety with the FeedInfo interface.

Also applies to: 9-9, 13-13


42-46: Good error handling addition.

The error state provides users with clear feedback when feed fetching fails, improving the user experience.

apps/app/src/components/profile/overview/CuratorFor.tsx (2)

2-2: Consistent refactoring with ApproverFor component.

The changes mirror the improvements in ApproverFor.tsx, using FeedInfo type for better type safety and simplifying the component structure. This consistency is good for maintainability.

Also applies to: 4-4, 9-9, 13-13


42-46: Error handling implementation matches ApproverFor.

The error state handling is consistent with the other component, providing a uniform user experience across both curator and approver views.

Also applies to: 47-47, 53-53

@elliotBraem elliotBraem merged commit fee0deb into main Jun 20, 2025
6 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant