Skip to main content

Database Entities

Ever Works uses TypeORM entities to define the database schema. All entities live in packages/agent/src/entities/ and are registered in the centralized ENTITIES array in database.config.ts.

Entity Registry

The platform registers 15 entities across core domain, authentication, billing, and plugin concerns:

export const ENTITIES = [
Work,
WorkAdvancedPrompts,
WorkMember,
User,
RefreshToken,
OAuthToken,
CacheEntry,
WorkGenerationHistory,
SubscriptionPlan,
UserSubscription,
WorkSchedule,
UsageLedgerEntry,
Notification,
PluginEntity,
UserPluginEntity,
WorkPluginEntity
];

Core Entities

Work

Table: works | Primary Key: UUID

The central domain entity representing a work project. Contains 40+ columns spanning generation state, deployment, scheduling, community PRs, comparisons, and website template tracking.

Column GroupKey FieldsNotes
Identityid, name, slug, userIdSlug used for repository naming
Gitowner, gitProvider, repoVisibilityDefault provider: github
DeploydeployProvider, deploymentState, deploymentStartedAtDefault: vercel
GenerationgenerateStatus, generationStartedAt, generationProgressedAt, generationFinishedAtStatus stored as simple-json
Domain TypedomainType, domainTypeConfidence, domainTypeManuallySetFor smart image routing
SchedulingscheduledUpdatesEnabled, scheduledCadence, scheduledNextRunAt, scheduledStatusInline schedule fields
Website TemplatewebsiteTemplateAutoUpdate, websiteTemplateUseBeta, websiteTemplateLastCommit, websiteTemplateLastErrorAuto-update tracking
Community PRcommunityPrEnabled, communityPrAutoClose, communityPrStatePR processing state as JSON
TimestampscreatedAt, updatedAtAuto-managed by TypeORM

Relations:

Work --> User (ManyToOne, eager, CASCADE delete)
Work --> GenerationHistory (OneToMany)
Work --> WorkSchedule (OneToOne)
Work --> WorkMember (OneToMany)

Helper Methods:

  • getDataRepo() -- Returns <slug>-data
  • getWebsiteRepo() -- Returns <slug>-website
  • getMainRepo() -- Returns the slug itself
  • getRepoOwner() -- Returns owner or user's username
  • isCreator(userId) -- Checks if user is the original creator
  • hasAccess(userId) -- Checks creator or member status
  • getUserRole(userId) -- Returns the user's role in this work

User

Table: users | Primary Key: UUID

ColumnTypeNotes
usernamestringDisplay name
emailstringUnique constraint
passwordstringBcrypt hashed
registrationProviderstringlocal, github, google
avatarstringNullable
emailVerifiedbooleanDefault false
emailVerificationTokenstringFor email confirmation
isActivebooleanDefault true
lastLoginAt, lastLoginIpDate, stringLogin tracking
passwordResetToken, passwordResetExpiresstring, DatePassword reset flow
defaultPlanIdstringFK to SubscriptionPlan

All OneToMany relations on User use lazy: true (return Promises) to avoid loading large collections eagerly.

WorkGenerationHistory

Table: work_generation_history | Primary Key: UUID

Tracks every generation run with metrics, timing, and error state.

Indexes: [workId, status], [triggeredBy], [scheduleId]

ColumnTypePurpose
statusGenerateStatusTypeCurrent generation status
generationMethodGenerationMethodRECREATE, APPEND, or UPDATE
triggeredBy'user' | 'schedule' | 'api'Who initiated the run
triggerRunIdstringTrigger.dev run identifier
metricsGenerationMetrics (JSON)URLs scanned, items extracted, tokens, cost
newItemsCount, updatedItemsCount, totalItemsCountintItem counters
startedAt, finishedAt, durationInSecondstimestamp/intTiming
errorMessagetextError details if failed

WorkMember

Table: work_members | Primary Key: UUID

Implements role-based access control for work collaboration.

Unique Constraint: [workId, userId] -- A user can only have one membership per work.

RoleLevelCapabilities
OWNER4Reserved for work creator (implicit, not assignable)
MANAGER3Edit content, manage members
EDITOR2Edit content only
VIEWER1Read-only access

Helper methods: hasRoleOrHigher(role), canManageMembers(), canEdit().

Authentication Entities

RefreshToken

Table: refresh_tokens

Supports refresh token rotation with family-based tracking for detecting token reuse attacks.

ColumnPurpose
tokenUnique token string (indexed)
familyGroups related tokens for rotation
revoked, revokedAt, revokedReasonRevocation tracking
userAgent, ipAddressDevice fingerprinting
expiresAtTTL (indexed)

OAuthToken

Table: oauth_tokens

Stores OAuth access and refresh tokens per provider per user. Uses lazy: true for the User relation.

ColumnPurpose
providergithub, google, etc.
accessToken, refreshTokenToken values (text)
username, emailProvider profile data
scopeComma-separated granted scopes
metadataJSON for provider-specific data

Billing Entities

SubscriptionPlan

Table: subscription_plans

Indexes: [code] (unique), [active]

Defines available subscription tiers with pricing and feature limits.

ColumnTypePurpose
codeSubscriptionPlanCodefree, standard, premium
displayNamestringHuman-readable name
maxWorksintWork limit for the plan
allowedCadencessimple-jsonArray of allowed schedule frequencies
monthlyPricedecimal(10,2)Plan price
overagePricePerRundecimal(10,2)Cost per extra generation run
currencystringDefault: usd
activebooleanWhether plan is available

UserSubscription

Table: user_subscriptions

Indexes: [userId, status], [planCode]

ColumnTypePurpose
planCodeSubscriptionPlanCodeSubscribed plan tier
statusSubscriptionStatusactive, canceled, past_due, trialing
billingProviderSubscriptionBillingProviderstripe or manual
currentPeriodEndDateWhen current billing period ends
cancelAtPeriodEndbooleanScheduled cancellation flag
paymentMethodMetaJSONProvider-specific payment data

UsageLedgerEntry

Table: usage_ledger_entries

Indexes: [userId, status], [workId], [createdAt], [scheduleId]

Tracks individual generation runs for usage-based billing.

ColumnTypePurpose
triggerTypeUsageLedgerTriggerTypemanual or scheduled
billingModeWorkScheduleBillingModesubscription or usage
unitsintNumber of generation units consumed
amountCentsintCharge in cents
statusUsageLedgerStatuspending, queued_for_settlement, paid, canceled
generationHistoryIdstringLinks to the specific generation run

Scheduling Entity

WorkSchedule

Table: work_schedules

Indexes: [status, nextRunAt], [userId, status], [workId] (unique)

One-to-one with Work. Manages recurring generation runs.

ColumnTypePurpose
cadenceWorkScheduleCadenceFrequency (daily, weekly, monthly, etc.)
statusWorkScheduleStatusdisabled, active, paused
billingModeWorkScheduleBillingModesubscription or usage
nextRunAt, lastRunAtDateSchedule timing
failureCountintConsecutive failures
maxFailureBeforePauseintDefault: 3, auto-pauses after this many failures
alwaysCreatePullRequestbooleanForce PR mode for scheduled runs
providerOverridessimple-jsonOverride AI/search providers per schedule

Support Entities

WorkAdvancedPrompts

Table: work_advanced_prompts

One-to-one with Work. Stores per-work custom prompt overrides for each pipeline stage.

FieldPipeline Stage
relevanceAssessmentWeb page relevance filtering
itemGenerationInitial AI item generation
itemExtractionItem extraction from web pages
searchQuerySearch query generation
categorizationCategory and tag assignment
deduplicationDuplicate detection and merging
sourceValidationSource URL validation

All fields are nullable text. When non-empty, values are appended as "Additional User Instructions" to the base prompts.

Notification

Table: notifications

Indexes: [userId, isRead], [userId, deduplicationKey] (unique, partial)

ColumnTypePurpose
typeNotificationTypeNotification kind
categoryNotificationCategoryGrouping category
title, messagestring, textContent
actionUrl, actionLabelstringOptional CTA link
isRead, isDismissedbooleanRead/dismiss state
isPersistentbooleanWhether notification persists across sessions
expiresAtDateAuto-expiry timestamp (indexed)
deduplicationKeystringPrevents duplicate notifications

CacheEntry

Table: cache_entries | Primary Key: key (varchar)

Simple key-value store with TTL support for caching arbitrary data.

ColumnTypePurpose
keyvarchar (PK)Cache key
valuetextSerialized cache value
expiresAtbigintUnix timestamp for TTL (indexed)

Shared Types

Key enums defined in entities/types.ts:

enum GenerateStatusType {
GENERATING,
GENERATED,
ERROR,
CANCELLED,
IDLE
}

enum WorkMemberRole {
OWNER = 'owner', // Reserved for creator
MANAGER = 'manager', // Assignable
EDITOR = 'editor', // Assignable
VIEWER = 'viewer' // Assignable
}

enum SubscriptionPlanCode {
FREE = 'free',
STANDARD = 'standard',
PREMIUM = 'premium'
}

The GenerateStatus interface provides granular progress tracking with step names, indices, percentages, and warning arrays.

Custom Column Decorators

The TimestampColumn decorator (from entities/_types.ts) normalizes timestamp handling across database drivers (SQLite stores as strings, PostgreSQL as native timestamps).