My Projects
No projects yet
Create your first project to get started
QA Check
Quality score across all projects. Worst first. Click a project or PM to open it.
| Project | Client | PM | Status | Score | Issues | Last update |
|---|
No projects match
Resource Allocation
Projects Overview
Project & phase timeline. Color is driven by the latest phase end date; a red strip shows a phase that ended but is still marked active.
No projects with phase data
Project Servers
Flat registry of deployments per project (env, url, host, port, git). Source of truth is the maintainer's Excel — re-import to refresh.
| Project | Code | Env | Component | URL | Server | Port | Git | Comment | Actions |
|---|
No servers found.
Try clearing filters, importing the Excel file, or adding one manually.
Dashboard
-
-
-
Income
Revenue by Client
| Project | Client | Phase | Spent | Contract | Consumed |
|---|
| Project | Client | Total Amount | Client Status | Contract Status | Bonus % | Contributors | Bonus Amount | |
|---|---|---|---|---|---|---|---|---|
| Total | ||||||||
Management Staff Bonus
| Role | Name | Condition (M-1) | Value (M-1) | Status | Bonus |
|---|---|---|---|---|---|
| Total Management Bonus | |||||
Recap per Person
| Name | Contract Type | Total Bonus | Action |
|---|
| Date | Bank Account | Third | Category | Wording | Amount | |
|---|---|---|---|---|---|---|
| Total | ||||||
| Category | Jan | Feb | Mar | Apr | May | Jun | Jul | Aug | Sep | Oct | Nov | Dec | Total |
|---|
Clients
No clients yet
Add your first client to get started
Team Members
Manage your global team directory. Members can then be assigned to projects with specific roles.
No team members yet
Projects
No projects for this client
Quality Check
| Name | Contract | Rate | CV | Passport | Bank | Phone | Nationality | Valid | Active TO |
|---|
Team
Contracts
Task Orders
Leave Management
Résumé des paiements
Missing payment account
Salaires
| Nom | Entité | Compte | Montant | Notes | Actions |
|---|---|---|---|---|---|
| Total | |||||
Payment Requests
| Consultant | Entity | Period | Amount | Status | Actions |
|---|---|---|---|---|---|
| Total | |||||
Expense Reports
| Reference | Consultant | Entity | Title | Period | Total TTC | Status | Submitted | Actions |
|---|
Notifications
Pay Parameters
Salary grid parameters used to calculate target annual salary. Formula: (Base × Experience + Seniority + Responsibility) × Setup × Workload
Budget Codes
Settings
Database Backup & Restore
Download a backup of the database or restore from a previous backup file.
Backup
Download a snapshot of the current database. Use this to transfer data between environments or as a safety backup.
Restore
Upload a .db backup file to replace the current database. A safety backup is created automatically before restoring.
Drag & drop a .db file here, or click to browse
Scheduled Backups (S3)
Daily at 2:00 AM Paris time — retained for 60 days
| File | Date | Size |
|---|
No backups found in S3
Loading backups...
Restore Database
You are about to replace the current database with:
This action will overwrite all current data. A backup of the current database will be saved automatically before restoring.
Login Logs
Track user login activity with IP and location.
| Date | User | IP Address | Location |
|---|
No login logs yet
Accountants
Configure accountant email addresses for notifications. Separate multiple addresses with ;
Test Portals
Generate test access links to preview the different portals. Links expire after 7 days.
Loading...
MCP API Keys
Per-user bearer tokens for the Model Context Protocol server (Claude.ai custom connector). Keys are hashed at rest; the plaintext token is shown only once at creation.
Loading...
Recent requests
Click Refresh to load.
Architecture
Where data is stored and how the system is structured.
Server (Docker)
Flask + Gunicorn running in Docker on port 8003.
What's on the server:
- SQLite database —
data/portal.db(WAL mode) - All structured data: projects, clients, invoices, contracts, consultants, team members, portal tokens, audit logs
- JSON columns for nested data (budget, deliverables, line items, etc.)
Backed up automatically to S3 every day at 2 AM (Paris) + manual download via Settings → Database
AWS S3
Bucket ra-customer-portal-data in eu-west-1.
What's in S3:
- Documents — invoices (PDF), contracts (PDF/DOCX), signed documents
- Generated files — AI-generated reports, exported spreadsheets
- Signatures — consultant signature images (PNG)
- DB backups — daily automated backups under
backups/prefix (60-day retention)
Authentication
- Admin users — Firebase Auth (Google SSO) for @reliefapplications.org, @oortcloud.tech, @ouirace.com
- Consultant portals — magic links via portal tokens (no password)
- Client portals — magic links via portal tokens (no password)
Firebase users are managed outside the app — not in the DB backup
External Services
- AWS SES — sending emails (magic links, notifications)
- Mistral AI — content generation, document analysis
- Anthropic (Claude) — AI-assisted features
Stateless — no data stored externally
Domains & URLs
Single app serving multiple domains via Host header detection.
- dashboard.humanitarian.tech — Admin dashboard (all entities)
- portal.reliefapplications.org — RA consultant portal
- portal.oortcloud.tech — Oort consultant portal
- portal.ouirace.com — OuiRace consultant portal
All domains proxy to the same Docker container on port 8003 via nginx
In short
Core Business
projects
Core entityEach project belongs to a client and has phases, deliverables, time entries, and budget tracking.
id TEXT PK
name, slug (unique), status
client_id → clients
project_manager_id → consultants
project_type deliverable | time_material
timetrack_code e.g. #05BW
budget_eur, days_contract, days_spent
start_date, end_date
JSON columns:
budget, phases, deliverables
contacts, time_entries, invoice_ids
consumption_types, monthly_consumption
clients
Core entityOrganizations that own projects. One client can have many projects.
id TEXT PK
name, slug
contact_name, contact_email
sector, country
active INTEGER (bool)
notes
invoices
Core entityClient invoices with amounts, line items, and linked documents in S3.
id TEXT PK
invoice_number, title, client_name
amount, amount_ht, tva, ttc
currency, status
issue_date, due_date, year
tracking_code, document_key
JSON: line_items, tags
contracts
Core entityClient-facing contracts with value, dates, and linked PDF/DOCX in S3.
id TEXT PK
title, client_name, contract_type
value, currency
start_date, end_date
document_key
JSON: key_obligations, tags
consultants
Person recordPeople who work on projects. Each consultant can have multiple staff_contracts and task_orders.
id TEXT PK
full_name, email (unique)
position, nationality, country
phone, address
bank_name, bank_iban, bank_bic
password_hash, is_active, role
cv_document_key, passport_document_key
weekly_capacity_days REAL, NULL = consultant pattern (no fixed FTE)
color avatar palette color
portal_tokens
AuthMagic-link tokens for client portal access. One token per project + email.
token TEXT PK
project_id → projects
email, expires_at, last_accessed
allocations
Resource AllocationWeekly planned days per (project, member, ISO week). Source of truth for the Resource Allocation views and per-project Resource Allocation tab. Phase 1: planned only; consumed days will live in a future time_entries table (Phase 2).
id TEXT PK random hex
project_id → projects
member_id → consultants
iso_week 'YYYY-Www', e.g. 2026-W17
planned_days REAL ≥0, 0.25 step
removed_at soft-flag (spec §9); NULL = active
updated_by, created_at, last_modified
Constraint: UNIQUE(project_id, member_id, iso_week)
HR Module
staff_contracts
HRFramework agreements between the company and a consultant. Links to a consultants person record.
id TEXT PK
contract_id, name, position
consultant_id → consultants
contract_type, legal_entity
daily_rate, hourly_rate, currency
start_date, end_date, status
framework_signed, onboarding_complete
annual_salary, pagas, seguro
task_orders
HRSpecific work assignments under a staff contract. Tracks hours, deadlines, and signatures.
id TEXT PK
task_order_id, consultant_name
staff_contract_id → staff_contracts
project_id → projects
total_hours, hours_used, hours_remaining
rate, total_days, currency
status, to_status
consultant_signed, company_signed
payment_requests
HRConsultant payment submissions with invoice/timesheet documents. Goes through approval workflow.
id TEXT PK
staff_contract_id → staff_contracts
consultant_name, legal_entity
period_start, period_end, period_label
extracted_amount, validated_amount
status in_progress | validated | approved | rejected
Related: payment_request_lines, payment_request_logs, payment_supporting_documents
leave_records
HRVacation, sick leave, overtime, and primes for consultants.
id TEXT PK
staff_contract_id → staff_contracts
legal_entity, leave_type
date_start, date_end, day_type
status pending | approved | rejected
budget_codes
HRBudget line codes used to allocate task orders and payment lines to specific budgets.
id TEXT PK
code (unique), label
budget_eur, active
Supporting & System
project_bonuses
Monthly bonus percentages per project+phase. Contributors stored as JSON.
bonus_validations
Tracks which months have been validated (locked) for bonus distribution.
audit_logs
Login events, IP addresses, geolocation. Used in Settings → Logs.
hr_settings
Key-value store for HR config (accountant emails, CC addresses).
salary_history
Tracks salary changes over time for each staff contract.
signed_document_uploads
Uploaded signed versions of generated FA/TO documents.
monthly_export_log
Records of monthly payroll exports sent to accountants.
todos
Internal task tracking with priority, status, and entity (RA/OuiRace).
Key Relationships
clients 1 — N projects (via client_id)
consultants 1 — N staff_contracts (via consultant_id)
staff_contracts 1 — N task_orders (via staff_contract_id)
staff_contracts 1 — N payment_requests (via staff_contract_id)
staff_contracts 1 — N leave_records (via staff_contract_id)
payment_requests 1 — N payment_request_lines (via payment_request_id)
payment_requests 1 — N payment_request_logs (via payment_request_id)
projects 1 — N portal_tokens (via project_id)
projects 1 — N project_bonuses (via project_id)
Note: JSON columns (phases, deliverables, time_entries, contacts) are stored inside the projects table, not as separate tables.
Automated Daily Backup
A scheduled job runs every day at 2:00 AM Paris time. It creates a consistent DB snapshot and uploads it to S3.
S3 location: s3://ra-customer-portal-data/backups/portal_backup_YYYYMMDD_HHMMSS.db
Retention: 60 days — older backups are automatically deleted after each run
Can also be triggered manually from Settings → Database → "Backup Now"
Manual Download
Downloads a snapshot directly to your browser. Uses SQLite's native backup API — safe during active use.
What's included: all structured data (projects, clients, invoices, contracts, HR data, etc.)
What's NOT included: files in S3 (PDFs, signatures), Firebase user accounts
Restore
Upload a .db file (from manual download or S3 backup) to replace the current database.
1. Dry run — validates the file, compares row counts, flags resurrected records
2. Actual restore — creates a safety backup (portal.db.bak), replaces the DB, runs schema migration, re-applies deletions
Safety nets
- 60 days of daily backups in S3 — recover from any point in the last 2 months
- Automatic
portal.db.bakcreated before every restore - Integrity + schema validation before any overwrite
- Dry run to preview changes without risk
- Resurrection guard: previously deleted records are re-deleted automatically
Roles
raphael@reliefapplications.org). Inherits all rights.| Capability | Super Admin | Admin | HR | PM | BizDev | Consultant | Client |
|---|---|---|---|---|---|---|---|
| Admin Dashboard Access | |||||||
| Sign in (Google SSO) | |||||||
| Impersonate other users | |||||||
| Projects | |||||||
| See project list & QA Check page | assigned | own | |||||
| Open a project (enter the card) | team only | team only | team only | assigned | own | ||
| Create new projects | |||||||
| Edit a project (details, time, deliverables, phases) | team only | team only | read | read | |||
| Delete projects | |||||||
| Resource Allocation | |||||||
| View Resource Allocation page (Project + People views) | |||||||
| Edit allocations inline on the global grid | |||||||
| Edit allocations on a project's Resource Allocation tab | own projects | ||||||
| Edit budget-code (overhead) allocations | |||||||
| Edit consultant weekly capacity (cap/wk) | |||||||
| Soft-flag a member as removed from a project | own projects | ||||||
| Clients | |||||||
| View clients | |||||||
| Create / edit / delete clients | linked | ||||||
| Biz Dev | |||||||
| Access Biz Dev page (portfolio export) | |||||||
| Invoices & Contracts | |||||||
| Manage invoices (CRUD, bulk import) | own | ||||||
| Manage contracts | own | ||||||
| Manage bonuses | |||||||
| HR Module | |||||||
| Manage consultants (profiles, contracts, salary) | self | ||||||
| Approve leave requests | request | ||||||
| Approve payment requests | view | request | |||||
| Salary history, payroll exports | |||||||
| Settings | |||||||
| Manage team members & roles | |||||||
| Database backup & restore | |||||||
| Audit logs | |||||||
| Generate test portal links | |||||||
| Tech documentation (this page) | |||||||
| Consultant Portal | |||||||
| View own profile, contracts, payslips | |||||||
| Submit time, leave, payment requests | |||||||
| Client Portal | |||||||
| View own project (deliverables, invoices, contracts) | |||||||
| Sign documents | |||||||
Enforced server-side via the @require_role decorator and the per-project _can_access_project check in app.py. Super-admin inherits all rights; HR inherits admin rights for shared endpoints; BizDev is strictly read-only on projects/clients with no inheritance. Project list & QA Check are visible to every dashboard role; opening a specific project ("team only") requires being super-admin, admin, the PM, or listed in the project's team assignments.
My TODOs
Biz Dev
Company Information
Loading…
Core Documents
Uploaded policies with AI-generated summaries. Used by the MCP connector for compliance / due diligence questions.
Loading policies…
Consultant roster
Loading…
TO Management
How Task Orders work in the portal.
Request a TO
Project Managers can request a new Task Order for a consultant directly from the portal. Here's how it works:
- Navigate to HR → Task Orders and click Request TO
- Select the consultant from the team list. Only consultants with an active contract can be assigned a TO.
- Fill in the details:
- Project — the project this TO is linked to
- Budget code — for financial tracking
- Start & deadline dates
- Total hours or days allocated
- Rate — daily or hourly rate for the consultant
- Description — scope of the work
- Submit the request. The TO is created with status draft.
After the request
- Generate the TO document — click to generate the PDF.
- Send for signature — click to email the TO to the consultant. They receive a magic link to review and sign.
- Consultant signs — the consultant opens the link, reviews the TO, and signs electronically. Status moves to Ongoing.
TO lifecycle
Consultant Invoice
How consultants submit invoices through the portal.
Submitting an invoice
Consultants submit invoices via the Consultant Portal. Each invoice is tied to a Task Order and a specific month.
- Open the portal — the consultant accesses their portal via the magic link sent by email.
- Select the Task Order — choose the active TO for which they want to submit an invoice.
- Fill in the payment request:
- Month — the period covered by the invoice
- Amount — the invoiced amount (based on days/hours worked × rate)
- Invoice PDF — upload the invoice document
- Timesheet — upload the signed timesheet for the period
- Submit — both the invoice and timesheet must be uploaded and the amount confirmed before submission is allowed.
What happens next
- Review — the PM and admin team are notified. They review the invoice and timesheet in the admin portal under HR → Payments.
- Approval — the payment request is validated and processed for payment.
- Payment — once paid, the status is updated and the consultant can see it in their portal.
Payment request lifecycle
Important notes
- Invoices must match the rate and conditions defined in the Task Order.
- A signed timesheet is mandatory for each payment request.
- Consultants can only submit invoices for Task Orders with status Ongoing.
- If a payment request needs correction, the admin can reject it and the consultant will be notified to resubmit.
Welcome to your AI space 🎉
Two gifts have been waiting for you. Click to unwrap — each one unlocks a new way to bring our portal data into your favorite LLM.
An AI-ready portfolio
One file with every project we've ever shipped. Drop it in any LLM and find a relevant project example in seconds.
Plug your AI into the dashboard
Give your favorite LLM its own personal API key. It can then query projects, clients, invoices, and TOs in real time.
- OAuth (claude.ai web/desktop): you sign in with your portal Google account each time the token is refreshed. Only RA admins, PMs, HR, and BizDev are allowed; consultants are blocked.
- Static
mcp_…keys (CLIs, ChatGPT, Gemini): one key per device/LLM, auditable per person.
Claude.ai (web & desktop)
OAuth — no token- Open claude.ai → Settings → Connectors → Add custom connector.
- Name:
RA Portal - URL:
https://dashboard.humanitarian.tech/api/mcp - Leave authentication empty — claude.ai will detect OAuth automatically.
- Click Connect. A popup will ask you to sign in with your portal Google account, then to confirm consent. Allow it — you're done.
- Enable the connector in a new chat. Try: "list my active projects".
mcp_… key and pass it as a header:
claude mcp add ra-portal --transport http https://dashboard.humanitarian.tech/api/mcp --header "Authorization=Bearer mcp_YOUR_TOKEN"
ChatGPT
native MCP Plus / Team / Enterprise- Open chatgpt.com → Settings → Connectors (or Apps → Custom MCP depending on your plan).
- Choose Add custom connector → MCP server.
- Name:
RA Portal - URL:
https://dashboard.humanitarian.tech/api/mcp - Authentication: Bearer / API key = your
mcp_…token. (If only "header" is offered, use header nameAuthorizationwith valueBearer mcp_YOUR_TOKEN.) - Enable the connector for the conversation, then ask a portal question.
Gemini
via CLI / proxyConsumer Gemini (gemini.google.com) doesn't expose remote MCP yet. Two practical options:
gemini mcp add ra-portal --transport http https://dashboard.humanitarian.tech/api/mcp --header "Authorization=Bearer mcp_YOUR_TOKEN"
mcp-remote for clients that only support local stdio MCP. Run:
npx mcp-remote https://dashboard.humanitarian.tech/api/mcp --header "Authorization: Bearer mcp_YOUR_TOKEN"
Then point your Gemini-based tool at the local stdio bridge.
Mistral / Le Chat
via proxyLe Chat doesn't currently expose remote MCP servers in the consumer UI. Options:
- mcp-remote bridge — same command as for Gemini above. Use it with any Mistral-API-compatible client that supports local MCP (Continue.dev, Cline, etc.).
- Mistral La Plateforme — if you're calling the Mistral API yourself, attach the portal as a tool by proxying through your own MCP-compatible runtime.
- Use Claude.ai or ChatGPT instead for portal questions if you don't need Mistral specifically — both have native MCP support.
Other MCP clients
Any MCP-compatible client (Cursor, Continue.dev, VS Code MCP extension, custom code) can connect with these details:
https://dashboard.humanitarian.tech/api/mcp2024-11-05Authorization: Bearer mcp_YOUR_TOKENAuthorization: Bearer mcpat_… — discovery at /.well-known/oauth-authorization-serverGET /api/mcp/healthTry these prompts
- "What can you tell me about my portal?" — the LLM will call
get_system_documentationandget_rights_matrix. - "List all active projects, group by client."
- "Which task orders are about to run out of hours?"
- "Summarize Alice's activity this year." (operational view only — no salary or leave data)
- "Top 5 clients by total invoiced revenue."
- "Search for anything mentioning ILO."
Lost your token? Rotate it.
The plaintext token is only shown once at creation. If you've lost it, or you suspect it's compromised, rotate it yourself from the card above:
- Click Revoke next to the suspect key. The revoke is immediate and irreversible.
- Click Create key at the top right of the card to issue a new one. Copy the new
mcp_…token from the modal that pops up. - Update each connector (Claude.ai, ChatGPT, Gemini, …) with the new token.