Skip to content

Conversation

@drifter089
Copy link
Owner

@drifter089 drifter089 commented Jan 2, 2026

Summary

Refactored type definitions to eliminate duplications and establish single sources of truth for Prisma enums and tRPC output types.

Key Changes

  • Prisma enums: Import and re-export Cadence and GoalType from @prisma/client instead of manually redefining them
  • tRPC types: Use RouterOutputs directly with inline type aliases instead of centralized wrapper file
  • Removed src/types/dashboard.ts: Unnecessary abstraction layer that only wrapped tRPC types
  • Server-side util: Added note explaining why manual type definition is needed to avoid circular dependency

Benefits

  • Single source of truth prevents type drift
  • Automatic propagation of Prisma schema changes
  • Simpler, more maintainable codebase
  • Type-safe with zero compilation errors

Summary by CodeRabbit

  • New Features

    • Enhanced dashboard charts hook: added loading, error and processing state helpers for better UI feedback.
  • Refactor

    • Centralized and adjusted type sourcing across dashboard and metric components for cleaner type management.
    • Switched cadence and goal type exports to shared enum definitions to unify usages.
  • Documentation

    • Added clarifying JSDoc about chart typing to avoid circular references.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Jan 2, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
org-os Ready Ready Preview, Comment Jan 5, 2026 5:52am

@coderabbitai
Copy link

coderabbitai bot commented Jan 2, 2026

📝 Walkthrough

Walkthrough

This PR replaces a centralized exported DashboardChartWithRelations type with locally defined aliases derived from tRPC RouterOutputs across dashboard and metric components, re-exports Prisma enums (Cadence, GoalType), expands the use-dashboard-charts hook return types, and removes the central src/types/dashboard.ts alias.

Changes

Cohort / File(s) Summary
Dashboard components with local type aliasing
src/app/dashboard/[teamId]/_components/dashboard-metric-card.tsx, src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx, src/app/dashboard/[teamId]/_components/metric-settings-drawer.tsx
Removed import of DashboardChartWithRelations from src/types/dashboard; added import { type RouterOutputs } from "@/trpc/react" and local type DashboardChartWithRelations = RouterOutputs["dashboard"]["getDashboardCharts"][number].
Dashboard hook with expanded public API
src/app/dashboard/[teamId]/_components/use-dashboard-charts.ts
Replaced external DashboardChartWithRelations with local RouterOutputs-derived alias; expanded UseDashboardChartsReturn to include isLoading, isError, isProcessing(metricId), and getError(metricId) alongside charts.
Metric components with local type aliasing
src/app/metric/_components/base/MetricDialogBase.tsx, src/app/metric/_components/manual/ManualMetricContent.tsx
Switched from importing DashboardChartWithRelations from src/types/dashboard to a local alias derived from RouterOutputs; updated imports to import { type RouterOutputs, api } from "@/trpc/react".
Type exports — Prisma migration
src/lib/goals/types.ts, src/lib/metrics/transformer-types.ts
Removed local Cadence/GoalType string-union types; imported and re-exported Prisma enums (import { Cadence, GoalType } from "@prisma/client" / export { Cadence }).
Type centralization removal
src/types/dashboard.ts
Deleted exported DashboardChartWithRelations type alias and its RouterOutputs dependency.
Documentation note
src/server/api/utils/enrich-charts-with-goal-progress.ts
Added JSDoc comments noting DashboardChartWithRelations must be defined manually to avoid circular AppRouter dependency; no runtime changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I nibble at types, tidy and spry,
From shared export to local sky,
Prisma enums hop in to try,
No loops, just clean type-sunset high. ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main objective of the changeset: eliminating type duplications and establishing single sources of truth by replacing locally defined types with imports from Prisma and using inline tRPC type aliases.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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

Comment @coderabbitai help to get the list of available commands and usage tips.

@claude
Copy link
Contributor

claude bot commented Jan 2, 2026

Code Review

Summary

This is an excellent refactoring that eliminates type duplication and establishes single sources of truth. The approach is clean, well-documented, and follows TypeScript best practices.

✅ Strengths

  1. Single Source of Truth: Properly imports Prisma enums instead of manually redefining them, preventing type drift
  2. Inline Type Aliases: Moving DashboardChartWithRelations to inline definitions is the right pattern for tRPC-derived types
  3. Circular Dependency Handling: Excellent note in enrich-charts-with-goal-progress.ts:13-14 explaining why the manual type definition is needed
  4. Clean Migration: All 6 files using DashboardChartWithRelations were correctly updated with inline type aliases
  5. Consistent Pattern: All inline type definitions use the exact same pattern:
    type DashboardChartWithRelations =
      RouterOutputs["dashboard"]["getDashboardCharts"][number];

🔍 Code Quality

Type Safety: ✅ No compilation errors, proper type inference maintained

Import Organization: ✅ Clean imports with inline type imports where used

Documentation: ✅ Clear explanatory comments added

Backwards Compatibility: ✅ No breaking changes - all type references work identically

🎯 Verification

I verified that:

  • ✅ All Prisma enum values match (DAILY/WEEKLY/MONTHLY, ABSOLUTE/RELATIVE)
  • ✅ All 6 previous consumers of src/types/dashboard.ts were updated
  • ✅ No remaining manual type definitions for these enums exist (checked codebase)
  • ✅ The pattern is consistent across all files

📋 Observations

  1. String literal usage: I noticed many places in the codebase still use string literals like "DAILY" | "WEEKLY" | "MONTHLY" for type guards and AI prompts. This is acceptable since:

    • Type guards need runtime string checks anyway
    • AI-facing code uses strings for clarity
    • These aren't type definitions, just usage
  2. Test Coverage: Consider adding a simple test to verify Prisma enum imports work as expected, though not critical for this PR

🚀 Recommendation

LGTM - Approve and merge

This refactoring delivers exactly what it promises: eliminates duplication, establishes single sources of truth, and improves maintainability. The code is production-ready.

💡 Minor Suggestion (Optional)

Consider documenting this pattern in CLAUDE.md for future reference:

## Type System Patterns

- **Prisma Enums**: Always import from @prisma/client, never redefine
- **tRPC Types**: Use inline RouterOutputs type aliases instead of centralized files
- **Server Utils**: Manual type definitions are OK when needed to avoid circular deps (document why)

Great work! 🎉

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 (3)
src/app/metric/_components/base/MetricDialogBase.tsx (1)

19-20: Type alias duplication noted.

This type alias is duplicated across multiple files. See the refactoring suggestion in dashboard-metric-drawer.tsx (lines 22-23).

src/app/dashboard/[teamId]/_components/dashboard-metric-card.tsx (1)

21-22: Type alias duplication noted.

This type alias is duplicated across multiple files. See the refactoring suggestion in dashboard-metric-drawer.tsx (lines 22-23).

src/app/metric/_components/manual/ManualMetricContent.tsx (1)

15-16: Type alias duplication noted.

This type alias is duplicated across multiple files. See the refactoring suggestion in dashboard-metric-drawer.tsx (lines 22-23).

🧹 Nitpick comments (1)
src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx (1)

22-23: Consider extracting the duplicated type alias to a shared location.

This type alias RouterOutputs["dashboard"]["getDashboardCharts"][number] is now defined identically in at least 4 files (dashboard-metric-drawer.tsx, dashboard-metric-card.tsx, MetricDialogBase.tsx, ManualMetricContent.tsx). While deriving from RouterOutputs achieves the PR's goal of a single source of truth, the duplication of the alias definition itself creates maintenance overhead.

Consider creating a shared types file (e.g., src/app/dashboard/[teamId]/_components/types.ts) that exports this alias once, then import it where needed. This would maintain the benefits of RouterOutputs derivation while following DRY principles.

💡 Example shared types file
// src/app/dashboard/[teamId]/_components/types.ts
import type { RouterOutputs } from "@/trpc/react";

export type DashboardChartWithRelations =
  RouterOutputs["dashboard"]["getDashboardCharts"][number];

Then in each component:

-import { type RouterOutputs, api } from "@/trpc/react";
+import { api } from "@/trpc/react";
+import type { DashboardChartWithRelations } from "./types";

-type DashboardChartWithRelations =
-  RouterOutputs["dashboard"]["getDashboardCharts"][number];
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2afa9b1 and 0113a03.

📒 Files selected for processing (10)
  • src/app/dashboard/[teamId]/_components/dashboard-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
  • src/app/dashboard/[teamId]/_components/metric-settings-drawer.tsx
  • src/app/dashboard/[teamId]/_components/use-dashboard-charts.ts
  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/metric/_components/manual/ManualMetricContent.tsx
  • src/lib/goals/types.ts
  • src/lib/metrics/transformer-types.ts
  • src/server/api/utils/enrich-charts-with-goal-progress.ts
  • src/types/dashboard.ts
💤 Files with no reviewable changes (1)
  • src/types/dashboard.ts
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Use TypeScript 5.9 with strict type checking for all frontend and backend code

Files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/metric/_components/manual/ManualMetricContent.tsx
  • src/lib/metrics/transformer-types.ts
  • src/server/api/utils/enrich-charts-with-goal-progress.ts
  • src/app/dashboard/[teamId]/_components/dashboard-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/metric-settings-drawer.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
  • src/app/dashboard/[teamId]/_components/use-dashboard-charts.ts
  • src/lib/goals/types.ts
src/**/*.tsx

📄 CodeRabbit inference engine (GEMINI.md)

Prefer Server Components for initial data fetching; use Client Components ('use client') only for interactivity

Files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/metric/_components/manual/ManualMetricContent.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/metric-settings-drawer.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
src/**/*/*.tsx

📄 CodeRabbit inference engine (GEMINI.md)

Client Components must use import { api } from '@/trpc/react' for standard HTTP/Hooks wrapper

Files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/metric/_components/manual/ManualMetricContent.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/metric-settings-drawer.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
**/*.tsx

📄 CodeRabbit inference engine (GEMINI.md)

Use Tailwind CSS 4 for styling with shadcn/ui and Radix UI primitive components

Files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/metric/_components/manual/ManualMetricContent.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/metric-settings-drawer.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
src/app/**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

src/app/**/*.tsx: Use the dual tRPC API pattern: direct calls in Server Components (api.team.getById) for 10x faster performance, and React hooks in Client Components (api.team.getById.useQuery)
Use getUserDisplayName(userId, members) utility (client-side sync) from @/lib/helpers/get-user-name for displaying user names in components

Files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/metric/_components/manual/ManualMetricContent.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/metric-settings-drawer.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
src/app/metric/_components/**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

src/app/metric/_components/**/*.tsx: Create metric dialogs with pattern: [Provider]MetricDialog.tsx (dialog wrapper) + [Provider]MetricContent.tsx (form content) in src/app/metric/_components/[provider]/, then register in index.ts
Use shared MetricDialogBase component from base/ for all metric dialog implementations

Files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/metric/_components/manual/ManualMetricContent.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use @trivago/prettier-plugin-sort-imports with inline type imports for import organization

Files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/metric/_components/manual/ManualMetricContent.tsx
  • src/lib/metrics/transformer-types.ts
  • src/server/api/utils/enrich-charts-with-goal-progress.ts
  • src/app/dashboard/[teamId]/_components/dashboard-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/metric-settings-drawer.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
  • src/app/dashboard/[teamId]/_components/use-dashboard-charts.ts
  • src/lib/goals/types.ts
src/lib/metrics/**/*.ts

📄 CodeRabbit inference engine (GEMINI.md)

Metric transformation logic should be organized in src/lib/metrics/ to support the 3-stage pipeline: Ingestion → Aggregation → Visualization

Files:

  • src/lib/metrics/transformer-types.ts
src/server/api/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

src/server/api/**/*.ts: Use fetchUserDisplayName(userId) utility (server-side async WorkOS) from @/server/api/utils/get-user-display-name for server-side user name retrieval
Use enrichRolesWithUserNames() for flat role arrays and enrichChartRolesWithUserNames() for nested chart roles from src/server/api/utils/organization-members.ts

Files:

  • src/server/api/utils/enrich-charts-with-goal-progress.ts
src/app/**/*.ts

📄 CodeRabbit inference engine (GEMINI.md)

src/app/**/*.ts: Server Components must use import { api } from '@/trpc/server' for direct DB calls without HTTP overhead
For API routes with cron jobs and webhooks, ensure proper authentication and input validation

Files:

  • src/app/dashboard/[teamId]/_components/use-dashboard-charts.ts
🧠 Learnings (20)
📓 Common learnings
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.165Z
Learning: Applies to src/app/(metric|dashboard)/**/*.tsx : Use three-stage metrics transformation: API → DataPoints (DataIngestionTransformer), DataPoints → ChartConfig (ChartTransformer), ChartConfig → UI (DashboardMetricChart)
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to src/components/dashboard-metric-card.tsx,src/app/dashboard/[teamId]/_components/public-dashboard-metric-card.tsx : Dashboard metric cards are duplicated with public variant. Consolidate into single component with `readOnly` mode prop instead of maintaining separate components.
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.165Z
Learning: Applies to src/hooks/**/*.ts : For role-metric cache updates, optimistically update both role cache (role.getByTeamId) and dashboard cache (dashboard.getDashboardCharts) to maintain UI consistency
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.165Z
Learning: Applies to src/app/**/*.tsx : Use the dual tRPC API pattern: direct calls in Server Components (api.team.getById) for 10x faster performance, and React hooks in Client Components (api.team.getById.useQuery)
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to src/app/dashboard/[teamId]/**/*.{ts,tsx} : Dashboard cache updates for role-metric assignments must update both `role.getByTeamId` and `dashboard.getDashboardCharts` caches during mutations. Use onMutate for optimistic updates on both caches, then invalidate both on success.
📚 Learning: 2025-12-29T21:27:04.176Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.176Z
Learning: Applies to src/app/metric/_components/**/*.tsx : Use shared MetricDialogBase component from base/ for all metric dialog implementations

Applied to files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/metric/_components/manual/ManualMetricContent.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/metric-settings-drawer.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
  • src/app/dashboard/[teamId]/_components/use-dashboard-charts.ts
📚 Learning: 2025-12-29T21:27:04.176Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.176Z
Learning: Applies to src/app/metric/_components/**/*.tsx : Create metric dialogs with pattern: [Provider]MetricDialog.tsx (dialog wrapper) + [Provider]MetricContent.tsx (form content) in src/app/metric/_components/[provider]/, then register in index.ts

Applied to files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/metric/_components/manual/ManualMetricContent.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/metric-settings-drawer.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
📚 Learning: 2025-12-29T12:52:42.935Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to src/app/metric/_components/**/*.tsx : Metric dialog components should follow the pattern: [Provider]MetricDialog.tsx (dialog wrapper) and [Provider]MetricContent.tsx (form content). Register in src/app/metric/_components/index.ts and inherit from shared MetricDialogBase.

Applied to files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/metric/_components/manual/ManualMetricContent.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/metric-settings-drawer.tsx
📚 Learning: 2025-12-29T21:27:04.176Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.176Z
Learning: Applies to src/app/(metric|dashboard)/**/*.tsx : Use three-stage metrics transformation: API → DataPoints (DataIngestionTransformer), DataPoints → ChartConfig (ChartTransformer), ChartConfig → UI (DashboardMetricChart)

Applied to files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/metric/_components/manual/ManualMetricContent.tsx
  • src/lib/metrics/transformer-types.ts
  • src/server/api/utils/enrich-charts-with-goal-progress.ts
  • src/app/dashboard/[teamId]/_components/dashboard-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/metric-settings-drawer.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
  • src/app/dashboard/[teamId]/_components/use-dashboard-charts.ts
📚 Learning: 2025-12-29T12:52:42.935Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to src/app/metric/_components/**/*.tsx : Metric dialog components have nearly identical wrapper patterns (5 files). Consider implementing a factory pattern or generic wrapper to reduce duplication across provider dialogs.

Applied to files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/metric/_components/manual/ManualMetricContent.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/metric-settings-drawer.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
📚 Learning: 2025-12-29T12:52:42.935Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to src/components/dashboard-metric-card.tsx,src/app/dashboard/[teamId]/_components/public-dashboard-metric-card.tsx : Dashboard metric cards are duplicated with public variant. Consolidate into single component with `readOnly` mode prop instead of maintaining separate components.

Applied to files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/metric/_components/manual/ManualMetricContent.tsx
  • src/server/api/utils/enrich-charts-with-goal-progress.ts
  • src/app/dashboard/[teamId]/_components/dashboard-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/metric-settings-drawer.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
  • src/app/dashboard/[teamId]/_components/use-dashboard-charts.ts
📚 Learning: 2025-12-29T12:52:42.935Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to src/app/dashboard/[teamId]/**/*.{ts,tsx} : Dashboard cache updates for role-metric assignments must update both `role.getByTeamId` and `dashboard.getDashboardCharts` caches during mutations. Use onMutate for optimistic updates on both caches, then invalidate both on success.

Applied to files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/metric/_components/manual/ManualMetricContent.tsx
  • src/server/api/utils/enrich-charts-with-goal-progress.ts
  • src/app/dashboard/[teamId]/_components/dashboard-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/metric-settings-drawer.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
  • src/app/dashboard/[teamId]/_components/use-dashboard-charts.ts
📚 Learning: 2025-12-29T21:27:04.165Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.165Z
Learning: Applies to src/hooks/**/*.ts : For role-metric cache updates, optimistically update both role cache (role.getByTeamId) and dashboard cache (dashboard.getDashboardCharts) to maintain UI consistency

Applied to files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/metric/_components/manual/ManualMetricContent.tsx
  • src/server/api/utils/enrich-charts-with-goal-progress.ts
  • src/app/dashboard/[teamId]/_components/dashboard-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/metric-settings-drawer.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
  • src/app/dashboard/[teamId]/_components/use-dashboard-charts.ts
📚 Learning: 2025-12-20T22:12:00.576Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-20T22:12:00.576Z
Learning: Applies to src/lib/metrics/**/*.ts : Metric transformation logic should be organized in `src/lib/metrics/` to support the 3-stage pipeline: Ingestion → Aggregation → Visualization

Applied to files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/metric/_components/manual/ManualMetricContent.tsx
  • src/lib/metrics/transformer-types.ts
  • src/server/api/utils/enrich-charts-with-goal-progress.ts
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
📚 Learning: 2025-12-20T22:12:00.576Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-20T22:12:00.576Z
Learning: Applies to src/**/*/*.tsx : Client Components must use `import { api } from '@/trpc/react'` for standard HTTP/Hooks wrapper

Applied to files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/metric/_components/manual/ManualMetricContent.tsx
  • src/app/dashboard/[teamId]/_components/use-dashboard-charts.ts
📚 Learning: 2025-12-29T12:52:42.935Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to **/*.{ts,tsx} : For client components using tRPC, use the React Query pattern with `import { api } from '@/trpc/react'` and access data via `api.[router].[procedure].useQuery()`. For server components, use direct calls with `import { api } from '@/trpc/server'` and await the result.

Applied to files:

  • src/app/metric/_components/manual/ManualMetricContent.tsx
  • src/app/dashboard/[teamId]/_components/use-dashboard-charts.ts
📚 Learning: 2025-12-29T21:27:04.176Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.176Z
Learning: Applies to src/app/**/*.tsx : Use the dual tRPC API pattern: direct calls in Server Components (api.team.getById) for 10x faster performance, and React hooks in Client Components (api.team.getById.useQuery)

Applied to files:

  • src/app/metric/_components/manual/ManualMetricContent.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
  • src/app/dashboard/[teamId]/_components/use-dashboard-charts.ts
📚 Learning: 2025-12-20T22:12:00.576Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-20T22:12:00.576Z
Learning: Applies to prisma/schema.prisma : When modifying the Prisma schema, especially for Metric Transformers, ensure AI-generated code generation and execution logic is updated accordingly

Applied to files:

  • src/lib/metrics/transformer-types.ts
  • src/lib/goals/types.ts
📚 Learning: 2025-12-20T22:12:00.576Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-20T22:12:00.576Z
Learning: The Metrics Pipeline processes data through 3 stages: DataIngestionTransformer (Raw API → MetricDataPoint), ChartTransformer (MetricDataPoint → Chart Config), and Visualization (Chart Config → Recharts UI)

Applied to files:

  • src/lib/metrics/transformer-types.ts
  • src/server/api/utils/enrich-charts-with-goal-progress.ts
  • src/app/dashboard/[teamId]/_components/metric-settings-drawer.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
📚 Learning: 2025-12-29T21:27:04.176Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.176Z
Learning: Applies to src/server/api/**/*.ts : Use enrichRolesWithUserNames() for flat role arrays and enrichChartRolesWithUserNames() for nested chart roles from src/server/api/utils/organization-members.ts

Applied to files:

  • src/server/api/utils/enrich-charts-with-goal-progress.ts
📚 Learning: 2025-12-20T22:12:00.576Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-20T22:12:00.576Z
Learning: Applies to src/app/teams/[teamId]/**/*.tsx : Avoid modifying `enrichNodesWithRoleData` flow without understanding the complete canvas serialization logic for saving/loading React Flow nodes to the database

Applied to files:

  • src/server/api/utils/enrich-charts-with-goal-progress.ts
📚 Learning: 2025-12-29T12:52:42.935Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to src/lib/metrics/**/*.ts : Goal calculation utility is 271 lines and should be refactored to approximately 50 lines. Simplify logic and extract helper functions.

Applied to files:

  • src/server/api/utils/enrich-charts-with-goal-progress.ts
  • src/lib/goals/types.ts
📚 Learning: 2025-12-20T22:12:00.576Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-20T22:12:00.576Z
Learning: Applies to src/app/teams/[teamId]/**/*.tsx : React Flow nodes must store minimal data (e.g., just `roleId`); fetch full Role data from TanStack Query cache in the Node component to keep canvas and sidebars in sync

Applied to files:

  • src/app/dashboard/[teamId]/_components/dashboard-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/metric-settings-drawer.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
  • src/app/dashboard/[teamId]/_components/use-dashboard-charts.ts
📚 Learning: 2025-12-29T21:27:04.165Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.165Z
Learning: Applies to src/app/teams/[teamId]/**/*.tsx : Use shared React Flow primitives (BaseNode, BaseHandle, ZoomSlider) from src/components/react-flow/ in all canvas implementations

Applied to files:

  • src/app/dashboard/[teamId]/_components/metric-settings-drawer.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
  • src/app/dashboard/[teamId]/_components/use-dashboard-charts.ts
🧬 Code graph analysis (6)
src/app/metric/_components/base/MetricDialogBase.tsx (1)
src/trpc/react.tsx (1)
  • RouterOutputs (42-42)
src/app/metric/_components/manual/ManualMetricContent.tsx (1)
src/trpc/react.tsx (1)
  • RouterOutputs (42-42)
src/app/dashboard/[teamId]/_components/dashboard-metric-card.tsx (1)
src/trpc/react.tsx (1)
  • RouterOutputs (42-42)
src/app/dashboard/[teamId]/_components/metric-settings-drawer.tsx (1)
src/trpc/react.tsx (1)
  • RouterOutputs (42-42)
src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx (1)
src/trpc/react.tsx (1)
  • RouterOutputs (42-42)
src/app/dashboard/[teamId]/_components/use-dashboard-charts.ts (1)
src/trpc/react.tsx (1)
  • RouterOutputs (42-42)
🔇 Additional comments (5)
src/server/api/utils/enrich-charts-with-goal-progress.ts (1)

13-14: LGTM - Clear documentation of circular dependency constraint.

The added note appropriately documents why this type must be manually defined rather than derived from RouterOutputs, helping future maintainers understand the architectural constraint.

src/app/dashboard/[teamId]/_components/metric-settings-drawer.tsx (1)

34-41: LGTM! Type sourcing refactor aligns with PR objectives.

The replacement of the centralized import with a RouterOutputs-derived local alias ensures automatic synchronization with the tRPC endpoint definition, preventing type drift.

src/lib/goals/types.ts (1)

1-4: LGTM! Prisma enum sourcing prevents type drift.

Importing and re-exporting Cadence and GoalType from @prisma/client establishes the database schema as the single source of truth, ensuring automatic propagation of any schema changes to dependent code.

src/lib/metrics/transformer-types.ts (1)

5-13: LGTM! Consistent Prisma enum sourcing.

The import and re-export of Cadence from @prisma/client maintains consistency with the refactoring in src/lib/goals/types.ts and ensures transformer types remain synchronized with the database schema.

src/app/dashboard/[teamId]/_components/use-dashboard-charts.ts (1)

5-8: LGTM! RouterOutputs-derived type ensures API contract alignment.

Deriving DashboardChartWithRelations directly from the tRPC router outputs eliminates the centralized wrapper file and ensures the hook's type signature automatically reflects any changes to the getDashboardCharts endpoint.

- Import Prisma enums (Cadence, GoalType) instead of redefining them
- Remove unnecessary types/dashboard.ts wrapper file
- Use tRPC RouterOutputs directly with inline type aliases
- Add circular dependency note for server-side enrich util
@claude
Copy link
Contributor

claude bot commented Jan 5, 2026

Code Review: Eliminate type duplications and use single source of truth

Summary

This PR successfully refactors type definitions to use Prisma enums as the single source of truth and consolidates tRPC output types using inline type aliases. The approach is solid and aligns well with the project's architecture patterns.


✅ Strengths

  1. Correct approach to type consolidation: Using Prisma enums as the source of truth for Cadence and GoalType is the right architectural decision.

  2. Inline type aliases: The pattern of defining DashboardChartWithRelations inline where it's used is clean and reduces unnecessary abstraction layers.

  3. Circular dependency handling: The note added in enrich-charts-with-goal-progress.ts:13-15 clearly explains why the manual type definition is necessary—good documentation!

  4. Complete cleanup: Successfully removed src/types/dashboard.ts with no remaining imports.

  5. Consistent pattern: All 6 files that previously imported from the deleted file now use the same inline pattern.


⚠️ Issues Found

1. Incomplete Cadence type consolidation (MEDIUM PRIORITY)

The PR consolidates Cadence in some places but missed several duplicate definitions:

Still using lowercase string unions:

  • src/lib/metrics/periods.ts:6 - export type Cadence = "daily" | "weekly" | "monthly";
  • src/app/metric/_components/manual/period-range-step.tsx:23 - type Cadence = "daily" | "weekly" | "monthly";
  • src/app/metric/_components/manual/ManualMetricContent.tsx:19 - type Cadence = "daily" | "weekly" | "monthly";

Problem: These files define Cadence as lowercase string literals ("daily", "weekly", "monthly") while Prisma uses uppercase enums (DAILY, WEEKLY, MONTHLY). This creates two different type systems for the same concept.

Recommendation:

  • Decide on one approach:

    • Option A (Recommended): Use Prisma's uppercase Cadence enum everywhere and convert at API boundaries
    • Option B: Keep lowercase for UI-only contexts but document the distinction clearly
  • If these are genuinely different types (database vs UI), rename the UI version to something like CadenceDisplay or UICadence to avoid confusion.

2. Type safety concern in ManualMetricContent.tsx

Lines 19-20 define local types that may not match Prisma:

type Cadence = "daily" | "weekly" | "monthly";

This component likely interacts with the database. If values are passed directly without conversion, you risk runtime type mismatches.


💡 Suggestions

1. Add type conversion utilities (if needed)

If you need both lowercase (UI) and uppercase (DB) versions:

// lib/helpers/cadence.ts
import { Cadence as PrismaCadence } from "@prisma/client";

export const cadenceToDb = (cadence: string): PrismaCadence => {
  return cadence.toUpperCase() as PrismaCadence;
};

export const cadenceFromDb = (cadence: PrismaCadence): string => {
  return cadence.toLowerCase();
};

2. Consider a follow-up PR

To keep this PR focused, consider addressing the remaining Cadence duplications in a follow-up PR. The current changes are self-contained and valuable.

3. Add a type test

Ensure type compatibility:

// Ensure Prisma Cadence values match expected usage
import { Cadence } from "@prisma/client";
const _typeCheck: Cadence = "DAILY" as const; // Should compile

🔒 Security

✅ No security concerns identified.


⚡ Performance

✅ No performance impact. Type-only changes are compile-time only.


🧪 Testing

  • Missing: No test changes included
  • Recommendation: Run full test suite to ensure type changes don't break any runtime behavior
  • Command: pnpm exec playwright test + pnpm check

📝 Documentation

✅ Good inline comment added explaining the circular dependency constraint.


Final Verdict

APPROVE WITH RECOMMENDATIONS

The core refactoring is sound and improves maintainability. The DashboardChartWithRelations consolidation is perfect. However, the Cadence type duplication issue should be addressed either in this PR or tracked in a follow-up issue to prevent future type drift.

Before merging:

  1. Run pnpm check to verify no type errors
  2. Run full test suite
  3. Decide on approach for remaining Cadence duplicates (create issue if deferring)

Great work on improving type safety! 🎯

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

Fix all issues with AI Agents 🤖
In @src/server/api/utils/enrich-charts-with-goal-progress.ts:
- Around line 13-14: The custom type DashboardChartWithRelations used by
enrichChartsWithGoalProgress is underspecified: it documents
metric.id/metric.goal/chartTransformer.cadence/chartTransformer.selectedDimension
but omits metric.roles required by enrichChartRolesWithUserNames, and the
current [key: string]: unknown` index signature hides this mismatch; update the
types so the Prisma shape is explicit—either expand DashboardChartWithRelations
to include metric.roles (and any other fields consumed downstream) or extract a
shared schema-driven type used by getDashboardCharts,
enrichChartsWithGoalProgress, and enrichChartRolesWithUserNames; additionally
add a short comment listing the exact Prisma selection fields required so future
changes to getDashboardCharts surface type errors rather than being masked by
the index signature.
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0113a03 and cf5532e.

📒 Files selected for processing (10)
  • src/app/dashboard/[teamId]/_components/dashboard-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
  • src/app/dashboard/[teamId]/_components/metric-settings-drawer.tsx
  • src/app/dashboard/[teamId]/_components/use-dashboard-charts.ts
  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/metric/_components/manual/ManualMetricContent.tsx
  • src/lib/goals/types.ts
  • src/lib/metrics/transformer-types.ts
  • src/server/api/utils/enrich-charts-with-goal-progress.ts
  • src/types/dashboard.ts
💤 Files with no reviewable changes (1)
  • src/types/dashboard.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/app/dashboard/[teamId]/_components/dashboard-metric-card.tsx
  • src/app/metric/_components/manual/ManualMetricContent.tsx
  • src/lib/metrics/transformer-types.ts
  • src/app/dashboard/[teamId]/_components/use-dashboard-charts.ts
  • src/lib/goals/types.ts
  • src/app/dashboard/[teamId]/_components/metric-settings-drawer.tsx
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Use TypeScript 5.9 with strict type checking for all frontend and backend code

Files:

  • src/server/api/utils/enrich-charts-with-goal-progress.ts
  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use @trivago/prettier-plugin-sort-imports with inline type imports for import organization

Files:

  • src/server/api/utils/enrich-charts-with-goal-progress.ts
  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
src/server/api/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

src/server/api/**/*.ts: Use fetchUserDisplayName(userId) utility (server-side async WorkOS) from @/server/api/utils/get-user-display-name for server-side user name retrieval
Use enrichRolesWithUserNames() for flat role arrays and enrichChartRolesWithUserNames() for nested chart roles from src/server/api/utils/organization-members.ts

Files:

  • src/server/api/utils/enrich-charts-with-goal-progress.ts
src/**/*.tsx

📄 CodeRabbit inference engine (GEMINI.md)

Prefer Server Components for initial data fetching; use Client Components ('use client') only for interactivity

Files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
src/**/*/*.tsx

📄 CodeRabbit inference engine (GEMINI.md)

Client Components must use import { api } from '@/trpc/react' for standard HTTP/Hooks wrapper

Files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
**/*.tsx

📄 CodeRabbit inference engine (GEMINI.md)

Use Tailwind CSS 4 for styling with shadcn/ui and Radix UI primitive components

Files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
src/app/**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

src/app/**/*.tsx: Use the dual tRPC API pattern: direct calls in Server Components (api.team.getById) for 10x faster performance, and React hooks in Client Components (api.team.getById.useQuery)
Use getUserDisplayName(userId, members) utility (client-side sync) from @/lib/helpers/get-user-name for displaying user names in components

Files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
src/app/metric/_components/**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

src/app/metric/_components/**/*.tsx: Create metric dialogs with pattern: [Provider]MetricDialog.tsx (dialog wrapper) + [Provider]MetricContent.tsx (form content) in src/app/metric/_components/[provider]/, then register in index.ts
Use shared MetricDialogBase component from base/ for all metric dialog implementations

Files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
🧠 Learnings (17)
📓 Common learnings
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.176Z
Learning: Applies to src/app/(metric|dashboard)/**/*.tsx : Use three-stage metrics transformation: API → DataPoints (DataIngestionTransformer), DataPoints → ChartConfig (ChartTransformer), ChartConfig → UI (DashboardMetricChart)
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to src/components/dashboard-metric-card.tsx,src/app/dashboard/[teamId]/_components/public-dashboard-metric-card.tsx : Dashboard metric cards are duplicated with public variant. Consolidate into single component with `readOnly` mode prop instead of maintaining separate components.
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.176Z
Learning: Applies to src/hooks/**/*.ts : For role-metric cache updates, optimistically update both role cache (role.getByTeamId) and dashboard cache (dashboard.getDashboardCharts) to maintain UI consistency
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to src/app/dashboard/[teamId]/**/*.{ts,tsx} : Dashboard cache updates for role-metric assignments must update both `role.getByTeamId` and `dashboard.getDashboardCharts` caches during mutations. Use onMutate for optimistic updates on both caches, then invalidate both on success.
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.176Z
Learning: Applies to src/app/**/*.tsx : Use the dual tRPC API pattern: direct calls in Server Components (api.team.getById) for 10x faster performance, and React hooks in Client Components (api.team.getById.useQuery)
📚 Learning: 2025-12-29T21:27:04.176Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.176Z
Learning: Applies to src/app/(metric|dashboard)/**/*.tsx : Use three-stage metrics transformation: API → DataPoints (DataIngestionTransformer), DataPoints → ChartConfig (ChartTransformer), ChartConfig → UI (DashboardMetricChart)

Applied to files:

  • src/server/api/utils/enrich-charts-with-goal-progress.ts
  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
📚 Learning: 2025-12-29T21:27:04.176Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.176Z
Learning: Applies to src/server/api/**/*.ts : Use enrichRolesWithUserNames() for flat role arrays and enrichChartRolesWithUserNames() for nested chart roles from src/server/api/utils/organization-members.ts

Applied to files:

  • src/server/api/utils/enrich-charts-with-goal-progress.ts
📚 Learning: 2025-12-29T12:52:42.935Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to src/lib/metrics/**/*.ts : Goal calculation utility is 271 lines and should be refactored to approximately 50 lines. Simplify logic and extract helper functions.

Applied to files:

  • src/server/api/utils/enrich-charts-with-goal-progress.ts
📚 Learning: 2025-12-29T21:27:04.176Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.176Z
Learning: Applies to src/hooks/**/*.ts : For role-metric cache updates, optimistically update both role cache (role.getByTeamId) and dashboard cache (dashboard.getDashboardCharts) to maintain UI consistency

Applied to files:

  • src/server/api/utils/enrich-charts-with-goal-progress.ts
  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
📚 Learning: 2025-12-20T22:12:00.576Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-20T22:12:00.576Z
Learning: Applies to src/app/teams/[teamId]/**/*.tsx : Avoid modifying `enrichNodesWithRoleData` flow without understanding the complete canvas serialization logic for saving/loading React Flow nodes to the database

Applied to files:

  • src/server/api/utils/enrich-charts-with-goal-progress.ts
📚 Learning: 2025-12-29T12:52:42.935Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to src/app/dashboard/[teamId]/**/*.{ts,tsx} : Dashboard cache updates for role-metric assignments must update both `role.getByTeamId` and `dashboard.getDashboardCharts` caches during mutations. Use onMutate for optimistic updates on both caches, then invalidate both on success.

Applied to files:

  • src/server/api/utils/enrich-charts-with-goal-progress.ts
  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
📚 Learning: 2025-12-29T12:52:42.935Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to src/components/dashboard-metric-card.tsx,src/app/dashboard/[teamId]/_components/public-dashboard-metric-card.tsx : Dashboard metric cards are duplicated with public variant. Consolidate into single component with `readOnly` mode prop instead of maintaining separate components.

Applied to files:

  • src/server/api/utils/enrich-charts-with-goal-progress.ts
  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
📚 Learning: 2025-12-20T22:12:00.576Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-20T22:12:00.576Z
Learning: The Metrics Pipeline processes data through 3 stages: DataIngestionTransformer (Raw API → MetricDataPoint), ChartTransformer (MetricDataPoint → Chart Config), and Visualization (Chart Config → Recharts UI)

Applied to files:

  • src/server/api/utils/enrich-charts-with-goal-progress.ts
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
📚 Learning: 2025-12-20T22:12:00.576Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-20T22:12:00.576Z
Learning: Applies to src/lib/metrics/**/*.ts : Metric transformation logic should be organized in `src/lib/metrics/` to support the 3-stage pipeline: Ingestion → Aggregation → Visualization

Applied to files:

  • src/server/api/utils/enrich-charts-with-goal-progress.ts
  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
📚 Learning: 2025-12-29T21:27:04.176Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.176Z
Learning: Applies to src/app/metric/_components/**/*.tsx : Use shared MetricDialogBase component from base/ for all metric dialog implementations

Applied to files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
📚 Learning: 2025-12-29T21:27:04.176Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.176Z
Learning: Applies to src/app/metric/_components/**/*.tsx : Create metric dialogs with pattern: [Provider]MetricDialog.tsx (dialog wrapper) + [Provider]MetricContent.tsx (form content) in src/app/metric/_components/[provider]/, then register in index.ts

Applied to files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
📚 Learning: 2025-12-29T12:52:42.935Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to src/app/metric/_components/**/*.tsx : Metric dialog components should follow the pattern: [Provider]MetricDialog.tsx (dialog wrapper) and [Provider]MetricContent.tsx (form content). Register in src/app/metric/_components/index.ts and inherit from shared MetricDialogBase.

Applied to files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
📚 Learning: 2025-12-29T12:52:42.935Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to src/app/metric/_components/**/*.tsx : Metric dialog components have nearly identical wrapper patterns (5 files). Consider implementing a factory pattern or generic wrapper to reduce duplication across provider dialogs.

Applied to files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
📚 Learning: 2025-12-29T21:27:04.176Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.176Z
Learning: Applies to src/app/**/*.tsx : Use the dual tRPC API pattern: direct calls in Server Components (api.team.getById) for 10x faster performance, and React hooks in Client Components (api.team.getById.useQuery)

Applied to files:

  • src/app/metric/_components/base/MetricDialogBase.tsx
📚 Learning: 2025-12-20T22:12:00.576Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-20T22:12:00.576Z
Learning: Applies to src/app/teams/[teamId]/**/*.tsx : React Flow nodes must store minimal data (e.g., just `roleId`); fetch full Role data from TanStack Query cache in the Node component to keep canvas and sidebars in sync

Applied to files:

  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
📚 Learning: 2025-12-29T21:27:04.176Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.176Z
Learning: Applies to src/app/teams/[teamId]/**/*.tsx : Use shared React Flow primitives (BaseNode, BaseHandle, ZoomSlider) from src/components/react-flow/ in all canvas implementations

Applied to files:

  • src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx
🧬 Code graph analysis (2)
src/app/metric/_components/base/MetricDialogBase.tsx (1)
src/trpc/react.tsx (1)
  • RouterOutputs (42-42)
src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx (1)
src/trpc/react.tsx (1)
  • RouterOutputs (42-42)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: claude-review
🔇 Additional comments (2)
src/app/dashboard/[teamId]/_components/dashboard-metric-drawer.tsx (1)

11-11: LGTM! Type derivation follows single source of truth pattern.

The inline type alias derived from RouterOutputs eliminates the centralized wrapper and ensures automatic propagation of any tRPC schema changes. The use of inline type import (type RouterOutputs) follows the project's import organization guidelines.

Also applies to: 23-24

src/app/metric/_components/base/MetricDialogBase.tsx (1)

17-17: LGTM! Consistent type derivation pattern.

The inline type alias from RouterOutputs matches the pattern used in other dashboard components and eliminates dependency on the centralized type wrapper. The enriched result at line 100 correctly constructs the expected type by adding the required goalProgress, valueLabel, dataDescription, and metric.goal fields.

Also applies to: 19-20

Comment on lines +13 to +14
* NOTE: This type must be manually defined here to avoid circular dependency.
* Cannot use tRPC RouterOutputs because AppRouter depends on this util file.
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n src/server/api/utils/enrich-charts-with-goal-progress.ts

Repository: drifter089/orgOS

Length of output: 6454


🏁 Script executed:

# Search for getDashboardCharts router definition
rg -n "getDashboardCharts" --type=ts -A 10 src/server/api/routers/

Repository: drifter089/orgOS

Length of output: 974


🏁 Script executed:

# Look for the RouterOutputs type to understand tRPC output structure
rg -n "RouterOutputs" --type=ts src/server/

Repository: drifter089/orgOS

Length of output: 197


🏁 Script executed:

cat -n src/server/api/routers/dashboard.ts | head -150

Repository: drifter089/orgOS

Length of output: 5765


🏁 Script executed:

# Search for the complete getDashboardCharts definition and its return type
rg -n "getDashboardCharts" -A 50 src/server/api/routers/dashboard.ts | head -100

Repository: drifter089/orgOS

Length of output: 1847


🏁 Script executed:

# Search for usages of getDashboardCharts in client components
rg -n "getDashboardCharts" --type=ts --type=tsx src/app/ | head -20

Repository: drifter089/orgOS

Length of output: 87


🏁 Script executed:

# Check enrichChartsWithGoalProgress usage to see what fields are actually accessed
rg -n "enrichChartsWithGoalProgress" -B 2 -A 5 src/

Repository: drifter089/orgOS

Length of output: 3914


🏁 Script executed:

# Look at enrichChartRolesWithUserNames to see what it adds to the type
cat -n src/server/api/utils/organization-members.ts | grep -A 30 "enrichChartRolesWithUserNames"

Repository: drifter089/orgOS

Length of output: 1915


🏁 Script executed:

# Check if there are any TypeScript compilation errors in these files
rg -n "type DashboardChart" --type=ts src/server/api/

Repository: drifter089/orgOS

Length of output: 156


🏁 Script executed:

# Verify the function is being used correctly and all required fields are present
cat -n src/server/api/utils/organization-members.ts | sed -n '196,220p'

Repository: drifter089/orgOS

Length of output: 826


🏁 Script executed:

# Check how enrichChartRolesWithUserNames is called and what it receives
cat -n src/server/api/routers/dashboard.ts | sed -n '95,106p'

Repository: drifter089/orgOS

Length of output: 528


🏁 Script executed:

# Search for any type mismatch issues or related tests
find src -name "*.test.ts" -o -name "*.spec.ts" | xargs grep -l "enrichChartsWithGoalProgress" 2>/dev/null

Repository: drifter089/orgOS

Length of output: 44


🏁 Script executed:

# Check the Prisma schema for DashboardChart and related models
rg -n "model DashboardChart" -A 20 prisma/schema.prisma

Repository: drifter089/orgOS

Length of output: 960


🏁 Script executed:

# Check if there are any recent changes or related issues
rg -n "DashboardChartWithRelations" --type=ts src/

Repository: drifter089/orgOS

Length of output: 1644


🏁 Script executed:

# Compare the type definitions in different files
for file in "src/server/api/utils/enrich-charts-with-goal-progress.ts" "src/app/metric/_components/manual/ManualMetricContent.tsx" "src/app/dashboard/\[teamId\]/_components/use-dashboard-charts.ts"; do
  echo "=== $file ==="
  rg -A 15 "type DashboardChartWithRelations" "$file"
done

Repository: drifter089/orgOS

Length of output: 1087


🏁 Script executed:

# Check if client-side code is using data from the server endpoint
rg -n "getDashboardCharts" src/app/ -B 2 -A 5 | head -50

Repository: drifter089/orgOS

Length of output: 4145


🏁 Script executed:

# Check the AppRouter to see what RouterOutputs would infer
rg -n "export const appRouter" -A 20 src/server/api/root.ts

Repository: drifter089/orgOS

Length of output: 672


🏁 Script executed:

# Verify that the manual type is actually missing fields by checking what fields are accessed
rg -n "metric\." src/server/api/utils/enrich-charts-with-goal-progress.ts

Repository: drifter089/orgOS

Length of output: 652


🏁 Script executed:

# Check for metric.roles access in related code
rg -n "\.metric\.roles" src/server/api/ src/app/

Repository: drifter089/orgOS

Length of output: 380


🏁 Script executed:

# Check the generic constraint of enrichChartRolesWithUserNames
rg -B 2 -A 8 "enrichChartRolesWithUserNames<" src/server/api/utils/organization-members.ts

Repository: drifter089/orgOS

Length of output: 434


🏁 Script executed:

# Verify what the actual Prisma query returns for metric.roles
cat -n src/server/api/routers/dashboard.ts | sed -n '76,93p'

Repository: drifter089/orgOS

Length of output: 614


Type drift risk exists but is partially mitigated by the index signature.

The manual DashboardChartWithRelations type only documents fields required by enrichChartsWithGoalProgress (metric.id, metric.goal, chartTransformer.cadence, chartTransformer.selectedDimension). However, enrichChartRolesWithUserNames requires metric.roles which isn't declared in this type. While the [key: string]: unknown index signature masks this gap, it creates an implicit contract: if the Prisma query in getDashboardCharts changes, there's no type-level verification that all downstream functions still receive their required fields.

Consider documenting the required fields in a comment listing which properties the Prisma query must include, or extract a shared schema-driven type to eliminate the manual maintenance burden.

🤖 Prompt for AI Agents
In @src/server/api/utils/enrich-charts-with-goal-progress.ts around lines 13-14,
The custom type DashboardChartWithRelations used by enrichChartsWithGoalProgress
is underspecified: it documents
metric.id/metric.goal/chartTransformer.cadence/chartTransformer.selectedDimension
but omits metric.roles required by enrichChartRolesWithUserNames, and the
current [key: string]: unknown` index signature hides this mismatch; update the
types so the Prisma shape is explicit—either expand DashboardChartWithRelations
to include metric.roles (and any other fields consumed downstream) or extract a
shared schema-driven type used by getDashboardCharts,
enrichChartsWithGoalProgress, and enrichChartRolesWithUserNames; additionally
add a short comment listing the exact Prisma selection fields required so future
changes to getDashboardCharts surface type errors rather than being masked by
the index signature.

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.

2 participants