#TradeForce — product overview
#Product summary
TradeForce is a shift marketplace for concrete-trade contractors and the companies that hire them. Companies post jobs and shifts, contractors browse and apply, both sides track time and approvals, and contractors review payment cycles. Platform admins verify accounts, inspect shifts and invoices, and set skill-based rates.
Unauthenticated visitors land on the public index, where they can sign in, sign up, request a password reset, or complete email verification. After authentication, the product routes each person by role and onboarding state: unfinished profiles go through role onboarding; contractors enter the shifts-and-profile workspace; companies enter the shift dashboard; admins enter the admin console. Shared chrome (header plus contractor or company side navigation) then opens time tracking, payments, chat, and related tabs.
The rebuild keeps that product shape: React SPA under app/, Supabase auth/data/edge under app/supabase/. New users start unapproved (Approve false on signup). Money-field and most database writes that today run in the browser must become server-authorised in the target stack. Marketplace Connect/payout behaviour is present as fields and settings, not as a fully documented in-app Connect journey — treat it as a programme boundary (see open questions).
Out of product journey scope: the stub 404 page.
#Roles
Three roles are encoded on the user profile (Role option set; storage values contractor, company, admin):
| Role | Who | What they can do |
|---|---|---|
| Contractor | Individual trade worker | Complete contractor onboarding (skills, docs, location), browse/filter open shifts, apply and manage My Shifts, maintain profile documents, record time, view payment cycles, chat |
| Company | Hiring organisation operator | Complete company onboarding, post and manage shifts, review applicants, open job detail, end jobs, work time-tracking approvals, chat |
| Admin | Platform operator | Verify companies and contractors, inspect open/active shifts, manage invoices and payment schedules, set skill rates |
Signup captures role from a type dropdown and sets approval to false. Index page-load routing then sends:
- users who still need onboarding → onboarding
- admin → admin console
- contractor (active / onboarded) → contractor shifts & profile
- company (active / onboarded) → company shift dashboard
Verification and “active” flags gate entry into the marketplace surfaces; admin tabs separately list verified vs not-verified companies and contractors.
#Capabilities
| Capability | Outcome | Primary surfaces |
|---|---|---|
| Sign-in and account access | Register, verify, sign in, reset password; land in the correct role home | Index; reset-password page |
| Workspace chrome | Authenticated navigation into shift, time, payment, admin, and chat areas | Header; contractor sidebar; company side menu |
| Role onboarding | Choose Contractor or Company path; capture profile, skills/pay practices, required documents, and region (states/cities via external location API) before marketplace use | Onboarding page |
| Company shift marketplace | Filter posted/upcoming/closed shifts; post jobs; edit rates and headcount; approve/cancel applicants; open detailed job view; end a job | Company dashboard; shared job detail, row actions, end-job popup |
| Contractor shifts and profile | Filter open shifts; open job detail; apply / update My Shifts; upload or replace credentials | Contractor shifts & profile; shared job detail and row actions |
| Time tracking and approvals | Record hours and breaks; submit reports; company approval path; backend list-create and recursive approve helpers (must become queue/cursor work in target) | Contractor time-tracking page; end-job popup (shared); backend tracking events |
| Contractor payments | View upcoming and previous payment cycles; follow linked schedule/Stripe profile fields when present; receive upcoming-cycle email | Contractor payment page |
| Admin verification and ops | Switch admin tabs for verified/unverified users, shifts, invoices, payment schedules; set custom rates | Admin page |
| Messaging | Open threads, send messages, notify recipients by email | Chat page; chat reusable |
Skill specialties in the product today (option set skill_set): Concrete Finisher, Concrete Laborer, Concrete Walls, Concrete Carpenter. Document types for onboarding credentials (option set docs_type): Diplomas, Resume, Mask Fit Test, Driver's license, Hearing examination-OSHA, References from two foreman/managers, and specialty credentials.
#Cross-cutting rules
- Authentication is native Bubble today. Index workflows perform Sign Up, Log In, and Send Password Reset Email; the reset-password page performs Reset Password; header/onboarding can Log Out. Target identity must be chosen and cut over deliberately — sessions and password hashes do not transfer.
- Role + onboarding + approval gate access. Signup sets
Approvefalse and stores role from the type dropdown. Page-load redirects combine logged-in state, role, onboarding flag, and active flag before opening role homes. - Shared UI ownership. Job detail, shift row actions, and end-job popup are single implement surfaces reused by company and contractor (and time-tracking) flows — do not fork them per module.
- Writes must move server-side. Nearly all persistent mutations live in page/reusable client workflows today. Money fields on company, end-job, admin, and payment flows especially need transactional server authority; the same rule applies more broadly to shift, admin, payment, and time-tracking writes.
- Time-tracking backends are not a line-for-line port. Backend events create tracking lists, send approvals (including a self-scheduling approve workflow), and provide a delay helper. Rebuild as explicit jobs/queues with retries.
- Transactional email is Postmark (template sends). Used for canceled shifts, new chat messages, new time-tracking reports (companies), and upcoming payment cycles (contractors). Calls are client-side in the export and need a secret-bearing server endpoint in target.
- Location lookup is Country State City API. Onboarding fetches US states and cities; also client-side in the export → server proxy in target.
- Every live type carries privacy roles. All nine types that survive in the export have rules (user, shifts, documents, skill_set, chat, message, notification, custom_rate, time_tracking1). The five without rules —
company,job,rates,time_tracking,current_contractors_info— are markeddeleted: truein the export and are not migrated (seedocs/DATA-MODEL.md), so no live type is unprotected. Target RLS re-expresses those nine role sets; note thatprivacy_role:user:everyonegrantssearch_forto unauthenticated visitors — the only permission anyeveryonerole carries. - Marketplace money is a programme boundary. User Stripe account id / name fields and Stripe Connect client settings exist; do not invent Connect KYC or payout UX beyond export evidence until scope is answered.
- One live time-tracking type.
time_tracking1(display “Time tracking”) holds live rows and is the only one every surface writes; the oldertime_trackingisdeleted: truein the export and is not migrated. The single leftover reference is the stalebtype_idin thesend_tracking_approvecondition — its parameter is alreadycustom.time_tracking1.
#Traceability
| Product concept | Target (route / component / table) | Evidence |
|---|---|---|
| Public entry / auth hub | / (index) |
bTGYf |
| Password reset | /reset-password |
AAL (Bubble page reset_pw) |
| Role onboarding | /onboarding |
bTHDn0 |
| Contractor workspace | /contractor/shifts |
bTHMg (Bubble page contractor_shifts_profile) |
| Company shift dashboard | /company/shifts |
bTITd (Bubble page company_dashboard_shifts) |
| Contractor time tracking | /contractor/time-tracking |
bTJFi0 (Bubble page contractor_time-tracking) |
| Contractor payments | /contractor/payments |
bTIzV0 (Bubble page contractor_payment) |
| Admin console | /admin |
bTHun0 |
| Chat | /chat |
bTJQD0 (Bubble page chat_page) |
| Stub 404 (excluded) | /404 |
AAU |
| Roles Contractor / Company / Admin | profiles.role enum (contractor | company | admin) |
role, bTHAB0, bTHAC0, bTIrk, role_option_role |
| Signup sets role + unapproved | Auth signup → profiles | bTHpx1, approve1_boolean |
| Post-login role routing | Auth redirect service | bTHqV1, bTKna, bTKnB, bTKnO |
| Header / side nav chrome | Shell layout | bTHOe, bTHMl, bTMyh2, nav |
| Admin nav / verification tabs | Admin chrome | adminnav, admintab |
| Job detail / row actions / end job | Shared shift UI | bTIgC, bTHTn, bTHkx |
| Shifts, jobs, companies, documents | Domain tables | shifts, job, company, documents, user |
| Chat + messages | Messaging tables | chat, message, bTJQB0 |
| Time-tracking backends | Edge/jobs | bTLsx, bTMBg, bTKPV, bTMBT |
| Postmark email | Edge mailer | external_ns:bTNMZ |
| Country State City | Edge geo proxy | external_ns:bTKtr |
| Stripe Connect fields | profiles + secrets (programme boundary) | stripe_account_id_text |
| User privacy roles present | RLS policies | privacy_role:user:everyone |
| Skill specialties (4) | skill specialty enum / onboarding filters | skill_set, bTJKH, bTJKI, bTJKJ, bTJKN |
| Onboarding document types (7) | documents.type enum / credential uploads | docs_type, bTKzB1, bTKzC1, bTKzD1, bTKzH1, bTKzI1, bTKzJ1, bTKzN1 |
#IR evidence
#Pages and module map
| Inventory id | Page name | Module |
|---|---|---|
bTGYf |
index | MOD-AUTH |
AAL |
reset_pw | MOD-AUTH |
bTHDn0 |
onboarding | MOD-ONBOARDING |
bTHMg |
contractor_shifts_profile | MOD-CONTRACTOR-SHIFTS |
bTITd |
company_dashboard_shifts | MOD-COMPANY-SHIFTS |
bTJFi0 |
contractor_time-tracking | MOD-TIME-TRACKING |
bTIzV0 |
contractor_payment | MOD-PAYMENTS |
bTHun0 |
admin | MOD-ADMIN |
bTJQD0 |
chat_page | MOD-CHAT |
AAU |
404 | excluded |
Slices (path-key → prefer inventory id): /pages/bTGbC → bTGYf; /pages/AAW → AAL; /pages/bTHDr0 → bTHDn0; /pages/bTHMh → bTHMg; /pages/bTIbd → bTITd; /pages/bTJIF0 → bTJFi0; /pages/bTIzW0 → bTIzV0; /pages/bTHuo0 → bTHun0; /pages/bTJSr0 → bTJQD0; /pages/AAX → AAU.
#Reusables (element definitions)
| Inventory id | Name | Notes |
|---|---|---|
bTHOe |
Header | Shell; logout workflow |
bTHMl |
SideBar | Contractor nav |
bTMyh2 |
SideMenuCompany | Company nav |
bTIgC |
DetailedViewJob | Owned by company-shifts module |
bTHTn |
RGaction | Owned by company-shifts module |
bTHkx |
EndJobPopup | Owned by company-shifts; used by time tracking |
bTJQB0 |
Chat | Chat UI reusable |
#Auth actions chased
- Sign Up (
bTHpx1on index): writesrole_option_rolefrom dropdownbTGzw0, setsapprove1_booleanfalse. - Log In (
bTHop1), Send Password Reset Email (bTHqz1), Reset Password (bTHrP1on reset_pw), Log Out (headerbTHuE1, onboardingbTKpS). - Index PageLoaded ChangePage targets: onboarding
bTHDn0, adminbTHun0, contractorbTHMg, companybTITd(workflowsbTHqV1,bTKna,bTKnB,bTKnO) conditioned on role option valuesadmin/contractor/companyplus onboarding/active flags.
#Backend API events
| Id | wf_name |
Notes |
|---|---|---|
bTKPV |
15_minuts_delay |
Delay helper for tracking flows |
bTLsx |
create_list_tracking |
ignore_privacy_rules true |
bTMBg |
send_tracking_approve |
Self-scheduling approve; ignore_privacy_rules true |
bTMBT |
shift |
Shift-related backend event |
#Privacy & authorization
Types with privacy roles: user, shifts, documents, skill_set, chat, message, notification, custom_rate, time_tracking1.
Types without privacy roles in export: company, job, rates, time_tracking, current_contractors_info — target access must be decided (HQ-3).
#Skill specialties (skill_set option values)
| Inventory id | Display |
|---|---|
bTJKH |
Concrete Finisher |
bTJKI |
Concrete Laborer |
bTJKJ |
Concrete Walls |
bTJKN |
Concrete Carpenter |
#Onboarding document types (docs_type option values)
| Inventory id | Display |
|---|---|
bTKzB1 |
Diplomas |
bTKzC1 |
Resume |
bTKzD1 |
Mask Fit Test |
bTKzH1 |
Driver's license |
bTKzI1 |
Hearing examination-OSHA |
bTKzJ1 |
References from two foreman/managers |
bTKzN1 |
Credentials detailing your ability to work by the specialty |
#External systems
external_ns:bTNMZ— Postmark template emails (canceled shifts, new message, new time-tracking report, upcoming payment cycle).external_ns:bTKtr— Country State Citystates/citiescalls for onboarding location.
#Open programme risks (module-map)
MON-MARKETPLACE→ MOD-PAYMENTSMON-CLIENT-WRITES/LOG-CLIENT-WRITES→ company shifts (and related write surfaces)LOG-RECURSIVE→ MOD-TIME-TRACKINGACC-AUTH-SURFACE→ MOD-AUTH
#Needs human clarification
| Id | Question | Why unclear (plain + evidence) | Impact |
|---|---|---|---|
| HQ-1 | Should Stripe Connect, KYC, balances, and payouts be a separate programme from the core TradeForce rebuild? | Plain: The export shows Stripe Connect client settings and per-user Stripe account id/name fields, but no complete in-app Connect onboarding journey to port as ordinary screens. Marketplace money can dominate scope if folded into the app cutover. Evidence: chased stripe_account_id_text, stripe_name_text, public_key:stripe_client_id_test; payment page is schedule/history UI (bTIzV0), not Connect KYC. |
blocks_implement |
| HQ-2 | Which auth provider and credential cutover plan should replace native Bubble Sign Up / Log In / Reset Password? | Plain: Source clearly uses Bubble native auth actions; those sessions and password stores cannot move as-is. Product behaviour on index/reset_pw is known; target identity and how existing users re-authenticate is not. Evidence: bTHpx1 SignUp, bTHop1 LogIn, bTHqz1 SendPasswordResetEmail, bTHrP1 ResetPassword on bTGYf / AAL. |
blocks_implement |
| HQ-3 (resolved — no answer needed) | Answered from the export, 2026-09-22. The five types without privacy roles — company, job, rates, time_tracking, current_contractors_info — are each marked deleted: true in source/tradeforce-50323.sanitized.bubble (user_types.*.deleted); Bubble drops a type's rules when the type is deleted. None of them becomes a target table (docs/DATA-MODEL.md § Dead and folded types), and all nine live types carry privacy roles, so there is no unprotected live type to design access for. ir/inventory.json does not carry the type-level deleted flag (only the field-level one), which is why this looked like an open question — filed as toolkit defect DEF-141. |
resolved (was blocks_implement) |