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.
Dashboard
The dashboard is the entry point for all roles. It aggregates key metrics in real time and surfaces pending actions without navigating away.
| Role | What they see |
|---|---|
| consultant | Own assignments, own leave balance, personal occupancy |
| manager | Team occupancy, pending validations, project status |
| admin | Full KPIs, financial summary, all pending actions |
| super_admin | Cross-tenant view (all companies) |
Consultants
The consultant directory is the operational core of the platform. Each profile tracks availability, assignments, financial cost, and leave entitlements.
Contract types drive behaviour across the platform:
| Field | Employee | Freelance |
|---|---|---|
| Daily cost basis | Salary × (1 + charges%) ÷ days/yr | Billed TJM (or per-assignment override) |
| CP / RTT | ✓ tracked | — not applicable |
| Leave requests | CP, RTT, unpaid, auth. absence | Unpaid, auth. absence only |
| Profitability margin | Revenue − fully-loaded cost | Revenue − 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 / yearapp_metadata.Projects & clients
Projects are the financial and operational unit of the platform. Each project links a client, a team, and a financial envelope.
| Status | Description | Visible in financials |
|---|---|---|
| draft | Project created, not yet active. No assignments. | No |
| active | Ongoing — included in occupancy and financial views. | Yes |
| on_hold | Paused — consultants retained but not counted as assigned. | No |
| completed | Closed — historical data preserved. | No |
| archived | Hidden from main views. | No |
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.
// Entry states
empty → no entry (0d)
half → 0.5d (half day)
full → 1d
draft → saved but not submitted
submitted → awaiting manager approval
approved → locked| Role | Can enter | Can submit | Can approve |
|---|---|---|---|
| consultant | ✓ own | ✓ own | — |
| manager | ✓ team | ✓ team | ✓ team |
| admin | ✓ all | ✓ all | ✓ all |
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.
| Type | Available to | Duration |
|---|---|---|
| Paid leave (CP) | Employee only | Custom — calculated in working days |
| Flex days (RTT) | Employee only | Custom — from RTT balance |
| Unpaid leave | All | Custom |
| Authorised absence | All | Fixed by legal motif (bereavement, marriage…) |
Planning
Two complementary views give a spatial sense of team availability and workload.
| Colour | Meaning |
|---|---|
| Green | Free / available |
| Cyan | On assignment (100%) |
| Gold | Partial / 50% |
| Pink | On leave |
| Dim | Weekend |
Finance & profitability
Financial data is admin-only. Two views expose different angles: project-level margins in Finances, and consultant-level profitability in Profitability.
// 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)canViewFinancials(role) — only admin and super_admin can access them. Managers and consultants see no financial data.| Metric | Source | Scope |
|---|---|---|
| Sold rate | project.sold_rate | Per project |
| Actual daily cost | consultant_profitability view | Per consultant (calculated) |
| Target rate | consultant.target_rate | Per consultant (admin-set) |
| Gross margin | revenue − consultant_cost | Per consultant / project |
| Margin % | gross_margin / revenue | Per consultant / project |
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.
| Status | Description | Editable |
|---|---|---|
| draft | Created but not sent — fully editable | Yes |
| sent | Marked as sent to client | Admin only |
| paid | Payment received — paid_at date recorded | No |
| overdue | Past due date — computed automatically by view | No |
| cancelled | Voided invoice | No |
-- 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
}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 & 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.
| Role | Scope | Key permissions |
|---|---|---|
| consultant | Own data only | View own assignments, submit timesheets, request leave |
| freelance | Own data only | All consultant permissions + create and view own invoices. No leave (CP/RTT). |
| manager | Team | View team, approve timesheets & leave, manage assignments |
| admin | Company | Full CRUD, financial views, invoices, invite consultants |
| super_admin | All tenants | Cross-tenant access, company management |
// 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()
)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());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.mode | Team section | Leave management | Timeline | Finance |
|---|---|---|---|---|
| team | Visible | Visible | Visible | Full (admin/manager) |
| solo | Hidden | Hidden | Hidden | Full (self only) |