Skip to main content

PBS - Entities Reference for Product Managers

Document Version: 2.0 Last Updated: 2025-10-22 Purpose: Non-technical explanation of all database entities, their properties, and relationships


Table of Contents​

  1. System Overview
  2. Entity Domains
  3. Detailed Entity Reference
  4. Relationship Summary
  5. Data Flow Examples

System Overview​

PBS organizes data into 7 main domains:

1. Company & Access ────┐
2. People (Staff) β”œβ”€β”€> Core System
3. Projects & Teams β”‚
4. Assignments β”˜
5. Logistics
6. Staff Pool (Intake)
7. Documents & Exports

Hierarchy:

PBS Platform
└─ Company (Your customer, e.g., NCP)
β”œβ”€ Users (Login accounts - Admins and Staff)
β”œβ”€ Profiles (Staff directory - all crew members)
β”œβ”€ Function Catalog (Roles: Camera Op, Sound Mixer, etc.)
β”œβ”€ Projects
β”‚ β”œβ”€ Teams (Optional groups within project)
β”‚ β”œβ”€ Project Functions (Required roles for project)
β”‚ β”‚ └─ Assignment Offers (PM sends to multiple people)
β”‚ β”‚ └─ Assignment (Confirmed booking - one winner)
β”‚ β”‚ β”œβ”€ Travel Bookings
β”‚ β”‚ β”œβ”€ Hotel Bookings
β”‚ β”‚ └─ Documents (Contracts, NDAs, Road Books)
β”‚ └─ Exports (Reports: crew lists, meal lists, etc.)
└─ Staff Pool Links (Public intake forms)
└─ Profile Submissions (Pending approvals)

Entity Domains​

Domain 1: Company & Access Control​

Purpose: Manage customer accounts and user permissions

EntityPurposeKey Concept
CompaniesYour customers (e.g., NCP)Top-level tenant - all data isolated per company
UsersLogin accountsCan be Admin (company user) or Staff (crew member self-service)
Project ID SettingsProject code generation rulesHow to auto-generate project codes (e.g., ESC-001, ESC-002)

Domain 2: People (Staff & Freelancers)​

Purpose: Manage your crew directory and their skills

EntityPurposeKey Concept
ProfilesStaff directoryAll crew members - employees, freelancers, contractors
Functions CatalogAvailable roles/positionsCamera Operator, Sound Mixer, Producer, etc.
Profile FunctionsWho can do whatLinks profiles to functions (many-to-many relationship)

Domain 3: Projects & Teams​

Purpose: Define your events and required roles

EntityPurposeKey Concept
ProjectsYour events/productionsEurovision 2025, Sports Broadcast, etc.
Project TeamsSub-groups within projectOptional - e.g., "OB Team 1", "Audio Crew"
Project FunctionsRequired roles for project"Need 3x Camera Operators for 10 work days + 2 travel days"

Domain 4: Assignments (The Booking Process)​

Purpose: Assign people to projects (offer β†’ negotiation β†’ confirmation)

EntityPurposeKey Concept
Assignment OffersProposals to staffPM sends to multiple people for same slot, with individual rates
AssignmentsConfirmed bookingsOne person locked to one project function (the winner)
Assignment Status LogsLifecycle trackingTimeline: confirmed β†’ contract β†’ travel β†’ completed

Domain 5: Logistics​

Purpose: Track travel and accommodation

EntityPurposeKey Concept
Travel BookingsFlight/train/car detailsPer assignment - manually entered for MVP
Hotel BookingsHotel staysPer assignment - check-in/out dates, costs

Domain 6: Staff Pool & Intake​

Purpose: Collect freelancer data via public forms

EntityPurposeKey Concept
Staff Pool LinksPublic intake formsShareable URLs (e.g., /pool/esc2025) for freelancers to submit info
Profile SubmissionsIncoming applicationsPending review - approved submissions become Profiles

Domain 7: Documents & Exports​

Purpose: File management and reporting

EntityPurposeKey Concept
DocumentsFile attachmentsCan attach to Profiles (photos, passports) or Assignments (contracts, NDAs)
ExportsGenerated reportsCrew lists, meal lists, hotel bookings, clothing sizes

Detailed Entity Reference​


1. Companies​

What it is: Your customers - the organizations that use PBS (e.g., NCP, SVT Sports, etc.)

Why it exists: Multi-tenant isolation - each company's data is completely separate

Properties:

PropertyTypeRequired?DescriptionExample
idUUIDYesUnique identifier550e8400-e29b-41d4-a716-446655440000
nameTextYesCompany name"New Century Production"
org_numberTextNoBusiness registration number"556677-8899"
default_currencyCode (3 chars)NoISO currency code"SEK", "EUR"
settingsJSONNoCompany-wide settings{"timezone": "Europe/Stockholm", "locale": "sv_SE"}
created_atTimestampAutoWhen company was created2025-01-15 10:30:00
updated_atTimestampAutoLast modified2025-01-20 14:22:00

Relationships:

  • Has many: Users, Profiles, Projects, Function Catalog, Staff Pool Links
  • Has one: Project ID Settings

Business Rules:

  • βœ“ One company per customer
  • βœ“ All data scoped to company (profiles, projects, etc.)
  • βœ“ MVP: Only one company, but schema supports multiple

2. Users​

What it is: Login accounts for accessing the system

Why it exists: Authentication and role-based permissions

Properties:

PropertyTypeRequired?DescriptionExample
idUUIDYesUnique identifier-
company_idUUIDYesWhich company they belong toLinks to Companies
emailEmailYesLogin email (unique)"anna@ncp.se"
passwordEncryptedYesHashed password-
nameTextYesDisplay name"Anna Andersson"
roleEnumYesUser role"ADMIN", "CREW", "PROJECT_MANAGER", etc.
profile_idUUIDNoLink to Profile (if CREW role)For crew self-service portal
email_verified_atTimestampNoEmail verification-
last_login_atTimestampNoLast login time2025-10-22 09:15:00

User Roles:

RoleMVP?DescriptionTypical User
ADMINβœ“ YesFull access to company settings and all projectsNCP Project Manager
CREWβœ“ YesSelf-service portal - view/edit own profile, see assignmentsFreelancer/crew member
PROJECT_MANAGERFutureCan create/manage projects, assign staff-
TEAM_LEADFutureLimited to their team(s)-
VIEWERFutureRead-only accessClient stakeholder

Relationships:

  • Belongs to: Company
  • Optionally belongs to: Profile (if role = CREW)

Business Rules:

  • βœ“ Email must be unique across entire system
  • βœ“ CREW role users must have a profile_id (links to their crew profile)
  • βœ“ ADMIN role users typically don't have a profile_id

3. Project ID Settings​

What it is: Rules for generating project codes

Why it exists: Auto-generate project codes like "ESC-001", "ESC-002" or allow manual entry

Properties:

PropertyTypeRequired?DescriptionExample
company_idUUIDYes (PK)One-to-one with company-
modeEnumYesAuto or manual generation"auto", "manual"
prefixTextNoCode prefix"ESC", "SPORTS", "PROD"
sequence_numberIntegerNoAuto-increment counter1, 2, 3...

Examples:

ModePrefixSequenceResult
auto"ESC"1"ESC-001"
auto"ESC"2"ESC-002"
autonull42"PROJECT-042"
manual--User types any code

Relationships:

  • Belongs to: Company (one-to-one)

4. Profiles​

What it is: Staff directory - all crew members (employees, freelancers, contractors)

Why it exists: Centralized database of everyone who can be assigned to projects

Properties:

PropertyTypeRequired?DescriptionExample
Identity
idUUIDYesUnique identifier-
company_idUUIDYesWhich company they belong to-
typeEnumYesStaff type (MVP: use 'staff' for all)"staff", "employee", "freelancer"
first_nameTextYesFirst name"Anna"
last_nameTextYesLast name"Andersson"
emailEmailNoContact email"anna.andersson@email.com"
phoneTextNoPhone number"+46 70 123 4567"
Address & Identity
addressTextNoFull postal address"Kungsgatan 12, 111 43 Stockholm"
personal_id_numberTextNoPersonnummer or national ID"19850315-1234"
nationalityCodeNoISO country code"SE", "NO", "DK"
passport_numberTextNoPassport number"AB1234567"
home_base_cityTextNoDeparture city for travel"Stockholm", "Oslo"
Emergency Contact
emergency_contact_nameTextNoEmergency contact name"Erik Andersson"
emergency_contact_phoneTextNoEmergency phone"+46 70 999 8888"
emergency_contact_relationTextNoRelationship"Spouse", "Parent", "Sibling"
Freelancer-Specific (only if type='freelancer')
org_numberTextNoCompany/VAT number"556688-9900"
invoicing_emailEmailNoSeparate email for invoices"faktura@company.se"
invoicing_addressTextNoBilling address"Box 123, 100 00 Stockholm"
Visual
photo_urlURLNoProfile photo for crew passes"/storage/profiles/123/photo.jpg"
Flexible Attributes (JSON)
languagesJSONNoLanguages spoken[{"code":"en","proficiency":"fluent"},{"code":"sv","proficiency":"native"}]
food_preferencesJSONNoDietary restrictions, allergies{"allergies":["peanuts","shellfish"],"diet":"vegetarian"}
clothing_sizesJSONNoClothing sizes{"shirt":"M","pants":"32","shoes":"42"}
Metadata
notesTextNoInternal notes (not visible to staff)"Preferred for Eurovision projects"
availability_statusEnumNoAvailability"available", "busy", "unavailable"
created_atTimestampAutoWhen created-
updated_atTimestampAutoLast modified-

Staff Self-Service Portal (what staff can view/edit):

  • βœ“ Can edit: Basic info (name, email, phone), photo, emergency contact, languages, food preferences, clothing sizes
  • βœ— Cannot edit: Type, company assignment, notes (internal), availability_status (PM manages)
  • βœ“ Future: Upload passport, view their assignments

Relationships:

  • Belongs to: Company
  • Has many: Profile Functions (skills), Assignments, Documents (photos, passports)
  • Can have: User account (for self-service portal login)

Business Rules:

  • βœ“ MVP: Use type='staff' for everyone (no employee/freelancer distinction yet)
  • βœ“ Future: Type 'freelancer' requires org_number and invoicing details
  • βœ“ Photo required for crew passes/accreditation
  • βœ“ Languages stored as array of objects with proficiency levels

Example Profile JSON:

{
"first_name": "Anna",
"last_name": "Andersson",
"email": "anna@email.com",
"phone": "+46 70 123 4567",
"address": "Kungsgatan 12, Stockholm",
"personal_id_number": "19850315-1234",
"nationality": "SE",
"home_base_city": "Stockholm",
"languages": [
{"code": "sv", "proficiency": "native"},
{"code": "en", "proficiency": "fluent"},
{"code": "no", "proficiency": "basic"}
],
"food_preferences": {
"allergies": ["peanuts"],
"diet": "vegetarian",
"notes": "Prefers gluten-free options"
},
"clothing_sizes": {
"shirt": "M",
"pants": "32",
"shoes": "42",
"jacket": "L"
}
}

5. Functions Catalog​

What it is: Company's catalog of available roles/positions

Why it exists: Define what job functions exist and their typical rates

Properties:

PropertyTypeRequired?DescriptionExample
idUUIDYesUnique identifier-
company_idUUIDYesWhich company this belongs to-
departmentTextNoGrouping/category"Camera", "Audio", "Production"
nameTextYesFunction name"Camera Operator", "Sound Mixer"
descriptionTextNoJob description"Operates broadcast cameras during live events"
avg_work_rate_centsIntegerNoAverage rate for work days (in cents)50000 (= €500.00)
avg_travel_rate_centsIntegerNoAverage rate for travel days (in cents)20000 (= €200.00)
avg_rate_currencyCodeNoCurrency for rates"EUR", "SEK"
is_customBooleanNoStandard or custom functiontrue/false

Why work vs travel rates?

  • Work days = actual event days (full rate)
  • Travel days = just traveling to/from event (lower rate, often 40-50% of work rate)

Standard vs Custom Functions:

  • Standard (is_custom=false): Pre-loaded catalog (Camera Op, Sound Mixer, Gaffer, etc.) - same for all companies
  • Custom (is_custom=true): Company-created roles for their specific needs

Relationships:

  • Belongs to: Company
  • Used by: Project Functions (what roles projects need)
  • Linked to profiles via: Profile Functions (who can do this role)

Business Rules:

  • βœ“ SaaS: Standard catalog provided, companies can add custom functions
  • βœ“ Average rates used for budget estimation only (actual rates set per assignment offer)
  • βœ“ Travel rate typically 40-50% of work rate

Example Functions:

DepartmentNameAvg Work RateAvg Travel RateIs Custom
CameraCamera Operator€500/day€200/dayfalse
AudioSound Mixer€450/day€180/dayfalse
ProductionLine Producer€600/day€250/dayfalse
CustomEurovision Stage Manager€550/day€220/daytrue

6. Profile Functions​

What it is: Junction table - which profiles can perform which functions

Why it exists: Many-to-many relationship (one profile can do multiple functions, one function can be done by many profiles)

Properties:

PropertyTypeRequired?DescriptionExample
idUUIDYesUnique identifier-
profile_idUUIDYesWhich person-
function_idUUIDYesWhich role-
seniorityEnumNoExperience level"junior", "mid", "senior", "expert"

Example:

Anna Andersson can do:
- Camera Operator (seniority: senior)
- Drone Pilot (seniority: mid)

BjΓΆrn Svensson can do:
- Camera Operator (seniority: junior)
- Sound Assistant (seniority: mid)

Relationships:

  • Links: Profile ↔ Function Catalog

Business Rules:

  • βœ“ One profile can have multiple functions
  • βœ“ Seniority affects rate negotiation (senior = higher rates)
  • βœ“ Used for searching: "Find all senior Camera Operators"

7. Projects​

What it is: Your events/productions (Eurovision, sports broadcasts, conferences, etc.)

Why it exists: The top-level container for all staffing work

Properties:

PropertyTypeRequired?DescriptionExample
idUUIDYesUnique identifier-
company_idUUIDYesWhich company owns this project-
project_codeTextYesUnique code (auto or manual)"ESC-2025-001"
nameTextYesProject name"Eurovision Song Contest 2025"
client_nameTextNoExternal client (if different from company)"EBU"
statusEnumYesProject lifecycle"planning", "confirmed", "completed"
start_dateDateNoProject start date2025-05-10
end_dateDateNoProject end date2025-05-15
budget_centsIntegerNoTotal budget in cents5000000 (= €50,000)
budget_currencyCodeNoBudget currency"EUR"
location_cityTextNoEvent city"MalmΓΆ"
location_countryCodeNoCountry code"SE"
notesTextNoInternal notes"Largest production of the year"

Project Status Lifecycle:

StatusMeaningTypical Duration
planningPlanning phase - defining requirementsWeeks/months
confirmedProject confirmed - crew assigned, event happeningDays/weeks
completedEvent finished, ready for financial review-

Relationships:

  • Belongs to: Company
  • Has many: Project Teams, Project Functions, Exports
  • Has many (indirect): Assignments (via project functions)

Business Rules:

  • βœ“ Project code must be unique across company
  • βœ“ Dates optional (planning phase projects may not have dates yet)
  • βœ“ Budget optional (used for cost tracking comparison)

8. Project Teams​

What it is: Sub-groups within a project (e.g., "Camera Crew", "Audio Team", "OB Team 1")

Why it exists: Organize large crews into manageable teams (OPTIONAL - not all projects use teams)

Properties:

PropertyTypeRequired?DescriptionExample
idUUIDYesUnique identifier-
project_idUUIDYesWhich project-
nameTextYesTeam name"OB Team 1", "Audio Crew"
colorHex codeNoUI color for visual grouping"#FF5733"
sort_orderIntegerNoDisplay order1, 2, 3...

When to use teams:

  • βœ“ Large projects with 50+ people
  • βœ“ Multiple parallel crews (e.g., OB Team 1 works stadium, OB Team 2 works arena)
  • βœ— Small projects can skip teams (flat list of roles)

Relationships:

  • Belongs to: Project
  • Has many: Project Functions (roles assigned to this team)

Business Rules:

  • βœ“ Teams are completely optional
  • βœ“ If used, project functions can be grouped by team
  • βœ“ Visual: Different colors help distinguish teams in UI

9. Project Functions​

What it is: Required roles for a project (e.g., "Need 3 Camera Operators for 10 work days + 2 travel days")

Why it exists: Define staffing requirements before assigning specific people

Properties:

PropertyTypeRequired?DescriptionExample
idUUIDYesUnique identifier-
project_idUUIDYesWhich project-
team_idUUIDNoWhich team (optional)-
function_idUUIDYesWhich role from catalog"Camera Operator"
work_daysIntegerYesNumber of work days10
travel_daysIntegerYesNumber of travel days2
quantityIntegerYesHow many people needed3 (need 3 Camera Ops)
target_rate_centsIntegerNoBudget target rate (work day)50000 (= €500)
target_rate_currencyCodeNoCurrency"EUR"
notesTextNoRequirements"Must speak Swedish, own drone license preferred"

Example:

Project: Eurovision 2025
Function: Camera Operator
- Quantity: 3 people
- Work days: 10
- Travel days: 2
- Target rate: €500/work day
- Team: OB Team 1

This means: "We need 3 Camera Operators, each working 10 days + 2 travel days,
budget is €500/day per person"

Relationships:

  • Belongs to: Project
  • Optionally belongs to: Project Team
  • References: Function Catalog (which role)
  • Has many: Assignment Offers (PM sends offers for this slot)
  • Has one: Assignment (the confirmed booking)

Business Rules:

  • βœ“ If quantity > 1, PM creates multiple assignment offers/assignments
  • βœ“ Target rate is for budgeting only (actual rates negotiated per person)
  • βœ“ Work + travel days define project duration per person

10. Assignment Offers​

What it is: Proposals from PM to specific people for specific roles

Why it exists: PM can send offers to multiple candidates for same slot, with individual rates, and support negotiation

Properties:

PropertyTypeRequired?DescriptionExample
idUUIDYesUnique identifier-
project_function_idUUIDYesWhich slot/role-
profile_idUUIDYesWho this offer is for-
work_day_rate_centsIntegerYesOffered rate for work days (cents)50000 (= €500)
travel_day_rate_centsIntegerYesOffered rate for travel days (cents)20000 (= €200)
rate_currencyCodeYesCurrency"EUR", "SEK"
departure_cityTextNoWhere they'll depart from"Stockholm"
statusEnumYesOffer status"pending", "accepted", "declined", "negotiating", "withdrawn", "converted"
pm_notesTextNoInternal PM notes"First choice candidate"
staff_responseTextNoMessage from staff"Can do it but rate too low"
counter_work_rate_centsIntegerNoStaff counter-offer (work days)55000 (= €550)
counter_travel_rate_centsIntegerNoStaff counter-offer (travel days)22000 (= €220)
sent_atTimestampNoWhen offer was sent2025-05-01 10:00
responded_atTimestampNoWhen staff responded2025-05-01 15:30
expires_atTimestampNoResponse deadline2025-05-03 23:59
assignment_idUUIDNoLink to final assignment (if converted)-
created_by_user_idUUIDYesWhich PM created this-

Offer Status Workflow:

pending ──────────┐
β”œβ”€β”€> accepted ────┐
β”œβ”€β”€> declined β”‚
└──> negotiating ────> converted (PM confirms) β†’ Creates Assignment
β”‚
withdrawn β—„β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Example Scenario:

Project Function: Camera Operator for Eurovision (1 person needed)

PM creates 3 offers:

Offer #1 to Anna:
- Work rate: €500/day
- Travel rate: €200/day
- Status: accepted

Offer #2 to BjΓΆrn:
- Work rate: €450/day
- Travel rate: €180/day
- Status: declined (unavailable)

Offer #3 to Clara:
- Work rate: €550/day
- Travel rate: €220/day
- Status: negotiating
- Counter-offer: €600/day work, €250/day travel

PM Decision: Accept Anna's offer at original rate
Result: Offer #1 converted to Assignment, others withdrawn

Relationships:

  • Belongs to: Project Function (which slot)
  • Belongs to: Profile (who)
  • Can create: Assignment (when PM confirms)
  • Created by: User (PM)

Business Rules:

  • βœ“ Multiple offers allowed for same project_function (competing candidates)
  • βœ“ Only one offer can be converted to assignment per slot
  • βœ“ Rates can differ per person (PM sets individually)
  • βœ“ Staff can negotiate (counter-offer)
  • βœ“ PM manually picks winner

11. Assignments​

What it is: Confirmed bookings - one person locked to one project role

Why it exists: The final, confirmed staffing decision (created when PM accepts an offer)

Properties:

PropertyTypeRequired?DescriptionExample
idUUIDYesUnique identifier-
project_function_idUUIDYesWhich role-
profile_idUUIDYesWho is assigned-
work_day_rate_centsIntegerYesAgreed work rate (cents)50000 (= €500)
travel_day_rate_centsIntegerYesAgreed travel rate (cents)20000 (= €200)
rate_currencyCodeYesCurrency"EUR"
departure_cityTextNoDeparture city"Stockholm"
current_statusEnumYesLifecycle status"confirmed", "contract_sent", "active", etc.
start_dateDateNoAssignment start (for conflict detection)2025-05-10
end_dateDateNoAssignment end (for conflict detection)2025-05-15
notesTextNoInternal notes-

Assignment Status Lifecycle (Fixed workflow):

confirmed β†’ contract_sent β†’ contract_signed β†’ travel_booked β†’
hotel_booked β†’ active β†’ completed

(Can jump to 'cancelled' at any point)

Status Descriptions:

StatusMeaningTypical Actions
confirmedPM has accepted offer, booking confirmedSend confirmation email
contract_sentContract/NDA sent to staffWait for signature
contract_signedContract returned, signedFile document
travel_bookedTravel arrangements madeRecord booking details
hotel_bookedHotel reservation madeRecord booking details
activeProject is happening now, person is on-site-
completedProject finished, person returnedPrepare invoicing
cancelledAssignment cancelled (any reason)-

Relationships:

  • Belongs to: Project Function (which role)
  • Belongs to: Profile (who)
  • Has many: Status Logs (timeline), Travel Bookings, Hotel Bookings, Documents (contracts, NDAs, road books)
  • Created from: Assignment Offer (when PM converts)

Business Rules:

  • βœ“ One assignment per project_function slot (quantity > 1 = multiple assignments)
  • βœ“ Start/end dates used for conflict detection
  • βœ“ Status workflow is fixed (not customizable per company)
  • βœ“ Rates locked in (no more negotiation after confirmation)

Conflict Detection Example:

Anna is assigned to:
- Eurovision (May 10-15)
- Sports Broadcast (May 14-18) ← CONFLICT WARNING!

System warns PM: "Anna already assigned to Eurovision during overlapping dates"

12. Assignment Status Logs​

What it is: Audit trail for assignment lifecycle

Why it exists: Track timeline and changes (who did what, when)

Properties:

PropertyTypeRequired?DescriptionExample
idUUIDYesUnique identifier-
assignment_idUUIDYesWhich assignment-
statusEnumYesStatus at this point"contract_sent"
noteTextNoContext for change"Sent via DocuSign"
changed_by_user_idUUIDNoWho made the change-
created_atTimestampYesWhen change happened2025-05-02 14:30:00

Example Timeline:

Assignment for Anna / Camera Operator:

2025-05-01 10:00 confirmed (by PM Maria) "Accepted at €500/day"
2025-05-01 15:00 contract_sent (by PM Maria) "Contract sent via email"
2025-05-02 09:00 contract_signed (by PM Maria) "Received signed PDF"
2025-05-03 11:00 travel_booked (by Admin Karin) "SAS flight SK1234"
2025-05-03 14:00 hotel_booked (by Admin Karin) "Scandic Hotel, 3 nights"
2025-05-10 08:00 active (by PM Maria) "Project started"
2025-05-15 18:00 completed (by PM Maria) "All good!"

Relationships:

  • Belongs to: Assignment
  • Changed by: User (optional)

Business Rules:

  • βœ“ Append-only log (never delete/edit entries)
  • βœ“ Automatic: System records when status changes
  • βœ“ Timeline view: Show full history to PM

13. Travel Bookings​

What it is: Travel details per assignment (flights, trains, cars)

Why it exists: Track and manage crew transportation

Properties:

PropertyTypeRequired?DescriptionExample
idUUIDYesUnique identifier-
assignment_idUUIDYesWhich assignment-
typeEnumYesTravel mode"flight", "train", "car", "other"
from_cityTextNoDeparture city"Stockholm"
to_cityTextNoArrival city"MalmΓΆ"
departure_atTimestampNoDeparture time2025-05-10 07:30
arrival_atTimestampNoArrival time2025-05-10 08:45
booking_referenceTextNoBooking/ticket number"SAS-ABC123"
cost_centsIntegerNoCost in cents89900 (= €899)
cost_currencyCodeNoCurrency"SEK"
notesTextNoAdditional info"Window seat requested"

MVP Note: Manually entered by PM/admin (no flight API integration yet)

Relationships:

  • Belongs to: Assignment (one assignment can have multiple travel bookings, e.g., outbound + return)

Business Rules:

  • βœ“ MVP: Manual entry only
  • βœ“ One assignment can have multiple travel bookings (outbound, return, mid-project transfers)
  • βœ“ Used for reports: Travel overview per project

14. Hotel Bookings​

What it is: Hotel accommodation details per assignment

Why it exists: Track crew lodging

Properties:

PropertyTypeRequired?DescriptionExample
idUUIDYesUnique identifier-
assignment_idUUIDYesWhich assignment-
hotel_nameTextNoHotel name"Scandic MalmΓΆ City"
check_in_dateDateNoCheck-in2025-05-10
check_out_dateDateNoCheck-out2025-05-15
nightsIntegerYesNumber of nights5
rate_per_night_centsIntegerNoNightly rate (cents)120000 (= €1,200)
total_cost_centsIntegerNoTotal cost (cents)600000 (= €6,000)
cost_currencyCodeNoCurrency"SEK"
booking_referenceTextNoConfirmation number"BOOK-12345"
notesTextNoSpecial requests"Breakfast included"

MVP Note: Manually entered by PM/admin

Relationships:

  • Belongs to: Assignment

Business Rules:

  • βœ“ One assignment = one hotel booking (typically)
  • βœ“ Used for reports: Hotel booking overview, rooming lists

What it is: Public intake forms for collecting freelancer data

Why it exists: Allow external people to submit their info via shareable URL (e.g., /pool/esc2025)

Properties:

PropertyTypeRequired?DescriptionExample
idUUIDYesUnique identifier-
company_idUUIDYesWhich company-
slugTextYesURL slug (unique)"esc2025", "sports-crew"
titleTextYesForm title"Eurovision 2025 Crew Application"
welcome_textText (Markdown)NoIntro message"We're looking for experienced broadcast crew..."
enabled_fieldsJSONYesWhich fields to show["name","email","phone","functions","languages"]
allowed_functionsJSONNoWhich roles can be selected["camera-op-id","sound-mixer-id"]
is_activeBooleanNoForm accepting submissions?true/false
expires_atTimestampNoOptional deadline2025-04-01 23:59

Example Public Form URL: https://pbs.app/pool/esc2025

Form Configuration:

{
"enabled_fields": ["name", "email", "phone", "photo", "functions", "languages", "food_preferences", "clothing_sizes"],
"allowed_functions": ["camera-op-uuid", "sound-mixer-uuid", "lighting-tech-uuid"]
}

Relationships:

  • Belongs to: Company
  • Has many: Profile Submissions (incoming applications)

Business Rules:

  • βœ“ Slug must be unique across system
  • βœ“ Can be enabled/disabled without deleting
  • βœ“ Welcome text supports Markdown formatting
  • βœ“ Can restrict which functions applicants can choose

16. Profile Submissions​

What it is: Incoming applications from public staff pool forms

Why it exists: Pending review before becoming full profiles

Properties:

PropertyTypeRequired?DescriptionExample
idUUIDYesUnique identifier-
staff_pool_link_idUUIDYesWhich form-
dataJSONYesAll submitted fields{"first_name":"Anna","email":"anna@email.com",...}
statusEnumYesReview status"pending", "approved", "rejected"
approved_profile_idUUIDNoLink to created profile (if approved)-
reviewed_by_user_idUUIDNoWho reviewed-
reviewed_atTimestampNoWhen reviewed2025-05-01 10:00
submitted_atTimestampYesWhen submitted2025-04-28 14:30

Workflow:

1. Freelancer fills form β†’ submission created (status: pending)
2. PM reviews submission β†’ approves or rejects
3. If approved β†’ Profile created, submission linked

Example Submission Data:

{
"first_name": "Anna",
"last_name": "Andersson",
"email": "anna@example.com",
"phone": "+46 70 123 4567",
"functions": ["camera-op-uuid"],
"languages": [{"code":"sv","proficiency":"native"},{"code":"en","proficiency":"fluent"}],
"food_preferences": {"diet":"vegetarian"},
"clothing_sizes": {"shirt":"M","pants":"32"}
}

Relationships:

  • Belongs to: Staff Pool Link
  • Can create: Profile (when approved)
  • Reviewed by: User

Business Rules:

  • βœ“ Pending submissions await review
  • βœ“ Approved β†’ System creates Profile with submitted data
  • βœ“ Rejected β†’ Submission kept for record, no profile created

17. Documents​

What it is: File attachments (PDFs, images, etc.)

Why it exists: Store documents related to profiles or assignments

Properties:

PropertyTypeRequired?DescriptionExample
idUUIDYesUnique identifier-
documentable_typeEnumYesWhat it attaches to"Profile", "Assignment"
documentable_idUUIDYesWhich profile/assignment-
doc_typeEnumYesDocument category"photo", "passport", "contract", "nda", "road_book", etc.
file_urlURL/PathYesFile location"/storage/profiles/123/photo.jpg"
file_nameTextYesOriginal filename"anna_photo.jpg"
file_size_bytesIntegerNoFile size245678
mime_typeTextNoFile type"image/jpeg", "application/pdf"
expires_atDateNoExpiration (for passports, IDs)2030-12-31
uploaded_by_user_idUUIDNoWho uploaded-
created_atTimestampAutoUpload time-

Polymorphic Relationship (can attach to different entities):

Profile Documents:

  • photo - Crew pass photo, accreditation badge
  • passport - Passport copy (future: for accreditation)
  • id_card - National ID

Assignment Documents:

  • contract - Employment contract
  • nda - Non-disclosure agreement
  • road_book - Individual travel planning document
  • accreditation - Event access pass

Example:

Profile: Anna Andersson
- Document #1: type=photo, file=anna_photo.jpg
- Document #2: type=passport, file=anna_passport.pdf, expires=2030-05-15

Assignment: Anna β†’ Eurovision Camera Op
- Document #3: type=contract, file=contract_anna_esc2025.pdf
- Document #4: type=nda, file=nda_signed.pdf
- Document #5: type=road_book, file=roadbook_anna.pdf

Relationships:

  • Polymorphic belongs to: Profile OR Assignment
  • Uploaded by: User

Business Rules:

  • βœ“ Staff can upload their own photo via self-service portal
  • βœ“ PM/Admin uploads contracts, NDAs
  • βœ“ Road book can be uploaded or generated
  • βœ“ Passport expiration tracked (alert when expiring)

18. Exports​

What it is: Generated reports and export files

Why it exists: Create crew lists, meal lists, hotel overviews, etc.

Properties:

PropertyTypeRequired?DescriptionExample
idUUIDYesUnique identifier-
project_idUUIDYesWhich project-
typeEnumYesReport type"crew_list", "hotel_bookings", "meal_list", "clothing_sizes"
filtersJSONNoExport parameters{"team_id":"team-1-uuid","date_range":"2025-05-10 to 2025-05-15"}
file_urlURL/PathYesGenerated file location"/storage/exports/crew_list_20250501.pdf"
file_formatEnumYesFile type"pdf", "excel", "csv"
generated_by_user_idUUIDNoWho generated-
generated_atTimestampYesWhen generated2025-05-01 10:30

Export Types (MVP - all critical):

TypeDescriptionTypical Format
crew_listAll assigned staff with contact info, functionsPDF, Excel
hotel_bookingsHotel overview with check-in/out datesPDF, Excel
meal_listFood preferences, allergies for cateringPDF, Excel
clothing_sizesSizes for ordering crew uniformsExcel

Example Filters:

{
"team_id": "ob-team-1-uuid",
"include_travel": true,
"date_range": {
"start": "2025-05-10",
"end": "2025-05-15"
}
}

Relationships:

  • Belongs to: Project
  • Generated by: User

Business Rules:

  • βœ“ SaaS: Export templates are fixed (not customizable)
  • βœ“ Can regenerate exports as data changes
  • βœ“ Kept for history (can see old exports)

Relationship Summary​

Visual Relationship Map​

Companies (1) ──────────> (Many) Users
Companies (1) ──────────> (1) Project ID Settings
Companies (1) ──────────> (Many) Profiles
Companies (1) ──────────> (Many) Functions Catalog
Companies (1) ──────────> (Many) Projects
Companies (1) ──────────> (Many) Staff Pool Links

Profiles (Many) ←──────> (Many) Functions Catalog
(via Profile Functions - junction table)

Projects (1) ──────────> (Many) Project Teams
Projects (1) ──────────> (Many) Project Functions
Projects (1) ──────────> (Many) Exports

Project Functions (1) ──> (Many) Assignment Offers
Project Functions (1) ──> (1) Assignment (the winner)

Assignment Offers (1) ──> (1) Assignment (when converted)

Assignments (1) ────────> (Many) Assignment Status Logs
Assignments (1) ────────> (Many) Travel Bookings
Assignments (1) ────────> (Many) Hotel Bookings
Assignments (1) ────────> (Many) Documents (contracts, etc.)

Profiles (1) ───────────> (Many) Documents (photos, passports)

Staff Pool Links (1) ───> (Many) Profile Submissions
Profile Submissions (1) -> (1) Profile (when approved)

Data Flow Examples​

Example 1: Creating a Project and Staffing It​

Step-by-step:

  1. Create Project

    Company: NCP
    Project: "Eurovision 2025"
    Code: ESC-2025-001
    Dates: May 10-15, 2025
    Location: MalmΓΆ, Sweden
    Budget: €500,000
  2. Define Required Roles (Project Functions)

    Role #1: Camera Operator
    - Quantity: 3 people
    - Work days: 10
    - Travel days: 2
    - Target rate: €500/work day, €200/travel day
    - Team: OB Team 1

    Role #2: Sound Mixer
    - Quantity: 2 people
    - Work days: 10
    - Travel days: 2
    - Target rate: €450/work day, €180/travel day
    - Team: Audio Team
  3. PM Creates Offers (for Camera Operator slot #1)

    Offer A β†’ Anna Andersson
    - Work rate: €500/day
    - Travel rate: €200/day
    - Sent: May 1, 10:00

    Offer B β†’ BjΓΆrn Svensson
    - Work rate: €450/day
    - Travel rate: €180/day
    - Sent: May 1, 10:05

    Offer C β†’ Clara Nilsson
    - Work rate: €550/day
    - Travel rate: €220/day
    - Sent: May 1, 10:10
  4. Staff Respond

    Anna: ACCEPTED (May 1, 15:00)
    BjΓΆrn: DECLINED (unavailable)
    Clara: NEGOTIATING - Counter: €600/day work, €250/day travel
  5. PM Picks Winner

    PM accepts Anna's offer (original terms)
    β†’ Assignment created
    β†’ Offers B and C marked as "withdrawn"
  6. Assignment Lifecycle

    May 1: confirmed
    May 2: contract_sent (contract uploaded)
    May 3: contract_signed
    May 4: travel_booked (SAS flight recorded)
    May 5: hotel_booked (Scandic MalmΓΆ, 5 nights)
    May 10: active (project started)
    May 15: completed
  7. Generate Reports

    PM exports:
    - Crew list (PDF) - all assigned staff
    - Hotel bookings (Excel) - rooming list
    - Meal list (PDF) - dietary requirements

Example 2: Staff Self-Service Portal​

Freelancer Perspective (Anna's experience):

  1. Receive Public Form Link

    Email from NCP: "Join our crew pool for upcoming events"
    Link: https://pbs.app/pool/ncp-crew-2025
  2. Fill Out Form

    - Name: Anna Andersson
    - Email: anna@example.com
    - Phone: +46 70 123 4567
    - Functions: Camera Operator, Drone Pilot
    - Languages: Swedish (native), English (fluent)
    - Food: Vegetarian, no peanuts
    - Clothing: Shirt M, Pants 32
    - Upload photo
  3. Submission Reviewed

    PM reviews β†’ Approves
    β†’ Profile created in system
    β†’ Anna receives email: "Welcome! Create your login"
  4. Anna Creates Account

    Sets password, logs in
    Role: CREW (self-service portal)
  5. Anna Uses Portal

    Can view/edit:
    - Basic info (email, phone, address)
    - Profile photo
    - Emergency contact
    - Languages
    - Food preferences
    - Clothing sizes

    Can view:
    - Her assignments (past and upcoming)
    - Pending offers from PMs

    Future:
    - Upload passport
    - Accept/decline offers directly
    - View travel/hotel details
  6. Anna Receives Offer

    Notification: "You have a new offer for Eurovision 2025"
    Offer details:
    - Role: Camera Operator
    - Dates: May 10-15
    - Work rate: €500/day (10 days)
    - Travel rate: €200/day (2 days)
    - Total: €5,400

    Options:
    - Accept
    - Decline (with reason)
    - Negotiate (enter counter-offer)
  7. Anna Accepts

    Status: accepted
    PM receives notification
    PM converts offer β†’ Assignment
    Anna can now see:
    - Contract document (download/sign)
    - Travel details (when booked)
    - Hotel info (when booked)

Example 3: Conflict Detection​

Scenario: PM tries to assign Anna to overlapping projects

Existing Assignment:
- Project: Eurovision 2025
- Dates: May 10-15

New Assignment Attempt:
- Project: Sports Broadcast
- Dates: May 14-18

System Alert:
⚠️ "Anna Andersson is already assigned to Eurovision 2025 (May 10-15).
This overlaps with Sports Broadcast (May 14-18).

Continue anyway? [Yes] [No]"

PM Options:
1. Cancel new assignment (find someone else)
2. Continue anyway (maybe Anna can do both if schedules work out)
3. Adjust dates

Technical: Query checks assignment.start_date and assignment.end_date for overlaps:

WHERE profile_id = anna_id
AND start_date <= '2025-05-18'
AND end_date >= '2025-05-14'

Conclusion​

This document provides a complete reference for all 18 entities in the PBS system, their properties, relationships, and business rules. Use this alongside:

  • schema.dbml - Technical database definition
  • USER_CASES.md - Detailed user stories and workflows (see separate document)
  • Visual ER Diagram - Generated from DBML at dbdiagram.io

Next Steps:

  1. Review with PM team
  2. Validate all properties and relationships
  3. Confirm business rules match real-world processes
  4. Identify any missing entities or fields
  5. Proceed to user case scenarios document