Files
twenty/packages/twenty-front/codegen-metadata.cjs
T
77d4bd9158 Add billing usage analytics dashboard with ClickHouse integration (#18592)
## Summary
This PR adds a comprehensive billing usage analytics feature that
provides detailed breakdowns of credit consumption across execution
types, users, resources, and time periods. The implementation includes a
new ClickHouse-backed analytics service, GraphQL API endpoint, and a
frontend dashboard component.

## Key Changes

### Backend
- **New BillingAnalyticsService**: Queries ClickHouse for usage
breakdowns by user, resource, execution type, and time series data
- **BillingEventWriterService**: Writes billing events to ClickHouse for
analytics while maintaining best-effort semantics (never blocks Stripe
billing)
- **ClickHouse Schema**: Added `billingEvent` table with 3-year TTL for
storing detailed billing event data
- **GraphQL Resolver**: New `getBillingAnalytics` query that aggregates
usage data for the current billing period, protected by feature flag and
billing permissions
- **Enhanced BillingUsageEvent**: Added `userWorkspaceId` field to track
per-user credit consumption
- **AI Billing Integration**: Updated AI billing service to pass
`userWorkspaceId` when recording usage events

### Frontend
- **SettingsBillingAnalyticsSection**: New component displaying:
  - Usage breakdown by execution type with progress bars
  - Daily usage time series chart (28-day view)
  - Per-user credit consumption breakdown
  - Per-resource (agent/workflow) credit consumption breakdown
- **SettingsUsage Page**: Dedicated page for viewing usage analytics
- **GraphQL Query**: `GetBillingAnalytics` query with generated hooks
- **Navigation**: Added Usage menu item in settings (feature-flagged)
- **Mock Data**: Included screenshot mock data for preview/testing

### Feature Flag
- Added `IS_USAGE_ANALYTICS_ENABLED` feature flag to control visibility
and access to analytics features

## Implementation Details
- Analytics data is queried in parallel for performance
- ClickHouse writes are non-blocking to ensure billing operations never
fail
- Progress bars use dynamic coloring from a predefined palette
- Time series visualization normalizes bar heights relative to max value
- Empty state handling when no analytics data is available
- Responsive UI with proper text truncation for long names

https://claude.ai/code/session_01Y1EqrX6PFq3EJxJq89h7DF

---------

Co-authored-by: Claude <[email protected]>
2026-03-23 10:28:23 +01:00

55 lines
1.9 KiB
JavaScript

process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
module.exports = {
schema:
(process.env.REACT_APP_SERVER_BASE_URL ?? 'http://localhost:3000') +
'/metadata',
documents: [
'./src/modules/auth/graphql/**/*.{ts,tsx}',
'./src/modules/users/graphql/**/*.{ts,tsx}',
'./src/modules/views/graphql/**/*.{ts,tsx}',
'./src/modules/ai/graphql/**/*.{ts,tsx}',
'./src/modules/applications/graphql/**/*.{ts,tsx}',
'./src/modules/workspace/graphql/**/*.{ts,tsx}',
'./src/modules/workspace-member/graphql/**/*.{ts,tsx}',
'./src/modules/workspace-invitation/graphql/**/*.{ts,tsx}',
'./src/modules/settings/**/graphql/**/*.{ts,tsx}',
'./src/modules/logic-functions/graphql/**/*.{ts,tsx}',
'./src/modules/databases/graphql/**/*.{ts,tsx}',
'./src/modules/analytics/graphql/**/*.{ts,tsx}',
'./src/modules/object-metadata/graphql/**/*.{ts,tsx}',
'./src/modules/navigation-menu-item/**/graphql/**/*.{ts,tsx}',
'./src/modules/command-menu-item/graphql/**/*.{ts,tsx}',
'./src/modules/attachments/graphql/**/*.{ts,tsx}',
'./src/modules/file/graphql/**/*.{ts,tsx}',
'./src/modules/onboarding/graphql/**/*.{ts,tsx}',
'./src/modules/front-components/graphql/**/*.{ts,tsx}',
'./src/modules/page-layout/widgets/**/graphql/**/*.{ts,tsx}',
'./src/modules/dashboards/graphql/**/*.{ts,tsx}',
'./src/modules/page-layout/graphql/**/*.{ts,tsx}',
'./src/modules/marketplace/graphql/**/*.{ts,tsx}',
'!./src/**/*.test.{ts,tsx}',
'!./src/**/*.stories.{ts,tsx}',
'!./src/**/__mocks__/*.ts',
],
overwrite: true,
generates: {
'./src/generated-metadata/graphql.ts': {
plugins: ['typescript', 'typescript-operations', 'typed-document-node'],
config: {
skipTypename: false,
scalars: {
DateTime: 'string',
UUID: 'string',
},
namingConvention: { enumValues: 'keep' },
},
},
},
};