People Tool
Overview
Section titled “Overview”The People tool provides a directory of all active employees and an org chart visualization. Data is synced from Productive.io using their People API.
Features
Section titled “Features”- People directory — Searchable, sortable table of all active employees with avatar, name, title, email, and manager
- Person profile page — Full-page profile with four tabs: Details (Contact, Role, Personal, System), Employment (Tenure, Pay, Leave, Financial), Documents, and Activity. Navigates via
?id=personId - Org chart — Tree visualization showing the reporting hierarchy based on manager relationships
- Org chart peek sheet — Simplified quick-peek drawer when clicking a node in the org chart, showing Contact/System info, Activity tab, and a “View Profile” button
- Xero sync on profiles — Executives can link a person to their Xero employee record (with smart name/email matching) and trigger payroll data sync directly from the profile System card
- Productive sync — Manual sync button (executive only) pulls active people from Productive and matches them to app users by email
- User enrichment — Sync updates matched users’ job title and profile picture from Productive
- TTL-based refresh — Data auto-refreshes in the background after 6 hours
Toggle between two views using tabs:
- Directory (default) — Table with sortable columns (name, title, email) and manager lookup. Clicking a row navigates to the full profile page
- Org Chart — Hierarchical tree with collapsible nodes, showing first 2 levels expanded by default. Clicking a node opens a peek sheet with quick info and a link to the full profile
- Profile Page — Shown when
?id=personIdis present. Tabs are permission-scoped: Employment, Documents, and Activity require manager/head/executive access
Sync Behaviour
Section titled “Sync Behaviour”When an executive clicks “Sync”:
- Fetches all active people from Productive (paginated, max 200 per page)
- Upserts into the
peopletable, matched byproductive_id - Matches people to app users by email (case-insensitive)
- Resolves manager relationships (self-referencing FK)
- Updates matched users’
job_titleandpicturefrom Productive data - Upserts
user_external_idsfor theproductiveprovider - Removes people no longer active in Productive
Permissions
Section titled “Permissions”| Access Level | View | Update | Manage (Sync) |
|---|---|---|---|
| Executive | Yes | Yes | Yes |
| Head | Yes | No | No |
| Manager | Yes | No | No |
| Lead | Yes | No | No |
| Employee | Yes | No | No |
URL State
Section titled “URL State”| Parameter | Type | Description |
|---|---|---|
view | string | directory (default) or org-chart |
id | string | Person ID — when present, renders the full profile page |
Data Model
Section titled “Data Model”people table
Section titled “people table”The people table is the source of truth for all employee/HR data. Employee fields (employment, contact, demographics, financial) are stored here rather than on users, which allows Xero sync for people who don’t have an app account. The users table is auth-only (id, email, name, picture, access_level, template IDs).
| Column | Type | Description |
|---|---|---|
| id | TEXT PK | UUID |
| productive_id | TEXT UNIQUE | Productive person ID |
| user_id | TEXT FK | Matched app user (nullable) |
| first_name | TEXT | First name |
| last_name | TEXT | Last name |
| TEXT | Email address | |
| title | TEXT | Job title from Productive |
| avatar_url | TEXT | Profile picture URL |
| squad | TEXT | Squad/team name |
| manager_id | TEXT FK | Self-referencing FK to manager’s people row |
| xero_employee_id | TEXT | Linked Xero employee GUID |
| start_date | TEXT | Employment start date |
| end_date | TEXT | Employment end date (nullable) |
| employment_status | TEXT | active (default) or terminated |
| employment_basis | TEXT | FULLTIME, PARTTIME, CASUAL, etc. |
| location | TEXT | Work location |
| gender | TEXT | Gender code from Xero |
| date_of_birth | TEXT | Date of birth |
| phone | TEXT | Work phone |
| mobile | TEXT | Mobile number |
| personal_email | TEXT | Personal email address |
| home_address | TEXT | Home address (JSON from Xero) |
| super_fund_name | TEXT | Superannuation fund name |
| super_fund_type | TEXT | REGULATED or SELFMANAGED |
| super_member_number | TEXT | Super fund member number |
| bank_account_name | TEXT | Bank account holder name |
| bank_bsb | TEXT | Bank BSB |
| bank_account_number | TEXT | Bank account number |
| synced_at | TEXT | Last sync timestamp |
Components
Section titled “Components”| File | Purpose |
|---|---|
src/routes/people.tsx | Route with ?view and ?id search params |
src/components/people/people-page.tsx | Main page with view toggle, search, sync button; renders profile page when id param present |
src/components/people/people-directory.tsx | Searchable/sortable table view |
src/components/people/person-profile.tsx | Full-page person profile with tabbed layout |
src/components/people/person-peek-sheet.tsx | Simplified peek drawer for org chart |
src/components/people/org-tree.tsx | Recursive tree visualization |
src/components/people/org-card.tsx | Individual person card in org chart |
src/hooks/use-people.ts | TanStack Query hooks |
worker/routes/people.ts | API endpoints |