Schema Changes

Schema Changes
Phases 2-4

Three phases of feature work. Zero new custom objects. One new field. One new Custom Metadata Type. One new Apex service.

Last Updated: March 27, 2026

0
New Objects
1
New Fields
1
New CMTs
1
New Apex Services
~25
New Reports
1

Phase 2: Polish -- No New Schema

Phase 2 added zero new objects or fields. Everything was reports, tabs, and UI.

Zero new objects or fields

Everything was reports, tabs, and UI

2Report Types

Activity_Logs, Work_Logs (for existing ActivityLog__c and WorkLog__c)

3Report Folders

DeliveryHubClient, DeliveryHubVendor, DeliveryHubPipeline

~25Reports

Active Deliveries, Attention Items, Blocked, Budget Health, Monthly Hours, Velocity by Week, and more

2Tabs

Delivery_Activity_Dashboard, Delivery_Workspace

2Flexipage Updates

DeliveryDocumentRecordPage, DeliveryHubAdminHome

Phase 2 focused entirely on surfacing existing data through reports and workspace -- no schema bloat.

2

Phase 3: Self-Service -- 1 New Field

Phase 3 added one field to an existing object.

PortalAccess__c.AccessTokenTxt__c

128-bit hex token, auto-generated during client onboarding

// Onboarding flow
1. Admin runs Getting Started wizard
2. System creates PortalAccess__c record
3. Generates random AccessTokenTxt__c
4. Token returned to LWC → admin shares with client
// Client uses token for portal login

Why on PortalAccess__c?

This object already existed for tracking who has portal access. The token is the auth credential -- it belongs with the access record.

No new objects. The template manager and workflow picker are pure LWC/Apex -- they read existing CMT records (WorkflowType__mdt, WorkflowStage__mdt).

3

Phase 4: Intelligence -- 1 CMT + 1 Service

Phase 4 added one new Custom Metadata Type (DeveloperCapacity__mdt) and one new Apex service (DeliveryVelocityService.cls), plus enhanced the existing WorkItemETAService.

DeveloperCapacity__mdt

Custom Metadata Type with 6 fields

FieldTypePurpose
DeveloperUserIdTxt__cTextThe Salesforce User ID of the developer
WeeklyCapacityHoursNumber__cNumberHow many hours/week this developer is available (default assumption: 40)
AllocationPercentNumber__cNumberWhat percentage of their time is allocated to this workflow type (e.g., 80% means 32 of 40 hours)
WorkflowTypeNameTxt__cTextWhich workflow type this capacity record applies to (e.g., "Software_Delivery")
EffectiveDateDt__cDateWhen this capacity allocation takes effect. Allows scheduling future capacity changes.
IsActiveBool__cCheckboxWhether this capacity record is currently active. Inactive records are ignored by the velocity service.

How it works together

1

Entry point

DeliveryVelocityService.getVelocityDashboard("Software_Delivery")

2

Velocity (no CMT needed)

Queries WorkItem__c for items in terminal stages over the last 8 weeks, groups by week → bar chart

3

Projection (no CMT needed)

Counts remaining non-terminal items, divides by average velocity → estimated weeks + projected completion date

4

Capacity (uses DeveloperCapacity__mdt)

Loads all capacity records for the workflow type, calculates allocated hours per developer, counts active items → utilization %

5

What-if (client-side only)

User enters "what if we add N items?" → JS recalculates projected weeks instantly without an Apex call

Why CMT instead of a custom object?

Configuration, not transactional data

"Glen works 40hrs/week at 80% allocation" doesn't change per work item.

Deploys with the package

Survives installs and upgrades.

Admin-editable in Setup

No code required to change capacity values.

Consistent with existing pattern

WorkflowType__mdt, WorkflowStage__mdt, WorkflowPersonaView__mdt are all CMT.

Queryable without DML or CRUD checks

Simpler Apex, no permission concerns.

Why not just use User fields?

Can't easily add custom fields to the standard User object in a managed package.

Allocation varies per workflow type -- same person might be 80% on Software_Delivery and 20% on Loan_Approval.

CMT records are version-controlled in the repo.

DeliveryVelocityService.cls

New Apex service -- all Phase 4 server-side logic

MethodPurpose
getTeamVelocity(workflowType, weeks)Rolling velocity calculation -- items completed per week over the specified window (default 8 weeks)
getProjectedETAs(entityId)Queue-aware ETA projection for all items under an entity, factoring in position and team throughput
getDeveloperUtilization()Reads DeveloperCapacity__mdt records, calculates allocated vs. available hours per developer
getWhatIfProjection(params)Scenario modeling -- "what if we add N items?" or "what if we lose a developer?"
getVelocityDashboard(workflowType)Composite method that returns velocity, projection, and capacity data in a single call for the LWC dashboard

WorkItemETAService Enhancement

The existing ETA service is parameterized to accept velocity data instead of relying solely on static estimates. Falls back to estimate-based ETAs when velocity data is insufficient.

estimateBasedETA (existing)velocityBasedETA (new)hybridETA (blended)confidenceScore (0-100)

What happens without any DeveloperCapacity__mdt records: Velocity chart still works (queries WorkItem__c directly). Projected completion still works (based on velocity + remaining items). Capacity section shows "No developer capacity configured" -- graceful degradation. The CMT is purely additive.

4

The Big Picture

Combined schema impact across three phases of development.

Total schema impact across Phases 2, 3, and 4

0New custom objects across all 3 phases
1New fields (AccessTokenTxt__c on existing PortalAccess__c)
1New CMTs (DeveloperCapacity__mdt with 6 fields)
1New Apex services (DeliveryVelocityService.cls)
~25New reports
2New tabs

Velocity Data Flow

WorkItem__c(existing)—query—→DeliveryVelocityService(new)—→deliveryVelocityDashboard LWC
DeveloperCapacity__mdt(new)—query—↑
DeliveryVelocityService—feeds—→WorkItemETAService(enhanced)

Keep the schema small.
Surface existing data through code, not more fields.

Related Pages

Dive deeper into each phase or see the full roadmap.