// overview

Platform overview

staff7 is a multi-tenant SaaS platform built for ESNs, consulting agencies, and independent firms. It centralises the full operational stack — from consultant availability to project profitability — in a single, role-aware interface.

Consultant management
Profiles, skills, status, occupancy, contract type (employee/freelance), and financial costs.
Project & client tracking
External and internal projects, client CRM, assignment management, and budget tracking.
Timesheets (CRA)
Weekly time entry with draft/submit/approve workflow, per project, per consultant.
Leave management
CP, RTT, unpaid, authorised absence — request, approve, and balance tracking.
Planning & timeline
Weekly availability grid and monthly Gantt-style view across the team.
Financial tracking
TJM sold vs actual, gross margin per project, profitability per consultant.
All data is multi-tenant and RLS-enforced. Each company's data is isolated at the database level — no query can cross tenant boundaries.
// dashboard

Dashboard

The dashboard is the entry point for all roles. It aggregates key metrics in real time and surfaces pending actions without navigating away.

KPI cards
Active consultants, active projects, occupancy rate, and pending leave requests — updated on every load.
Mini calendar
Monthly calendar with colour-coded events: leave requests, project milestones, and availability blocks.
Activity feed
Recent team actions — assignments, leave approvals, new projects — in reverse chronological order.
Project snapshot
Active projects with deadline proximity and assigned consultant count.
RoleWhat they see
consultantOwn assignments, own leave balance, personal occupancy
managerTeam occupancy, pending validations, project status
adminFull KPIs, financial summary, all pending actions
super_adminCross-tenant view (all companies)
// consultants

Consultants

The consultant directory is the operational core of the platform. Each profile tracks availability, assignments, financial cost, and leave entitlements.

Employee profile
Gross salary, employer charges (%), working days/year → actual daily cost calculated automatically.
Freelance profile
Billed daily rate with per-assignment override. No paid leave or flex-day entitlements.
Target rate
Admin sets a target daily rate — the platform tracks the gap vs actual cost to flag margin risk.
Occupancy tracking
Real-time occupancy % derived from active assignments, updated across planning views.

Contract types drive behaviour across the platform:

FieldEmployeeFreelance
Daily cost basisSalary × (1 + charges%) ÷ days/yrBilled TJM (or per-assignment override)
CP / RTT✓ tracked— not applicable
Leave requestsCP, RTT, unpaid, auth. absenceUnpaid, auth. absence only
Profitability marginRevenue − fully-loaded costRevenue − billed rate
// Actual daily cost formula (employee)
actual_daily_cost = gross_annual_salary × (1 + employer_charges_pct / 100) / working_days

// Default values (FR market)
charges_pct      = 42%  // employer charges
working_days     = 218  // working days / year
Consultant accounts are linked via user_id. An admin can send an email invitation directly from the consultant drawer — the platform creates a Supabase auth account and sets the role in app_metadata.
// projects

Projects & clients

Projects are the financial and operational unit of the platform. Each project links a client, a team, and a financial envelope.

Client CRM
Client directory with sector, contact info, and linked projects. Revenue and active project counts per client.
Project lifecycle
Draft → Active → On hold → Completed → Archived. Each status gates what actions are available.
Team assignments
Assign consultants with start/end dates and allocation %. Freelancers can have a per-assignment TJM override.
Financial envelope
TJM sold, days sold, total budget — visible to admins only. Used to calculate gross margin.
StatusDescriptionVisible in financials
draftProject created, not yet active. No assignments.No
activeOngoing — included in occupancy and financial views.Yes
on_holdPaused — consultants retained but not counted as assigned.No
completedClosed — historical data preserved.No
archivedHidden from main views.No
// timesheets

Timesheets

The timesheet module provides weekly time tracking with a structured validation workflow. Each day entry can be 0, 0.5, or 1 day — and moves through draft → submitted → approved.

Weekly grid
Each consultant sees their week with day cells. Click to toggle empty → half → full day.
Submit workflow
Consultant submits the week → manager/admin reviews and approves per consultant.
Manager view
Managers see all team members for the selected week. Can approve all submitted entries in one click.
Approval lock
Approved entries are locked — no edits without admin override.
// Entry states
empty     → no entry (0d)
half      → 0.5d (half day)
full      → 1d
draft     → saved but not submitted
submitted → awaiting manager approval
approved  → locked
RoleCan enterCan submitCan approve
consultant✓ own✓ own
manager✓ team✓ team✓ team
admin✓ all✓ all✓ all
// leaves

Leave management

The leave module handles request submission, manager approval, and balance tracking. Freelancers have a restricted set of leave types — CP and RTT are not available.

Leave request
Consultant selects type, dates, and submits. Working days calculated automatically (weekends excluded).
Approval workflow
Manager/admin sees pending requests with impact warnings. One-click approve or refuse.
Balance tracking
CP and RTT balances displayed per consultant with a visual bar. Depletes automatically on approval.
Impact warning
System flags if an approved leave overlaps with an active project assignment.
TypeAvailable toDuration
Paid leave (CP)Employee onlyCustom — calculated in working days
Flex days (RTT)Employee onlyCustom — from RTT balance
Unpaid leaveAllCustom
Authorised absenceAllFixed by legal motif (bereavement, marriage…)
Authorised absence has a fixed legal duration per motif — the end date is calculated automatically. No CP/RTT balance is deducted.
// planning

Planning

Two complementary views give a spatial sense of team availability and workload.

Weekly availability
Row per consultant, column per weekday. Colour cells show: free / on assignment / partial / leave / weekend.
Monthly timeline
Gantt-style view. Assignment bars span across days. Leave blocks appear as a separate layer.
Export
Monthly view can be exported. Format depends on deployment configuration.
Live status
Views derive status from assignments and leave_requests in real time — no manual sync needed.
ColourMeaning
GreenFree / available
CyanOn assignment (100%)
GoldPartial / 50%
PinkOn leave
DimWeekend
// finance

Finance & profitability

Financial data is admin-only. Two views expose different angles: project-level margins in Finances, and consultant-level profitability in Profitability.

Project margins
Sold rate vs actual daily cost per project. Gross margin in € and %. Colour-coded by health threshold.
Consultant profitability
Revenue generated, gross margin, occupancy rate — per consultant, sorted by any metric.
Target vs actual
Admin sets a target daily rate per consultant. Platform shows the gap % — red if margin < 10%.
Alert system
Banner surfaces consultants whose target rate leaves less than 10% margin over actual cost.
// Gross margin per consultant
revenue      = SUM(sold_rate × days) on active assignments
cost         = actual_daily_cost × billed_days
gross_margin = revenue - cost
margin_pct   = gross_margin / revenue × 100

// Margin health thresholds
≥ 25%  →  Excellent  (green)
15–25% →  Correct    (gold)
< 15%  →  Watch      (pink)
Financial views are gated by canViewFinancials(role) — only admin and super_admin can access them. Managers and consultants see no financial data.
MetricSourceScope
Sold rateproject.sold_ratePer project
Actual daily costconsultant_profitability viewPer consultant (calculated)
Target rateconsultant.target_ratePer consultant (admin-set)
Gross marginrevenue − consultant_costPer consultant / project
Margin %gross_margin / revenuePer consultant / project
// invoices

Invoices

The invoice module lets admins, managers, and freelancers generate client invoices directly from approved timesheets or project budgets. Each invoice carries a legal snapshot of emitter and client data at generation time.

Timesheet import
Select a month — platform pulls all approved entries, groups by consultant × project, and pre-fills line items with quantities and rates.
Project import
Load a project directly to pre-fill the sold rate as a line item. Editable before save.
Manual mode
Full line-by-line entry. Units: day / hour / unit. Each line has a description, detail field, and live total.
Live preview
Split-screen layout — form on the left, PDF-style preview on the right, updating on every keystroke.
Legal compliance
SIRET, VAT number, IBAN/BIC, legal mention, auto-entrepreneur clause — all sourced from companies.billing_settings.
Auto-numbering
Invoice numbers follow a configurable prefix + sequential counter (e.g. NEX-2026-0001). Thread-safe via atomic SQL update.
StatusDescriptionEditable
draftCreated but not sent — fully editableYes
sentMarked as sent to clientAdmin only
paidPayment received — paid_at date recordedNo
overduePast due date — computed automatically by viewNo
cancelledVoided invoiceNo
-- Invoice number generation (atomic, thread-safe)
SELECT next_invoice_number(company_id);
-- → 'NEX-2026-0004'

-- billing_settings (companies table, jsonb)
{
  "siret":          "12345678901234",
  "tva_number":     "FR12345678901",
  "tva_rate":       20,
  "payment_terms":  30,
  "bank_iban":      "FR76 ...",
  "bank_bic":       "BNPAFRPPXXX",
  "legal_mention":  "Auto-entrepreneur...",
  "invoice_prefix": "NEX-2026-",
  "invoice_counter": 4
}
Freelance RLS — a freelance user can only see and edit invoices where consultant_id matches their own consultant record. Admins and managers see all company invoices. Freelancers can only update or delete invoices in draft status.
// roles

Roles & access

Roles are stored in auth.users.app_metadata.user_role — not in a user-editable table. They are set at invite time and can only be changed by an admin.

RoleScopeKey permissions
consultantOwn data onlyView own assignments, submit timesheets, request leave
freelanceOwn data onlyAll consultant permissions + create and view own invoices. No leave (CP/RTT).
managerTeamView team, approve timesheets & leave, manage assignments
adminCompanyFull CRUD, financial views, invoices, invite consultants
super_adminAll tenantsCross-tenant access, company management
freelance is a leaf role — it inherits all consultant permissions and adds invoice creation scoped to the freelancer's own consultant record. Leave requests (PTO / flex days) are hidden for freelance accounts.
// RLS JWT path (Supabase)
auth.jwt() -> 'app_metadata' ->> 'user_role'

// Guard helpers (lib/auth.ts)
isAdmin(role)             // admin + super_admin
canEdit(role)             // admin + manager + super_admin
canViewFinancials(role)   // admin + super_admin
canViewOwnInvoices(role)  // freelance + admin + manager + super_admin

// Freelance invoice RLS — own records only
consultant_id IN (
  SELECT id FROM consultants WHERE user_id = auth.uid()
)
// multitenancy

Multi-tenancy

Every table has a company_id column. Supabase RLS policies enforce that queries only return rows matching the user's tenant. No application-level filtering is required.

-- RLS policy example (consultants table)
CREATE POLICY "tenant_isolation" ON consultants
  USING (company_id = my_company_id());

-- my_company_id() helper function
CREATE FUNCTION my_company_id() RETURNS uuid AS $$
  SELECT (auth.jwt() -> 'app_metadata' ->> 'company_id')::uuid
$$ LANGUAGE sql STABLE;

-- super_admin bypass
CREATE POLICY "super_admin_all" ON consultants
  USING (is_super_admin());
Database-level isolation
RLS policies on every table. Even direct API calls cannot access another tenant's data.
Company profiles
Each tenant has a companies record. The company name is displayed in the topbar badge.
AI agent isolation
The AI route uses the user's JWT — not a service key — so RLS applies to all agent queries.
Super admin view
super_admin role bypasses RLS via is_super_admin() — used for platform-level management.
Solo mode — a company can be created with mode: 'solo' for independent freelancers who use Staffd for themselves. The admin of a solo tenant sees a simplified sidebar (no team management, no timeline) and full access to their own projects, timesheets, and invoices. Multi-tenancy architecture is identical — solo is a UI/UX mode, not a separate deployment.
companies.modeTeam sectionLeave managementTimelineFinance
teamVisibleVisibleVisibleFull (admin/manager)
soloHiddenHiddenHiddenFull (self only)