Direct Database Schema

Static IP Required

DDI requires your system to have a static IP address. Without one, the connection may be unstable or interrupted.

This reference documents every view (table) exposed by the Mosaic Direct Database Integration (DDI). Each table section lists its columns, data types, foreign-key relationships, and usage notes.

All views are scoped to your team automatically via the DDI connection credentials.

Use the api schema — Query the documented tables using the api schema rather than the public schema.


Quick Reference

View NameDescription
membersTeam members (employees / contractors)
rolesOrganization-level roles (positions)
portfoliosProject portfolios
projectsProjects
phasesProject phases and milestones
phase_membershipsMembers assigned to phases
work_categoriesPhase-level work categories
standard_work_categoriesOrganization-level work category templates
project_membershipsMembers assigned to projects
project_rolesRoles assigned to project members
phase_budgetsThe budget Mosaic displays for each phase
member_budgetsTime budgets per member or open role on each work category
project_scopesScope items on a project
project_scope_assignmentsMembers assigned to scope items
task_listsTask list groupings
project_tasksIndividual tasks on a project
project_task_assignmentsMembers assigned to tasks
project_notesNotes attached to projects
time_entriesLogged time entries
work_plansResource plans / schedule bars

Core Entities

Members

Team members represent the people in your organization.

View: members

ColumnTypeFKNullableDescription
idbigintnoPrimary key.
first_namestringyesFirst name.
last_namestringyesLast name.
emailstringyesEmail address.
employment_typestringyesEmployment type. See values below.
reference_numberstringyesExternal reference / employee number.
archived_atdatetimeyesWhen this member was archived. NULL if active.

employment_type values:

ValueMeaning
MemberStandard employee (default).
Contractor (Internal)Internal contractor.
Contractor (External)External contractor.
GuestGuest user.

Roles

Organization-level roles that can be assigned to project members.

View: roles

ColumnTypeFKNullableDescription
idbigintnoPrimary key.
namestringnoRole name.
is_defaultbooleannoWhether this is the default role.
created_atdatetimenoWhen this role was created.
updated_atdatetimenoWhen this role was last updated.
archived_atdatetimeyesWhen this role was archived. NULL if active.

Portfolios

Portfolios group projects together.

View: portfolios

ColumnTypeFKNullableDescription
idbigintnoPrimary key.
namestringnoPortfolio name.
archived_atdatetimeyesWhen this portfolio was archived. NULL if active.
created_atdatetimenoWhen this portfolio was created.
updated_atdatetimenoWhen this portfolio was last updated.

Projects

Projects are the primary unit of work in Mosaic.

View: projects

ColumnTypeFKNullableDescription
idbigintnoPrimary key.
project_numberstringyesThe project number.
titlestringyesProject title.
descriptionstringyesProject description.
billablebooleanyesWhether work on this project is billable.
portfolio_idbigintportfolios.idyesThe portfolio this project belongs to.
project_typestringnoregular for a normal project, template for a project template.
rate_multipliernumericyesThe project's bill rate multiplier. NULL for a team that tracks budgets in hours. See Rate Multipliers.
cost_rate_multipliernumericyesThe project's cost rate multiplier. NULL for a team that tracks budgets in hours.
independent_phase_ratesbooleannotrue when the project's Independent Phase Rates setting is on, so its phases and work categories use their own multipliers.
archived_atdatetimeyesWhen this project was archived. NULL if active.
created_atdatetimenoWhen this project was created.
updated_atdatetimenoWhen this project was last updated, including changes to its multipliers or Independent Phase Rates setting.

Project Structure

Phases

Phases divide a project into budgeted stages or milestones.

View: phases

ColumnTypeFKNullableDescription
idbigintnoPrimary key.
project_idbigintprojects.idnoParent project.
namestringyesPhase name.
phase_numberstringyesPhase number identifier.
is_budgetbooleannotrue = Phase, false = Milestone.
is_defaultbooleannoWhether this is the default phase.
is_mainbooleannoWhether this is the main phase of the project.
feenumericyesTotal budget amount for the phase.
contract_typestringyesContract type. See values below.
bill_rate_typestringyesHow billing rates are determined. See values below.
billablebooleanyesWhether work in this phase is billable.
hours_budgetnumericyesHours budget entered on the phase. For the budget Mosaic displays, use phase_budgets.
currency_budgetnumericyesCurrency budget entered on the phase. For the budget Mosaic displays, use phase_budgets.
budget_statusstringyesPhase budget status. See values below.
budget_fixed_fee_withstringyesHow the fixed-fee budget is calculated. See values below.
budget_hourly_withstringyesHow the hourly budget is calculated. See values below.
budget_internal_withstringyesHow the internal budget is calculated. See values below.
budget_phase_bystringyesHow the phase is budgeted. See values below.
ancestorsinteger[]yesArray of ancestor phase IDs (parent chain).
rate_multipliernumericyesThe phase's own bill rate multiplier. Used only when the project's independent_phase_rates is true. NULL on a milestone or for a team that tracks budgets in hours. See Rate Multipliers.
cost_rate_multipliernumericyesThe phase's own cost rate multiplier, under the same conditions as rate_multiplier.
start_datedatetimeyesPhase start date.
end_datedatetimeyesPhase end date.
archived_atdatetimeyesWhen this phase was archived. NULL if active.
created_atdatetimenoWhen this phase was created.
updated_atdatetimenoWhen this phase was last updated.

contract_type values:

ValueMeaning
Fixed FeeFixed-fee contract.
HourlyHourly contract.
InternalInternal (non-client) work.

bill_rate_type values:

ValueMeaning
work_categoryRates determined by work category.
memberRates determined by team member.
roleRates determined by role.
NULLNot set.

budget_status values (phases):

ValueMeaning
not startedBudget has not started (default).
holdBudget is on hold.
activeBudget is active.
completeBudget is complete.

budget_fixed_fee_with / budget_hourly_with / budget_internal_with values:

ValueMeaning
phase_estimateUse the phase-level estimate.
member_estimatesUse member-level estimates.
spent_and_plannedUse spent + planned hours.
work_category_estimatesUse work category estimates.
phase_estimate_percentageUse phase estimate as a percentage.

budget_phase_by values:

ValueMeaning
total hoursBudget by total hours.
member estimatesBudget by member estimates.
spent and plannedBudget by spent + planned.

Phase Memberships

Associates team members with specific project phases.

View: phase_memberships

ColumnTypeFKNullableDescription
idbigintnoPrimary key.
project_membership_idbigintproject_memberships.idnoThe project membership this belongs to.
phase_idbigintphases.idnoThe phase the member is assigned to.
member_idbigintmembers.idyesThe assigned member.
created_atdatetimenoWhen this assignment was created.
updated_atdatetimenoWhen this assignment was last updated.
archived_atdatetimeyesWhen this assignment was archived. NULL if active.

Only phase memberships with a valid project_membership_id are included in this view.


Work Categories

Phase-level work categories define billable/budgetable line items within a phase.

View: work_categories

ColumnTypeFKNullableDescription
idbigintnoPrimary key.
project_idbigintprojects.idnoParent project.
phase_idbigintphases.idnoParent phase.
standard_work_category_idbigintstandard_work_categories.idyesThe org-level template this is based on.
totalnumericyesTotal budget amount for this work category.
is_defaultbooleannoWhether this is the default work category.
billablebooleanyesWhether work in this category is billable.
start_datedatetimeyesStart date.
end_datedatetimeyesEnd date.
estimated_hoursnumericyesEstimated hours budget.
estimated_costnumericyesEstimated cost budget.
budget_statusstringyesWork category budget status. See values below.
rate_multipliernumericyesThe work category's own bill rate multiplier. Used only when the project's independent_phase_rates is true. NULL for a team that tracks budgets in hours. See Rate Multipliers.
cost_rate_multipliernumericyesThe work category's own cost rate multiplier, under the same conditions as rate_multiplier.
is_ptobooleannoWhether the work category is a paid time off category.
archived_atdatetimeyesWhen this work category was archived. NULL if active.
created_atdatetimenoWhen this work category was created.
updated_atdatetimenoWhen this work category was last updated.

budget_status values (work categories):

ValueMeaning
activeWork category is active (default).
proposalWork category is in proposal stage.
holdWork category is on hold.
completeWork category is complete.

Note: Work category budget_status values differ from phase budget_status values. Work categories use proposal where phases use not started.


Standard Work Categories

Organization-level work category templates. Individual work_categories on phases reference these.

View: standard_work_categories

ColumnTypeFKNullableDescription
idbigintnoPrimary key.
titlestringnoCategory name.
archivedbooleannoWhether this category is archived.
billablebooleanyesWhether work in this category is billable.
is_defaultbooleannoWhether this is the default category.
is_custombooleannoWhether this is a custom (team-created) category.
created_atdatetimenoWhen this category was created.
updated_atdatetimenoWhen this category was last updated.

People on Projects

Project Memberships

Represents a member's or open role's place on a project.

View: project_memberships

ColumnTypeFKNullableDescription
idbigintnoPrimary key.
project_idbigintprojects.idnoThe project.
member_idbigintmembers.idyesThe member. NULL for an open (unfilled) role; the role comes from project_roles.
archived_atdatetimeyesWhen this membership was archived. NULL if active.
created_atdatetimenoWhen this membership was created.
updated_atdatetimenoWhen this membership was last updated.

Project Roles

Assigns a role to a project member, with optional date ranges.

View: project_roles

ColumnTypeFKNullableDescription
idbigintnoPrimary key.
project_membership_idbigintproject_memberships.idnoThe project membership this role belongs to.
role_idbigintroles.idyesThe role assigned.
role_numberstringyesThe position number for this role assignment.
start_datedateyesWhen this role assignment starts.
end_datedateyesWhen this role assignment ends.
created_atdatetimenoWhen this assignment was created.
updated_atdatetimenoWhen this assignment was last updated.
archived_atdatetimeyesWhen this assignment was archived. NULL if active.

Budgets

All dollar amounts in these views are at bill rate, in the currency they were stored in. No currency code is published.

Phase Budgets

The budget Mosaic displays on the project Budget screen for each phase, in hours and dollars. Unlike phases.hours_budget and phases.currency_budget, which hold the value entered on the phase, this view returns the calculated budget for every Budget With setting.

View: phase_budgets

ColumnTypeFKNullableDescription
phase_idbigintphases.idnoThe phase.
project_idbigintprojects.idnoThe project.
budget_withstringyesThe budget setting in force for the phase. See values below.
hours_budgetnumericyesThe hours budget Mosaic displays.
currency_budgetnumericyesThe dollar budget Mosaic displays, at bill rate. NULL for a team that tracks budgets in hours.

Which rows appear: one row per phase, including subphases and archived phases. Milestones (phases.is_budget = false) have no row.

budget_with values:

ValueSetting in Mosaic
phase_estimateUse Entered Budget (Total Hours on a team that tracks budgets in hours)
member_estimatesTotal Member Time Budget
spent_and_plannedTotal Spent + Planned Time
work_category_estimatesSubphase Budgets
phase_estimate_percentage% of Parent Phase Budget

budget_with is the one column to read for a phase's budget setting. For a team that tracks budgets in currency, it is chosen by the phase's contract type (the Fixed Fee or Hourly setting). For a team that tracks budgets in hours, it is the phase's hours setting, published in the same vocabulary.

Empty vs. zero: A phase on Use Entered Budget with nothing entered returns NULL. A phase on a calculated setting with nothing to add up returns 0.

Hours on a currency team: For a team that tracks budgets in currency, hours_budget follows the dollar setting. The phase's own hours setting and any hours entered on the phase do not apply.


Member Budgets

Time budgets for each member and open role on each work category. These are the figures behind the phase's Member Budget panel, and the detail behind a phase set to Total Member Time Budget in phase_budgets.

View: member_budgets

ColumnTypeFKNullableDescription
project_idbigintprojects.idnoThe project.
phase_idbigintphases.id, phase_budgets.phase_idnoThe phase or subphase the work category belongs to.
work_category_idbigintwork_categories.idnoThe work category.
project_membership_idbigintproject_memberships.idnoThe member's or open role's place on the project. Also joins to project_membership_id in phase_memberships and project_roles.
member_idbigintmembers.idyesThe team member. NULL for an open role.
hours_budgetnumericnoBudgeted hours. 0 when there is no time budget.
currency_budgetnumericyesBudgeted dollars at bill rate. 0 when there is no time budget. NULL for a team that tracks budgets in hours.
archived_atdatetimeyesWhen the member's place on this work category, phase or project was archived, whichever came first. NULL while active.
created_atdatetimenoWhen the member or open role was added to the work category.
updated_atdatetimenoWhen the row last changed. See below.

What a row is: one member or open role on one work category of a phase. Every member and open role on a work category has a row, with 0 when they have no time budget, matching the "0h" the Budget screen shows. To count budgeted members, filter on hours_budget > 0.

Which time budgets are counted: the same ones phase_budgets counts, so the two always agree.

  • Open roles are included. member_id is NULL; join project_membership_id to project_roles to get the role.
  • Archived members are included, with archived_at set. The Budget screen hides them in its member rows but counts them in the phase total. If you filter them out, your totals will be lower than the phase budget.
  • Members removed from the project are excluded. This mostly covers open roles replaced when someone was assigned.
  • Deleted work categories and milestones have no rows.
  • Scope estimates follow each project's own setting. If the project uses scope estimates, a member's scope-level time budgets are summed into their work category row. Otherwise only phase-level time budgets count.
  • When a phase hides its work categories, only its default work category has rows, as on the Budget screen.

Placeholders: a project with no phases budgets on a placeholder phase, shown in Mosaic as "Project Schedule" (phases.is_default / phases.is_main). A phase with no work categories, or one that hides them, budgets on a placeholder work category, shown as "No Work Category" or "Time on Phase" (work_categories.is_default). Rows on placeholders are published like any other.

Reconciling with phase_budgets: on a phase set to Total Member Time Budget (budget_with = 'member_estimates'), the rows on that phase and its subphases add up to the phase's hours_budget and currency_budget in phase_budgets, within rounding. On phases with other settings, the rows still show each member's budget but the phase total comes from elsewhere.

About the dollar figures: Mosaic stores a member's dollar budget when it is saved, using that day's rate, multiplier and (where enabled) exchange rate, and refreshes it in the background when a rate or multiplier changes. A published dollar figure can therefore differ from hours × today's rate. The Budget screen reads the same stored amounts, so the two match.

updated_at and incremental pulls: updated_at moves on every change to a row, including clearing a time budget (the row stays, now with 0), archiving or unarchiving the member at any level, and turning the project's scope estimates on or off. A pull of rows changed since your last pull returns new and edited rows. It cannot return rows that leave the view (for example, a removed member or a deleted work category), so run a periodic full pull to replace your copy.


Rate Multipliers

Mosaic applies one bill rate multiplier and one cost rate multiplier to each piece of work. Which one applies depends on the project's Independent Phase Rates setting (projects.independent_phase_rates):

  • true: work on a work category uses that work category's multiplier (work_categories.rate_multiplier). Work on a phase uses the phase's multiplier (phases.rate_multiplier).
  • false: all work on the project uses the project's multiplier (projects.rate_multiplier). The phase and work category values are kept but unused, and apply again if the setting is turned back on.

Multipliers never stack: a phase's multiplier is never applied on top of the project's. The same rule applies to cost_rate_multiplier.

Read the setting before the value. Many projects have Independent Phase Rates off while their phases and work categories still hold different stored multipliers. Reading those values without checking independent_phase_rates gives the wrong multiplier.

Values are published as stored, unrounded. The Budget screen rounds them (for example, 3.2x). Multipliers are already included in the published rates and dollar amounts (time_entries.rate, phase_budgets, member_budgets), and they apply to non-billable work too. Mosaic keeps only the current multiplier: after a change, it reapplies the new value to past figures, so there is no multiplier history.

Multiplier in effect for each phase. This is the badge shown next to Member Budget on the phase (the cost rate multiplier is shown instead when the Budget screen shows cost rates):

SELECT
  ph.id AS phase_id,
  ph.name AS phase_name,
  p.independent_phase_rates,
  CASE WHEN p.independent_phase_rates THEN ph.rate_multiplier ELSE p.rate_multiplier END AS bill_rate_multiplier,
  CASE WHEN p.independent_phase_rates THEN ph.cost_rate_multiplier ELSE p.cost_rate_multiplier END AS cost_rate_multiplier
FROM phases ph
JOIN projects p ON p.id = ph.project_id
WHERE ph.is_budget;

For work on a work category, use work_categories.rate_multiplier in place of phases.rate_multiplier when independent_phase_rates is true.


Scope & Tasks

Project Scopes

Scope items represent deliverables or work items at the project level.

View: project_scopes

ColumnTypeFKNullableDescription
idbigintnoPrimary key.
project_idbigintprojects.idnoParent project.
phase_idbigintphases.idyesAssociated phase.
standard_work_category_idbigintstandard_work_categories.idyesAssociated standard work category.
work_category_idbigintwork_categories.idyesAssociated work category.
descriptionstringyesScope item description.
created_atdatetimenoWhen this scope item was created.
updated_atdatetimenoWhen this scope item was last updated.

Project Scope Assignments

Assigns members to scope items.

View: project_scope_assignments

ColumnTypeFKNullableDescription
idbigintnoPrimary key.
member_idbigintmembers.idyesThe assigned member.
assigner_idbigintmembers.idyesThe member who made the assignment.
project_scope_idbigintproject_scopes.idnoThe scope item.
project_membership_idbigintproject_memberships.idyesThe project membership.
created_atdatetimenoWhen this assignment was created.
updated_atdatetimenoWhen this assignment was last updated.
archived_atdatetimeyesWhen this assignment was archived. NULL if active.

Task Lists

Task lists group tasks within a project.

View: task_lists

ColumnTypeFKNullableDescription
idbigintnoPrimary key.
namestringnoTask list name.
project_idbigintprojects.idnoParent project.
created_atdatetimenoWhen this task list was created.
updated_atdatetimenoWhen this task list was last updated.

Project Tasks

Individual tasks within a project.

View: project_tasks

ColumnTypeFKNullableDescription
idbigintnoPrimary key.
descriptionstringyesTask description.
project_idbigintprojects.idnoParent project.
phase_idbigintphases.idyesAssociated phase.
standard_work_category_idbigintstandard_work_categories.idyesAssociated standard work category.
work_category_idbigintwork_categories.idyesAssociated work category.
estimated_hoursnumericyesEstimated hours for this task.
task_list_idbiginttask_lists.idyesThe task list this task belongs to.
task_list_sort_rankintegeryesSort order within the task list.
work_category_sort_rankintegeryesSort order within the work category.
completed_atdatetimeyesWhen this task was completed.
archived_atdatetimeyesWhen this task was archived. NULL if active.
created_atdatetimenoWhen this task was created.
updated_atdatetimenoWhen this task was last updated.

Project Task Assignments

Assigns members to project tasks.

View: project_task_assignments

ColumnTypeFKNullableDescription
idbigintnoPrimary key.
member_idbigintmembers.idyesThe assigned member.
assigner_idbigintmembers.idyesThe member who made the assignment.
project_task_idbigintproject_tasks.idnoThe task.
project_membership_idbigintproject_memberships.idyesThe project membership.
created_atdatetimenoWhen this assignment was created.
updated_atdatetimenoWhen this assignment was last updated.
archived_atdatetimeyesWhen this assignment was archived. NULL if active.

Project Notes

Notes attached to projects.

View: project_notes

ColumnTypeFKNullableDescription
idbigintnoPrimary key.
titlestringyesNote title.
bodystringyesNote body text.
project_idbigintprojects.idnoParent project.
creator_idbigintyesIdentifier of the note creator.
created_atdatetimenoWhen this note was created.
updated_atdatetimenoWhen this note was last updated.

Important: creator_id is not directly joinable with the members table. It uses a different internal ID space.


Time & Resource Planning

Time Entries

Logged time records.

View: time_entries

ColumnTypeFKNullableDescription
idbigintnoPrimary key.
project_idbigintprojects.idnoParent project.
phase_idbigintphases.idyesAssociated phase.
work_category_idbigintwork_categories.idyesAssociated work category.
standard_work_category_idbigintstandard_work_categories.idyesAssociated standard work category.
descriptionstringyesEntry description.
billablebooleanyesWhether this entry is billable.
hoursnumericyesHours logged.
datedateyesDate of the time entry.
ratenumericyesBill rate applied.
cost_ratenumericyesCost rate applied.
member_idbigintmembers.idyesThe member who logged the time.
statusstringyesApproval status. See values below.
created_atdatetimenoWhen this entry was created.
updated_atdatetimenoWhen this entry was last updated.

status values:

ValueMeaning
not_submittedDraft / not yet submitted for approval.
submittedSubmitted and awaiting approval.
approvedApproved.
rejectedRejected by approver.

Work Plans

Resource allocation schedule bars that define planned work over a date range.

View: work_plans

ColumnTypeFKNullableDescription
idbigintnoPrimary key.
project_idbigintprojects.idnoParent project.
phase_idbigintphases.idyesAssociated phase.
standard_work_category_idbigintstandard_work_categories.idyesAssociated standard work category.
work_category_idbigintwork_categories.idyesAssociated work category.
descriptionstringyesWork plan description.
start_datedateyesStart date of the plan.
end_datedateyesEnd date of the plan.
daily_hoursnumericyesHours allocated per day. NULL when weekly planning is enabled.
weekly_hoursnumericyesHours allocated per week. NULL when daily planning is used.
total_hoursnumericyesTotal planned hours for the full date range.
member_idbigintmembers.idyesThe planned member.
project_membership_idbigintproject_memberships.idyesThe project membership.
effective_hoursnumericnoTotal planned hours for this work plan, computed as the sum of its per-day hour breakdowns. Should approximately equal total_hours. Defaults to 0.
created_atdatetimenoWhen this work plan was created.
updated_atdatetimenoWhen this work plan was last updated.

Daily vs. Weekly Planning: Each work plan uses either daily or weekly hour allocation, never both.

  • When daily planning is used: daily_hours contains the value, weekly_hours is NULL.
  • When weekly planning is used: weekly_hours contains the value, daily_hours is NULL.

Relationships Overview

The following describes the key join paths between DDI views:

portfolios
 └── projects (via projects.portfolio_id)
      ├── phases (via phases.project_id)
      │    ├── phases.ancestors[] → other phase IDs (parent chain)
      │    ├── work_categories (via work_categories.phase_id)
      │    │    └── member_budgets (via member_budgets.work_category_id)
      │    ├── phase_budgets (via phase_budgets.phase_id)
      │    └── phase_memberships (via phase_memberships.phase_id)
      ├── project_memberships (via project_memberships.project_id)
      │    ├── project_roles (via project_roles.project_membership_id)
      │    │    └── roles (via project_roles.role_id)
      │    ├── phase_memberships (via phase_memberships.project_membership_id)
      │    ├── project_task_assignments (via project_task_assignments.project_membership_id)
      │    ├── project_scope_assignments (via project_scope_assignments.project_membership_id)
      │    ├── member_budgets (via member_budgets.project_membership_id)
      │    └── work_plans (via work_plans.project_membership_id)
      ├── project_scopes (via project_scopes.project_id)
      │    └── project_scope_assignments (via project_scope_assignments.project_scope_id)
      ├── task_lists (via task_lists.project_id)
      ├── project_tasks (via project_tasks.project_id)
      │    └── project_task_assignments (via project_task_assignments.project_task_id)
      ├── project_notes (via project_notes.project_id)
      ├── time_entries (via time_entries.project_id)
      └── work_plans (via work_plans.project_id)

members
 ├── project_memberships (via project_memberships.member_id)
 ├── phase_memberships (via phase_memberships.member_id)
 ├── project_task_assignments (via project_task_assignments.member_id)
 ├── project_scope_assignments (via project_scope_assignments.member_id)
 ├── member_budgets (via member_budgets.member_id)
 ├── time_entries (via time_entries.member_id)
 └── work_plans (via work_plans.member_id)

standard_work_categories
 ├── work_categories (via work_categories.standard_work_category_id)
 ├── project_scopes (via project_scopes.standard_work_category_id)
 ├── project_tasks (via project_tasks.standard_work_category_id)
 ├── time_entries (via time_entries.standard_work_category_id)
 └── work_plans (via work_plans.standard_work_category_id)

Common Query Patterns

Use the api schema — These queries target the api schema, not public. If you're using psql directly, run SET search_path TO api; before your SELECT queries.

Get all active project members with their roles

SELECT
  m.first_name,
  m.last_name,
  p.title AS project_title,
  r.name AS role_name
FROM project_memberships pm
JOIN members m ON m.id = pm.member_id
JOIN projects p ON p.id = pm.project_id
LEFT JOIN project_roles pr ON pr.project_membership_id = pm.id AND pr.archived_at IS NULL
LEFT JOIN roles r ON r.id = pr.role_id
WHERE pm.archived_at IS NULL;

Get time entries with full context

SELECT
  te.date,
  te.hours,
  te.status,
  m.first_name || ' ' || m.last_name AS member_name,
  p.title AS project_title,
  ph.name AS phase_name,
  wc.id AS work_category_id
FROM time_entries te
JOIN members m ON m.id = te.member_id
JOIN projects p ON p.id = te.project_id
LEFT JOIN phases ph ON ph.id = te.phase_id
LEFT JOIN work_categories wc ON wc.id = te.work_category_id;

Compare planned vs. actual hours by project

SELECT
  p.title,
  COALESCE(SUM(wp.total_hours), 0) AS planned_hours,
  COALESCE(SUM(wp.effective_hours), 0) AS effective_hours
FROM work_plans wp
JOIN projects p ON p.id = wp.project_id
GROUP BY p.title
ORDER BY p.title;

Member budgets by phase, with each member's share of the phase budget

For each phase, sums each member's (or open role's) time budget across the phase's work categories and its subphases, as in the phase's Member Budget panel, and divides by the phase budget to get the % the Budget screen shows. The share uses dollars, or hours for a team that tracks budgets in hours (where the dollar columns are NULL).

SELECT
  ph.id AS phase_id,
  ph.name AS phase_name,
  mb.project_membership_id,
  COALESCE(m.first_name || ' ' || m.last_name, r.name || ' (open role)') AS member_or_role,
  SUM(mb.hours_budget) AS hours_budget,
  SUM(mb.currency_budget) AS currency_budget,
  ROUND(100.0 * COALESCE(
    SUM(mb.currency_budget) / NULLIF(pb.currency_budget, 0),  -- teams that track budgets in currency
    SUM(mb.hours_budget)    / NULLIF(pb.hours_budget, 0)      -- teams that track budgets in hours
  ), 1) AS pct_of_phase_budget
FROM phases ph
JOIN phase_budgets pb ON pb.phase_id = ph.id
-- rows on the phase itself or on any of its subphases
JOIN phases sub ON sub.project_id = ph.project_id
               AND (sub.id = ph.id OR ph.id = ANY(sub.ancestors))
JOIN member_budgets mb ON mb.phase_id = sub.id
LEFT JOIN members m ON m.id = mb.member_id
LEFT JOIN project_roles pr ON pr.project_membership_id = mb.project_membership_id
  AND mb.member_id IS NULL AND pr.archived_at IS NULL  -- open roles only
LEFT JOIN roles r ON r.id = pr.role_id
WHERE ph.project_id = 12345  -- your project
GROUP BY ph.id, ph.name, mb.project_membership_id, m.first_name, m.last_name, r.name,
         pb.currency_budget, pb.hours_budget
ORDER BY ph.name, member_or_role;

Archived members are counted in the phase budget. If you add WHERE mb.archived_at IS NULL, the shares will add up to less than 100%.