App design template · Example
Recruiting workspace design
Example: a company hiring across several countries. Resumes sit in a shared Google Drive folder and a hiring inbox, interviewers write feedback in different formats, and offers live in email. One App runs one workflow, from the first resume to the first day, across ten tables. Every candidate is one record with one thread, so the team and agents talk about a person in one place.
- Workflow
- First resume to first day
- App
- 1 custom App
- Tables
- 10
- Data sources
- Google Drive · Gmail · Google Calendar · Read AI
01 Business flow
Agents organize, match and draft. People make the calls: screening, interview feedback, the offer and the start date. Each candidate has one thread where the team and agents discuss that person.
First resume to first day
Every resume lands on one candidate record with its own thread. The agent matches, schedules, drafts feedback and emails; people screen, assess, approve the offer and own onboarding.
Stage 1 · Intake and screening
Resume arrives
A new file in the Google Drive hiring folder, or an email with an attachment in Gmail
resume_filesParse and dedupe
Extracts name, contact details and experience; matches on email and phone and attaches the file to the existing person
resume_filesMatch to positions
Checks each open position's requirements, lists what is met and missing, and suggests the best fit
positionsapplicationsScreening call
Move to interview, keep in the pool, or decline, from the candidate's thread
Stage 2 · Interviews and feedback
Schedule
Reads interviewer calendars and drafts the invite in Gmail; HR approves before it is sent
applicationsDraft feedback
Fills the position's scorecard with strengths, concerns and quotes with timestamps
evaluationsEdit and submit
Adjusts the draft and recommends hire, hold or no hire
evaluationsRound decision
Once all feedback is in, reviews it side by side and moves to the next round, an offer, or a decline
evaluationsapplicationsStage 3 · Offer and first day
Offer email and tasks
Drafts the offer email for HR to send; once accepted, creates the onboarding checklist
offers02 Tables
10 tables in 1 App. Positions, scorecard criteria and candidates are master data. Resume files, applications, interviews, feedback, offers and onboarding tasks track one candidate through one position. Activities log every email, note and stage change on the candidate's timeline.
erDiagram
direction LR
candidates ||--o{ resume_files : "sends"
candidates ||--o{ applications : "applies"
positions ||--o{ applications : "receives"
positions ||--o{ scorecard_criteria : "assessed by"
applications ||--o{ interviews : "schedules"
interviews ||--o{ evaluations : "produces"
applications ||--o| offers : "results in"
applications ||--o{ onboarding_tasks : "prepares"
candidates ||--o{ activities : "logs"
positionsPositionsOpen roles; requirements drive matching9 fields
Masterscorecard_criteriaScorecard criteriaWhat each interview round assesses for a position5 fields
MastercandidatesCandidatesOne record and one thread per person12 fields
Processresume_filesResume filesEach resume or document received, before and after parsing7 fields
ProcessapplicationsApplicationsOne candidate for one position; the stage drives the pipeline11 fields
ProcessinterviewsInterviewsOne record per round; interviewers see only their own9 fields
ProcessevaluationsFeedbackOne interviewer's feedback on one interview; private until submitted9 fields
ProcessoffersOffersSalary is visible to HR and approvers only9 fields
Processonboarding_tasksOnboarding tasksWhat has to happen before and on the first day6 fields
ProcessactivitiesActivitiesThe candidate's timeline: emails, notes, stage changes, agent actions6 fields
Workflow steps by table
One workflow, ten tables. Each step reads what it needs and writes its result to a table.
positions | scorecard_criteria | candidates | resume_files | applications | interviews | evaluations | offers | onboarding_tasks | activities | |
|---|---|---|---|---|---|---|---|---|---|---|
| 01 Resume arrives External system | Write | |||||||||
| 02 Parse and dedupe Agent | Read · Write | Read | Write | |||||||
| 03 Match to positions Agent | Read | Write | ||||||||
| 04 Screening call HR | Read · Write | Write | ||||||||
| 05 Schedule Agent | Read | Write | Write | |||||||
| 06 Record and transcribe External system | Write | |||||||||
| 07 Draft feedback Agent | Read | Read | Write | |||||||
| 08 Edit and submit Interviewer | Read · Write | |||||||||
| 09 Round decision Hiring manager | Write | Read | ||||||||
| 10 Draft the offer HR | Read | Write | ||||||||
| 11 Approve Approver | Read · Write | |||||||||
| 12 Offer email and tasks Agent | Read | Write | Write | |||||||
| 13 First day ready Hiring manager | Read · Write |
03 Fields
Each field lists its type, constraints, which source fills it and which roles can see it. Fields with no source are filled by people in the App or set by the process.
positions PositionsMaster9 fields
| Field | Type | Description | Constraint | Source | Visible to |
|---|---|---|---|---|---|
id | uuid | Primary key | PK | All roles | |
title | text | Position title | required | All roles | |
department | text | Department | required | All roles | |
location | text | Location or country | All roles | ||
hiring_manager | member | Hiring manager | required | All roles | |
requirements | text[] | Requirements, one per line, used for matching | required | All roles | |
headcount | int | Number of hires | default 1 | HRHiring manager | |
salary_band | text | Salary band | HRApprover | ||
status | enum | Open / Paused / Closed | default Open | All roles |
scorecard_criteria Scorecard criteriaMaster5 fields
| Field | Type | Description | Constraint | Source | Visible to |
|---|---|---|---|---|---|
id | uuid | Primary key | PK | All roles | |
position_id | uuid | Position | FK positions | All roles | |
round | enum | Round 1 / Round 2 / Final | required | All roles | |
criterion | text | What is assessed | required | All roles | |
what_good_looks_like | text | What a strong answer shows | All roles |
candidates CandidatesMaster12 fields
| Field | Type | Description | Constraint | Source | Visible to |
|---|---|---|---|---|---|
id | uuid | Primary key | PK | All roles | |
name | text | Full name | required | Google DriveGmail | All roles |
email | Email, the dedupe key | unique | Google DriveGmail | HRHiring manager | |
phone | text | Phone in E.164 format | Google Drive | HRHiring manager | |
location | text | Where they are based | Google Drive | All roles | |
current_company | text | Most recent company | Google Drive | All roles | |
current_title | text | Most recent title | Google Drive | All roles | |
years_exp | numeric | Years of experience | Google Drive | All roles | |
skills | tag[] | Skill tags, normalized to a tag dictionary | Google Drive | All roles | |
source_channel | enum | Drive folder / Inbox / Referral / LinkedIn | required | Google DriveGmail | HRHiring manager |
owner | member | Recruiter who owns this candidate | HR | ||
talent_status | enum | New / Active / Pool / Hired / Declined | default New | HR |
resume_files Resume filesProcess7 fields
| Field | Type | Description | Constraint | Source | Visible to |
|---|---|---|---|---|---|
id | uuid | Primary key | PK | All roles | |
candidate_id | uuid | Candidate | FK candidates | Google DriveGmail | All roles |
file_name | text | File name | required | Google DriveGmail | All roles |
file_url | url | Link to the original file | required | Google DriveGmail | HRHiring managerInterviewer |
source | enum | Drive folder / Inbox / Referral | required | Google DriveGmail | HR |
received_at | timestamp | Received at | required | Google DriveGmail | HR |
parse_status | enum | Parsed / Needs review / Duplicate | default Parsed | HR |
applications ApplicationsProcess11 fields
| Field | Type | Description | Constraint | Source | Visible to |
|---|---|---|---|---|---|
id | uuid | Primary key | PK | All roles | |
name | text | Display name: candidate · position | required | All roles | |
candidate_id | uuid | Candidate | FK candidates | All roles | |
position_id | uuid | Position | FK positions | Google DriveGmail | All roles |
stage | enum | Screen / Round 1 / Round 2 / Final / Offer / Hired / Rejected | required | All roles | |
fit_summary | text | Fit notes, drafted by the agent | HRHiring manager | ||
matched_reqs | text[] | Requirements met | HRHiring manager | ||
missing_reqs | text[] | Requirements missing | HRHiring manager | ||
manager_decision | enum | Pending / Meet / Pass | default Pending | HRHiring manager | |
next_step | text | What happens next | All roles | ||
applied_at | timestamp | Applied at | required | Gmail | HRHiring manager |
interviews InterviewsProcess9 fields
| Field | Type | Description | Constraint | Source | Visible to |
|---|---|---|---|---|---|
id | uuid | Primary key | PK | All roles | |
name | text | Display name: candidate · round | required | All roles | |
application_id | uuid | Application | FK applications | All roles | |
round | enum | Round 1 / Round 2 / Final | required | All roles | |
interviewer | member | Interviewer | required | Google Calendar | All roles |
scheduled_at | timestamp | Interview time, stored in UTC | Google Calendar | All roles | |
meeting_link | url | Meeting link | Google Calendar | All roles | |
transcript_url | url | Transcript link | Read AI | HRInterviewer | |
status | enum | To schedule / Scheduled / Done / Cancelled | default To schedule | All roles |
evaluations FeedbackProcess9 fields
| Field | Type | Description | Constraint | Source | Visible to |
|---|---|---|---|---|---|
id | uuid | Primary key | PK | Author only | |
name | text | Display name: candidate · round · interviewer | required | Author only | |
interview_id | uuid | Interview | FK interviews | Author only | |
strengths | text | Strengths against the scorecard | Read AI | Author only | |
concerns | text | Concerns | Read AI | Author only | |
evidence_quotes | text[] | Candidate quotes with timestamps | Read AI | Author only | |
recommendation | enum | Hire / Hold / No hire | required on submit | Author only | |
status | enum | Draft / Submitted | default Draft | Author only | |
submitted_at | timestamp | Submitted at | auto | Author only |
offers OffersProcess9 fields
| Field | Type | Description | Constraint | Source | Visible to |
|---|---|---|---|---|---|
id | uuid | Primary key | PK | HRApprover | |
name | text | Display name: candidate · position | required | HRHiring managerApprover | |
application_id | uuid | Application | FK applications | HRHiring managerApprover | |
level | text | Level | required | HRHiring managerApprover | |
base_salary | currency | Annual base salary | required | HRApprover | |
start_date | date | Proposed start date | required | HRHiring managerApprover | |
approver | member | Approver | required | HRApprover | |
status | enum | Draft / Pending approval / Approved / Sent / Accepted / Declined | default Draft | Gmail | HRHiring managerApprover |
sent_at | timestamp | Sent at | Gmail | HRApprover |
onboarding_tasks Onboarding tasksProcess6 fields
| Field | Type | Description | Constraint | Source | Visible to |
|---|---|---|---|---|---|
id | uuid | Primary key | PK | HRHiring manager | |
application_id | uuid | Application | FK applications | HRHiring manager | |
task | text | Task | required | HRHiring manager | |
owner | member | Who does it | required | HRHiring manager | |
due_date | date | Due date | required | HRHiring manager | |
status | enum | To do / Done | default To do | HRHiring manager |
activities ActivitiesProcess6 fields
| Field | Type | Description | Constraint | Source | Visible to |
|---|---|---|---|---|---|
id | uuid | Primary key | PK | All roles | |
candidate_id | uuid | Candidate | FK candidates | All roles | |
kind | enum | Email draft / Email sent / Note / Stage change / Agent action | required | Gmail | All roles |
summary | text | What happened | required | Gmail | All roles |
actor | text | Who did it, person or agent | required | All roles | |
occurred_at | timestamp | When | required | Gmail | All roles |
04 Field mapping
How fields from external systems land in the tables. Sources first, then each mapping with its field pairs and transform rules.
| Source | What we take | Sync | Direction | Writes to |
|---|---|---|---|---|
| Google Drive | Resume PDFs and docs in the hiring folder | Full backfill once, then incremental every 24 hours | In | resume_files |
| Gmail | Candidate emails, attachments, invite and offer drafts | On each new email; drafts sent after approval | In / Out | applications |
| Google Calendar | Interview events | When an event is created or changed | In | interviews |
| Read AI | Interview transcripts | After the meeting ends | In | evaluations |
Each new file becomes a resume file; the agent reads it and fills the candidate. If the email already exists, it attaches to that person and fills only empty fields.
| Source field | Target field | Transform rule |
|---|---|---|
| File name | resume_files.file_name | As is |
| File link | resume_files.file_url | Keep the Drive link, do not copy the file |
| Created time | resume_files.received_at | Store in UTC |
| Resume · name | candidates.name | Trim spaces and honorifics |
| Resume · email | candidates.email | Lowercase; dedupe key |
| Resume · phone | candidates.phone | Normalize to E.164 |
| Latest job · company and title | candidates.current_company, current_title | As is |
| All job start and end dates | candidates.years_exp | Merge overlapping ranges, sum, one decimal |
| Skills section | candidates.skills | Normalize to the tag dictionary |
| Parent folder name | applications.position_id | Folder name matches positions.title; no match goes to review |
Attachments go through the same resume intake. If the email names no position, the agent suggests one from the match and HR reviews it.
| Source field | Target field | Transform rule |
|---|---|---|
| From address | candidates.email | Lowercase; dedupe on it |
| Subject | applications.position_id | Match position titles; flag for review if several match |
| Received at | applications.applied_at | Store in UTC |
| Message summary | activities.summary | One line, kind Email received |
Invites the agent drafts carry the interview ID in the event title, which is how events match records.
| Source field | Target field | Transform rule |
|---|---|---|
| Interview ID in event title | interviews.id | Match on primary key |
| Start time | interviews.scheduled_at | Store in UTC, show in the viewer's time zone |
| Attendee email | interviews.interviewer | Match to a team member by email |
| Meeting link | interviews.meeting_link | As is |
Drafts appear only in that interviewer's feedback, as Draft. They count once the interviewer edits and submits.
| Source field | Target field | Transform rule |
|---|---|---|
| Transcript link | interviews.transcript_url | As is |
| Transcript, by scorecard criterion | evaluations.strengths / concerns | Organized by scorecard_criteria for that round |
| Candidate segments | evaluations.evidence_quotes | Quote verbatim with timestamps |
| Constant | evaluations.status | Draft |
Runs when an offer becomes Accepted. The checklist comes from the position's department; owners can edit it.
| Source field | Target field | Transform rule |
|---|---|---|
offers.start_date | onboarding_tasks.due_date | Each task due a set number of days before the start date |
positions.hiring_manager | onboarding_tasks.owner | For manager tasks; HR tasks go to the candidate owner |
| offers.status = Accepted | applications.stage | Set to Hired |
candidates.talent_status | candidates.talent_status | Set to Hired |
05 Who sees what
Interview feedback is isolated between interviewers until a round is complete, and salary is visible only to HR and approvers.
| HR | Hiring manager | Interviewer | Approver | |
|---|---|---|---|---|
| Positions and scorecards | Edit | Edit | View | View |
| Candidate profile and timeline | Edit | View | View | View |
| Contact details and resume files | Edit | View | Resume only | Hidden |
| Fit notes | View | View | Hidden | Hidden |
| Interview schedule | Edit | View | Own interviews | Hidden |
| Own feedback | Edit | Edit | Edit | Hidden |
| Others' feedback · round not complete | Hidden | Hidden | Hidden | Hidden |
| Others' feedback · round complete | View | View | This interview | View |
| Offer salary | Edit | Hidden | Hidden | Edit |
| Onboarding tasks | Edit | Edit | Hidden | View |
An agent reads data with the permissions of the person it is working for. When an interviewer asks it to draft feedback, it cannot read other interviewers' feedback.
06 From design to App
Once the design is signed off, the custom App is built from the same definition: one data entity per table, plus these pages. Every candidate page opens that person's thread.
Mock data for a quick build: 3 positions, 5 scorecard criteria, 5 candidates, 5 resume files, 5 applications, 5 interviews, 4 feedback, 1 offers, 3 onboarding tasks, 8 activities.
- PipelineHR · Hiring managerOne row per candidate with stage, position and next step; filter by stage or position
/?stage=&position= - Candidate pageEveryone, by roleProfile, applications, interviews and feedback, offer, onboarding and the timeline, with the candidate's thread one click away
/candidates/:candidateId?tab= - PositionsHR · Hiring managerOpen positions with requirements, scorecard criteria and how many candidates sit in each stage
/positions - InterviewsInterviewerUpcoming and past rounds with feedback status, filterable by interviewer
/interviews?interviewer=