Header report uses platform org via report_platform_issue
v0.109.0
Nouveauté
Meridian
Agents report Meridian issues automatically
Les agents (clients MCP externes et chat intégré) peuvent maintenant signaler
d'eux-mêmes un bogue de Meridian avec l'outil report_meridian_issue. Les
signalements identiques sont fusionnés, et l'agent vous donne la référence de
l'issue créée.
v0.108.0
Nouveauté
Meridian
Modules par organisation
Chaque organisation ne voit plus que les modules inclus dans son forfait :
Ventes, Projets, Facturation, Comptabilité, Connaissances, Agents, Portail
client, Acquisition, API et MCP, Router LLM. Les admins de l'organisation
plateforme ont maintenant accès à la console plateforme.
A stale user_roles row left after the organization_users row is deleted no
longer grants platform access.
v0.108.0
Correctif
Meridian
Per-org module check for CRM events, no all-org scan
v0.108.0
Correctif
Meridian
Keep Router settings reachable while router API is ungated
RouterLive.SettingsLive is :core and its settings nav link is no longer
module-gated until Phase 3 gates the router API pipelines, so orgs with
module_llm_router off can still see and revoke live keys.
v0.108.0
Nouveauté
Meridian
Hide entry points of disabled modules
v0.108.0
Nouveauté
Meridian
Interim ai_enabled/module_agents override control in org modal
Platform admins can pick Plan / Forced on / Forced off for ai_enabled and
module_agents in the edit modal, with the effective state shown, so the
overrides written by the phase-1 migrations stay reversible until the
Phase 2 org modules page.
v0.108.0
Nouveauté
Meridian
Declare per-org module keys and dependencies in the catalog
Catalog now lists the 12 module keys with their requires / requires_any
dependencies and platform_only flag, and exposes modules/0, module?/1,
module_spec/1, tenant_module_keys/0 and valid_value?/2. Every module key
is also a boolean entitlement defaulting to off.
Plan page gets labels for the new module entitlements (EN + FR).
v0.108.0
Correctif
Meridian
Backfill treats non-object snapshots/entitlements as {}
A JSON-null plan_snapshot made jsonb_set raise and a null entitlements
became an array through ||. Guard both with jsonb_typeof.
v0.108.0
Correctif
Meridian
Agents migration only forces module_agents on where v1 beta was on
module_agents := plan OR agents_v1_enabled. The previous migration wrote
module_agents=false for every org whose plan includes agents but had the
beta flag off, hiding Agents for most Pro orgs.
v0.108.0
Nouveauté
Meridian
Admins of the platform org get platform access
Platform access = is_super_admin OR admin_users_view/admin_roles_view in
the configured platform organization. Computed once per request into the
User.platform_access virtual field and the :platform_access assign; every
former is_super_admin authorization read now goes through it. The
settings_nav attr is renamed is_super_admin -> platform_access, and
impersonation audit entries record the access reason.
v0.108.0
Nouveauté
Meridian
Fail-closed module gate on every authenticated LiveView
v0.108.0
Nouveauté
Meridian
Gate Meridian REST and MCP tools by organization module
v0.108.0
Nouveauté
Meridian
Per-org entitlement overrides and module_enabled?/2
v0.108.0
Nouveauté
Meridian
Backfill module entitlements and move plan-less orgs to Pro
v0.108.0
Refactorisation
Meridian
Module_agents replaces agents_v1_enabled
v0.107.22
Correctif
Router
Historique des transactions lisible et paginé
L'historique des transactions de la page Router (onglet Aperçu) ne montre
plus les paires réservation / libération qui s'annulent (une par appel
IA) : il reste les vraies dépenses, les achats de crédits, les
réservations encore ouvertes et les remboursements partiels. Les lignes
écrites dans la même seconde sortent maintenant dans le bon ordre, donc
la colonne Solde se lit de haut en bas. Le tableau affiche 25 lignes par
page avec Précédent / Suivant et le nombre total de transactions.
v0.107.22
Nouveauté
Router
Export XLSX et PDF de l'historique des transactions
Dans l'onglet Aperçu de la page Router, choisissez une période (date de
début et de fin, incluses) puis « Exporter XLSX » ou « Exporter PDF ».
Le fichier contient les mêmes lignes que le tableau pour le filtre choisi
(Tout, Crédits ou Débits), dans l'ordre chronologique, avec le montant
exact de chaque appel (jusqu'à 5 décimales) et le total des crédits et
des débits. Les heures sont en UTC. Une période de plus de 10 000
transactions est refusée : choisissez une période plus courte.
v0.107.21
Nouveauté
Router
fetch : liens vers les documents PDF de la page
POST /api/v1/tools/fetch accepte l'option facultative document_links.
Elle ajoute document_links: [{url, text}] : les liens PDF de toute la page
(fiches techniques, guides d'installation, certificats), y compris ceux d'un
onglet, d'une barre latérale ou d'une section « Téléchargements ». Les
adresses sont absolues, sans fragment ni doublon, dans l'ordre de la page
(50 au plus). Sans l'option, la réponse est inchangée ; un appel identique
est servi depuis le cache d'environ 24 h. Documentation : /router/docs.
v0.107.21
Nouveauté
Meridian
Fetch document_links option (PDF links of the whole page)
POST /api/v1/tools/fetch accepts document_links: true and returns
document_links: [{url, text}]: PDF links (path ending in .pdf or
type="application/pdf") from the whole received HTML, absolute against
final_url, fragment-free, deduplicated, page order, at most 50. [] for
a PDF read directly or a remote error; absent unless requested; cached
like the other options.
v0.107.20
Amélioration
Meridian
Accueil : présentation complète de la plateforme
L'accueil présente à nouveau les modules, l'assistant IA, Router et
l'hébergement au Québec. Il ajoute la comptabilité, le temps et le calendrier,
le portail client, les agents autonomes, la base de connaissances et les
intégrations MCP avec Claude, ChatGPT et Cursor. Les forfaits en dollars
canadiens s'affichent avant le bloc final, qui propose l'essai de 14 jours ou
une démo.
v0.107.19
Nouveauté
Router
fetch : contenu principal, données produit, passages et résumé
POST /api/v1/tools/fetch accepte quatre options facultatives :
main_content, structured_data (produits schema.org normalisés, GTIN et
variantes), highlights (passages mot pour mot) et summary (résumé
conforme à un JSON Schema ; le fetch n'échoue plus à cause du résumé). Sans
ces options, la réponse est inchangée. Les appels identiques sont servis
gratuitement depuis un cache d'environ 24 h. Documentation : /router/docs.
/chat/completions valide désormais côté serveur les types union des JSON
Schema ("type": [..]) pour les modèles sans prise en charge native de
json_schema.
v0.107.19
Amélioration
Meridian
Linear main-content extraction
Replace quadratic index accumulation and per-node HtmlTree.text
regex with one bottom-up measurement pass. 2065ms -> 285ms on a
466KB/9k-element page.
v0.107.19
Nouveauté
Meridian
PageReader orchestrates enriched fetch
v0.107.19
Nouveauté
Meridian
Local verbatim highlights
v0.107.19
Correctif
Meridian
Nested products in non-product scopes; safe JSON-LD decode
Descend through non-product itemscopes (Magento WebPage wrapper)
to find product scopes; try raw JSON-LD decode before
trailing-comma cleanup.
Compute MainContent.extract lazily with a warning-logged fallback;
Exa [] highlights fall back to local and Exa highlights are capped;
request max_chars+1 from Exa for exact truncated; accept "true"
params.
v0.107.19
Correctif
Meridian
Fetch cache cap enforcement and missing-table safety
put/3 sweeps past max_entries; get/put/clear survive a missing ETS
table; pages over 500k chars are not cached.
Measure whitespace-collapsed text length per text node and drop the
+1-per-element term, so indented link lists no longer pass the paragraph
threshold or inflate link density.
v0.107.19
Nouveauté
Meridian
Exa /contents client for fetch
v0.107.19
Nouveauté
Meridian
24h fetch cache
v0.107.19
Correctif
Meridian
Never raise on odd union schemas in summary validation
v0.107.18
Correctif
Meridian
Sample Ecto query telemetry to stop database bloat
observability_events was 99% of database disk usage (8M rows / 7 days)
because every Ecto query was logged. Fast queries are now sampled at 1%
while slow queries (>= 100ms) are always kept, and the collector no longer
logs its own observability_events / observability_rollups writes.
v0.107.17
Sécurité
Meridian
Patched XML parser for Word documents and hardened the build pipeline
Word templates and uploaded .docx files are parsed with lxml, which was
not pinned. Meridian now requires lxml 6.1.0 or later (CVE-2026-41066, XXE)
alongside python-docx 1.2.0.
The October dependency audit found no other known vulnerabilities. The CI
vulnerability scan now covers every Elixir dependency, GitHub Actions and
Docker base images are pinned to immutable digests, and the build no longer
pipes install scripts from the internet.
v0.107.16
Correctif
Meridian
Boot-independent ids for stored document files and finance idempotency keys
Same class as the ledger reference_id bug: System.unique_integer restarts
every boot, so after a deploy
a new upload could reuse an existing <int><ext> filename and
Storage.cp! would overwrite another document's bytes (possibly another
org's);
a LiveView finance write (tx/transfer/reimbursement/dashboard expense)
could reuse an old idempotency_key and be silently "replayed" — the old
row returned, the new one never created.
Use UUIDs. Prod check 2026-10-03: no duplicate filenames or colliding
keys yet.
v0.107.15
Correctif
Meridian
Boot-independent ledger reference for tool/postpaid debits
debit_for_usage defaulted reference_id to "llm_#{System.unique_integer}".
That counter restarts on every boot, so after the v0.107.14 deploy new
tool debits collided with the previous run's ledger rows
(credit_ledger_entries_reference_id_unique) and /tools/fetch answered
500. Use a UUID instead.
Root causes read from the live node (stack sampling via rpc), not guessed:
/models + /classify spun forever (billions of reductions, never "Sent"):
Jev became a real OpenRouter id, so the catalog sync replaced its
metadata and dropped virtual_alias. fast_fallback then picked the
alias itself; scoring_model_id returned jev and ensure_priced /
pricing_cad_per_mtok recursed on it. virtual_alias? now also matches
the jev model_id.
web_search 500: runtime.exs stores an explicit nil SEARCH_URL;
Keyword.get/3 returned it over Exa's default -> URI.parse(nil).
Blank/nil config now falls back to the default.
json_schema 500 after the Bedrock downgrade: null content hit
Jason.decode(nil). Non-text content now fails closed as a 422
schema_validation_failed.
Unhandled errors under /api/v1 and /api/router/v1 render the OpenAI
error envelope instead of Phoenix's {"errors":{"detail":...}}.
v0.107.14
Nouveauté
Router
/classify on ~typesafe/jev-latest via OpenRouter Decisions API
Jev's classification model is a decisions model: it refuses
chat/completions and is served by POST /api/alpha/decisions. /classify
used a JSON prompt on the org's default chat model instead.
OpenRouterClient.decisions/3 + AiGateway.decide/3: Guard redacts every
text leaf (input, instructions, labels), flat minimum hold, real
upstream usage.cost billed, hold released on failure.
RouterClassifier: model id is now ~typesafe/jev-latest (jev-router is
rejected). single → one choice question; multi → one noul per
option (Decisions has no multi-label type); binary → one noul,
score = P(yes). Response model is the concrete upstream model.
Upstream timeout/429/503/provider errors map to 504/429/503/502
instead of falling through to a 500.
Verified live against OpenRouter (3 modes, ~$0.000015/call).
v0.107.13
Correctif
Meridian
Disable migration lock for concurrent ledger index
json_schema refused natively (Bedrock 400 'Extra inputs...') retries
ONCE as json_object + server validation (200 conformant or honest
422); never silent, never looping; no healing plugin on the retry.
/models builds one pricing context for the whole catalog (was N+1
usage aggregations); composite ledger index (concurrently).
OpenRouterClient sync chat/embeddings wrapped in a total Task
deadline: hung providers surface upstream_timeout (504 JSON), never
a proxy-side 524/plain 502. circuit_open mapping preserved.
Unblock models/classify, total upstream deadline, loud unconfigured search
/models builds one pricing context (settings+markup+FX) for the whole
catalog instead of re-aggregating usage per row; composite ledger
index for the summary query.
OpenRouterClient wraps sync chat/embeddings in a total Task deadline:
a dripping/hung provider now surfaces upstream_timeout (504 JSON)
instead of hanging until the edge proxy cuts (524/plain 502).
compose example passes SEARCH_* explicitly; .env.example documents
the mandatory container recreate.
v0.107.10
Nouveauté
Router
Pdftotext tier for PDFs + explicit search env in compose
PdfText: pdftotext (already in runner image) via temp file + timeout,
pure-Elixir flate/hex extractor as fallback; fixes vendor datasheets
rendering as raw endstream/obj bytes. Caught by test: Task.yield
return shape made the tool tier silently dead.
compose example passes SEARCH_BACKEND/API_KEY/URL explicitly so the
container can't miss them; .env.example documents + mandates recreate.
v0.107.9
Nouveauté
Router
Jev real-price resolution, search env wiring, PDF flate
v0.107.8
Correctif
Meridian
Keep step-1 values (password) server-side, not in step 2's HTML
Step-1 fields rode along as hidden inputs on step 2, so the plaintext
password sat in the DOM and in every LiveView diff until the end of the
signup. They are now kept in a server-side :personal assign and merged on
validate/submit.
v0.107.8
Correctif
Meridian
Only an org admin can hide the checklist for everyone
Dismissal is stored on the organization, so any member could hide the
admin's setup steps (Stripe, MCP) for the whole team. The "Hide" button now
renders only for org admins, and the handler ignores forged events from
other members.
v0.107.8
Correctif
Meridian
AiGateway chat_completion/embed specs include upstream error tuples
Dialyzer reported put_retry_after/2 and provider_error_message/1 in the
LLM and embeddings controllers as "never called". They are not dead: they
handle {:error, {:upstream_rate_limited, _}} and {:error, {:provider_error, _}},
which OpenRouterClient returns and AiGateway passes through (covered by
llm_upstream_errors_test.exs). The @specs only declared {:error, atom()},
so Dialyzer pruned those branches. Widened the two specs instead of
deleting live 429/502 handling.
v0.107.8
Correctif
Router
Jev priced + preserved, PDF flate extraction
Migration upserts typesafe/jev-router with a sane nominal price
(fixes 422 unpriced_model on /classify); sync sweep preserves
metadata.virtual_alias rows so the daily catalog sync can't delete it.
Fetcher inflates FlateDecode streams via :zlib on raw bytes before
scanning (vendor PDFs showed raw endstream/obj garbage); hex strings
decode (UTF-16BE BOM aware); UTF-8 scrub moved post-inflation.
v0.107.8
Amélioration
Meridian
Gate re-reads the org only when the session copy looks expired
The trial gate re-read the organization (+ billing_settings) on every
LiveView navigation for every user. It now checks the session's org first
(satellites are preloaded at mount, so no query) and only re-reads when
that copy looks expired, which still lets a subscription stored after
mount unlock the next navigation without a reload.
v0.107.5
Nouveauté
Meridian
Un parcours d'essai du début à la fin
Le forfait choisi sur la page Tarifs vous suit jusqu'au paiement. L'inscription se fait en deux étapes et vous connecte tout de suite. Le tableau de bord propose cinq étapes pour bien démarrer, et la page Forfait et facturation montre ce qui sera facturé, et quand.
v0.107.8
Correctif
Meridian
Slug follows the business name; step-1 errors go back to step 1
The hidden org_slug input echoed the previous value, so the "suggest only
while blank" rule froze the slug on the first keystroke ("Atelier" →
/contact/a). While the slug is not being edited by hand, it now always
derives from the business name.
An error on a step-1 field (email already in use) was attached while
step 2 was shown, so it was invisible and the submit looked dead. Such
errors now send the client back to step 1.
v0.107.8
Correctif
Meridian
Email banner only when a verification link was sent
email_verified_at was never backfilled, so every user created before email
verification shipped saw "Link sent to …" although no link was ever sent.
New Organizations.email_verification_pending?/1: unverified AND at least
one verification token exists.
v0.107.8
Correctif
Meridian
Provision agent trials through Signup.provision/1
Agent-created workspaces (PR #79) had their own provisioning: no plan row,
no trial_ends_at column, no entitlements in the snapshot. They showed no
trial countdown, never locked, got no J-3 reminder, had AI and modules off
(the default-off trap), could not pay from /settings/plan, and crashed when
no "equipe" row existed.
open_workspace/1 now calls Signup.provision/1 (inactive user, random
password, org locale/email passed as new optional attrs), then layers the
agent API's snapshot keys on top of the standard snapshot instead of
replacing it. Removes the now-unused insert_* / stamp_trial helpers.
v0.107.8
Correctif
Meridian
A paid plan without a Stripe price is never applied for free
free_plan?/1 treated "no Stripe price ID for the plan's own interval" as
free, and checkout's :no_stripe_price fell back to applying the plan. The
seeded Solo/Équipe/Pro rows have no price IDs until an admin sets them, and
the period toggle can pick a missing yearly price: orgs outside a trial
(legacy, agent-created) could switch to Pro without paying.
Free now means a zero price only; :no_stripe_price shows an error instead
of applying. Replaces the former "fall back to direct apply" test, whose
intent (no dead end) conflicted with not giving paid plans away.
v0.107.8
Correctif
Meridian
Secure headers on discovery pipeline + literal content types
Sobelow (precommit) flagged two findings from the agent-discovery merge:
Config.Headers: the :discovery pipeline served json/txt/md without
put_secure_browser_headers. Added (real hardening: nosniff on bodies
that embed the request host).
XSS.SendResp: false positive — the controller never serves HTML — but
Sobelow only trusts literal content types set in the same function, so
send_cached/3 now picks a literal, never-HTML type inline.
v0.107.7
Refactorisation
Meridian
Use StripeClient alias in StripeSession.create
v0.107.6
Nouveauté
Router
Ship pending model-sync migration, tests and logbook
Complements b18bb9cb (which carried the code + changelog entry):
the Oban-synced catalog needs
organization_billing_settings.router_restrict_to_platform_models,
otherwise Router calls fail on the missing column.
v0.107.5
Correctif
Meridian
Router a son propre site public
Les pages Router indiquent https://router.signalorange.ca comme adresse canonique. Le sitemap et le fichier llms.txt de Meridian ne listent plus Router. Sur le site Router, ils ne décrivent que Router.
v0.107.5
Correctif
Meridian
Page Router : description et image de partage
La description de la page Router est plus courte. L'image de partage des pages publiques est une image PNG. Le schéma de la page Router est du SVG valide.
Les modèles OpenRouter sont désormais synchronisés chaque jour et tous
exposés par défaut via l'API Router (GET /api/v1/models,
chat/completions). Depuis /router/settings/ai, chaque organisation peut
restreindre son API à ses seuls modèles plateforme. Les modèles utilisés par
les fonctionnalités Meridian restent choisis par l'organisation (ou le
super-admin plateforme).
v0.107.5
Nouveauté
Meridian
Where-am-I summary, shared cards with deltas, honest confirmation
v0.107.5
Nouveauté
Meridian
PublicPlans reads prices and limits from the plans table
v0.107.5
Nouveauté
Meridian
J-3 reminder email, sent once
v0.107.5
Refactorisation
Meridian
Satisfy credo-strict nesting and alias order
v0.107.5
Correctif
Meridian
Restore plan card anchors for json_ld and deep links
No response-healing plugin on json_schema (silent repair contradicts
the 422 contract; keeps native structured routes plugin-free).
v0.107.5
Nouveauté
Meridian
Agent discovery, trial signup, and flagged plan checkout
Agents can read public plans from /agents, /pricing.json, and llms.txt,
open an Équipe trial with a confirmation email, and, when
AGENT_CHECKOUT_ENABLED is true, receive a Stripe Checkout link in CAD.
The signed-in agents dashboard moved from /agents to /agents/dashboard.
v0.107.5
Correctif
Meridian
Update checklist component test to five-step contract
v0.107.5
Correctif
Meridian
Final-review wave (docs, period persistence, fresh trial gate)
v0.107.5
Correctif
Meridian
Preload satellites on fallback org so payers see no trial UI
v0.107.5
Nouveauté
Meridian
Log the new admin in with a one-time token
v0.107.5
Nouveauté
Meridian
Sidebar countdown and J-3 banner
v0.107.5
Nouveauté
Meridian
Five-step first-run checklist and email banner
v0.107.5
Correctif
Meridian
Follow homepage copy after PR #78 redesign (merge follow-up)
v0.107.5
Correctif
Meridian
Point Router canonical URLs at router.signalorange.ca
Router is a separate product. /router, /router/pricing and /router/docs
declare that host for canonical, og:url and hreflang even when Meridian
serves the copy. Meridian sitemap and llms.txt omit Router; the Router
host lists only its own pages and robots.txt points at its sitemap.
v0.107.5
Nouveauté
Meridian
Checkout bills at trial end and keeps the chosen interval
v0.107.5
Correctif
Meridian
Refuse plan switch server-side for subscribed orgs
v0.107.5
Correctif
Meridian
Refuse activate server-side for subscribed orgs
v0.107.5
Nouveauté
Meridian
Shared plan_card component
v0.107.5
Nouveauté
Meridian
Slug, yearly price and position as catalog of record
v0.107.5
Nouveauté
Meridian
Discovery, trial signup, and flagged plan checkout
Publish machine-readable plans and an agent guide, let an agent open an
Équipe trial that waits on a confirmation email, and return a Stripe
Checkout link only when AGENT_CHECKOUT_ENABLED is true. The signed-in
agents dashboard moves to /agents/dashboard.
v0.107.5
Nouveauté
Meridian
Two-step /inscription carrying forfait and periode
v0.107.5
Correctif
Meridian
Shorten Router descriptions and use a PNG share image
Close the Router diagram SVG explicitly and point public Open Graph tags at a 1200x630 PNG. Canonical URLs stay on the endpoint host, so a copy served on router.signalorange.ca does not declare a second canonical.
v0.107.5
Nouveauté
Meridian
Lock expired trials onto the plan page (UI, REST, MCP)
v0.107.5
Nouveauté
Meridian
Per-plan trial CTA into signup, next-steps strip, agent band
Tools.Settlement shared by both endpoints: gate -> execute -> settle,
billing cents now equal the debited quantum.
Fetch cost dynamic: base + per transferred byte (404s billed base,
SSRF/timeout/validation free); WebSearch unchanged USD path.
server_tools executions settle on the org too (billing_failure surfaces
as execution error, never silent free usage).
v0.107.3
Nouveauté
Meridian
Platform org SMTP as system fallback
v0.107.3
Nouveauté
Router
Web_search cost via org markup + FX like LLM usage
WebSearch backends report real USD cost (Exa costDollars.total, else
documented list-price fallbacks; 0 for searx/stub) and
RouterTools.usd_billing/2 runs it through AiGateway.calculate_cost_millicents
cost_cad_decimal — same economics as chat/completions. Endpoint and
chat server-tools keep the exact {cost_cad, cost_cad_cents, currency}
shape; cost_usd stays internal. Drops fixed SEARCH_COST_CAD.
v0.107.2
Nouveauté
Meridian
Stripe price IDs editable in plans form
v0.107.2
Nouveauté
Router
Generic SEARCH_* env for web_search + Exa backend
Rename ARTEMIS_SEARCH_* env vars to generic SEARCH_* / FETCH_COST_CAD:
the tools are available to every Router key, not Artemis-specific.
Add Exa backend (POST api.exa.ai/search, contents.highlights):
extractive excerpts fit the snippet contract; language inferred from
query, country passed as userLocation.
v0.107.1
Correctif
Meridian
Router : erreurs fournisseur en JSON et lecture des PDF binaires
Les erreurs renvoyées par les fournisseurs (OpenRouter 4xx/5xx, 429, délai
dépassé) sur POST /api/v1/chat/completions et /api/v1/embeddings
retombaient à tort sur « Internal error » (HTTP 500) au lieu des codes
documentés 502 upstream_error, 429 avec Retry-After et 504
upstream_timeout, toujours en JSON au format OpenAI. POST /api/v1/tools/fetch ne plantait plus sur les PDF contenant des données
binaires non UTF-8 : le texte est extrait comme avant, sans erreur 500.
v0.107.1
Correctif
Router
Single-wrap upstream errors (502/429/504, not 500) + scrub non-UTF-8 PDF bytes
OpenRouterClient wrapped classify_* results in an extra {:error, ...},
so every upstream 4xx/5xx/429/timeout fell through to generic 500
'Internal error' instead of upstream_error/rate_limited/upstream_timeout.
Fetcher crashed (Phoenix 500) on PDFs with non-UTF-8 binary; scrub once
via latin-1 so Regex/String never raise.
v0.107.0
Nouveauté
Meridian
Self-serve signup + trial
L’inscription est désormais en libre-service : créez votre organisation et votre
compte depuis la page d’accueil, profitez d’un essai gratuit de 14 jours sur les
plans payants, puis validez votre adresse e-mail pour activer l’accès.
Depuis Réglages → Plan & usage, changez de plan, gérez le paiement ou
résiliez en toute autonomie, avec un rappel visible avant la fin de l’essai.
v0.107.0
Nouveauté
Meridian
Router : structured outputs json_schema, outils serveur et option aucune-rétention
L'API Router accepte désormais response_format: {"type": "json_schema", ...}
sur POST /api/v1/chat/completions : les modèles OpenAI/Anthropic l'appliquent
nativement, les autres voient leur sortie validée par Router (HTTP 422
schema_validation_failed, sans facturation, jamais corrigée silencieusement).
Les stubs {"type": "web_search"} et {"type": "fetch"} dans tools sont
exécutés par Router pendant la conversation, avec tool_executions dans la
réponse. GET /api/v1/models expose supported_parameters par modèle.
Nouvelle option no_retention (body ou en-tête X-No-Retention) : aucun
prompt persisté et entraînement interdit côté fournisseur ; les modèles qui ne
peuvent le garantir sont refusés (HTTP 400). Détails : Confidentialité et
rétention.
v0.107.0
Nouveauté
Meridian
Self-serve upgrade/downgrade/cancel + changelog
v0.107.0
Nouveauté
Meridian
Tenancy & entitlement spine + trial fields
v0.107.0
Correctif
Meridian
Defer organization_created broadcast until after provision commits
v0.107.0
Correctif
Meridian
Atomic email verification + resend throttle
v0.107.0
Nouveauté
Meridian
Public /signup org + admin + plan select
v0.107.0
Correctif
Meridian
Require positive id match on subscription.deleted + drop stray report
P0-1 precise cost_cad + prompt/completion usage on chat/classify/tools.
P0-2/3 POST /api/v1/tools/web_search + /api/v1/tools/fetch (SSRF guard).
P0-4 server tools web_search/fetch in chat/completions (tool_executions).
P0-5 POST /api/v1/classify single/multi/binary with scores.
P0-6 response_format json_schema passthrough + server-side 422 validation.
P1-7 upstream errors as JSON (upstream_error/timeout), 429 Retry-After,
402 insufficient_credit, :batch rejected, rate limits documented.
P1-8 /api/v1/models enriched (context_length, pricing, supported_parameters).
P1-9 privacy doc + no_retention per request/key. P1-10 OpenAPI coverage.
v0.107.0
Correctif
Meridian
Final review wave (admin perms + robustness)
v0.107.0
Nouveauté
Meridian
Stripe subscription checkout + trial webhooks
v0.107.5
Nouveauté
Meridian
Tarifs publics et accueil ERP agentique
Les forfaits Meridian sont publics : Solo, Équipe, Pro et Entreprise, en
dollars canadiens, sur /tarifs et /en/pricing. Solo, Équipe et Pro incluent
5 $ de crédits IA par mois. L'accueil décrit le CRM, les soumissions, la
facturation et les projets pour les travailleurs autonomes et les petites
entreprises de services. L'essai de 14 jours ouvre le formulaire de contact
déjà en place.
v0.107.5
Correctif
Meridian
Plain public copy and $5 included AI credits
Replace the credit placeholder with $5 per month on Solo, Équipe, and Pro.
Rewrite the homepage and pricing text as short factual sentences.
v0.107.5
Nouveauté
Meridian
Public CAD pricing and agentic ERP homepage
Publish /tarifs and /en/pricing from a single plan module, and reposition
the public homepage for Quebec solopreneurs and small service businesses.
The trial still opens the existing contact form; Stripe billing is unchanged.
v0.106.1
Correctif
Meridian
Les fournisseurs n'apparaissent plus dans les clients
Les listes, statistiques, fiches et l'API clients n'affichent désormais que les
entreprises de type client. Les fournisseurs restent visibles uniquement dans
la section Fournisseurs de la comptabilité, avec une redirection propre si une
URL croisée est ouverte.
v0.106.1
Correctif
Meridian
Exclude suppliers from clients views
v0.106.0
Nouveauté
Meridian
Contacts CRM créables via l'API et le MCP
Les contacts des entreprises (nom, courriel, téléphone, fonction, notes)
sont maintenant créables, modifiables et supprimables via
POST /api/meridian/v1/contacts — et donc directement avec les outils MCP
create_contact, get_contact, list_contacts, update_contact et
delete_contact. Fini le contournement par les notes des fiches entreprises :
chaque contact est rattaché à son entreprise (company_id obligatoire).
v0.106.0
Nouveauté
Meridian
Expose CRM contacts on REST + MCP
Adds GET/POST/PATCH/DELETE /api/meridian/v1/contacts (auto-surfaced
as list/get/create/update/delete_contact MCP tools). company_id is
required and scoped to the org; companies permission slugs reused.
Changelog entry stays unstamped for the release task.
v0.105.1
Correctif
Meridian
Pages publiques prêtes pour les moteurs de recherche
Les pages publiques (Meridian, Router, documentation, changelog) ont maintenant
un titre, une description, une URL canonique et des balises Open Graph.
Le balisage schema.org est du JSON valide, et sitemap.xml liste ces pages.
v0.105.1
Correctif
Meridian
Make public Meridian and Router pages crawlable
Add unique titles, descriptions, canonical and social tags, valid JSON-LD,
and language tags. Serve a sitemap and robots.txt, name the gateway Router,
and deliver documentation screenshots as AVIF and WebP.
v0.105.0
Correctif
Meridian
Transaction drawer no longer crashes on categorized entries
Opening the detail drawer of a transaction linked to a categorized
expense crashed (ExpenseCategory has code/name_fr/name_en, no
name field). The drawer now shows the localized category name, and
attached receipts get inline image previews plus Preview (new tab) and
Download actions via short-lived signed URLs.
v0.105.0
Nouveauté
Meridian
Expense categories CRUD and drawer receipt preview
Categories are no longer seed-only: new ExpenseCategories context
(create/update/delete, delete refused when in use), REST endpoints +
create/update/delete_expense_category MCP tools, CRUD card in finance
settings. Fixes the unique constraint declaration so duplicate codes
surface on :code.
Also fixes the transaction drawer crash on categorized expenses
(ExpenseCategory has no name field; localized label instead) and adds
receipt preview/download via signed URLs.
v0.104.0
Nouveauté
Meridian
Receipts synced both ways, transactions visible everywhere
update_expense accepts document_id and mirrors the document link;
linking a document to an expense fills its receipt FK when empty
(backfilled by migration); new /finance/transactions page, accounting
section on supplier files, shared transaction detail drawer.
v0.105.0
Nouveauté
Meridian
Create, rename and delete expense categories
Expense categories are no longer seed-only: /finance/settings has a new
"Expense categories" card to create (code, French/English names,
deductible %), rename and delete them. Deleting a category used by
expenses or transactions is refused to protect posted history.
The MCP/API exposes the same CRUD: create_expense_category,
update_expense_category, delete_expense_category
(POST /finance/expense_categories,
PATCH/DELETE /finance/expense_categories/:id), so imports and agents
can create missing categories on the fly instead of failing on unknown
labels.
v0.104.0
Nouveauté
Meridian
Attach receipts to expenses later, open each transaction
Existing expenses can now receive their receipt after the fact:
PATCH /finance/expenses/:id (MCP tool update_expense) accepts
document_id (receipt uploaded via the documents tools first, org-scoped
like supplier, category and CCA class). create_document already links to
expense and invoice, and create_expense already takes document_id.
Each transaction line on the account page is now clickable and opens a
detail drawer: supplier, category, deductible %, linked expense/invoice,
receipts/documents, and the account.
v0.104.0
Nouveauté
Meridian
Receipts synced both ways, transactions visible everywhere
Receipts are now visible whichever field the UI reads: attaching a
document to an expense (create_document with expense) fills the
expense's receipt when empty, and setting a receipt via update_expense
(document_id) creates the document link so list_documents sees it.
Existing links were backfilled to the receipt field, so the attachment
icon shows on all previously linked expenses.
Transactions are also reachable from everywhere: a new
/finance/transactions page lists recent postings across all accounts,
and each supplier file has an "Accounting" section with its finance
entries. Every row opens the same detail drawer (supplier, category,
deductible %, linked expense/invoice, receipts and documents, account)
with a paperclip icon wherever a receipt exists.
v0.103.0
Nouveauté
Meridian
Link expenses to suppliers later, set tax frequency via API
Existing finance expenses can now be linked to their supplier and category
without voiding them: PATCH /finance/expenses/:id (MCP tool
update_expense) accepts company_id (vendor_id / supplier_id aliases),
category_id, plus description, reference, deductible % and CCA class.
Amounts, taxes, dates and payment method stay immutable once posted, and
void expenses are refused. Finance settings also accept
tax_period_frequency (monthly, quarterly, annual) via API/MCP, so
the fiscal cadence can be aligned without the web UI — close stale periods
with the existing close_tax_period tool.
v0.103.0
Nouveauté
Meridian
Update expense categorization and tax frequency setting
PATCH /finance/expenses/:id (MCP update_expense) links existing
expenses to a supplier (company/vendor/supplier aliases) and category
plus reference, deductible and CCA updates; amounts stay immutable
and void expenses are refused. update_finance_settings accepts
tax_period_frequency (monthly/quarterly/annual).
v0.102.0
Nouveauté
Meridian
Account controls, supplier API and import fixes
Account detail page with opening-balance edit and manual
revenue/expense posting plus reversal; same surface as MCP tools
(get_account, update_account, create_transaction, reverse_transaction).
Readable/writable finance settings (get/update_finance_settings) so the
operating account can be designated over MCP. Full supplier entity
(list/get/create/update/delete_supplier) plus web edit/delete.
create_expense maps catalog payment labels, aliases vendor_id and
rejects cross-org companies with explicit errors. Fixes
get_shareholder_balance crash on integer user_id.
v0.102.0
Nouveauté
Meridian
Account controls, supplier API and finance import fixes
Account controls are now exposed everywhere. Each account has a detail page
(/finance/accounts/:id) to edit the opening balance and details, record
manual revenue/expense transactions, and reverse them; the same operations
are available as MCP tools (get_account, update_account,
create_transaction, reverse_transaction). Finance settings can be read
and updated via API/MCP (get_finance_settings,
update_finance_settings), so the operating account can finally be
designated without the web UI — invoice payments, expenses and
reimbursements no longer fail with "Operating account not configured" once
it is set. Suppliers get a full API/MCP entity (list_suppliers,
get_supplier, create_supplier, update_supplier, delete_supplier)
plus edit/delete in the web UI. create_expense now accepts catalog
payment labels ("Virement bancaire", "Carte de crédit", "Chèque",
"Comptant", "Autre") with a clear error otherwise, takes vendor_id as an
alias for company_id, and rejects cross-org companies. Fixed
get_shareholder_balance crashing on integer user_id over MCP.
Close the MCP finance gaps blocking bookkeeping imports. New tools:
create_account (operating, tax reserve, shareholder advance),
list_tax_periods + create_tax_period (no more undiscoverable IDs),
list_expense_categories + list_cca_classes, update_invoice,
void_invoice, void_expense. create_expense accepts supplier, category,
deductible %, CCA class, receipt document and reference, plus foreign-currency
fields stored on the transaction; receipts can now link to expenses and
invoices. create_invoice accepts detail lines; record_invoice_payment
accepts partial amounts and a chosen cash account (invoices stay sent until
fully paid). Tool failures now return the actual error message instead of a
generic failure.
v0.101.0
Nouveauté
Meridian
Finance pages fixed, manual accounts, zero-dollar invoices paid on send
Fix "Not found" on Finance tax period, shareholder and settings pages and on
employee expense reports for organizations created before finance reference
data existed: a backfill migration seeds them, and page loads degrade instead
of crashing. Finance settings gains manual account creation (operating, tax
reserve, savings, credit card, shareholder advance) plus operating account,
tax reserve and primary shareholder assignment. The Received page follows the
design system shared components. CRM invoices totalling $0 are marked paid as
soon as they are sent.
v0.100.3
Correctif
Meridian
Drop observability events before buffer starts, handle seeded-models skip
v0.100.2
Correctif
Meridian
Fix dashboard header data failing to load
A crash in the session data loader meant the dashboard header silently fell
back to empty defaults on every page load: notification count, pending
approval badges, workspace branding, and the running timer could all appear
blank. The loader now detects the production database pool correctly and all
header data loads as expected.
v0.100.2
Correctif
Meridian
Skip Sandbox.allow outside test env so dashboard snapshot loads in prod
v0.100.0
Correctif
Meridian
CRM hub opens the first board you can access
/crm now sends you to opportunities, clients, proposals, or projects based
on your permissions instead of always bouncing through opportunities.
v0.100.0
Refactorisation
Meridian
Carve LineItems submodule from Proposals context
v0.100.0
Correctif
Meridian
Decimal-safe billing chart math and stabilize auth/billing tests
v0.100.0
Refactorisation
Meridian
Share RouterConsistency validator runner
v0.100.0
Correctif
Meridian
Use ConnCase.log_in_with_permissions/2 in CRMLive tests
Share template boilerplate; drop unused Proposals aliases
v0.100.0
Refactorisation
Meridian
Consolidate docx Python and proposal fetch rescue wrappers
Extract run_python/3 in Docx and Meridian.Actions.ProposalFetch so
repeated try/rescue blocks map Ecto.NoResultsError to proposal_not_found
in one place for the four Flow 2 proposal actions.
v0.100.0
Refactorisation
Meridian
Shrink qualification API to live funnel surface
v0.100.0
Refactorisation
Meridian
Extract shared list shell for CRM list components
v0.100.0
Correctif
Meridian
Address PR #58 Bugbot CRM landing and Oban worker rename
CRM /crm redirects to the first surface the user can open. Migration
rewrites oban_jobs.worker so BillingStartup/AutoReplenish uniqueness
survives the Meridian.Workers → AiGateway.Workers rename.
v0.99.0
Amélioration
Meridian
Migration de l'export XLSX finance vers xlsx_writer
L'export XLSX des données finance (Meridian.Finance.Export.Workbook) utilisait
elixlsx, une bibliothèque abandonnée. Il utilise maintenant xlsx_writer
(NIF Rust via rust_xlsxwriter), une alternative activement maintenue. Aucun
changement de comportement pour les utilisateurs : mêmes feuilles, mêmes
colonnes, même format de fichier .xlsx.
v0.99.0
Sécurité
Meridian
Harden PDF preview against PDF.js scripting CVE
CVE-2026-16633 allows malicious PDFs to execute JavaScript when PDF.js scripting
is enabled during document load. Meridian's Typst preview now loads PDFs with
enableScripting: false, and pdfjs-dist is upgraded to the 6.x line
(6.3.289) where the fix is available.
v0.99.0
Sécurité
Meridian
Replace retired Earmark with MDEx for Markdown rendering
Earmark 1.4.49 is retired on Hex and flagged for EEF-CVE-2026-48591 (stored XSS
via unescaped HTML attribute values). Meridian now uses MDEx (~> 0.13) for all
Markdown-to-HTML conversion, including NimblePublisher changelog/docs
(comrak_options replaces stale earmark_options), document extraction, CRM
email recaps, knowledge/FAQ pages, and admin directive previews.
v0.99.0
Amélioration
Meridian
Mise à jour de FullCalendar vers la v7
Le calendrier (planning, disponibilités, suivi du temps) utilise maintenant
FullCalendar 7 au lieu de la v6. Le module @fullcalendar/core et ses plugins
séparés sont remplacés par le package unique fullcalendar, avec le thème
standard « classic » (palette neutre grise, sans violet). Les couleurs
clair/sombre suivent le thème Meridian via les variables --fc-classic-*.
v0.99.0
Refactorisation
Meridian
Rename CRM.Invoice schema to Finance.ClientInvoice
v0.99.0
Refactorisation
Meridian
Split facade into autonomy/messaging/traces modules
v0.99.0
Correctif
Meridian
Align dunning tests and permission coverage gaps
Drain fan-out dunning child jobs in tests; declare public_funnel
@permissions; track admin LiveViews in the coverage allowlist.
v0.99.0
Refactorisation
Meridian
Big-bang callers to Finance.ClientBilling; drop CRM façades
v0.99.0
Refactorisation
Meridian
Pure changesets with injected catalog allow-lists
v0.99.0
Refactorisation
Meridian
Tidy invoices LiveView alias order for Credo
v0.99.0
Refactorisation
Meridian
Colocate Oban workers by domain
v0.99.0
Refactorisation
Meridian
Split proposals LiveView helpers and flow modal
Move flow_choice_modal into Modals, AI/Flow2 helpers into AiHelpers, and
remaining non-event helpers into LiveSupport so crm_proposals_live stays
orchestration-only under the fanout line-count target.
v0.99.0
Refactorisation
Meridian
Big-bang callers to Meridian.Proposals; drop CRM façade
v0.99.0
Refactorisation
Meridian
Remove Repo from remaining LiveViews + Credo ban
v0.99.0
Correctif
Meridian
Clean compile after arch health integration
Fix InvoiceMath default-arg heads and drop unused LiveView aliases
left by the scoped-reads port.
v0.99.0
Correctif
Meridian
Hex-encode sha2 0.11 digest without LowerHex
v0.99.0
Nouveauté
Meridian
Add Meridian.Actions façade over ActionRegistry
v0.99.0
Correctif
Meridian
Drain payment-receipt Oban jobs in ClientBilling tests
Document full Package D ownership in Meridian moduledoc after big-bang
façade removal and ClientInvoice rename.
v0.99.0
Correctif
Meridian
Close audit highs/mediums and sort-param oracles
Remediate tenant authz, finance races/validation, billing/Stripe integrity,
backup crypto, XSS/upload/prompt sinks, and related medium findings; add
allow-listed CRM sort params to stop to_existing_atom 500 oracles.
v0.99.0
Correctif
Meridian
Fail-closed LiveView permissions with @public
Register @public on unauthenticated LiveViews, deny mount when neither
@permission nor @public is declared, and add coverage/session tests.
v0.99.0
Refactorisation
Meridian
Break Organizations→CRM compile cycle via events/callbacks
v0.99.0
Refactorisation
Meridian
Route web controllers through contexts
Port portal, API v1 log, CRM, and finance controllers off direct Repo
to ScopedReads and domain contexts. Shrink NoRepoInWeb Credo allowlist to
health probe, session snapshot, and audit plug only.
v0.99.0
Refactorisation
Meridian
Extract OpenRouterClient and Documents upload staging seams
v0.99.0
Refactorisation
Meridian
Extract invoices LiveView list and modal components
Split list/board/table and modal HEEx out of InvoicesLive into
CRM.Invoices.ListComponents and Modals, matching DetailComponents.
v0.99.0
Refactorisation
Meridian
Scope struct, scoped proposal edit, gate stubs
Close cross-org Repo.get! in propose_proposal_edit; normalize action
context via Meridian.Scope; exclude not_implemented tools from dispatch.
v0.99.0
Refactorisation
Meridian
Scoped context reads and session snapshot
Port CRM/Finance/Organizations/Agents scoped_reads modules from wt-e,
consolidate AuthLiveSession mount reads via SessionSnapshot, and replace
direct Repo usage in targeted LiveViews with context helpers.
v0.99.0
Refactorisation
Meridian
Route api_keys_controller through ScopedReads
Last controller still hitting Repo; Credo NoRepoInWeb allowlist is now
infra-only (health, session_snapshot, audit plug).
Single source of truth for advance/regress paths; dedupe notification
and import_type case pairs.
v0.99.0
Refactorisation
Meridian
Run meeting Graph/Dispatcher side effects after commit
Keep book_meeting and cancel_meeting Multis to DB (+ Oban email) only so
Outlook/notification I/O cannot roll back a committed booking or cancel.
v0.99.0
Refactorisation
Meridian
Fan out perf and maintainability fixes
Centralize runtime config, extract god-LiveView components, move
side effects out of transactions, and add hot-path indexes plus
async logo/receipt workers.
v0.99.0
Correctif
Meridian
Drain payment-receipt Oban jobs in ClientBilling tests
Document full Package D ownership in Meridian moduledoc after big-bang
façade removal and ClientInvoice rename.
v0.99.0
Refactorisation
Meridian
Rename Meridian.Router domain to Meridian.AiGateway
v0.97.0
Amélioration
Meridian
Approve pending finance expenses and richer quick-expense entry
Managers with finance approve can approve expenses waiting for review via
MCP/API. On the Finance dashboard, quick expense entry supports credit card
and employee expense payment methods (not only operating), with receipt
upload.
v0.97.0
Correctif
Meridian
Export COGS/tax on P&L sheet and assert resale COGS split
v0.97.0
Refactorisation
Meridian
Clear Credo strict findings before push
v0.97.0
Nouveauté
Meridian
Prepaid allocation, project margin, and corp tax on P&L
Accrual expense recognition via expense records (prepaid daily allocation,
COGS from resale), corp tax estimate on profit, and project margin report.
v0.97.0
Correctif
Meridian
Satisfy dialyzer with schema types and nonempty xlsx workbook
v0.97.0
Nouveauté
Meridian
Ship org books module with MCP, Excel export, and LiveViews
Add finance domain (accounts, expenses, invoices, transfers, tax periods,
reimbursements), read/write MCP tools with body-key idempotency, multi-sheet
Excel export, and /finance UI. Wire expense reports to finance posting and
reimbursement; redirect legacy tresorerie/taxes routes; include Phase 1 MCP
fixes for get_me and knowledge tools.
v0.97.0
Correctif
Meridian
Match Transfers.create 3-tuple in cash position test
v0.97.0
Nouveauté
Meridian
Finance module · org books, MCP, and LiveViews
Meridian now has a first-class Finance context separate from CRM billing:
Employee expense reports post into finance on approval and reimburse via finance reimbursements. Legacy /comptabilite/tresorerie and /comptabilite/taxes redirect to /finance.
SignalOrange Excel import was deferred.
v0.96.0
Nouveauté
Meridian
Finance transfers, tax period, shareholder, and settings views
New finance pages cover account transfers, the current tax period
(accrual GST/QST with a “mark as filed” action), shareholder employee expense
balances, and finance settings (capitalization threshold, approval policy,
and per-user spending limits). Legacy Comptabilité Trésorerie and TPS/TVQ URLs
redirect to the finance module.
v0.96.0
Nouveauté
Meridian
Finance dashboard and quick expense entry
The new Finance page shows available cash (operating balance minus tax
hold) as the primary figure, with operating balance, tax reserve, and tax hold
as secondary KPIs. Users with edit permission can record a quick operating
expense with an optional receipt upload. Export the full finance workbook to
Excel from the dashboard header.
v0.96.0
Amélioration
Meridian
Surface spending limits and finance status on employee expense reports.
Expense reports show remaining budget when a limit is set, approval requirements, finance posting status on approved lines, and reimburse now creates a finance reimbursement.
v0.96.0
Nouveauté
Meridian
Show quote builder pickers below Typst PDF on client surfaces.
Hybrid layout keeps the compiled PDF iframe and adds option-group and optional line pickers when the proposal has client-selectable lines.
v0.96.0
Amélioration
Meridian
Mise à jour globale des dépendances (Elixir 1.20.4, Typst 0.15.1, npm, Docker)
Mise à jour de la stack et des bibliothèques du projet : runtime Elixir/OTP,
Hex, npm, crates Rust, assets vendored et images Docker.
Propositions Flow 2 : page publique et portail affichent le PDF compilé Typst quand disponible.
Factures récurrentes client : champs récurrence sur factures + worker quotidien pour générer les occurrences.
OCR reçus fournisseurs : scan PDF sur le formulaire de dépense fournisseur.
v0.96.0
Nouveauté
Meridian
Add employee expense reports with approval workflow.
Staff submit reimbursement reports at /comptabilite/depenses-employes with line items, CSV export, and permission-gated approve/reject flows.
v0.96.0
Nouveauté
Meridian
Add supplier receipt OCR via agent harness.
Upload a receipt on the supplier expense form to draft amounts and TPS/TVQ; parse_expense_receipt is registered as an agent tool.
v0.96.0
Nouveauté
Meridian
Show Flow 2 Typst PDF on public proposal preview.
Public and portal views embed the compiled PDF when flow 2 artifacts exist instead of legacy JSON sections only.
v0.96.0
Nouveauté
Meridian
Add recurring client invoice templates and daily worker.
Invoices can repeat monthly or yearly; Oban generates occurrences and the invoices UI exposes recurrence setup.
v0.96.0
Nouveauté
Meridian
Add version snapshot diff in CRM drawer.
Compare two saved proposal versions with field and line-item changes; document Phase B feats in LOGBOOK and changelog.
v0.96.0
Nouveauté
Meridian
Add quote builder with client-selectable line items.
Optional add-ons, mutually exclusive option groups, and recurring labels; clients adjust selections on the public page and portal with live totals.
v0.96.0
Refactorisation
Meridian
Centralize text helpers in Meridian.Text.
Move HTML escaping, slugify, and byte formatting into one module and update mailers, PDFs, and LiveViews to use it.
v0.96.0
Nouveauté
Meridian
Enrich client project status with phases and milestones.
Portal hub shows progress bars, phase list, upcoming milestones, and portal_status_visible gating per project.
v0.96.0
Nouveauté
Meridian
Add docx read_paragraphs internal tool
Register Docx.ReadParagraphs in the shared ToolRegistry for harness
spike work; fix agent-platform changelog frontmatter.
v0.96.0
Nouveauté
Meridian
Agent Platform tool registry and loop
Shared tool catalog for internal agents and MCP: ToolRegistry merges MCP
OpenAPI tools with harness-internal actions, ToolExecutor dispatches calls,
and Agents.Loop runs multi-turn tool-use over the Router.
Introduce Agent Platform foundation (AP-1): unified MCP + internal tool
catalog, ToolExecutor dispatch, and multi-turn Agents.Loop. Add Phase 2
plan, harness spike-plan, and changelog.
v0.93.0
Nouveauté
Meridian
Win/loss reasons and stale-deal alerts
Mark a deal lost with a catalog reason and optional notes; Analytics shows loss
breakdowns by reason, owner, and stage plus win rate over time. Open deals that
go quiet or pass their expected close date surface on the pipeline and dashboard,
with an optional daily email to the owner (Settings → Public funnel threshold;
Paramètres → Services → Raisons de perte).
v0.92.0
Nouveauté
Meridian
GEO & découvrabilité IA
Meridian émet désormais un fichier llms.txt public et du JSON-LD schema.org
(LocalBusiness, Service, FAQ) sur les pages publiques (contact, FAQ, réservation,
propositions, documentation).
Chaque organisation peut activer une surface MCP publique en lecture seule
(profil, services, FAQ, URL de contact) et consulter une vue GEO & IA dans
Paramètres : checklist de préparation, liens llms.txt / MCP, et accroche
forfait service géré (facturation stub).
v0.96.0
Nouveauté
Meridian
TPS/TVQ remittance report
Quebec sales tax remittance report with collected GST/QST minus input tax credits on paid expenses, period picker, and CSV export under Comptabilité.
v0.96.0
Nouveauté
Meridian
Phase budgets, budget report, and payroll export
Project phases now support hour budgets and member assignments. The time reports
page adds a Budget vs Actual tab with project and client filters, trend
projection, and CSV export. A monthly Payroll Export downloads per-member
hours (total, billable, and non-billable) for payroll processing.
v0.96.0
Nouveauté
Meridian
Pipeline stage configuration and forecasting
Configure CRM pipeline stages with win probability and color, drag-and-drop
Kanban moves, a weighted forecast view by month, and CSV export from the
opportunities table. Settings → Configure stages (catalogs_edit permission).
New Forecast link under Pipeline in the sidebar.
v0.96.0
Nouveauté
Meridian
Microsoft 365 CSP catalog and GDAP tenant linking
CSP SKU markup table for org admins and GDAP client-tenant linking with approval URL and status refresh.
v0.96.0
Nouveauté
Meridian
Ship next-action UI, invoice phase 2, trésorerie, and project margin
Wire opportunity next-action feedback and dashboard roll-up, add payment receipts,
proposal-to-invoice conversion, accounting CSV export, unified cash-flow dashboard,
and project labor margin with cost rates. Archive completed LOGBOOK dossiers and
register the product ledger MCP tool for create_ledger.
v0.96.0
Nouveauté
Meridian
Cloudflare managed-services rail
Link client Cloudflare accounts from Settings and list zones with deep links to the Cloudflare dashboard.
v0.96.0
Nouveauté
Meridian
Add configurable invoice options for InvoiceNinja parity
Expose org-level document settings (tax rates, payment instructions, numbering),
article/service line kinds, client details on PDFs, and tax-exempt handling so
Meridian can replace InvoiceNinja without a visual redesign.
v0.96.0
Nouveauté
Meridian
Project profitability and live hours
Projects now show labor cost, margin, and margin % in the billing drawer, based
on each member's org-scoped cost rate ($/h) set under Organization → Team.
Cost rates are snapshotted onto time entries when logged. Hours used and
remaining on a project are computed live from time entries instead of static
import fields.
v0.96.0
Nouveauté
Meridian
Organization invoice settings: email, payment instructions, defaults, and tax rates
Under Settings → Organisation you can now configure the seller details that
appear on invoices: a public contact email, payment instructions (for example
Interac e-Transfer text), and default invoice terms and notes that apply when a
new invoice leaves those fields blank. Tax rates (TPS/TVQ by default) are
editable as a simple label + percentage list and are snapshotted onto new
invoices as before.
Under Settings → Organisation you can configure how new invoice numbers are
built: prefix, digit padding, whether to include the year, and a starting
number (used when no invoices match the pattern yet — useful when migrating
from InvoiceNinja). Defaults remain INV-YYYY-NNN. Changing these settings
never rewrites existing invoice numbers.
v0.96.0
Nouveauté
Meridian
Article and Service line kinds on invoices
Invoice line items can now be marked as Article or Service. Time &
material generation creates service lines. When an invoice includes both kinds,
the invoice detail view and PDF split them into two sections with quantity/unit
price labels for articles and hours/rate labels for services (same underlying
fields — only the labels change).
v0.96.0
Nouveauté
Meridian
Invoice client details on PDF and tax-exempt clients
Invoice PDFs (and the invoice detail Bill To panel) now show the client's
location plus the primary contact's phone and email when available. Clients
marked Tax exempt on the edit form no longer have tax amounts applied on
invoices — tax labels and rates remain on the document, but amounts stay at
zero and the total equals the subtotal.
v0.95.0
Nouveauté
Meridian
Trésorerie cash-flow dashboard
A new Trésorerie page under Comptabilité unifies accounts receivable and
payable on one screen. KPI cards show cash in, cash out, and net position for
the selected period (month, quarter, or year). AR aging and AP due tables
summarize outstanding invoices and planned expenses; a six-month bar chart
visualizes in/out trends. Export a CSV of period transactions for your
accountant.
v0.92.0
Nouveauté
Meridian
Suggested next steps on deals
Opportunities now show a deterministic suggested next step on the detail page
(with Done / Later / Not relevant feedback), on kanban cards, and in the
dashboard Prochaines actions roll-up. Deferred or dismissed suggestions stay
hidden until the deal state changes.
v0.92.0
Nouveauté
Meridian
Payment receipts, proposal-to-invoice conversion, and accounting CSV export
When a payment is recorded on an invoice, Meridian emails the customer's primary
contact a PDF receipt (when the payment_receipt email type is enabled). You can
also download a receipt from each payment row on the invoice detail page.
Accepted proposals can be converted to a draft invoice with one click
(Convert to invoice in the proposal actions menu). Line items, taxes, and
client linkage are copied automatically; each proposal can only be converted once.
On CRM → Invoices, use the date range and Export (CSV) button to download
accounting data — one row per payment with invoice totals, TPS/TVQ breakdown,
method, and reference.
v0.95.0
Nouveauté
Meridian
Émettre une facture SignalOrange depuis la vente d'un produit satellite
POST /api/meridian/v1/products/:slug/ledger crée (ou réutilise) une
compagnie CRM dans les livres de l'organisation authentifiée, émet une
facture envoyée, puis enregistre le paiement Stripe. Idempotent sur le
PaymentIntent. Estrade s'en sert après le Checkout Illimité : l'acheteur
n'est pas un tenant Meridian.
feature
v0.94.1
Sécurité
Meridian
Re-check AI template, calendar, and agent writes after mount
AI prompt template edits now re-query settings_ai_edit on each write, so a
revoked editor cannot keep saving from a live session. Calendar and agent
detail action menus use the same edit guard as CRM dropdowns.
security
v0.94.1
Correctif
Meridian
Space on a kanban card opens it instead of scrolling the page
Focused opportunity, proposal, project, and invoice cards treat Space as
activate. The browser no longer scrolls the board underneath.
v0.94.1
Correctif
Meridian
Assigning a plan no longer crashes on a missing qualification status
Applying a plan in admin mirrors the platform as a supplier company. That
insert now seeds a default qualification status when the tenant catalog is
empty, instead of hitting a NOT NULL constraint.
v0.94.0
Correctif
Meridian
Guard CRM dropdown handle_info with the edit check
actions_dropdown_event called handle_event/3 as a function, skipping
attach_edit_guard, so a viewer could archive or delete via the menu.
security
v0.94.0
Correctif
Meridian
Preload task on locked T&M entries for invoice descriptions
lock_entries re-fetched rows without associations, so line items dropped
the task name. Preload :task after FOR UPDATE.
v0.94.0
Correctif
Router
Fail closed on billing, org catalog, and embeddings
OpenRouter omitting cost used a fake $0.001/1k rate or billed 0¢;
explicit unknown models were replaced by the org default; embeddings
skipped reservation and hardcoded a model id.
security
v0.94.0
Refactorisation
Meridian
Extract payment helpers and sort aliases for credo
v0.94.0
Sécurité
Meridian
Durcissement de sécurité : paiements, accès et permissions
Les paiements Stripe sont enregistrés une seule fois et réessayés en cas
d'échec. Les pages de paramètres, les clés API et les données d'organisation
sont désormais limitées à vos permissions. Les modèles de prompt, le
funnel public et le Router ne sont plus accessibles sans le droit
correspondant.
v0.94.0
Correctif
Meridian
Deny CRM writes that bypassed the edit-permission hook
handle_info called project status/milestone helpers and Flow 2
generation without going through attach_edit_guard, so a viewer
could still mutate.
security
v0.94.0
Correctif
Meridian
Scope prompt templates and gate settings writes
Prompt templates were loadable by bare id, follow-up/profile forms
cast plan/slug/domain, and Router/Public Funnel settings had no
permission checks — so a member could rewrite another tenant's
prompts or the org's billing identity.
security
Fixes #7
Fixes #8
Fixes #12
v0.94.0
Correctif
Meridian
Stop template skills from advertising send-email
security
Fixes #28
v0.94.0
Correctif
Meridian
Fail disconnect when Graph subscription teardown fails
Void duplicate recurring invoices before the unique period index so
migrate cannot fail on existing rows. Do not mark an M365 account
disconnected while remote webhook subscriptions remain active.
security
v0.94.0
Correctif
Meridian
Fail-loud dashboard, teardown M365, fix follow-up and recurring billing
security
v0.94.0
Correctif
Router
Settle catalog-free models and 422 unknown embeddings
Unknown embed models 500'd via the catch-all. Provider cost 0 on a
catalog-priced-at-zero model was treated as a billing failure.
security
v0.94.0
Correctif
Meridian
Wrap context/memory and fail loud on wizard generation crash
security
v0.94.0
Correctif
Meridian
CSRF logout, stubs, Autre note, timer/T&M races, leftover a11y
Logout, portal logout, and exit-impersonation are POST-only so CSRF applies.
/users redirects to team. Catch-all Autre requires a note and sorts last.
T&M billing locks unbilled rows; start_timer keeps one running timer per user.
v0.94.0
Correctif
Meridian
Require edit permission to generate Flow 2 proposals
View-only users could open the Flow 2 picker and send handle_info
messages that create a proposal without crm_opportunities_edit.
v0.94.0
Correctif
Meridian
Wrap untrusted prompts, fail stubs, drop dead LLM client
security
v0.94.0
Correctif
Meridian
Fail loud on CRM payment webhook errors and persist failures
Stripe ACKing handler errors dropped paid invoices, duplicate
payment_intent deliveries inflated paid_cents, and a failed PaymentIntent
persist still handed the client a secret.
security
Fixes #6
Fixes #17
Fixes #23
v0.94.0
Correctif
Meridian
Tokenize settings pages and kanban card shells
Payments, branding, and public-funnel table/card chrome now use design
tokens. Opportunity, invoice, and project board cards match proposal cards.
v0.94.0
Correctif
Meridian
Reject PaymentIntent reused on a different invoice
Lookup-by-PI-id treated a payment on invoice A as success for invoice B,
so the webhook could ACK Stripe and stamp B without updating paid_cents.
security
Fixes #17
v0.94.0
Correctif
Meridian
Require real org-admin perms and split CRM view from mutate
is_org_admin was any membership, CRM LiveViews mutated on view-only
permission, and backup/proposal/document downloads were auth-only.
security
Fixes #9
Fixes #10
Fixes #11
v0.94.0
Correctif
Meridian
Require knowledge_edit for client-tab and domain KB writes
crm_companies_edit alone could forge save_client_article, and
Knowledge.create/update/delete authorized any org member.
security
Fixes #46
v0.94.0
Correctif
Meridian
Send reminders, fix tokens, kanban a11y, and CRM nav
Billing audit "Send Reminder" now calls CRM.send_invoice/1. Invalid
--surface-default tokens are gone. Kanban cards are keyboard-activatable.
Proposal templates use modal_wrapper. /crm redirects to opportunities
and admin backups is a settings-nav page.
v0.94.0
Correctif
Meridian
Revoke MCP tokens on offboard and isolate keys/metrics/KB
Offboarded users kept OAuth access, the Router keys API listed meridian
key ids, MCP could mint keys, any org key scraped Prometheus, and the
knowledge base treated any role as editor.
Close anti-slop findings and wire Elixir-safe lint gates
Port only the anti-slop rules that match Phoenix/OTP (atom-table safety,
named specs, no Mimic/meck). Drop TS ports that fight Ecto map() attrs,
is_* guards, and Kernel.apply/3. Stop converting request strings to atoms,
tighten two Dialyzer specs, and decode JS values without typeof.
v0.94.0
Sécurité
Meridian
Stripe invoice payments are recorded once and retried on failure
Online invoice payments are no longer acknowledged as successful when
recording the payment in the CRM fails, so Stripe retries instead of
leaving a charged customer with an unpaid invoice. The same Stripe
PaymentIntent can no longer be recorded twice against an invoice.
v0.94.0
Sécurité
Meridian
Settings pages and prompt templates are scoped to your permissions
Prompt templates can no longer be opened or changed using another
organization's id. Follow-up and legal-profile forms ignore extra fields
such as plan, slug, and custom domain. Router settings and the public
funnel now require the matching settings permission.
v0.93.0
Correctif
Meridian
Rename orphaned account_id indexes, adopt existing mirror company
The accounts->organizations rename renamed the account_id columns, but
Postgres keeps index names on column rename. The follow-up cleanup
migration only fixed the three tables that were themselves renamed, so
~40 indexes on the other tables are still named "
account_id*".
Ecto matches constraint errors by name, so every
unique_constraint([:organization_id, ...]) has been silently dead —
duplicates raise Ecto.ConstraintError instead of becoming changeset
errors. This crashed OrganizationsLive on save when BillingLink tried to
insert a platform-org mirror company whose name already existed.
Also adopt a same-named unlinked client as the mirror instead of
colliding on the name, so the billing mirror is actually created.
Not run against a database yet (no local Postgres available).
Les trois listes du haut de votre catalogue — Types de produits, Services
et Besoins (contact) — peuvent désormais porter un libellé en français et
en anglais. L'affichage suit automatiquement la langue de la personne qui
consulte la page : formulaire de contact public, sélecteur de services dans une
opportunité, badges sur les fiches client et opportunité, et propositions
générées — sans jamais mélanger les deux langues sur un même écran.
Dans Paramètres → Listes & libellés, chaque entrée de ces trois listes
propose maintenant des champs « Nom (FR) » et « Nom (EN) » côte à côte, avec une
clé stable générée automatiquement. Un seul des deux noms suffit : si l'autre
langue n'est pas encore traduite, l'affichage retombe sur la langue disponible.
Sous le capot, chaque entrée reçoit une clé stable : renommer un libellé (dans
une langue ou l'autre) ne casse plus les opportunités, clients et blocs de
service qui y font référence. Les données existantes ont été migrées
automatiquement.
Changement d'API (rupture) — l'endpoint GET /api/me renvoie désormais les
catalogues services et product_types sous forme d'objets
{key, name_fr, name_en} au lieu de simples chaînes de caractères. Les
intégrations qui lisaient ces champs comme des chaînes doivent être adaptées.
v0.91.0
Correctif
Meridian
Catégorie par défaut des services hors catalogue
Un service ajouté « à la volée » (hors catalogue) depuis la modale d'opportunité
recevait la mauvaise catégorie par défaut : le code cherchait uniquement le
libellé anglais « Other », absent des catalogues francisés (« Autre »), et
retombait sur la première catégorie du catalogue (ex. « Validation CSV »)
plutôt que sur la catégorie fourre-tout. La catégorie « Autre »/« Other »
(insensible à la casse) est maintenant reconnue en priorité, avec repli sur la
dernière catégorie du catalogue si aucune n'est trouvée.
v0.91.0
Amélioration
Meridian
Envoi manuel des courriels de suivi d'opportunité
Les courriels de confirmation de réservation, de relance et de rappel de
rendez-vous peuvent maintenant être envoyés manuellement depuis la fiche
d'une opportunité, en plus de leur envoi automatique existant. Un bouton
« Envoyer » par type ouvre un aperçu éditable (destinataire, sujet, corps)
avant l'envoi. Le rappel n'apparaît que lorsqu'un rendez-vous est associé à
l'opportunité.
v0.91.0
Amélioration
Meridian
Catalogue de services unifié
Les catalogues « Catégories » et « Intérêts de service » sont fusionnés en un
seul catalogue « Services », partagé entre l'offre et la demande. Le formulaire
de contact public capte désormais les services souhaités par le prospect, et la
plateforme suggère automatiquement les blocs de service correspondants dans les
propositions — l'offre rencontre enfin la demande sur cet axe, comme c'était
déjà le cas pour les types de produits. La page Listes & Libellés est réordonnée
en trois groupes (offre → clients → pipeline) avec une courte introduction pour
guider l'ordre de configuration.
v0.91.0
Nouveauté
Meridian
FAQ publique en libre-service
Votre base de connaissances alimente désormais une page FAQ publique
(/faq/votre-slug). Cochez « Afficher dans la FAQ publique » sur un article de
portée Organisation pour le publier, classez-le par catégorie et fixez son ordre —
le contenu reste modifiable à un seul endroit, dans Connaissances.
Les articles rattachés à un client précis ne sont jamais exposés publiquement :
la page ne montre que les articles de portée Organisation, approuvés et marqués
publics.
v0.91.0
Amélioration
Meridian
Modèles par défaut pour les courriels de proposition et de facture
Vous pouvez maintenant pré-rédiger votre propre sujet et corps bilingues pour
les courriels de proposition envoyée et de facture, directement dans Réglages
(paramètres de l'entonnoir). L'éditeur est amorcé avec le modèle par défaut
actuel, bouton d'action et lien du portail client inclus. À l'envoi, l'éditeur
de prévisualisation est pré-rempli avec ce contenu — laissez le champ vide
pour conserver le modèle système par défaut.
v0.91.0
Nouveauté
Meridian
Récap pré-meeting à l'équipe
Avant une rencontre, le courriel de rappel envoyé à l'équipe inclut maintenant
un récapitulatif (client, besoin, opportunité, réponses de découverte);
rédigé par l'IA quand disponible, avec un repli structuré sinon — l'envoi
n'échoue jamais.
v0.91.0
Nouveauté
Meridian
Quantité par service dans les opportunités
Chaque service sélectionné dans une opportunité peut désormais recevoir une
quantité (1 par défaut). Elle multiplie le prix affiché dans le modal
d'opportunité et se propage automatiquement à la proposition générée — les
opportunités existantes restent inchangées puisque la quantité par défaut
demeure 1.
v0.91.0
Nouveauté
Meridian
Découverte dynamique
Le questionnaire de découverte s'adapte désormais au besoin et au service choisis
par le prospect : seules les questions pertinentes s'affichent, au lieu du même
jeu de questions pour tout le monde.
Un éditeur de questions de découverte est ajouté dans Paramètres → Site public,
onglet Découverte, pour créer, modifier et réordonner les questions (EN + FR,
obligatoire ou non, applicabilité par besoin et par service). Le courriel
d'invitation à la découverte porte lui aussi le bon jeu de questions.
v0.91.0
Correctif
Meridian
Supprimer un client depuis sa fiche
L'action « Supprimer » est maintenant accessible depuis le menu d'actions de la
fiche client (avec confirmation). La fiche se referme automatiquement une fois
le client supprimé.
v0.91.0
Amélioration
Meridian
Formulaire de contact : le besoin en tête
Sur le formulaire de contact public, le besoin (« De quoi avez-vous besoin? »)
passe désormais en tête du formulaire et se sélectionne en cartes multi-choix,
au lieu d'une liste déroulante à choix unique. Les trois axes du formulaire —
besoin, types de produit, services — s'affichent maintenant sous forme de
cartes cohérentes.
Choisir « Autre » dans le besoin ou les services demande une courte précision
en texte libre, conservée avec la demande. Un lien vers la foire aux questions
publique est ajouté pour répondre aux questions courantes avant l'envoi.
v0.91.0
Nouveauté
Meridian
Historique des communications client
La fiche client et la fiche d'opportunité affichent désormais un véritable
historique des communications : en plus des activités manuelles, chaque
courriel envoyé apparaît maintenant dans le journal, avec son statut
(« envoyé » ou « lu » lorsque l'ouverture a été détectée).
Les envois automatiques (relances, rappels, notifications) et manuels sont
consolidés dans un seul journal d'envois — l'ancien registre distinct propre
aux opportunités a été retiré, sans perte de traçabilité.
Le suivi des ouvertures se fait par pixel invisible inséré dans les courriels
HTML sortants. Comme il s'agit d'une technologie de suivi, chaque organisation
peut l'activer ou la désactiver depuis Paramètres → Public, onglet
Courriels — la bascule est désactivée d'un simple interrupteur et
s'applique à tous les envois futurs de l'organisation. Le suivi des
ouvertures reste un signal indicatif : certains clients de messagerie
préchargent les images ou les bloquent, ce qui peut sur- ou sous-évaluer le
nombre d'ouvertures réelles.
v0.91.0
Nouveauté
Meridian
Libellés de service bilingues
Chaque service du catalogue peut désormais porter un nom et une description en
anglais et en français. L'affichage suit automatiquement la langue de la
personne qui consulte la page — sélecteur de service dans une opportunité,
propositions générées et section Paramètres — sans jamais mélanger les deux
langues sur un même écran.
Le formulaire de gestion des services (Paramètres → Services) propose désormais
des champs distincts « Nom (EN) » / « Nom (FR) » et « Description (EN) » /
« Description (FR) ». Un seul des deux noms suffit pour enregistrer un service :
si l'autre langue n'est pas encore traduite, l'affichage retombe sur la langue
disponible.
v0.91.0
Nouveauté
Meridian
Fournisseurs (suppliers) and expense tracking
A new Fournisseurs section under Comptabilité lets any organization track the
companies it buys from. Suppliers reuse the full company record (contacts,
documents, notes), and each supplier page carries a Dépenses panel to record
one-off or scheduled expenses, mark them paid, and see planned / overdue / paid
totals at a glance.
Recurring expenses are supported as templates (monthly or yearly): a daily
worker expands each due template into a concrete expense occurrence, so planned
costs show up on their own schedule. Templates are listed separately from
occurrences so paying or deleting one never disturbs the schedule by accident.
The platform↔tenant billing link is now bidirectional. When the SignalOrange
platform bills a tenant for its subscription, the platform automatically appears
as a supplier in that tenant's own books, and each recurring subscription
invoice is mirrored as an expense — so every org sees what it owes us the same
way we see what they owe us.
v0.91.0
Nouveauté
Meridian
Share documents through the client portal
Vendors can now mark a document as "Shared with client" from a company or
proposal's documents list. Shared documents appear to the client in both the
magic-link portal hub and the in-app Received page, each with a download link.
Documents are private by default — only those explicitly shared are exposed.
The Received page now also respects the vendor's client-portal entitlement: if
a vendor no longer has the client portal module, their proposals, invoices, and
documents stop appearing for their clients, matching the magic-link portal.
v0.91.0
Nouveauté
Meridian
Proposals now capture an e-signature trail
Accepting a proposal is now a short signing step: the client types their full
name, confirms their email, and agrees to the terms. Meridian records who
signed, when, from which IP and device, and a fingerprint of the exact document
they agreed to — and stores a signed PDF with a signature certificate. The full
trail shows on the proposal's detail page, with a link to download the signed
PDF.
v0.91.0
Nouveauté
Meridian
Plans, entitlements, and subscription billing
Organizations now run on a plan that defines their entitlements and is billed
on a recurring cycle. Admins can view their plan, usage, and switch plans from
Settings → Plan.
v0.91.0
Nouveauté
Meridian
Configurable lead scoring
Lead scoring is now configurable per organization. A new Paramètres → Scoring
des leads page lets admins tune the point weights, target lists (aligned
products, clear needs, high-value industries, personal email domains) and the
hot/warm thresholds, with a live preview that re-scores a sample lead as you
type. Unconfigured organizations keep the previous built-in defaults.
v0.91.0
Nouveauté
Meridian
Automatic payment reminders and late interest on overdue invoices
Meridian now chases overdue invoices for you. Turn on automatic reminders
(relances) under Settings → Organisation → Reminders & late fees and set
the cadence — by default a reminder goes out 7, 14, and 30 days after the due
date — and Meridian emails the customer's primary contact on schedule. Each
reminder is sent once per stage, and you can opt any single invoice out with the
new "Skip automatic payment reminders" checkbox on the invoice.
You can also charge late interest: set an annual rate and an optional grace
period, and overdue reminders show the accrued interest and the running total
the customer owes.
v0.91.0
Nouveauté
Meridian
Client portal
Clients can now sign in to one place to review and sign proposals, view and pay
invoices, and track projects. Organizations that are themselves clients see what
their vendors sent them right inside the app under "Received".
v0.89.0
Correctif
Meridian
Pin ciphertext_len in decrypt bitstring match
v0.89.0
Correctif
Meridian
User_permissions must join through user_roles (was leaking all org perms)
v0.89.0
Correctif
Meridian
Render 'Prepared by' attribution from opportunity owner
get_prepared_by/1 was a stub returning nil, so the public proposal page never
showed the preparer. Resolve it from opportunity.owner_user (full_name, else
email), preloading owner_user on all four proposal load paths.
v0.89.0
Refactorisation
Meridian
Temporarily removed the client qualification section
The BANT qualification panel has been removed from the client drawer while we
re-design it. No data was lost — existing qualification information is preserved
and will return with the new version.
v0.89.0
Correctif
Meridian
Public pages now follow the visitor's language
Contact, booking and proposal pages now detect English visitors automatically
and offer a language switcher, instead of always showing French.
v0.89.0
Nouveauté
Meridian
Interactive status stepper on proposal detail
Proposal detail now shows Avancer/Reculer buttons next to the status stepper,
letting users with the crm_proposals_edit permission advance or regress a
proposal through its status path in one click. When advancing a proposal that
requires approval, the existing approval flow is triggered automatically.
v0.89.0
Amélioration
Meridian
Wider opportunity modal with per-line pricing and a live total
Creating an opportunity is roomier and clearer: pick multiple services, adjust
each line's price/hours, and see the total update live.
v0.89.0
Nouveauté
Meridian
Edit last contact on opportunities, pick next actions, and sort by last contact
Opportunities now have an editable "Last contact" just like clients, the client
"Next action" is a dropdown you can extend with your own actions, and both the
clients and opportunities tables can sort by last-contact date.
v0.89.0
Correctif
Meridian
Show dates and times in your organization's timezone
Dates and times across the app were rendered straight from their stored UTC
value, so an action taken in the evening (for example 8:30 PM in
America/Montreal, which is past midnight UTC) could display tomorrow's date.
Every display surface now shifts timestamps into the organization's timezone
before formatting — invoices, billing, the team roster, backups, agent traces,
admin screens, proposal and invoice PDFs, and the CRM detail panels. Date-only
fields that are backed by a real date (due dates, issue dates) are unchanged;
only stored timestamps that carry a time are shifted. A shared, tested helper
now drives all of this, so new screens get correct local display by default.
v0.89.0
Nouveauté
Meridian
Render dates/times in the org timezone app-wide
Routes every stored-UTC timestamp through the org-timezone display helpers
(Localization.shift_to_zone/2 + LiveHelpers.format_in_tz/3) so users see their
own wall clock instead of UTC. Previously ~30 format_date/format_datetime
helpers formatted straight off the UTC value, so an evening action could show
tomorrow's date (the cross-midnight bug).
v0.89.0
Correctif
Meridian
Close 3 minor gaps from the org-tz display review
agent_detail_live: render the chat conversation-list date in the org
timezone (was raw UTC via Calendar.strftime, drifted near midnight)
format_in_tz: promote a %Date{} to midnight in the org tz before
strftime so a date paired with a time-bearing format no longer raises
KeyError :hour; the date is preserved (DST-gap/invalid-tz → UTC midnight)
proposals/timezone_display_test: add a routed assertion that the detail
page renders the Sent timestamp in org wall clock, not UTC (was only
helper-isolation coverage)
v0.89.0
Nouveauté
Meridian
Add shared org-tz display primitives
Foundation for the app-wide UTC-display sweep. Adds
Localization.shift_to_zone/2 (the core tz-shift primitive: NaiveDateTime
assumed UTC, Date/nil pass through, invalid-tz falls back to the raw value)
and LiveHelpers.format_in_tz/3 (strftime display delegating to it).
saved_at_label/2 now reuses the primitive instead of duplicating the shift.
v0.89.0
Correctif
Meridian
Use design tokens for legible entries + render upload date in org timezone
The documents drawer rendered each entry with hardcoded zinc colors
(text-zinc-500 on bg-zinc-800/50 = grey-on-grey, illegible) and formatted
the UTC inserted_at with raw Calendar.strftime, so an evening upload showed
tomorrow's date. Entries now use --surface-overlay / --text-primary /
--text-secondary tokens, and a timezone attr threads the org timezone through
the clients/opportunities/proposals detail trees so the date shifts to the
org's wall clock.
v0.89.0
Nouveauté
Meridian
Claude MCP connector card + connected-sessions revoke
Adds a "Claude (web · Desktop · Cowork)" card to the Integrations settings
page surfacing the MCP connector URL with copy-to-clipboard, setup
instructions, and a connected-sessions table with per-session revoke.
Reuses the existing phx:copy event pattern (readonly input + dispatch).
v0.89.0
Correctif
Meridian
Verify linkable ownership in upload_url; handle link_document failure without orphaning
v0.89.0
Correctif
Meridian
Build MCP upload/download URLs from Endpoint.url() not conn.host; guide large files to web UI
The pre-signed upload/download URLs were built from conn.host, which behind
Cloudflare can be an internal host unreachable by a remote MCP client. Use the
configured public endpoint URL instead. Also reword the base64 over-cap message
and the create/upload_url tool descriptions: sandboxed clients (Cowork) cannot
PUT to the pre-signed URL, so large files should be uploaded via the Meridian web
UI; the handshake is only for clients with outbound network (e.g. Claude Desktop).
v0.89.0
Correctif
Meridian
Declare RS256 so Microsoft's alg-less JWKS keys parse
Microsoft's JWKS keys omit the per-key "alg" field. JokenJwks'
get_algorithm(nil, nil) returns {:error, :no_algorithm_supplied}, and
validate_and_parse_keys HALTS the entire key set on that error — so zero
signers were ever cached and every id_token validation failed with
{:id_token_invalid, :no_signers_fetched}. The boot log confirmed it:
"Failed to fetch signers. Reason: {:error, :no_algorithm_supplied}".
The prior first_fetch_sync change was necessary but not sufficient: it
made the (failing) fetch run at boot instead of an hour later, which is
exactly what surfaced this real root cause.
Set explicit_alg: "RS256" (Microsoft v2 id_tokens are RS256-signed) so
the keys parse and signers populate. Verified against Microsoft's live
JWKS endpoint: the boot-time "Failed to fetch signers" error is gone.
v0.89.0
Correctif
Meridian
Fetch JWKS signers synchronously on boot
JokenJwks' DefaultStrategyTemplate schedules its first signer fetch one
full time_interval (1h here) after boot and does no eager fetch unless
first_fetch_sync is set. The signer cache was therefore empty for the
first hour after every deploy, so every id_token validation failed with
{:id_token_invalid, :no_signers_fetched} and Microsoft 365 login was
broken until the first refresh fired.
Add first_fetch_sync: true so keys are fetched at startup. The strategy
is already supervised before the Endpoint, so keys are ready before the
first /auth/microsoft/callback is served.
Claude can read and attach documents to your CRM records
Through the Meridian connector, Claude can now list and read the documents
attached to your opportunities, proposals, and companies (quick text reading, or
the original file when fidelity matters), and upload new documents and attach them
to a record. Small files are sent inline; larger files use a secure, time-limited
upload link.
Access is governed by two new permissions, View documents and Upload
documents, which you can assign per role under Settings → Team.
v0.89.0
Amélioration
Meridian
Manage your Claude connector from Settings → Integrations
Settings → Integrations now shows the Claude connector URL with copy-and-paste
setup instructions for Claude.ai, Claude Desktop, and Cowork, plus a list of your
connected Claude sessions. You can disconnect any session at any time.
v0.89.0
Nouveauté
Meridian
Connect Claude (web, Desktop, Cowork) via a single remote MCP connector
Meridian now exposes a remote MCP endpoint that Claude.ai, Claude Desktop, and
Claude Cowork connect to as a custom connector. You add it once with the connector
URL and sign in with your Meridian account (OAuth), then ask Claude to work with
your opportunities, proposals, clients, and more.
This replaces the previous downloadable Claude Desktop extension (.mcpb): there is
nothing to install, and the same connector works across the web, desktop, and Cowork.
v0.89.0
Nouveauté
Meridian
Dynamic client registration in context
Implements Meridian.OAuth context with register_client/1, get_client/1,
and verify_client_secret/2. Also fixes Client changeset to correctly
reject empty redirect_uris (validate_length on array field validates
string lengths, not array count; replaced with get_field-based guard).
v0.89.0
Refactorisation
Meridian
Remove Claude Desktop .mcpb section from integrations LiveView
v0.89.0
Nouveauté
Meridian
Signed capability-URL upload/download transfer routes
Adds Meridian.Documents.Transfer (Phoenix.Token sign/verify for upload and
download grants, staging-dir helpers) and MeridianWeb.DocumentTransferController
(PUT /api/meridian/uploads/:token, GET /api/meridian/downloads/:token) on a
public :api pipeline — the signed token is the sole authorization.
Body-size cap: application/octet-stream PUTs bypass the global 4 MB
Plug.Parsers limit because that parser only covers :urlencoded/:multipart/:json;
octet-stream is passed through unread and the controller reads it directly with
a 50 MB cap via Plug.Conn.read_body/2. Confirmed by a 5 MB upload integration
test that asserts 200 and correct staged file size.
Adds issue_tokens/3, validate_access_token/1, refresh/2, list_connections/1,
and revoke_connection/2 to the OAuth context; all covered by 4 new TDD tests.
v0.89.0
Nouveauté
Meridian
JSON-RPC endpoint POST /api/meridian/mcp via :mcp_auth (initialize, tools/list, tools/call, ping)
v0.89.0
Correctif
Meridian
Bound upload memory to ~cap+chunk, real 413 integration test, configurable cap, nonce guard, ttl test
v0.89.0
Nouveauté
Meridian
Authorization code create/consume with PKCE
v0.89.0
Refactorisation
Meridian
Remove dead /api/meridian/v1/mcp/tools discovery endpoint
Controller, test, route, and both @tool_specs/@permissions map entries
removed; catalog boot-validation still passes clean.
Adversarial review of the last 2-3 days of features (optimistic locking,
CRM.Sales split, invoice payments, a11y/UX hardening, LiveView test coverage).
Fixes all confirmed findings; each has a regression test that fails before the fix.
Security (pre-existing escalation, surfaced by the review):
TeamLive (/organization/team) gated mount + all mutations on
can_administer_organization? (MEMBERSHIP only), so any org member could manage
users/roles and grant themselves admin. Add LiveHelpers.authorize_permission/2
and require admin_users_view|admin_roles_view on mount, all 7 mutation
re-checks, and the previously-ungated set_default_approver.
Correctness (MAJOR):
Optimistic-lock stale-entry branches (clients/opportunities/proposals/invoices
_live) flashed "Reloading…" but never closed the edit modal, trapping the user
in an infinite re-conflict loop on the stale struct. Close the modal in each
{:error, :stale_entry} branch (mirror the success branch).
Proposal double-submit guard sat on the preview-prep step, not the terminal
send. Guard confirm_send_email/skip_email so a double-click emails the client
once (first send nils :email_action_proposal; re-entrant message dropped).
Branding autosave silently dropped the rich-editor public_description while the
"Saved at" indicator claimed success. Extract put_editor_description/2 and apply
it on both the explicit-save and autosave paths.
v0.89.0
Nouveauté
Meridian
Authorization_codes schema + migration
v0.89.0
Nouveauté
Meridian
Dispatcher invokes REST action with permission gate
Implements Meridian.Mcp.Dispatcher which executes MCP tools/call by
invoking the matching REST controller action directly via Plug.Test
capturing conn, enforcing required_permission via user_has_permission?.
v0.89.0
Nouveauté
Meridian
Authorize consent screen (PKCE, org binding, no open redirect)
GET /oauth/authorize renders a consent page for authenticated users,
redirecting unauthenticated users to /login with :user_return_to stored.
POST /oauth/authorize issues an auth code bound to current_user +
current_organization; rejects unregistered redirect_uris (no open
redirect) and enforces PKCE S256 presence. EN + FR gettext added.
v0.89.0
Nouveauté
Meridian
MCP access-token auth plug + :mcp_auth pipeline
v0.89.0
Correctif
Meridian
Rate-limit DCR, validate redirect_uri scheme, strengthen metadata test
Drop desktop-key context functions + partial unique index
Remove @desktop_key_name, get_desktop_key/2, generate_desktop_key/2,
revoke_desktop_key/2, and the private maybe_deactivate_desktop_key/2
helper from Organizations context (all callers removed in prior tasks).
Drop the api_keys_user_org_desktop_unique partial index via reversible
migration; remove the corresponding describe block from organizations_test.
Remove priv/skill/meridian-desktop/, lib/meridian/mcp/desktop_bundle.ex, the
:desktop build clause in mix meridian.skill.build, and the :desktop path in
SkillBundleController. The :code bundle build, serve, and tests are fully intact.
Remaining integrations_live.ex desktop-key UI/assigns are left for Tasks 6/7.
v0.89.0
Correctif
Meridian
Nil-safe token grants (400 not 500), www-authenticate, bundle scope; cover grant edge cases
v0.89.0
Correctif
Meridian
Atomic revoke, drop expired from list_connections, honest issue_tokens contract; cover rejection branches + index
v0.89.0
Correctif
Meridian
Audit OAuth requests (nullable api_key_id), strip _dispatch from tools/list, echo id on -32600, pin protocolVersion; forbidden test
v0.89.0
Correctif
Meridian
Consume user_return_to after login, catch-all authorize clause, cover PKCE/deny/auth-bypass/binding
v0.89.0
Nouveauté
Meridian
Well-known metadata + DCR registration endpoints
v0.88.0
Correctif
Meridian
Fix online invoice payment form not loading
The public invoice payment page (/pay/:token) never initialized the Stripe
payment form because the payment-intent creation code path was unreachable, so
customers could not pay invoices online. The page now initializes the payment
intent when the invoice is payable. A fully-paid (zero-balance) invoice is now
shown as already paid instead of attempting a Stripe payment for $0.
A round of quality-of-life improvements across the app:
No more accidental double-sends. Sending or resending a proposal can no
longer fire twice from an impatient double-click, so clients won't receive
duplicate emails. Many other create/update buttons now disable themselves while
saving.
Concurrent-edit protection. If two people edit the same opportunity,
invoice, client, or proposal at once, the second save is now caught: you're told
the record changed and it reloads with the latest data instead of silently
overwriting the other person's work.
Auto-save on settings. The organization profile and branding settings pages
now save automatically as you type, with a "Saved at HH:MM" indicator, and warn
you if you try to leave a page with unsaved changes.
Accessibility. Form errors are now announced to screen readers, every dialog
traps keyboard focus and closes on Escape, and a "Skip to content" link lets
keyboard users jump past the navigation.
Consistent notifications. All in-app messages now use a single,
auto-dismissing toast style.
v0.88.0
Correctif
Meridian
More reliable AI billing and a safer organization admin form
Per-organization AI, email, and billing configuration now live in dedicated tables
behind the scenes, reducing write contention on busy billing counters. As part of
the change, a bug that could interrupt billing on prepaid AI calls has been fixed,
and the admin organization form now saves all of its sections together: if one
field is invalid, nothing is saved and the values you entered are kept on screen
with the error highlighted, instead of silently saving part of the form.
v0.86.0
Nouveauté
Meridian
Version 0.86.0
🚀 Nouveautés
Cut over schema, context, migration, and all callers to satellites
Add BillingSettings satellite schema
Add EmailConfig satellite schema
Add AiSettings satellite schema
Enforce OpenAPI validation on OpenAI-compat + Router admin surfaces
Enforce OpenAPI validation on Meridian CRM surface
Add OpenAPI operation spec to mcp/tools endpoint
OpenAI-compat 422 renderer for OpenAPI validation
Structured 422 renderer for OpenAPI validation
Split tax into snapshotted TPS/TVQ tax_lines (schema, compute, PDF)
Cost-by-module breakdown on AI overview
Graceful degradation flashes + 503 for open circuits
Org_usage_by_use_case analytics query
Expose external-service breaker state in health check
Contact & legal section on org settings page
Report exhausted Oban jobs to ErrorTracker
Render org legal_name + legal/contact footer on invoice and proposal
Per-tenant SMTP circuit breaker with worker snooze
Align StructuredValidationError with house plug style
Drop unused profile_form assign (added later with the form)
Avoid spurious breaker rows on success; clarify open_keys docs
Use DateTime.add for usec coercion (clearer than map-update)
v0.88.0
Amélioration
Meridian
API requests validated against their OpenAPI specs
Incoming requests to the public APIs are now validated against the published OpenAPI
specs before they reach a controller. Malformed requests — missing required fields, wrong
types, out-of-range values — are rejected up front with a clear error. The OpenAI-compatible
endpoints (/api/v1/*) return a 400 in the OpenAI error envelope, and the Meridian and
Router-admin endpoints return a 422 describing each offending field. Extra fields that
OpenAI SDKs send (such as top_p or n) continue to be accepted.
v0.88.0
Amélioration
Meridian
More resilient external services
Meridian now fails fast and degrades gracefully when an external provider (AI, payments,
or email) is temporarily unavailable, instead of hanging or retrying indefinitely. Email
delivery problems are now isolated per organization.
v0.88.0
Correctif
Meridian
Scheduled backups now run reliably
Fixed a precision mismatch that caused the scheduled-backup worker to crash when a backup became due, which prevented automatic backups from running. Scheduled backups now execute and advance to their next run time as expected.
v0.88.0
Correctif
Meridian
No more reminder events for paid invoices
Fixed a filter that failed to exclude paid invoices when scheduling upcoming-due reminders, so paid invoices no longer generate spurious anticipatory reminder events.
v0.85.0
Amélioration
Meridian
Documentation produit revue, corrigée et illustrée
Les pages de documentation publiques (/docs) ont été entièrement revues par
rapport au produit réel :
Navigation et chemins Paramètres → … corrigés pour correspondre à
l'application.
Fonctionnalités décrites mais non encore disponibles retirées des pages et
consignées au backlog (avec des notes « À venir »).
Captures d'écran ajoutées : tableau de bord, pipeline, image de marque,
intégrations et suivi du temps.
v0.85.0
Nouveauté
Meridian
Multi-account and multi-calendar Microsoft 365 sync
Connect more than one Microsoft 365 account and choose exactly which calendars
sync into Meridian. Your calendar now shows events from every connected account
and every opted-in calendar in one place, with the same meeting appearing once
even when it lives on several calendars.
Connect multiple Microsoft 365 mailboxes; each one picks its own account at sign-in.
Turn individual calendars on or off for sync in Settings -> Integrations -> Microsoft.
Create, update, and delete events on a specific calendar (editable calendars only).
v0.84.0
Nouveauté
Meridian
Version 0.84.0
🚀 Nouveautés
Calendar opt-in toggles in settings
Unified cross-account calendar view
Unified cross-account event query with ical dedup
Calendar-targeted write-back + default-calendar stamping for legacy writers
Initial sync discovers calendars and syncs opted-in ones
Per-calendar subscriptions, webhook routing, and opt-in wiring
Per-calendar sync worker
Per-calendar CalendarSync with isolated failures
List calendars and toggle sync opt-in
Discover mailbox calendars from Graph
Force account picker so users can add multiple accounts
Graph retries on 429 with Retry-After and on 5xx with backoff
Graph auto-refreshes account token on 401
Add Graph client with GET happy path and structured errors
Add Auth.validate_id_token
Add Auth.exchange_code and Auth.refresh
Add Auth.authorize_url and PKCE helpers
Add JWKS strategy for id_token validation
Add CalendarEvent, Message, and DeltaLink schemas
Add Subscription schema
Add Account schema with encrypted tokens
Replace Outlook tables with microsoft_* schema
Phase 0 setup — deps, queue, runtime config
🐛 Correctifs
Address validation review findings
Add @type t to schemas for context @spec references
Use bigint PKs on microsoft_* tables for codebase consistency
♻️ Refactorisations
Demolish Outlook integration and rewire CRM to Microsoft.*
v0.82.0
Nouveauté
Meridian
Observabilité de production — dashboard, Prometheus/Grafana, ErrorTracker
Visibilité complète sur les erreurs, latences et régressions par
version d'application. Page admin unifiée pour les admins
d'organisation, infrastructure Prometheus/Grafana optionnelle pour
le monitoring système.
Nouveautés
Page d'admin /admin/observability — KPIs (erreurs, P95
latence HTTP, échecs Oban, échecs métier), graphiques temporels
Chart.js avec marqueurs de version, tables des erreurs et
endpoints les plus lents, drill-down par catégorie avec export
CSV. Org admins voient leur organisation, super admins voient
tout.
ErrorTracker à /admin/errors — capture et navigation des
exceptions non-gérées (Phoenix, Oban, LiveView), stack traces
groupés par signature, super admin uniquement.
Pipeline de collecte — Collector attaché à 10 événements
télémétrie (Phoenix, Ecto, Oban, proposals Typst, skills agents,
SMTP, AI), buffer ETS avec flush 10s vers Postgres, rollups
horaires/journaliers, purge automatique (7j brut, 90j horaire,
daily indéfini).
Endpoint Prometheus /metrics — protégé par les clés API
Meridian existantes, pipeline allégé sans audit/idempotency.
Grafana avec 4 dashboards pré-provisionnés (system overview,
HTTP performance, Oban jobs, AI/business ops). Ports bindés sur
127.0.0.1, secrets gérés via env vars et fichiers gitignored.
Logs structurés JSON en production — formatter LoggerJSON,
correlation IDs ajoutés à la metadata (request_id, org_id,
user_id) via un plug appliqué aux pipelines :browser et
:api.
Health check étendu — /health (liveness) et /ready
(readiness) vérifient maintenant DB, Oban et PubSub.
Fix ClientEnrichment test data shape + bump version to 0.81.0
Update Stripe test assertions to match atom params + add ex_unit to PLT
Resolve all 748 Dialyzer warnings — clean exit 0
Select semantic_type separately in ClientEnrichment proposal query
Remove stale this.panel reference in SidebarHook._sync()
♻️ Refactorisations
Fix remaining CyclomaticComplexity issues in lib/meridian_web/
Fix Credo nesting, arity, and some complexity issues in lib/meridian_web/ (partial)
Fix Credo nesting, complexity, and arity issues in lib/meridian/
v0.80.0
Amélioration
Meridian
Mise à jour des dépendances Rust — Typst 0.14.2, Rustler 0.38
Le compilateur de propositions PDF (NIF Rust) passe à Typst 0.14.2 et
Rustler 0.38. Les PDFs générés incluent maintenant le balisage
d'accessibilité (tagged PDF) par défaut.
Changements
Typst 0.13.1 → 0.14.2 — corrections de bugs, améliorations du
rendu PDF, support des PDFs tagués pour l'accessibilité
Rustler 0.37 → 0.38 — support OTP-29, atomes UTF-8
Suppression des dépendances explicites comemo et ecow (résolues
transitivement par Typst)
v0.79.0
Nouveauté
Meridian
Version 0.79.0
🚀 Nouveautés
Expose org catalogs and custom statuses on /me
Regroup org catalog sidebar items under Catalogues sub-header
Split Activity.type into system_event + org-catalog activity_type
icon.png: replace 1-bit monochrome placeholder with branded 256x256
orange (#FF6B35) icon with white "M"
McpToolsController: read version via Application.spec(:meridian, :vsn)
at runtime instead of baking Mix.Project.config()[:version] at compile
IntegrationsLive:
distinguish "generated" vs "regenerated" flash messages
add data-confirm on Regenerate (silently invalidating an installed
Desktop key was easy to do accidentally)
align date format with the rest of the page (%b %d, %Y)
extract do_generate_desktop_key/2 helper (deduplicated, contiguous
handle_event/3 clauses for warnings-as-errors)
Organizations.generate_desktop_key/2: replace pattern-match-or-raise
in the deactivation step with a clean with/rollback chain
server/index.ts: replace hardcoded version "0.0.0" with PACKAGE_VERSION
constant, substituted at build by the Mix task
McpToolsControllerTest: assert a second permission-gated tool is also
filtered for a regular user (update_client / crm_companies_edit)
v0.78.0
Nouveauté
Meridian
Formulaire de contact intégrable sur votre site web
Le formulaire de contact public peut maintenant être intégré directement
dans une page de votre site web existant, sans remplacer celle-ci.
Le visiteur reste sur votre site, votre entête, votre navigation et votre
pied de page sont conservés ; seul le formulaire vit dans un <iframe>
qui s'ajuste automatiquement en hauteur.
Comment l'utiliser
Dans Réglages → Site public → Formulaire contact, copiez le snippet
de la nouvelle carte « Intégrer à votre site web » et collez-le dans
le HTML de votre page :
Vous pouvez basculer la langue par défaut (FR/EN) dans la carte avant de
copier. Les soumissions arrivent dans le CRM exactement comme celles du
formulaire hébergé — même création d'opportunité, même notification de
nouveau lead.
Sécurité : CSP frame-ancestors * scopé au préfixe /embed/*
uniquement ; tout le reste de Meridian garde X-Frame-Options
d'origine. Le formulaire ne traite que des leads anonymes (pas de
session, pas de données sensibles), et le rate-limit :contact_form
s'applique aux POST embed comme aux POST hosted.
Le formulaire embed n'inclut pas le hero marketing, l'entête org, ni
le switch de langue — ce sont des éléments que votre page hôte gère
déjà.
Pas de DNS à configurer, pas de sous-domaine à créer. Le snippet
pointe sur l'hôte Meridian canonique.
v0.78.0
Nouveauté
Meridian
Serialize/1 emits MCP-format tools with _dispatch metadata
Adds serialize/1 to OpenApiToTools, mapping Tool structs to the JSON
shape consumed by GET /api/meridian/v1/mcp/tools. The _dispatch map
carries method, path, pathParams, queryParams, and bodyParams for the
bundled Node MCP server to use when routing tool calls.
v0.78.0
Correctif
Meridian
Dismiss desktop key modal via JS.hide + JS.push
The "I've copied the key" button and the modal's X / backdrop / escape
key all relied solely on a server-side assign clear + LiveView re-render
to remove the modal from the DOM. In practice the modal stayed visible
in the browser (server handler ran fine; tests pass; diff observably
didn't take effect).
Switch to the canonical Phoenix modal pattern: wrap the modal in a
stable outer div (id="desktop-key-modal-wrapper") and chain
JS.hide(to: "#...") |> JS.push("dismiss_desktop_key_modal") on every
close action. The JS.hide takes effect immediately client-side; the
push still clears the assign so the modal stays gone on the next render.
v0.78.0
Nouveauté
Meridian
Classify query vs body params on each converted Tool
Adds convert/0 (alias for all/0), populates query_params and body_params
on each Tool by extracting keys from the OpenAPI body/query schemas. Also
enriches the update_opportunity OpenAPI spec with enumerated body properties
so dispatch metadata is accurate for PATCH endpoints.
v0.78.0
Nouveauté
Meridian
Generate/regenerate/revoke Claude Desktop key
Wire generate_desktop_key, regenerate_desktop_key, revoke_desktop_key,
and dismiss_desktop_key_modal event handlers. Add a one-time reveal modal
(mirroring the existing mint modal) that shows the raw key with a
three-step install guide and a download link. Includes Task 10 tests.
v0.78.0
Refactorisation
Meridian
Rename MeridianMcp.* to Meridian.Mcp.*, add query/body_params fields
Aligns the MCP module namespace with the codebase convention (Meridian..*).
Renames ToolRegistry → OpenApiToTools, adds query_params/body_params to the Tool struct.
Branding CSS variables now propagate to the embed layout via
style={branding_style(...)} on . The submit button already
used the org color (inline style) but focus rings and any other
--color-primary references were stuck on Meridian defaults. Now the
whole form picks up the org's branding consistently.
Thank-you booking link uses target="_blank" (was target="_top").
target=_top navigated the entire host page away from the org's site
to Meridian — the opposite of the chosen "thank-you in-place"
behavior. _blank opens booking in a new tab and the visitor stays
on the host page. Adds rel=noopener for the usual security reason.
"Copy code" button shows a brief "Copied!" pill next to it
(JS.show + delayed JS.hide with opacity transitions). Previously the
click had zero visual feedback.
New "Preview" link in the embed card opens the embed URL in a new
tab so the org can see the rendered form before integrating it.
Adds a controller-level test that asserts org branding CSS variables
are inlined on the embed's element.
v0.78.0
Nouveauté
Meridian
Embed in third-party sites via iframe
Adds an iframe-friendly contact form surface at /embed/contact/:slug so
orgs can drop the form inside an existing page on their own marketing
site instead of redirecting visitors to /contact/:slug. The first org
with this need is Patero.
Routes (new :embed pipeline)
GET /embed/contact/:slug form-only render
GET /embed/contact/:slug/thank-you in-iframe thank you
POST /embed/contact/:slug same logic as ContactController
Headers (scoped to /embed/* only via Plugs.AllowEmbedding)
X-Frame-Options removed
Content-Security-Policy frame-ancestors *
Form-only view strips the hero pane, mobile banner, org_brand_header
and locale switcher, keeps me-glass-frame and all seven existing
fields. Submit + thank-you both stay inside the iframe (same-origin
→ native Phoenix CSRF, no CORS surface). An inline 15-line script
posts {type:"meridian:resize", height} to the parent on load and on
ResizeObserver; a 25-line priv/static/embed.js on the host side
matches by contentWindow and sets iframe.style.height.
Settings UI (Settings → Public site → Contact form) gets a new "Embed
on your website" card with a copyable snippet (textarea + phx:copy)
and a FR/EN locale toggle that swaps ?locale= in the snippet.
Out of scope for now (Phase 2 candidates): per-org allowlist of
embedding domains, widget JS / JSON-API alternatives, CSS theming
beyond branding.primary_color, parent→iframe pre-fill via
postMessage, analytics submit events, bot protection beyond rate
limit. See LOGBOOK/features/feat-contact-form-embed/design.md.
v0.78.0
Nouveauté
Meridian
Node MCP server with tools/list cache and tools/call dispatch
v0.78.0
Nouveauté
Meridian
Partial unique index on api_keys for 'Claude Desktop' name per user
v0.78.0
Correctif
Meridian
Restore exec bit on meridian_request.sh after rename
v0.78.0
Nouveauté
Meridian
Mix meridian.skill.build --target=desktop produces a .mcpb
Replaces the old flat-directory desktop output with a proper .mcpb zip
containing manifest.json (version-substituted), icon.png, server/index.mjs
(built via npm ci && npm run build), server/package.json, SKILL.md, and
INSTALL.md. Output: _build/skill/meridian-desktop-.mcpb.
v0.78.0
Nouveauté
Meridian
Render Claude Desktop section (empty state)
Add desktop_key and desktop_key_just_generated assigns to mount/3,
and render a new Claude Desktop card below the Calendar card showing
the empty-state CTA or the active-key actions (Download/Regenerate/Revoke).
Includes Task 9 smoke test.
Three user-reported issues from the first local install attempt:
Bundle install failed with "Impossible de se connecter au serveur
d'extension". Root cause: server/index.ts checked
import.meta.url === \file://${process.argv[1]}`` which fails
when Claude Desktop installs into a path containing spaces (e.g.
"Application Support/Claude/..."). import.meta.url percent-encodes
spaces, argv[1] doesn't. main() never ran, stdio handshake never
started, Desktop bailed. Switched to pathToFileURL(argv[1]).href
which is the canonical Node ESM entry-point check, and wrapped
main() in .catch() so future startup errors land in stderr.
Desktop connector title showed "meridian" instead of the user's
org. manifest.json display_name now templates "Meridian — ${ORG_NAME}".
The build task accepts org_name + org_slug opts; the SkillBundleController
passes the current_organization. Bundles are cached per (version, org_slug)
so each org gets its own file. CLI mix task without args defaults
org_name to "Workspace".
The dedicated "Claude Desktop" card on /settings/integrations is now
redundant with the top-row download button (which generates + opens
the reveal modal). Card removed entirely. The active Desktop key
still shows up in the regular Meridian API keys table for revoke.
v0.78.0
Correctif
Meridian
Drop leftover remote-MCP URL display
The remote MCP connector approach was abandoned in favor of the .mcpb
desktop extension. This removes the obsolete URL display, its assign,
and the test that asserted /api/meridian/mcp on the page. Also renames
the top-row Desktop download CTA from (.zip) to (.mcpb).
v0.78.0
Nouveauté
Meridian
/skill-bundle?target=desktop serves .mcpb
Switches desktop downloads from .zip to .mcpb (application/octet-stream).
The .mcpb is built on-demand by build(:desktop) if missing; code target
retains the existing zip-from-flat-dir behavior.
v0.78.0
Nouveauté
Meridian
GET /api/meridian/v1/mcp/tools returns user-filtered tool catalog
Adds McpToolsController with index/1 that calls OpenApiToTools.list_for/2
then serialize/1, returning server metadata + MCP-shaped tool list. Route
registered in the :api_meridian_auth scope (auth + rate-limit + audit
automatic). McpToolsController registered in @tool_specs and @permissions
to satisfy the router-walk boot validation.
v0.77.0
Nouveauté
Meridian
Connecteur Claude Desktop (.mcpb)
Meridian s'installe maintenant dans Claude Desktop comme une extension
.mcpb : un fichier téléchargeable depuis Paramètres → Intégrations →
Claude Desktop qui s'installe en un double-clic.
Au moment du téléchargement, Meridian génère une clé API dédiée
("Claude Desktop") affichée une seule fois. Cette clé est stockée par
Claude Desktop dans le trousseau du système d'exploitation (Keychain
macOS / Credential Manager Windows) — elle n'est jamais dans le fichier
.mcpb lui-même.
Une fois installé, tous les outils Meridian (list_opportunities,
create_proposal, get_me, etc.) apparaissent dans Desktop. Les
permissions utilisateur sont appliquées côté serveur : un utilisateur
ne voit dans Desktop que les outils qu'il a le droit d'invoquer.
Pour Claude Code (Bash + curl), le skill meridian-code reste
disponible sans changement.
v0.77.0
Amélioration
Router
Endpoints d'administration Router déplacés sous /api/router/v1/*
Les quatre endpoints d'administration Router ont été déplacés vers un nouveau
namespace dédié. Mettez à jour vos scripts :
/api/v1/router/audit → /api/router/v1/audit
/api/v1/billing/* → /api/router/v1/billing/*
/api/v1/api_keys → /api/router/v1/api_keys
/api/v1/logs → /api/router/v1/logs
Les endpoints compatibles OpenAI (/api/v1/chat/completions, /api/v1/embeddings,
/api/v1/models) sont inchangés. Ce déplacement ne les affecte pas. La
documentation interactive est maintenant disponible sous /api/router/docs/
(anciennement /api/docs/).
v0.77.0
Nouveauté
Meridian
Clés API personnelles et Skill Claude
Les utilisateurs peuvent maintenant générer des clés API personnelles depuis
Paramètres → Intégrations pour accéder à l'API CRM Meridian (/api/meridian/v1/*).
Chaque clé hérite exactement des permissions de l'utilisateur qui l'a créée — aucun
accès élargi, aucun accès inter-organisations. Un Skill Claude téléchargeable depuis
la même page permet d'interroger et d'agir sur votre organisation directement depuis
n'importe quel client Claude, en tant que vous-même.
v0.78.0
Amélioration
Meridian
Clés API · compteur et limite affichés dans les paramètres
Les paramètres du Router (onglet Clés API) affichent maintenant le nombre
de clés actuel par rapport à la limite par organisation (50 par défaut).
Quand la limite est atteinte, le bouton « Créer une clé API » est
désactivé et une bannière explique qu'il faut révoquer une clé inutilisée
avant d'en créer une nouvelle.
Auparavant, la limite n'était surfaçée qu'au moment de la création
(erreur HTTP 422 côté API, message flash côté interface). Le compteur
inclut les clés actives et révoquées, comme la vérification serveur.
v0.76.0
Nouveauté
Meridian
Structured editors for 6 constitution sections
Six new editable forms in the constitution drawer on /agents/:slug:
authority (4 lists), allowed contacts, escalation rules, guardrails,
business context (read + write), and KPIs. The autonomy matrix already
had interactive promote/demote and stays as-is.
Mixed data shape (string-or-map) handled by reading both shapes and
writing canonical map shape on save — no DB migration needed. Empty
rows are dropped on save (clearing inputs deletes the row). EN + FR
gettext entries included.
v0.75.2
Correctif
Meridian
Sub-cent accumulator stops 3x credit over-billing
Many small LLM calls (typical of agent workloads) were each rounded up
to a whole cent before markup+FX, then floored at 1¢ per call, producing
roughly 3x over-billing. 200 calls at $0.00375 USD each ($0.75 total)
drained $4 CAD instead of the expected $1.38.
Switch the cost pipeline to compute exact millicents (1/1000 cent) with
a single round at the end, and accumulate sub-cent residuals on the
organization so they only bill once they roll over to a whole cent.
Also fixes a separate reconciler bug: llm_settle markers (idempotency
artifacts that don't actually decrement balance) were being summed as
debits, which would silently force balances downward by 1¢ per call.
v0.76.0
Nouveauté
Meridian
Constitution · 6 nouveaux éditeurs sur la page d'agent
La constitution d'un agent (autorité, contacts permis, règles d'escalade,
garde-fous, contexte d'affaires, KPIs) s'éditait jusqu'ici en touchant
le JSON brut. Six éditeurs structurés viennent d'arriver dans le tiroir
de la page agent :
Autorité · 4 listes (autonome, propose, ne peut pas, hors-portée)
Contacts permis · table avec agent, types et usage typique
Contexte d'affaires · accès en lecture et en écriture
KPIs · métrique, cible, fréquence
Les entrées existantes (chaînes ou maps mélangées) restent affichées
correctement et sont normalisées au format map au prochain
enregistrement, sans migration de données.
v0.75.2
Correctif
Meridian
Crédits IA · facturation au sous-cent près
Les crédits IA pouvaient se vider plus vite que la consommation réelle
lorsque le travail se faisait en plusieurs petits appels (typique des
flux d'agents). Une organisation pouvait perdre jusqu'à trois fois la
valeur consommée.
La cause: chaque appel arrondissait son coût USD au cent supérieur avant
d'appliquer la majoration et la conversion CAD, puis appliquait un
plancher de 1¢ par appel. Sur 200 appels à 0,375¢ USD chacun (0,75 USD
total), l'organisation se faisait facturer 4,00 $ CAD au lieu de
1,38 $ CAD.
Le calcul utilise maintenant le coût USD exact jusqu'au bout, puis
accumule le résidu sous-cent sur l'organisation pour le facturer
seulement quand un cent entier est atteint. Les soldes restent corrects
même sur des centaines de micro-appels.
v0.75.1
Correctif
Meridian
Stabilité des actions IA en cas d'erreur d'un fournisseur
Quand un fournisseur d'IA (OpenAI, OpenRouter, etc.) renvoyait une
erreur HTTP, certaines actions internes (recherche d'entreprise,
qualification, résumés de transcripts, génération de propositions)
plantaient au lieu de signaler l'erreur proprement.
Le routeur retourne maintenant systématiquement la même forme
d'erreur, et toutes les actions reprennent leur chemin d'erreur normal
plutôt que de crasher. L'agent Business Development en particulier
reste stable quand la recherche d'entreprise échoue côté fournisseur.
v0.75.0
Amélioration
Meridian
Action et étape en cours visibles dans le tableau des clients
Le tableau des clients affiche maintenant deux nouvelles colonnes éditables
en place : Étape en cours et À faire. L'en-tête du tableau reste
visible quand on défile.
Les actions à faire ouvertes sur l'ensemble des clients de l'organisation
apparaissent aussi dans la carte « Prochaines actions » du tableau de bord.
Cliquer ✓ marque l'action comme faite et la retire de la liste.
v0.75.0
Correctif
Meridian
Install Node 22 LTS from NodeSource for pdfjs-dist
Debian bookworm's nodejs package is v18, but [email protected] declares
engines.node: ">=20.19.0 || >=22.13.0 || >=24". npm ci was failing
with EBADENGINE on the asset install step.
Switch to NodeSource's setup_22.x to install Node 22 LTS (which also
ships its own npm, so we drop the separate npm apt package).
v0.75.0
Correctif
Meridian
Copy native/ into builder so rustler can compile typst NIF
The builder image was missing COPY native native, so when mix compile
hit Meridian.Proposals.Typst.Compiler rustler errored with:
spawn: Could not cd to native/typst_compiler
** (RuntimeError) calling `cargo metadata` failed.
.dockerignore already keeps the source (only native/*/target/ is
excluded), so a plain COPY native native before mix compile is
enough.
v0.75.0
Nouveauté
Meridian
Assign ResearchCompany + backfill platform actions on BD agents
Adds Meridian.Actions.ResearchCompany to the business-development agent in
all three templates so newly seeded orgs cover every action listed in
SetupAlerts.platform_actions/0. Introduces AgentActionsBackfill to
idempotently add the 5 platform actions (and silent autonomy rules) to the
BD agent of existing orgs that were seeded before these actions existed.
v0.75.0
Correctif
Meridian
Activate/pause buttons now fire from dashboard and detail page
On the dashboard the agent row was wrapped in <.link navigate>, so clicks
on the inner activate/pause buttons were swallowed by the anchor's default
navigation — event.stopPropagation() doesn't suppress that. Switched the
row to a phx-click={JS.navigate(...)} div so the inner buttons' click
handlers actually run.
On the agent detail page the ActionsDropdownComponent dispatched
{:actions_dropdown_event, "activate_agent", id} via send/2, but no
handle_info/2 clause captured it — the catch-all swallowed every status
change. Added a handler that updates status and starts or stops the
supervisor accordingly.
v0.74.1
Nouveauté
Meridian
Expose new grouped keys in canonical_paths
v0.74.1
Correctif
Meridian
Strip empty strings from ServiceBlock product_types validator
Critical bug surfaced by Phase 3 code review. Real browsers submit
multi-checkbox arrays like service_block[product_types][]= as part of
the form encoding (a hidden empty input ensures an empty array reaches
the server when nothing is checked). Plug.Conn.Query decodes that
into ["", "Cosmetics"], and the org-catalog validator rejected the
empty string as "not in catalog: ", so NO service block save would
succeed through the modal.
Tests passed because Phoenix.LiveViewTest.form/3 (Floki) silently
strips empty hidden inputs during serialization, hiding the issue.
v0.74.1
Nouveauté
Meridian
Inline off-catalog service add with optional catalog inclusion
v0.74.1
Nouveauté
Meridian
Feed structured services_by_category to the AI prompt
v0.74.1
Nouveauté
Meridian
Add 'Catalogue de services' nav entry under Organisation
v0.74.1
Nouveauté
Meridian
Enrich line_items with service_block context
v0.74.1
Nouveauté
Meridian
Catalog tab table
v0.74.1
Nouveauté
Meridian
Banner on inherited services + cat. badge on line items
Show service_allocations section (fixed/hourly/recurring)
v0.74.1
Nouveauté
Meridian
Step-note banner on company detail page
v0.74.1
Nouveauté
Meridian
Scaffold /settings/services LiveView with 5 pills
v0.74.1
Nouveauté
Meridian
Inline edit of manual_last_contact (date + kind)
v0.74.1
Nouveauté
Meridian
Add grouped views for services (by category/kind, essentials, scope)
v0.74.1
Refactorisation
Meridian
Drop Opportunities & Proposals columns from clients table
v0.74.1
Nouveauté
Meridian
Presets tab with delete
v0.74.1
Refactorisation
Meridian
Read product_types from org catalog instead of hardcoded list
v0.74.1
Nouveauté
Meridian
Inline company + first contact creation in modal
v0.74.1
Nouveauté
Meridian
Persist selected services on opportunity save
v0.74.1
Nouveauté
Meridian
Create/edit service block modal
v0.74.1
Correctif
Meridian
Visual & UX polish from phase 4 review
C1: replace 5 occurrences of undefined CSS token --surface-elevated
with --surface-raised. Without this, the count badge, service rows,
and 3 sub-form panels rendered with no background (invisible in
dark mode).
I1: add dark: variants to ESSENTIEL pill (text-emerald) and the
unchecked-essentials warning banner (amber bg/border/text), per
the project's dark-mode pairing convention.
I3: add put_flash success on save_inline_company so users get
acknowledgement after "Créer & sélectionner" (was silently
closing the sub-form).
v0.74.1
Nouveauté
Meridian
Soft warning when essentials are unchecked
v0.74.1
Refactorisation
Meridian
Delete /crm/service-blocks (replaced by /settings/services)
v0.74.1
Nouveauté
Meridian
Editable client_status pill in clients table
v0.74.1
Nouveauté
Meridian
Save & load opportunity presets from modal
v0.74.1
Nouveauté
Meridian
Services panel in opportunity modal with auto-essential pre-check
v0.74.1
Nouveauté
Meridian
Help panel with cascade explainer
v0.74.1
Nouveauté
meridian
Catalogue de services et cascade opportunité → projet
Les services se définissent maintenant dans Paramètres → Catalogue de services.
Sélectionner un type de produit (Cosmetics, NHP, …) sur une opportunité fait
apparaître la liste des services associés, avec les essentiels pré-cochés. Les
choix sont copiés automatiquement comme line items à la création de la
proposition, puis comme tâches forfait, banques d'heures ou suivi récurrent
sur le projet à l'acceptation.
Améliorations du tableau client :
Statut client manuel et configurable (cellule éditable directement dans la liste)
Suivi des contacts hors-système (appels, courriels, rencontres) avec colonne
« Dernier contact » mise à jour
Création de compagnie + premier contact directement depuis la modale d'opportunité
v0.74.1
Nouveauté
Meridian
Unique constraints on cascade tables
Adds two unique indexes flagged by Phase 0 code review:
crm_opportunity_presets(organization_id, name) — prevents duplicate
preset names within an org (would be ambiguous in the picker)
crm_project_service_allocations(project_id, proposal_line_item_id) —
enforces 1:1 between a line item and its allocation, matching the
cascade invariant from spec §6.3
Extend ServiceBlock with product_types, essential, defaults; category becomes free-text
v0.73.1
Nouveauté
Meridian
Unify cockpit shell across skills/triggers/inbox/traces
Extract agents_subnav_link/1 to AgentDetailComponents as a public def,
then apply the breadcrumb + sub-nav + entity_header shell to all 4
agents sub-pages to match the dashboard cockpit pattern.
v0.73.1
Correctif
Meridian
Replace broken --surface and --surface-default tokens
These tokens are not defined in app.css — references to them rendered as
transparent (cards invisible against page bg) or as text-color clashes.
All bg-[var(--surface)] → bg-[var(--surface-raised)]
All bg-[var(--surface-default)] → bg-[var(--surface-raised)]
text-[var(--surface-default)] (Activity tab filter active state) → text-white
active filter pill now uses primary bg + glow shadow per design system
Cards in Overview/Activity/Capabilities/Chat used --surface-default which
became the same shade as the new --surface-base page background, removing
visual contrast. Switched to --surface-raised + --shadow-surface across all
shared agent_detail_components and the chat panel container.
v0.73.0
Nouveauté
Meridian
Full-width detail shell with breadcrumb + entity_header
Replace the agent detail page header with the canonical Meridian
breadcrumb + entity_header pattern, expand the container to full-width
(px-6 py-4), update the sticky pill bar to use --surface-base with
-mx-6 px-6, and delete the dead agent_header/1 component along with
its now-unused icon/gradient/status_color helpers.
v0.73.0
Refactorisation
Meridian
Extract remaining constitution sections to AgentConstitutionComponents
Ports 9 constitution sections from agent_detail_live.ex into dormant
function components (2 forms + 7 read-only sections). Lifts level_color,
level_icon, and display_entry from private LiveView defp to public
AgentDetailLive.Helpers, and moves authority_list to
AgentConstitutionComponents as a private component.
v0.73.0
Nouveauté
Meridian
Add <.line_editor> for repeatable list-of-strings inputs
Adds a reusable Phoenix function component and paired JS hook (LineEditorHook)
for client-side add/remove of repeatable string lists; submits as name[] arrays.
v0.73.0
Amélioration
meridian
Agents : liste cockpit, détail full-width, Constitution scannable
Les pages Agents ont été affinées pour le monitoring quotidien et l'admin.
Liste /agents : nouvelle structure cockpit. Une section « Demande de l'attention » apparaît en haut quand des agents sont en pause/erreur ou ont une inbox en attente. La grille décorative devient un roster compact 1-colonne avec les signaux essentiels (statut, inbox). Le digest hebdomadaire passe en section pliable en bas.
Détail /agents/:slug : la page passe en pleine largeur, adopte le breadcrumb et le entity_header cohérents avec le reste du CRM. Les cartes ont maintenant une vraie profondeur (ombres + surfaces tokenisées).
Constitution : refondue en vue snapshot. Un seul card lisible d'un coup résume toute la constitution (identité, autorité, comportement, performance), et chaque section s'édite dans un drawer dédié — fini le scroll infini avec des forms inline.
Sous le capot, deux nouveaux composants <.line_editor> et <.segmented_control> couvrent les patterns de form les plus communs ; l'extension <:footer> slot sur <.drawer> permet le pattern Cancel / Save standardisé dans les drawers d'édition.
v0.73.0
Refactorisation
Meridian
Extract Constitution helpers + identity/voice form components
Create MeridianWeb.AgentDetailLive.Helpers with the 7 shared defp helpers
(c/3, ensure_list/1, split_lines/1, parse_int/2, tier_label/1,
resolved_model_name/2, resolved_default_model_name/2)
Replace duplicate defp definitions in AgentDetailLive with import
Create MeridianWeb.AgentConstitutionComponents skeleton with identity_form/1
and voice_form/1 as canonical text-form and line_editor+segmented_control
examples (remaining 9 forms deferred to T4b)
v0.73.0
Nouveauté
Meridian
Add <:footer> slot to <.drawer> for sticky actions
v0.73.0
Nouveauté
Meridian
Cockpit list — Need attention + roster + collapsible digest
v0.73.0
Nouveauté
Meridian
Add inbox_pending_count + last_error_at to list_agents/1
Two new virtual fields on the Agent struct, populated via left-joins on
HumanInboxItem (status="pending") and AgentTrace (outcome in error/rejected/
escalated). Powers the "Need attention" section on the redesigned /agents list.
v0.73.0
Refactorisation
Meridian
Remove unused <.constitution_group>
Replaced by the snapshot + drawer pattern in the Constitution tab refactor.
v0.73.0
Nouveauté
Meridian
Refactor Constitution tab to snapshot + drawer pattern
Replaces the 4 stacked inline-form groups with a compact snapshot card on
the left, an aside_panel with 11 section links on the right, and a single
shared drawer that opens for whichever section is active. The 4 editable
sections (identity, ai_model, voice, memory) get Save/Cancel footers; the
7 read-only sections (authority, autonomy_matrix, allowed_contacts,
escalations, guardrails, business_context, kpis) show a Done button only.
v0.73.0
Nouveauté
Meridian
Add <.segmented_control> for form-driven enum choice
La page d'un agent (/agents/:slug) passe d'une longue colonne de sections à un layout 5-tabs avec pills.
Overview — décisions à prendre (promotion d'autonomie suggérée à partir des traces récentes), KPIs cette semaine, dernières activités.
Activity — chart des 7 derniers jours + liste filtrable des traces, drawer pour le détail complet d'une trace.
Capabilities — skills attachées en cards avec leur rail « déclenchée par · utilise », plus un disclosure pour les actions orphelines.
Constitution — 4 groupes (Identity & Voice / Authority & Autonomy / Behavior & Memory / Measurement) + bouton « Voir le prompt » qui ouvre le system prompt réel envoyé au LLM avec les sections cliquables.
Chat — conversation avec l'agent embarquée dans la page (la route /agents/:slug/chat séparée n'existe plus).
Un nouveau moteur de recommandations (Meridian.Agents.DecisionSupport) calcule les suggestions à partir des traces, autonomy_rules, et de l'inbox — promotion/démotion d'autonomie, items pending, capabilities idle, trajectoire de confiance. Chaque carte est dismissable pour 7 jours.
v0.72.0
Nouveauté
Meridian
Chat tab — port AgentChatLive + delete /agents/:slug/chat route
Big-bang migration per CLAUDE.md (no redirect). Chat content lives at
?tab=chat on the agent detail page. PubSub subscription set up at mount
so streaming responses keep arriving across tab switches.
Decision cards driven by Meridian.Agents.DecisionSupport. Promote/demote
event handlers update AutonomyRule and refresh the recommendations.
Dismiss persists a 7-day snooze in agent_state.
v0.72.0
Nouveauté
Meridian
Move proposal templates listing to /settings/proposal-templates
v0.72.0
Nouveauté
Meridian
Live streaming Typst preview with syntax highlighting
v0.72.0
Nouveauté
Meridian
Retry Typst generation up to 3x on AST or compile failures
v0.72.0
Correctif
Meridian
Tighten Typst prompt + retry once on AST validation failure
v0.72.0
Correctif
Meridian
Split LLM-generation phase from PDF-compile phase in preview
v0.72.0
Nouveauté
Meridian
Move AI Directive into org config modal with markdown preview; remove /settings/knowledge
Add :ai_directive textarea + live Earmark markdown preview to the admin
organizations modal (super-admin only).
Remove :ai_model and :ai_max_tokens form inputs from the modal (schema
unchanged).
Delete /settings/knowledge route, LiveView, settings sidebar entry,
and corresponding test. The directive lives in the admin org modal now.
7-day bar chart with click-to-filter-day. Outcome filter pills (all,
success, escalated, failed). Trace list reuses <.trace_row>.
AgentTraceDrawerComponent slides over with full trace detail when a row
is clicked. URL params drive everything (filter, day, trace).
v0.72.0
Nouveauté
Meridian
Full-width wiki layout with left nav rail and reader mode
v0.72.0
Nouveauté
Meridian
Unified flow picker on /crm/proposals + move template wizard under /settings
v0.72.0
Refactorisation
Meridian
Extract trace detail into AgentTraceDrawerComponent
LiveComponent reused by /agents/traces (global) and the Activity tab on
the agent detail page.
v0.72.0
Nouveauté
Meridian
Add Proposal Templates nav entry under Organisation
Four more function components in AgentDetailComponents. Module is now at
8 components total (trace_row, kpi_tile, activity_row, decision_card +
these four).
v0.72.0
Refactorisation
Meridian
Extract <.trace_row> into AgentDetailComponents
First component in a new module that will host the function components
for the agent detail page redesign. agents_traces_live.ex adopts it now
so the new Activity tab and global traces page render identically.
v0.72.0
Correctif
Router
Bake metadata pricing into catalog-added models + manual refresh action
v0.72.0
Nouveauté
Meridian
AgentPromptDrawerComponent — clickable system prompt preview
Renders Meridian.Agents.PromptBuilder.build_instructions/3 output with
[Section] anchors made clickable. Clicking sends a message to the parent
LiveView to jump to the corresponding edit panel.
Used by the Constitution tab on the agent detail page.
v0.72.0
Refactorisation
Meridian
Hoist outcome classifiers to AgentTrace + structured recs
Addresses code review I1 (domain knowledge in DecisionSupport) and I2
(hardcoded French in data model). Recommendation tuples now carry structured
payloads (counts, kinds) that the LiveView will gettext at render time.
v0.72.0
Correctif
Meridian
Rewrite Typst highlighter with matchAll to avoid placeholder collisions
v0.72.0
Nouveauté
Meridian
Drop list flow badge, route Open Editor by flow, rename Flow 1/2 to Manual/AI in UI
inbox_pending uses the existing HumanInbox API (or defensively returns []
if missing). idle_capability flags actions with 0 traces in 30d.
trust_trajectory emits a structured kind atom (:high|:moderate|:low) so
the LiveView gettext-formats at render. dismiss/2 stores a snooze in
agent_state with a 7-day expiry; dismissed?/2 filters at the boundary.
v0.72.0
Refactorisation
Meridian
Rename to AgentDetailLive + 5-tab pills shell
Constitution body moved verbatim into live_render_constitution/1 so the
existing edit flow keeps working. Other tabs (overview/activity/
capabilities/chat) are stubs filled in by Tasks 10-14.
v0.72.0
Correctif
Router
Tolerate numeric pricing values + admin toggle for agents_v1_enabled
v0.72.0
Correctif
Meridian
Match settings layout for proposal templates + activate Settings sidebar entry
v0.72.0
Nouveauté
Meridian
Capabilities tab — skills-centric with trigger/action rail
Skills attached to the agent render as cards with a rail showing what
triggers them and which actions they use. Orphan actions (attached to
the agent but not part of any skill) collapse into a disclosure block.
Surface Router error detail in wizard analysis step
v0.72.0
Nouveauté
Meridian
Split into wiki page at /knowledge + slim directive-only settings
Move the article list, AI suggestions queue, and create/edit/approve/reject
flows out of /settings/knowledge into a new top-level wiki page at /knowledge,
under the Outils sidebar section. /settings/knowledge keeps only the org-wide
AI directive editor plus a callout linking to the new page.
The pending-suggestions badge moves from the settings sidebar to the new top-
level entry. Article bodies in the drawer detail view render as Markdown via
Earmark.
v0.72.0
Correctif
Meridian
Rescue compile crashes + SVG thumbnails for layout cards
L'éditeur de proposition Flux 2 boucle son MVP : le panneau de validations affiche les anomalies (prix, dates,
sections requises, langue, scope, complétude) et permet de les résoudre ou de les ignorer ; un bouton « Lancer
complète » réexécute toute la suite. Les commentaires arrivent au niveau section avec fil de réponses et résolution.
Le bouton « Approuver et envoyer » dans la toolbar ouvre une confirmation et déclenche l'envoi par courriel au contact
principal — fin du parcours opérateur.
v0.72.0
Amélioration
meridian
Settings consolidés : pages à onglets pour Compte, Équipe, Site public et Router
EN: The settings sidebar has been simplified by merging closely-related pages into single tabbed views, modeled after the existing AI & Agents page:
Mon compte (/settings/account) — fuses Profil + Disponibilité.
Équipe (/organization/team) — fuses Utilisateurs + Rôles et permissions.
Site public (/settings/public) — fuses Formulaire contact + Qualification + Templates email.
Tabs use the standard pill_selector and now support deep-linking via ?tab=<name> so you can bookmark a specific tab and the browser back/forward buttons work as expected. The AI & Agents page (/router/settings/ai) was upgraded to the same URL pattern.
The settings sidebar drops from ~20 entries to ~12 without losing any functionality. Old URLs (/settings/user, /settings/availability, /organization/users, etc.) no longer resolve — use the sidebar to navigate.
FR : La barre latérale de paramètres est simplifiée : les pages étroitement liées sont regroupées en vues à onglets, sur le modèle de IA & Agents :
Mon compte (/settings/account) — fusionne Profil + Disponibilité.
Équipe (/organization/team) — fusionne Utilisateurs + Rôles et permissions.
Site public (/settings/public) — fusionne Formulaire contact + Qualification + Templates email.
Les onglets utilisent le même pill_selector que IA & Agents, avec deep-linking via ?tab=<name> (vous pouvez maintenant marquer un onglet spécifique en favori et les boutons précédent/suivant du navigateur fonctionnent comme attendu). La page IA & Agents (/router/settings/ai) bénéficie aussi de ce nouveau format d'URL.
La sidebar passe de ~20 entrées à ~12 sans perte de fonctionnalité. Les anciennes URLs (/settings/user, /settings/availability, /organization/users, etc.) ne fonctionnent plus — utilisez la barre latérale pour naviguer.
v0.71.0
Nouveauté
meridian
Base de connaissances d'organisation
EN: Two new tools to give your AI agents long-term context about your
organization and your clients:
Org Directive — write a single Markdown directive in
/settings/knowledge (e.g. tone, languages, confidentiality rules,
internal policies). It's injected into every agent's system prompt
automatically — no per-agent configuration needed.
Knowledge Base — articles scoped either organization-wide or to a
specific client. Edit them yourself in /settings/knowledge (or in the
Knowledge tab on a client page), or let agents propose articles
automatically from meeting transcripts. Proposals land in an approval
queue — nothing goes live until you say so.
When an agent works on an opportunity, it now sees both the global articles
and the articles for that opportunity's client, giving every proposal,
follow-up, or summary much richer context.
FR: Deux nouveaux outils pour donner à vos agents IA un contexte
long-terme sur votre organisation et vos clients :
Directive d'organisation — écrivez une seule directive Markdown dans
/settings/knowledge (ton, langues, règles de confidentialité, politiques
internes, etc.). Elle est injectée automatiquement dans le prompt système
de chaque agent — aucune configuration par agent nécessaire.
Base de connaissances — articles avec portée toute l'organisation ou
un client spécifique. Modifiez-les vous-même dans /settings/knowledge
(ou dans l'onglet Connaissances d'une fiche client), ou laissez les agents
proposer des articles automatiquement à partir des transcripts de meetings.
Les propositions arrivent dans une file d'approbation — rien ne devient
actif sans votre validation.
Quand un agent travaille sur une opportunité, il voit maintenant à la fois
les articles globaux et ceux du client concerné, ce qui enrichit chaque
proposition, suivi ou résumé.
v0.71.0
Nouveauté
meridian
Éditeur Flow 2 — édition IA en place
L'éditeur de proposition Flux 2 supporte maintenant les éditions assistées par IA. Survolez une section dans l'aperçu PDF
pour révéler les chips d'action (Réécrire, Étendre, Raccourcir, Régénérer) — un clic envoie l'édition à l'IA via Jido,
recompile, et met à jour le PDF en direct. Le panneau IA à droite affiche la conversation (l'historique des révisions)
et un champ de prompt libre avec sélection de section.
Côté fiabilité : les échecs LLM ou compile diffusent maintenant un statut :error à l'éditeur au lieu de laisser
l'indicateur figé sur « Compilation… ». Foundation prête pour B-3 (validations, commentaires, approbation).
v0.71.0
Correctif
Meridian
Scope_only filter + grammar fix on client article modal
v0.71.0
Nouveauté
Meridian
Get_for_editor preloads :template
v0.71.0
Correctif
Meridian
Dedupe knowledge extraction within 60s window
v0.71.0
Nouveauté
Meridian
FlowPickerComponent modal for Flow 1↔2 choice
v0.71.0
Correctif
Meridian
Broadcast on success, race-safe approval, cross-org tests
Broadcast only fires on {:ok, _} in create/update/delete/transition/update_directive
Add approve_article/reject_article fallback clauses returning {:error, :invalid_transition} for non-pending articles
Eliminate Repo.get!(Organization, ...) in update/delete/transition using admin_for_org_id? helper
Wires up the admin approve/reject buttons in the pending AI suggestions
section of /settings/knowledge. Approve transitions an ai_pending article
to ai_approved (moving it into the approved list); reject transitions it
to rejected (removing it from view). Both flows handle :unauthorized and
:invalid_transition results, and ids are validated via Integer.parse to
mirror the hardening in Task 9.
Adds EN/FR gettext strings for the new flash and confirmation copy.
v0.71.0
Correctif
Meridian
Gate /settings/proposals + use <.input> + extra tests
v0.71.0
Nouveauté
Meridian
Hover-revealed action chips on PDF section anchors
v0.71.0
Nouveauté
Meridian
Template_id FK on crm_proposals
v0.71.0
Nouveauté
Meridian
Show flow badge next to proposal names in list
v0.71.0
Correctif
Meridian
Sync directive on broadcast and harden scope_id parsing
v0.71.0
Nouveauté
Meridian
/settings/knowledge LiveView with directive + articles CRUD
Adds the org Knowledge Base settings page (Task 9):
Route: /settings/knowledge under live_session :authenticated.
Three sections: AI directive editor, approved articles list (CRUD via
modal, admin-only), pending AI suggestions (read-only — approve/reject
is Task 10).
Subscribes to Knowledge.topic(org_id) and reloads on
:knowledge_changed / :directive_changed broadcasts.
Adds a "Connaissances" entry to the settings sidebar.
Edit gating uses a per-LiveView can_edit? helper (super-admin OR member
with at least one role in the org) because is_org_admin and
user_permissions in this codebase are both org-membership signals, not
per-user role assignments.
v0.71.0
Nouveauté
Meridian
Conversation stream + free prompt input
v0.71.0
Nouveauté
Meridian
EN/FR translations for B-2 AI editing surface
v0.71.0
Nouveauté
Meridian
Knowledge sidebar pending count badge with PubSub updates
Extend settings_nav_item with optional :badge attr (renders pill when truthy/non-zero)
Load :knowledge_pending_count in AuthLiveSession on mount; subscribe to Knowledge.topic(org)
Update count live on {:knowledge_changed, _} broadcasts via attach_hook
Pass @knowledge_pending_count through all settings_nav callers
Fill EN/FR gettext translations for knowledge feature strings (16 entries)
v0.71.0
Nouveauté
Meridian
Gate Flow 1↔2 generation behind picker modal
v0.71.0
Nouveauté
Meridian
Inject [Org Directives] section into agent prompts
PromptBuilder.build_instructions/3 now emits a [Org Directives] block
between identity and authority when organizations.ai_directive is non-empty.
The migration enforces NOT NULL (default "") so the nil case cannot occur
in practice; pattern matches on nil are kept as safety belts for callers
that build Organization structs directly.
v0.71.0
Nouveauté
Meridian
EditorLive validations + comments + approve flow
Wire validations panel, comments panel, and approve & send modal into
EditorLive. Adds mount assigns, all event handlers (run_validations,
resolve_validation, create_comment, resolve_comment, open/close/confirm
approve), handle_info for :validations_updated, auto-debounced
:elixir_only validation on :compiled, and recipient_email/1 helper.
Approve path calls CRM.send_proposal + ProposalMailer.render + EmailDispatch.send_prepared.
v0.71.0
Nouveauté
Meridian
Announce organization knowledge base
v0.71.0
Nouveauté
Meridian
Create_flow_2_proposal writes template_id
v0.71.0
Nouveauté
Meridian
Persona auto-includes scoped knowledge articles
v0.71.0
Nouveauté
Meridian
Per-client Knowledge drawer on client detail view
Adds a Knowledge section in the aside panel of the client detail view
following the existing drawer pattern (alongside meetings, propositions,
documents, etc.). Lists company-scoped articles only (org-wide articles
remain in /settings/knowledge) and lets admins create new ones inline
with scope auto-set to the active company.
v0.71.0
Refactorisation
Meridian
Extract Flow 2 dispatch + wire picker tests
v0.71.0
Nouveauté
Meridian
Auto-trigger knowledge extraction post-summarize
v0.71.0
Nouveauté
Meridian
Comment context — create/reply/list/resolve
v0.71.0
Correctif
Meridian
FlowPickerComponent — CSS token, dead attr, safe parsing
v0.71.0
Correctif
Meridian
Constrain flow_badge attr values + a11y labels
v0.71.0
Nouveauté
Meridian
EN/FR translations for B-3
v0.71.0
Nouveauté
Meridian
/settings/proposals to pick default flow
Adds the org admin settings LiveView at /settings/proposals that lets an
organization choose its default_proposal_flow (flow_1 / flow_2 /
per_template). Drives the FlowPickerComponent's "Recommended" highlight.
Includes EN/FR gettext entries for the new strings.
v0.71.0
Nouveauté
Meridian
Belongs_to :template on Proposal
v0.71.0
Nouveauté
Meridian
Context with CRUD, approval, fetch_for_scope, directive
v0.71.0
Correctif
Meridian
Make ai_directive NOT NULL in migration
Add null: false to the ai_directive column in the organizations
migration to match auto_extract_knowledge and prevent a DB-level
nullable column that the schema treats as a non-null string with
default "".
v0.71.0
Nouveauté
Meridian
ReadKnowledgeBase Jido action wired into agent skills
Adds Meridian.Actions.ReadKnowledgeBase, a read-only Jido action that
wraps Knowledge.fetch_for_scope/2 and serializes approved articles to
plain maps for LLM consumption. Wires the action into every skill
actions list that already includes ReadContext (18 sites across
services, software, and pharma_consulting templates).
v0.71.0
Nouveauté
Meridian
List_recent_revisions/2 for conversation panel
Returns ProposalRevision rows newest-first for the editor's
conversation panel, with a configurable :limit (default 50).
v0.71.0
Nouveauté
Meridian
EN/FR translations + changelog for Flow picker
v0.71.0
Correctif
Meridian
Broadcast {:edit_failed} on terminal failures
Adds Meridian.Proposals.broadcast_failure/3 and wires it into all
terminal-failure branches of GenerateProposal, ProposeProposalEdit, and
RecompileProposalTypst so the editor's compile_status no longer gets
stuck on :compiling when an LLM call, compile, template-mismatch, or
section-not-found error occurs.
v0.71.0
Nouveauté
Meridian
Validations + comments + approve modal components
v0.71.0
Nouveauté
Meridian
Use <.flow_badge> with tooltip in editor toolbar
v0.71.0
Nouveauté
Meridian
Article schema with cross-tenant scope validation
Adds Meridian.Knowledge.Article (schema + changeset) with required-field
validation, source/scope_type enums, title/body length caps, and a DB-backed
scope consistency guard that prevents cross-tenant company references.
v0.71.0
Nouveauté
Meridian
Extract_knowledge_from_transcript with org/company scoping
v0.71.0
Correctif
Meridian
Canonical EN msgids, correct FR translations, dedupe PubSub, badge contrast
v0.71.0
Nouveauté
Meridian
Dispatch_validation/3 helper
v0.71.0
Nouveauté
Meridian
List_validations + resolve_validation helpers
v0.71.0
Nouveauté
Meridian
Add directive + knowledge_articles schema
v0.71.0
Nouveauté
Meridian
Dispatch_section_edit/2 helper
Thin context helper wrapping Task.Supervisor.start_child around
Meridian.Actions.ProposeProposalEdit.run/2, with :missing_keys
validation and run: false dry-run mode for tests.
v0.71.0
Nouveauté
Meridian
Sidebar nav entry for /settings/proposals
v0.71.0
Nouveauté
meridian
Choisir Flow 1 ou Flow 2 lors de la création d'une proposition
Les opérateurs peuvent maintenant choisir entre Flow 1 (DOCX, édition manuelle) et Flow 2 (Typst, piloté par l'IA) à chaque génération de proposition depuis une opportunité. La nouvelle page Paramètres → Flux de proposition permet aux administrateurs de l'organisation de définir le flow recommandé par défaut. Des badges visuels sur chaque proposition rendent évident quel flow est utilisé.
v0.71.0
Nouveauté
Meridian
Add <.flow_badge> shared function component
v0.71.0
Nouveauté
Meridian
Cast and validate default_proposal_flow on Organization
v0.71.0
Correctif
Meridian
Mix format on proposal_test.exs (post-merge follow-up)
v0.71.0
Nouveauté
Meridian
Add default_proposal_flow column to organizations
v0.70.0
Nouveauté
meridian
Wizard de création de templates de proposition (Flow 2)
Les org-admins peuvent maintenant créer un template de proposition Typst (Flow 2) en 7 étapes assistées par IA :
upload d'une inspiration DOCX/PDF (ou un des 3 modèles vierges fournis), analyse automatique de la structure, de la palette,
de la typographie et des variables candidates, puis raffinage interactif avec aperçu PDF en direct. Le résultat est un
template flow_2_native réutilisable depuis l'éditeur Flow 2.
v0.70.0
Nouveauté
meridian
Éditeur de proposition Flow 2 — fondations
L'éditeur Flow 2 (Typst) est maintenant accessible depuis le détail d'une opportunité. Le bouton « Générer une proposition Flux 2 »
crée un brouillon contre le modèle Flow 2 par défaut de l'organisation et redirige vers le nouvel éditeur split-pane pendant que l'IA
génère les sections initiales en arrière-plan.
Cette première livraison embarque la surface de l'éditeur : aperçu PDF live multi-pages, ancres de sections persistées depuis le
compilateur Typst (pour les chips à venir), verrou d'édition basé sur Phoenix.Presence pour empêcher deux opérateurs d'écrire en
même temps, et un bouton de bascule vers le Flux 1. Les chips d'édition IA, le panneau de validations, les commentaires et le flot
d'approbation arrivent dans les itérations suivantes.
v0.70.0
Nouveauté
Meridian
Scaffold Flow 2 wizard route + CTA on templates page
Adds placeholder WizardLive at /crm/proposal-templates/wizard (+ /:template_id
variant), registers both routes in the :authenticated live_session, and inserts
a "New Flow 2 template" secondary action button alongside the existing "New
Template" button on the templates list page. EN+FR gettext strings added.
Copy the Phoenix-managed temp file to a controlled path inside the
consume_uploaded_entries callback before spawning the async task, so
the file still exists when AnalyzeInspirationDocument reads it. The
Task cleans up the copy in a try/after regardless of success or crash.
Add a defensive {:error, _kind, detail} catch-all to RefineTemplate's
with/else so an unknown future NIF kind never falls through to a
2-tuple clause and raises WithClauseError. Contract test pins the NIF
kind to a String, detecting any future atom regression.
v0.70.0
Nouveauté
Meridian
Cast :section_layout on Proposal changeset
v0.70.0
Nouveauté
Meridian
Persist section_layout in RecompileProposalTypst
v0.70.0
Nouveauté
Meridian
AnalyzeInspirationDocument Jido action for template wizard
Implements step 2 of the Proposal v2 template wizard: reads a DOCX/PDF/TXT
via TextExtractor, sends content to Router (use_case: "template_analysis"),
and normalizes the response into a wizard_state envelope (sections, palette,
typography, logo_placement, cover_layout, language, variables).
v0.70.0
Nouveauté
Meridian
Section_layout column for Flow 2 editor anchors
v0.70.0
Correctif
Meridian
Align canonical_paths catalog to actual snapshot keys
Replace the placeholder dotted-namespace paths (e.g. opportunity.contact.name)
with the flat keys that Variables.build/1 and Computed.compute/2 actually
produce in the snapshot. Tighten the count assertion to exact (== 10) and
remove the dotted-notation check in favour of a non-empty-string check.
v0.70.0
Nouveauté
Meridian
EditorLive scaffold with lock + PubSub
v0.70.0
Nouveauté
Meridian
Opportunity-detail CTA generates Flow 2 + lands in editor
v0.70.0
Nouveauté
Meridian
Wizard steps 5-7 with live preview compile
Implements Voice (step 5), Preview & Refine (step 6), and Save (step 7)
in the proposal template wizard LiveView, plus the async Typst compile
pipeline (generate_typst → Task.async → handle_info cond → Task.start
compile → {:compile_done} → Storage.put → preview_pdf_url). Fixes
fuzzy gettext translations that were rendering wrong button labels in
EN/FR.
v0.70.0
Nouveauté
Meridian
Multi-page TypstPreview hook with section anchor data
v0.70.0
Nouveauté
Meridian
Expose canonical CRM variable paths for template wizard
Appends canonical_paths/0 to Meridian.Proposals.Variables, returning
a typed catalog of 17 dotted CRM paths the wizard's variable mapper will
dropdown into. Adds two unit tests covering shape and dotted-notation
invariants.
v0.70.0
Nouveauté
Meridian
Route /crm/proposals/:id/v2-editor
v0.70.0
Nouveauté
Meridian
Flow 2 template CRUD with versioning
Add list_flow_2_templates/1, create_flow_2_template/2,
update_flow_2_template/3, delete_flow_2_template/2 to Meridian.Proposals.
Each write op persists a proposal_template_versions row atomically via
Ecto.Multi; create broadcasts {:template_created, id} on PubSub;
cross-org deletes return {:error, :forbidden}.
v0.70.0
Nouveauté
Meridian
Compile_template_preview for wizard live PDF pane
Adds Proposals.compile_template_preview/2 and the supporting
synth_inputs/1 + synth_value/1 helpers. Compiles a Typst template
against synthetic dummy data derived from the variable manifest,
returning PDF bytes + hash without any persistence. Includes 6-test
suite covering success path, error handling, tmp cleanup, and all
synth_value type branches.
v0.70.0
Nouveauté
Meridian
Persist section_layout in ProposeProposalEdit
v0.70.0
Nouveauté
Meridian
Editor components (toolbar, PDF surface, navigator)
v0.70.0
Nouveauté
Meridian
SuggestPalette + SuggestTypography for the wizard identity step
v0.70.0
Nouveauté
Meridian
RefineTemplate action for free-form template iterations
v0.70.0
Nouveauté
Meridian
Create_flow_2_proposal/3 context helper
v0.70.0
Nouveauté
Meridian
EN/FR translations + changelog for the template wizard
v0.70.0
Nouveauté
Meridian
Persist section_layout in GenerateProposal
v0.70.0
Nouveauté
Meridian
Wizard function components
Add purely presentational function components for the proposal templates wizard:
wizard_stepper, color_palette_picker, font_pair_card, section_checklist,
variable_mapping_table, typst_preview, ai_prompt_input, and layout_card.
v0.70.0
Nouveauté
Meridian
Wizard preview PDF controller (auth-gated)
Add WizardPreviewController to serve transient wizard preview PDFs at
/preview/wizard/:org_id/:hash, cross-org 403 and unknown hash 404.
v0.70.0
Nouveauté
Meridian
EN/FR translations for Flow 2 editor B-1
v0.70.0
Nouveauté
Meridian
TypstPreview JS hook for live PDF rendering
Adds the TypstPreview LiveView hook that fetches a PDF URL from
data-pdf-url and renders the first page into a canvas via PDF.js.
The pdf.worker.mjs is built as a separate esbuild entry point and
served as a static asset at /assets/js/pdf.worker.mjs.
v0.70.0
Nouveauté
Meridian
Three starter template presets for the wizard
Add Meridian.Proposals.TemplatePresets with list/0, fetch!/1, and
slugs/0. Variable sources are validated against Variables.canonical_paths/0
at test time; retainer.start_date intentionally uses source: nil to force
operator mapping in the wizard picker.
v0.70.0
Nouveauté
Meridian
GenerateTypstTemplate action with AST + retry
Adds Step 6 of the proposal v2 wizard: synthesizes Typst source from
a wizard_state map, validates via Compiler.validate_fragment/2, and
retries once with the prior failure detail injected into the prompt.
v0.70.0
Correctif
Meridian
Address code review for persist_compile_artifacts seam
v0.70.0
Nouveauté
Meridian
Wizard LiveView state machine for steps 1-4
Replace the stub WizardLive with a full state machine covering Upload
(step 1), AI Analyse (step 2), Identité visuelle (step 3), and
Sections & variables (step 4). Steps 5-7 render a placeholder pending
Task 13. Async LLM work (AnalyzeInspirationDocument, MapVariablesToCRM)
runs via Task.async with proper demonitor + DOWN handling. Adds 4
LiveViewTest cases and extracts 14 new gettext strings.
v0.70.0
Nouveauté
Meridian
Get_for_editor + start_editor_session helpers
v0.70.0
Nouveauté
Meridian
MapVariablesToCRM Jido action constrained to canonical paths
v0.70.0
Refactorisation
Meridian
Persist_compile_artifacts/3 single seam
v0.69.0
Refactorisation
Meridian
Proposal v2 — architecture foundation (Typst NIF, schema, validations)
Foundation for the upcoming Proposal v2 flow. No user-facing UI yet —
Wizard (Option A) and Editor (Option B) build on this in subsequent
plans.
What landed:
Typst compile pile. Rust NIF (native/typst_compiler) wraps the
typst crate directly: dirty-CPU scheduled compile/3 returns the
PDF, a layout map (page + bbox per #section marker), and a SHA-256
of the PDF bytes. parse_section/2 and patch_section/3 are
AST-based and tolerate both #section(id: "x")[...] and
#section("x")[...] forms. validate_fragment/2 enforces an AST
whitelist on IA-generated edits. SandboxWorld rejects
parent-directory escapes and package-bound file ids.
Data model. New proposal_revisions, proposal_comments,
proposal_validations, proposal_templates (Flow 2 native, distinct
from the legacy DOCX templates). New columns on crm_proposals
(flow, typst_source, variables_snapshot, pdf_artifact_path,
pdf_compiled_hash, language, downgraded_*). archived status
added to the proposal enum. organizations.tax_config jsonb (default
TPS+TVQ).
Storage.Meridian.Proposals.Storage is a thin wrapper over
File.* with org-scoped paths. PDFs live at
org_<id>/proposals/<id>/pdf/<hash>.pdf. Auth-gated route
GET /crm/proposals/:id/pdf streams them.
Variables pipeline.Variables.compute/1 builds the snapshot from
the opportunity + line items + per-org tax config. The opportunity
listener auto-refreshes Flow 2 snapshots through
RefreshProposalSnapshotWorker and broadcasts a toast on diff.
Concurrency safety.SectionLock (Phoenix.Presence-backed)
serializes simultaneous editors at the section grain.
Operability. Dedicated :proposals Oban queue. Telemetry events
[:meridian, :proposals, :compile, :*]
span every compile call with proposal_id metadata. Daily
EmitProposalDiskUsageWorker cron emits a per-org disk_used gauge
(no quotas — telemetry only).
v0.69.0
Nouveauté
Meridian
Phoenix.Presence-backed exclusive editor lock
Add MeridianWeb.Presence tracker (wired into the supervision tree) and
Meridian.Proposals.SectionLock, a thin first-arriver-wins lock keyed by
proposal id. Auto-releases when the holding LiveView terminates via
Presence's built-in untrack-on-down behaviour.
Three pure-Elixir validators for Flow 2 proposals — no LLM, no DB.
Each exposes run/1 over a preloaded proposal-shaped map and returns
a list of issue maps %{kind, severity, message, source_refs}.
RequiredSections — uses Typst.Parser.list_section_ids/1 and
extract_section/2 to flag missing-or-empty sections declared in
the template's variables_manifest["sections"].
DateConsistency — flags past delivery_date and mismatches between
variables_snapshot["expected_close_date"] and the CRM
opportunity.expected_close_on column.
Completeness — flags empty values for every key in
variables_manifest["required"].
v0.69.0
Nouveauté
Meridian
Oban proposals queues + telemetry (compile, disk usage)
Introduce Meridian.Proposals.Telemetry with attach/0 + handlers
for [:meridian, :proposals, :compile, :start | :stop | :exception]
and a disk_used gauge under [:meridian, :proposals, :storage].
Wrap Compiler.compile/3 calls in the three actions
(GenerateProposal, ProposeProposalEdit, RecompileProposalTypst)
with :telemetry.span/3 so each compile carries proposal_id +
action metadata.
Attach telemetry handlers from Meridian.Application.start/2.
Add Meridian.Workers.EmitProposalDiskUsageWorker (daily cron at
04:30 UTC) that calls Telemetry.emit_disk_usage/0 to publish one
disk_used event per org root.
No quotas or enforcement — telemetry only (per Q4 / Q10).
v0.69.0
Nouveauté
Meridian
Standard Typst preamble (section, format_cad, format_date)
v0.69.0
Correctif
Meridian
Close foundation review gaps (AST guard, translations, unused queue)
Foundation review flagged three gaps:
GenerateProposal bypassed Compiler.validate_fragment/2 — the AST
whitelist that ProposeProposalEdit enforces on every IA-emitted
fragment. Bodies returned by the LLM were rendered straight into
Typst source without the gate. Add validate_sections/3 (single-
pass, no retry — mirrors the editor's first attempt; the
@max_ast_attempts 2 retry can be ported later) wired into the
with chain right after call_llm_for_sections/3. On the first
violation: persist a ProposalRevision with accepted: false,
error_kind: "ast", section_id, and metadata: %{"error", "fragment"},
broadcast {:edit_failed, "ast", msg}, and short-circuit with
{:error, %{reason: :ast_invalid, section_id, detail}}. The function
is exposed (not defp) so tests can drive it directly — the natural
path is gated by ai_enabled: false on the org default.
Three controller error strings were extracted into both default.po
files but left with empty msgstr:
"Proposal or PDF not found" / "PDF not yet compiled" /
"PDF file missing on disk". Filled in EN copies and FR translations.
mix gettext.extract --merge is now stable (no diff).
The :proposal_compile Oban queue was declared in config/config.exs
but no worker uses it (compile happens synchronously inside the
action; EmitProposalDiskUsageWorker uses :maintenance, the
snapshot worker uses :proposals). Drop the dead queue line; update
the foundation changelog entry to drop the stale reference.
Test plan: test/meridian/actions/generate_proposal_test.exs gains a
describe "validate_sections/3 (AST whitelist)" block with three cases:
(a) clean bodies return :ok and persist nothing; (b) a body with
#read("/etc/passwd") returns {:error, %{reason: :ast_invalid, section_id: "intro"}} and lands a rejected revision with the fragment
error in metadata; (c) the reducer halts on the first violation
(only one revision row, not two).
v0.69.0
Nouveauté
Meridian
Auth-gated GET /crm/proposals/:id/pdf route
Adds MeridianWeb.ProposalPdfDownloadController, mounted under the
authenticated [:browser, :load_user, :require_auth] pipeline next to
the existing /crm/proposals/:id/docx download. The route streams the
on-disk PDF artifact for a Flow 2 proposal, scoped to the caller's
current organization via Meridian.Proposals.fetch_for_org/2 — cross-
org access returns 404, as does a proposal that has not yet been
compiled.
Naming note: file is proposal_pdf_download_controller.ex to avoid a
filename collision with the pre-existing public-token-based
ProposalPDFController at /proposal/:token/pdf.
v0.69.0
Nouveauté
Meridian
Extract section bboxes from compiled Typst document
Walks the PagedDocument frame tree to find #metadata((kind: "section",
id: ...)) markers and emits JSON with their page + position. Layout
JSON is consumed by the Flow 2 editor to overlay HTML chips on top of
the PDF preview for hover-to-edit interactions.
v0.69.0
Nouveauté
Meridian
GenerateProposal Jido action for Flow 2 initial draft
Adds Meridian.Actions.GenerateProposal, a Jido action that generates
the initial Flow 2 (Typst) proposal draft from an opportunity + a
Meridian.Proposals.ProposalTemplate. Pipeline: freeze the variables
snapshot, ask Router (use_case proposal_edit, with proposal_id
metadata) for JSON-shaped section bodies via
chat_completion_json/3, render #section(id: ...)[body] markers,
prepend the preamble, compile via the Typst NIF, persist the PDF, and
write a ProposalRevision row tagged applied_by: "ai" /
accepted: true. Broadcasts {:compiled, hash} on
"proposal:<id>".
The action takes both a proposal_id and a template_id since the
existing crm_proposals table does not yet carry a template_id FK
to the new proposal_templates table — when that FK lands the call
collapses to one arg.
Registers the action's UI slot in Meridian.Agents.ActionMapping
under the proposal: entity (label, icon — module resolution happens
via the existing autonomy-rule lookup, not in this catalog).
Tests cover schema validation (org mismatch, incompatible flow_compat,
missing rows) and the :ai_disabled Router gate; this project does
not use Mox, matching the convention of proposal_assistant_test.exs.
v0.69.0
Nouveauté
Meridian
Schema for Flow 2 (revisions, comments, validations, templates)
Extends crm_proposals with Flow 2 columns (flow, typst_source,
variables_snapshot, pdf_artifact_path, pdf_compiled_hash, language,
downgraded_from_flow, downgraded_at) and creates 6 new tables:
proposal_revisions — append-only edit ledger for typst_source
proposal_comments — pin-anchored comments tied to section_id + char_range
Per-tenant scoping enforced via NOT NULL organization_id FKs on every
new table. The plan's status CHECK constraint is omitted: existing rows
already use values outside its narrow set (pending_approval, viewed,
changes_requested, accepted, rejected, expired) and Ecto.Enum on the
schema enforces validation at the application layer instead.
v0.69.0
Nouveauté
Meridian
Scaffold typst_compiler Rust crate (NIF stub)
First step of the Proposal v2 architecture foundation. Creates the
typst_compiler Rust crate with three NIF entry points (compile,
parse_section, patch_section) returning stubs. Body of each is filled
in by subsequent tasks. Pins typst* deps to a single version and
registers the crate via rustler_crates in mix.exs.
v0.69.0
Nouveauté
Meridian
Typst NIF compile/3 returning PDF + layout + hash
Wires the compile NIF to actually run typst::compile through
SandboxWorld, render to PDF via typst-pdf, SHA-256 hash the PDF, and
return all three (plus a stub layout JSON for Task 5) to Elixir.
Adds the Meridian.Proposals.Typst.Compiler wrapper module that loads
the NIF and exposes compile/3 with proper return shape, plus stubs for
parse_section/patch_section that Task 6 implements.
v0.69.0
Nouveauté
Meridian
Variables builder and computed snapshot (taxes per org)
Pure-function pipeline that turns a Flow 2 proposal (with its
opportunity, primary contact, company and line items preloaded) into the
raw variables map, then enriches it with subtotal_cad, per-rate taxes
and total_cad driven by organization.tax_config. The combined map is
the canonical input for Typst compile and the value persisted as the
proposal's variables_snapshot.
Adapted from the v2 plan to the real schemas: line items live on the
proposal (not the opportunity), the contact uses full_name /
preferred_locale, and the client company name comes from
opportunity.company.name.
v0.69.0
Nouveauté
Meridian
ValidateProposalConsistency Jido orchestrator with scope opts
Single Jido action that fans out to all six Flow 2 proposal
validators (3 Elixir-pure + 3 Router-driven), persists results to
proposal_validations, and broadcasts {:validations_updated, list}
on the per-proposal PubSub topic.
Schema: proposal_id, template_id (passed explicitly because
crm_proposals has no template_id FK yet — same convention as
Tasks 17+18), scope in [:elixir_only, :router_only, :all].
Fan-out via Task.async_stream/3 with a per-validator rescue so
one bad validator can't poison the run.
Persistence deletes prior unresolved rows before inserting, so
re-running doesn't double-stack (resolved/dismissed rows are kept
for audit).
Preload chain opportunity: [:primary_contact, meetings: :transcripts]
feeds all six validators with the data they need.
Also picks up a mix format whitespace fix on the Router-validations
test file.
v0.69.0
Nouveauté
Meridian
RecompileProposalTypst + ExportProposalPdf
Lightweight Jido actions for the auto-refresh worker (Task 15) and the
final-export pipeline.
RecompileProposalTypst is a pure recompile: it loads the proposal +
template, refreshes the template root's inputs.json from the
proposal's variables_snapshot, drives Typst.Compiler.compile/3
against the existing typst_source, persists the PDF, updates
pdf_artifact_path/pdf_compiled_hash, and broadcasts {:compiled, hash} on the per-proposal PubSub topic. It does NOT change
typst_source and does NOT insert a ProposalRevision — recompile is
not an edit. Mirrors the schema (proposal_id + template_id) and
error-handling shape of Tasks 17 and 18.
ExportProposalPdf is a thin composition over RecompileProposalTypst.
For MVP it propagates the result unchanged; future iterations will
also flip status to :sent and trigger the recipient email.
Both actions registered in Meridian.Agents.ActionMapping under the
:proposal slot.
v0.69.0
Nouveauté
Meridian
Sandboxed Typst World with root-restricted FS
Implements typst::World on SandboxWorld struct: sources/files resolved
through the configured root path, escapes rejected with
FileError::AccessDenied. Fonts loaded once from typst-assets at first
access (OnceLock-cached). Used by compile/3 NIF in Task 4.
v0.69.0
Nouveauté
Meridian
AST whitelist for IA-generated Typst fragments
Adds whitelist validator that walks the parsed Typst AST and rejects
any node whose SyntaxKind isn't in the allowed set, plus rejects FuncCall
to non-whitelisted callees. Core helpers (section, format_cad,
format_date) are always allowed; per-template helpers come from
variables_manifest.exposed_helpers. Used by the edit pipeline (Task 18)
to validate LLM-emitted fragments before patching them into a proposal
source.
Three Router-driven validators for Flow 2 proposals, each calling
Router.chat_completion_json/3 with use_case: "proposal_validation"
and proposal_id: id for ledger metadata, and parsing the structured
{found_issue, severity, message, source_refs} JSON contract.
RouterCheck — shared helper that wraps the Router call and
Sanitizer-wraps the user prompt.
PricingConsistency — extracts numeric tokens from
opportunity → meetings → transcripts.content (transcripts join via
meeting_id, not directly to opportunity) and asks the LLM whether
the snapshot pricing matches.
ScopeConsistency — synthesizes a qualification scope from
opportunity need, description, transcript_summary, and
transcript_requirements (no single qualification_scope column
exists) and compares against variables_snapshot["scope"].
LanguageConsistency — picks opportunity.locale_override ahead of
primary_contact.preferred_locale (the contact column is
preferred_locale, not language_preference) and checks against
the rendered Typst sample.
All three return [] on Router failure so a transient outage cannot
surface false-positive validation rows.
v0.69.0
Nouveauté
Router
Proposal_id metadata tag + new use_cases (proposal_edit, proposal_validation, template_analysis)
Tag ledger metadata with :proposal_id when callers pass it through
Router.chat_completion opts (Task 16, Proposal v2 plan).
Append three proposal-related use cases to the AI settings catalog:
proposal_edit, proposal_validation, template_analysis. Includes
matching icon/description helpers + EN/FR gettext entries.
Migration seed_proposal_use_cases inserts the three new rows for
every existing organization with on_conflict: :nothing.
v0.69.0
Nouveauté
Meridian
Ecto schemas for Flow 2 (proposal, revision, comment, validation, template)
Adds Flow 2 fields to the existing Meridian.CRM.Proposal schema and
introduces six new schemas under Meridian.Proposals.* for the new
Flow 2 tables.
Meridian.CRM.Proposal (extended in place):
new fields: flow, typst_source, variables_snapshot,
pdf_artifact_path, pdf_compiled_hash, language,
downgraded_from_flow, downgraded_at
validate_inclusion(:flow, [1, 2])
validate_flow_2_required_fields/1 — when flow == 2,
typst_source and variables_snapshot are required
(no-op for Flow 1, preserving existing changeset behavior)
:archived added to the @statuses Ecto.Enum
v0.69.0
Nouveauté
Meridian
ProposeProposalEdit with AST + compile retry
Section-scoped Jido action for editing one #section(id: ...) of a
Flow 2 (Typst) proposal. Pipeline:
Extract section body (Parser.extract_section/2).
Ask Router (use_case proposal_edit) for a new fragment.
AST-validate against the template's whitelist
(variables_manifest["exposed_helpers"]). Retry once with the
prior error appended to the prompt; persist a failure
ProposalRevision (error_kind: "ast") and return
{:error, %{reason: :ast_invalid}} if both attempts fail.
Patch + compile, retrying once on transient compile_failed;
persist a failure revision (error_kind: "compile") and return
{:error, %{reason: :compile_failed}} if both attempts fail.
On success, persist the PDF, update the proposal row, insert
an accepted ProposalRevision, and broadcast {:compiled, hash}.
Hard cap: max 2 LLM calls per AST stage, max 2 compile attempts.
Also adds Meridian.Proposals.Typst.Compiler.validate_fragment/2 —
NIF wrapper exposing crate::whitelist::validate_fragment so the
action can run the same allowlist gate the compile path enforces, but
on a raw fragment instead of a full source. Returns :ok or
{:error, kind, detail} with kind one of "forbidden_kind",
"forbidden_func", "parse_error".
Tests follow the project's no-Mox convention (cf.
generate_proposal_test.exs): the LLM call is exercised through the
:ai_disabled early-exit path, and the AST whitelist is tested
directly against the new NIF (clean fragment, core helper, forbidden
function, let binding, per-template helper allow/deny). Two-call
retry semantics are covered by the unit tests on validate_fragment
plus the action's pipeline shape; full two-call sequence belongs in
an integration suite gated on a network-bearing tag.
v0.69.0
Nouveauté
Meridian
Typst section parser/patcher NIF + Elixir wrapper
Replace the parse_section/2 and patch_section/3 NIF stubs with a real
AST-based span finder under native/typst_compiler/src/sections.rs and
expose them via lib/meridian/proposals/typst/parser.ex with
extract_section/2, patch_section/3, and a regex-based list_section_ids/1
for UI dropdowns. Pure-syntax operations -- no compile -- so they're cheap
to call from edit-pipeline LiveViews and Jido actions.
Implementation note: walks the parsed tree with typst_syntax::LinkedNode
to get absolute byte offsets via range() instead of the manual
offset += child.len() accumulation hinted at in the design plan. The
trailing #section(id: "x")[body] content block is parsed as a child of
the FuncCall's Args wrap (per typst-syntax 0.13.1 parser::args), so the
finder descends one level into Args to locate it.
v0.69.0
Nouveauté
Meridian
Auto-refresh variables_snapshot on opportunity update
Wire the Flow 2 snapshot pipeline end-to-end so any change to a CRM
opportunity propagates to its in-flight proposals:
Meridian.Proposals.freeze_snapshot/1 and
refresh_snapshot/1 (re)compute the proposal's
variables_snapshot from the current opportunity state and
broadcast :variables_refreshed on proposal:<id>.
Meridian.Proposals.SnapshotListener GenServer subscribes to the
new "opportunities:updated" PubSub topic and enqueues a
Meridian.Workers.RefreshProposalSnapshotWorker for every Flow 2
proposal still in :draft or :pending_approval on the touched
opportunity (approved/sent/etc. proposals are deliberately left
alone — their snapshot is locked).
Meridian.CRM.Sales.update_opportunity/2 now broadcasts
{:opportunity_updated, id} on success.
New :proposals Oban queue (concurrency 4) hosts the worker.
SnapshotListener wired into the supervision tree after the agent
layer (Phoenix.PubSub + Oban already up by then).
v0.69.0
Nouveauté
Meridian
Filesystem storage module with org-scoped paths
Introduces Meridian.Proposals.Storage, a thin wrapper over File.*
that gives proposal templates and compiled PDFs a stable, org-scoped
on-disk layout. Single Docker volume host-mount, no S3 abstraction.
Test config points the root at a unique tmp dir per run.
v0.69.0
Nouveauté
Meridian
Tax_config jsonb column with default TPS+TVQ
Adds tax_config (jsonb) to organizations with a Quebec-default of
TPS (5%) + TVQ (9.975%). Flow 2 proposals read tax rates from this
per-org config when computing line-item totals.
The default is set via execute rather than add :col, :map, default:
because Ecto's add macro does not reliably serialize a nested Elixir
map literal to a Postgres JSONB default; using a SQL JSON literal is
explicit and adapter-agnostic. Existing rows are backfilled.
v0.69.0
Nouveauté
Router
Per-organization Router configuration
Router now supports per-tenant configuration for the settings that
enterprise customers need to control themselves:
Bring-your-own OpenRouter key (BYOK). Organizations can pin their
own OpenRouter API key from Router → Settings → AI & Models →
Configuration. When set, Router calls bill against that account
instead of the platform default. Stored encrypted at rest; the UI
shows "Configured" / "Not configured" without revealing the key.
Custom rate limits. Super admins can override the per-org
requests-per-minute ceiling from Admin → Organizations. Leaving the
field blank uses the tier default (30 rpm free, 120 prepaid, 600
postpaid/enterprise) — the form now shows the active default in the
placeholder.
Per-org model overrides. From Router → Admin → LLM Models, super
admins can open the new "Per-org overrides" drawer to whitelist a
globally-disabled model for one organization, blacklist a globally-
enabled one, or reclassify the billing tier for that customer. A
filter input narrows the model list as the catalog grows.
Detect skills whose required_actions reference unimplemented modules and
surface them as "Coming soon" in the UI; SkillExecutor short-circuits
execution with {:error, {:coming_soon, missing}} instead of crashing
Notify ai_access admins (in-app, deduped 24h) and render a "Setup
pending" card on /agents when background workers find no agent owning
an action they need
Tag credit_ledger_entries metadata and Stripe meter events with
api_key_id and user_id to enable per-key cost audit
Strip stale fuzzy flags from 76 AI-perimeter gettext entries and queue
the rest as tech debt in TODO.md
v0.69.0
Correctif
Meridian
Repair 4 test clusters + 2 production bugs
Cluster A (production bug): Meridian.Actions.QueryMessages and QueryTraces
were ordering by m.inserted_at, but the AgentMessage and AgentTrace schemas
expose a custom :created_at field and do not call timestamps(). Both queries
crashed at runtime with ERROR 42703 (undefined_column). Switched the order_by
clauses to :created_at. Also pinned the trace ordering test setup to use
explicit, separated created_at values, since :created_at is naive_datetime
(second resolution) and rapid back-to-back inserts shared a timestamp,
making ordering non-deterministic.
Cluster B (mailer refactor): Meridian.CRM.Billing.InvoiceMailer and
Meridian.CRM.Emails were refactored to expose only render_*/1 functions;
sending now goes through Meridian.Organizations.EmailDispatch. Rewrote the
two affected test files to call render_invoice_email/1 and
render_confirmation/1 and assert on %{subject, body_html, text_body, ...}
instead of using assert_email_sent/Swoosh test assertions. The "email is
sent to the correct recipient" test was reframed as "rendered output
references the recipient company" since recipient resolution moved to
EmailDispatch.
Cluster C (LiveView permission gates): a new MeridianWeb.PermissionLiveSession
on_mount hook enforces an @permission module attribute on each protected
LiveView. Updated the test conn_case.ex register_and_log_in_user/1 helper to
also create a per-test role containing every seeded permission and assign it
to the test user. This unblocks every authenticated LiveView test that
previously redirected to / with "You don't have permission...". Verified one
test from each affected LiveView module renders.
Cluster D edge cases:
Meridian.Backups.Encryptor.decrypt/2 length guard relaxed from > to >=
iv+tag size so that empty-plaintext roundtrips work (a legitimate case;
AES-256-GCM with no payload is still a valid 28-byte ciphertext).
Meridian.GuardTest custom_patterns assertion now matches by prefix instead
of equality, since the regex error message gained a ": missing terminating
]..." suffix.
BookingLive test for the pre-selected slot now asserts the design token
border-[var(--color-primary)] instead of the legacy border-blue-500 class.
Meridian.Actions.ResearchCompany not-found test now uses a guaranteed-
missing positive id and passes agent: nil in context so we reach the
CRM.get_company! call (which is the path under test) instead of crashing
earlier on context.agent.
v0.69.0
Nouveauté
Router
Streaming hardening + strict error shape
C1: fall back to token-based cost estimate when OpenRouter omits
usage.cost in the final SSE event; warn if both cost and usage are
missing.
C10: error responses uniformly include OpenAI-compat shape
{error: {message, type, code, param}} with param always present
(nil when N/A).
C11: emit SSE keep-alive comment every 30s during streaming to keep
intermediate proxies from closing slow streams.
C12: bound SSE parser buffer to prevent unbounded growth on malformed
upstream events; abort with :sse_buffer_overflow on overflow.
C13: move streaming state out of the process dictionary into an
explicit accumulator for reentrancy safety.
mix precommit green.
v0.69.0
Refactorisation
Meridian
Migrate CRM AI to Jido actions; kill ProposalDrafter & WritingAgent
Replaces direct Router calls from CRM LiveViews and workers with Jido
action dispatch. CRM AI features now run through the agent runtime,
producing agent_traces rows and respecting autonomy rules.
v0.69.0
Amélioration
Meridian
Agents: 'Coming soon' skills and setup-pending alerts
Two improvements to make the agent surface honest about what it can actually
do for your organization:
'Coming soon' skills. Template-seeded skills that depend on actions
not yet implemented are now shown with a "Coming soon" badge in the
skills library and on the skill detail page (with the missing actions
listed). The Run-now button is disabled for these skills, and triggers
that fire them are short-circuited with an informative log instead of
silently erroring.
Setup-pending alerts. When a background event fires (qualification
scoring, transcript extraction/summary, opportunity insights, company
research) and no active agent in your organization owns the matching
action, admins now get an in-app notification (deduplicated to one per
action per 24h) and a "Setup pending" card on the Agents dashboard
listing every unassigned platform action.
v0.69.0
Nouveauté
Router
Customer-facing API keys management + public pricing page
C7: /router/settings/api-keys LiveView for org users to create,
revoke, and audit usage of their Router API keys. Plaintext shown
once on creation; rest of the time only prefix is visible.
Permission: router_api_keys_manage. Sidebar entry added.
C9: /router/pricing public LiveView with per-model pricing table
(CAD primary, USD secondary, includes platform fee) and an
interactive cost estimator using CostEstimator.estimate/3. Mounted
in the public marketing live_session.
mix precommit green.
v0.69.0
Nouveauté
Router
Per-org configuration (BYOK key, rate limit, model overrides)
C2: confirmed pre-existing — guard_policies table + Pipeline already
per-org (created in earlier P5 work). Settings_guard_live UI already
exposes strict_mode toggle, detector controls, custom patterns and
allowlist editor; no schema or pipeline changes needed.
C4: organizations.openrouter_api_key_override (encrypted via
Meridian.Encrypted.Binary); Router.get_api_key/1 prefers per-org BYOK
over Platform.openrouter_api_key over Application env. Added test
seam Router.test_resolve_api_key/1. settings_ai_live shows
Configured / Not configured status without revealing the key; "clear"
sentinel removes the override.
C5: organizations.rate_limit_rpm (nullable); RateLimiter.resolve_limit/1
returns explicit override → tier default by billing_mode (free 30,
prepaid 120, postpaid/enterprise 600) → 60 fallback. Admin
organization edit form gets a number input with placeholder showing
the current tier default.
C6: org_model_overrides table + OrgModelOverride schema; LlmModel
gains list_active_for_org/1 + list_all_for_org/1 that LEFT JOIN
overrides. Billing.resolve_model now consults the org-aware list so
per-org blacklists/whitelists take effect across explicit model_id,
agent.llm_model_id, use_case, and org default paths. Router admin
LLM Models page gains a "Per-org overrides" drawer with org picker,
filter input, per-model effective enabled toggle, tier override
select, and reset button.
EN+FR gettext translations added for all new strings.
Use Application.spec instead of Mix.Project in release
Mix is not available at runtime in an Elixir release, so calling
Mix.Project.config()[:version] inside a migration crashes the boot
on production deploys (UndefinedFunctionError) and aborts every
subsequent pending migration. Read the version via Application.spec/2,
which works in both dev and release.
v0.69.0
Nouveauté
Meridian
Polish agents UX + CRM AI-touching LiveViews
D — Agents:
D5: trigger outcome detail (last_fire_outcome + last_fire_reason)
surfaced in triggers UI; structured outcomes (executed, agent_inactive,
skill_archived, filter_mismatch, no_owning_agent, error) with hover
tooltip showing the human-readable reason
D6: human inbox :retry resolution mode — re-dispatches the original
action via JidoAgent.submit_action; UI button next to Approve/Reject
D7: org-level autonomy_learning_mode flag (opt-in). When enabled,
AutonomyServer auto-promotes escalate to propose_first after N
consecutive successful runs (default 5, configurable per org via
autonomy_learning_threshold). Hooked into SkillExecutor success path.
Toggle exposed in admin organizations settings.
D8: implement triggers-using-this-skill list (was Task 23 placeholder)
D9/D10: gettext + design tokens in agent_chat_live (replaced bg-gray-,
text-gray- with var(--surface-), var(--text-); added Send message
aria-label)
D11: surface model save errors in agent_constitution_live with
changeset.errors translation and inline
below the model select
D12: explain "Skill library coming soon" with helper text + lock icon
for clearer deferred-feature signal
D14: weekly digest skeleton card shown while LiveView is not yet
connected
E — CRM:
E2: cancel button for AI rewrite during generation; cancel_ai_rewrite
event uses cancel_async on both :ai_rewrite and :ai_slash_command tasks
E3: stop button for docx composer; ProposalDocxComposer.cancel/1 sets
a :persistent_term flag the forwarder loop checks; PubSub :cancelled
event lets the LiveView reset its UI immediately
E4: cost display in docx progress UI (estimated CAD spent based on
cumulative token count)
E6: design tokens in opportunities/modals (no more bg-blue-100 /
bg-gray-100 / dark:bg-* duplication)
E7: gettext on opportunities/modals raw English strings
[E10: streaming for chat/rewrite — skipped per plan]
v0.69.0
Refactorisation
Router
Split Router from CRM AI; rename URLs; add safety fixes
Move Router web modules to lib/meridian_web/live/router/ +
lib/meridian_web/live/router_admin/ + lib/meridian_web/router/
Move tests to test/meridian/router/{billing,guard}/ and
test/meridian/router_test.exs etc.
Add @moduledoc to llm/embeddings/models controllers identifying them
as Router product API.
URL renames + sidebar Router group:
/settings/ai → /router/settings/ai
/settings/guard → /router/settings/guard
/admin/llm-models → /router/admin/llm-models
301 redirects from old URLs via MeridianWeb.RedirectController
(remove after one release of grace).
Settings sidebar gains a "Router" group containing AI Settings,
Guard, and Models Catalog (super-admin only). active_page values
renamed accordingly: ai_settings → router_ai_settings,
guard_settings → router_guard_settings,
admin_llm_models → router_llm_models.
/settings/billing-credits not currently routed → no rename needed.
Safety fixes:
B1: CostEstimator returns {:error, :unpriced_model} for unknown
models (no synthetic 0.001/0.002 fallback). Router gateway gains
ensure_priced/1 step before reservation; chat_completion,
chat_completion_stream, and embed all surface the error.
llm_controller + embeddings_controller return 422 with
OpenAI-compat shape (code: "unpriced_model", param: "model").
B2: embeddings_controller returns 422 (was 412) for guard halts
with OpenAI-compat shape exposing only the high-level category
names — never regex source or matched substring.
B3: Confirmed input halt skips reservation/debit (the with-chain
short-circuits before run_with_reservation) and writes a
halted: true audit row via record_halt_audit. Fixed a latent
String.Chars crash in record_halt_audit when called from
chat_completion (messages list now serialized via
serialize_messages/1 before audit insert).
Tests added:
Meridian.Router.Billing.CostEstimatorTest now asserts
{:error, :unpriced_model} for unknown models.
Meridian.RouterTest covers chat_completion unpriced rejection and
guard halt no-debit / audit-row invariant.
Meridian.RouterEstimateTest renamed and updated for :unpriced_model.
LlmControllerTest gains 422 unpriced model integration test.
New EmbeddingsControllerTest covers guard halt 422, unpriced 422,
missing input 400, and 401 without auth.
CLAUDE.md updated: AI architecture table now reflects new paths;
new forbidden rule blocks direct Router.Billing imports outside
Router product code.
Surgical drift fixes across 17 test files plus one production fix.
context_resolver: replace map[:key] access with Map.get(map, :key) so
Ecto schema structs (which don't support [] access) work correctly.
Real bug surfaced by agents_jido_test.
crm_clients (11): selector drift after action_button migration.
crm_proposals_live + crm/proposals: align with require_proposal_approval
default; set false in test fixtures where pre-approval flow is intended.
crm_opportunities (8): assertions updated for drawer-based Intelligence
panel and design-token buttons.
dashboard (5): follow redirect to /dashboard, update section names.
organizations: use new ApiKey API, update constraint name and
log_api_key_usage return shape.
crm_projects: assert on phx-click selector instead of localized button
label (gettext drift).
Big-bang removal of dead/deprecated AI code paths after the move to a
Router-only LLM gateway.
Delete Meridian.AI.OpenAIClient (no production callers; only ModelCache used it)
Delete Meridian.AI.ModelCache (zombie supervised child, no callers)
Drop openai_api_key, openai_workspace_id, ai_system_prompt columns from
organizations table; remove BYOK form fields from admin/settings UIs.
Migration: priv/repo/migrations/20260426034202_drop_byok_columns_from_organizations.exs
Delete Meridian.Agents.AgentProcess (replaced by JidoAgent; no callers)
Standardize JidoAgent.submit_task signature on {org_id, slug}; add
submit_task_by_id/2 helper for callers that only have an agent UUID;
fix chat_server.ex which was passing a bare agent_id.
mix precommit green.
v0.68.0
Nouveauté
Meridian
AI rewrite Word templates with full opportunity context
Replace the placeholder-token flow with a single AI pass that sees the whole
template plus the full proposal/opportunity context (company, contact,
discovery, transcripts, line items, instructions) and decides per paragraph
whether to keep, rewrite, or delete. Operations are applied via python-docx
so layout, tables, headings and styles are preserved. Streaming progress is
broadcast on Phoenix.PubSub so the proposal detail view shows live phases
and a token counter while generation runs.
Also fixes the per-chunk "No x-openrouter-cost header" warning by asking
OpenRouter to include usage in the SSE stream and demoting the missing-header
log to debug — cost is now reported accurately for streamed completions.
Removes the two-step tokenize-then-fill approach (TemplateTokenizer,
Docx.tokenize/3, original_file_path column, modal "Upload PDF" / "Import as
Draft" tabs) which produced inconsistent results.
v0.68.0
Nouveauté
Meridian
AI rewrites Word proposals from your templates
Generating a Word proposal now uses a single AI pass over the entire template
with full opportunity context — company, contact, discovery, transcripts,
internal notes, line items, and any extra instructions. The model decides per
paragraph whether to keep, rewrite, or delete, so finished-proposal templates
work as inspiration: layout, tables, headings and styles are preserved while
mandate-specific paragraphs are personalized for the client.
The proposal detail panel now shows live progress while generation runs —
preparing, writing, applying — with a token counter so you can see the AI
working in real time.
v0.67.0
Nouveauté
Meridian
Add agent_skills join table
v0.67.0
Nouveauté
Meridian
Trigger schema + Triggers context with filter predicates
Surfaces the latest WeeklyDigest (reclaimed hours, run count, override rate,
WoW delta, narrative highlights, needs-attention) at the top of the Agents
Dashboard, falling back to a friendly placeholder when no digest exists yet.
v0.67.0
Nouveauté
Meridian
Skills library LiveView
Introduces AgentsSkillsLive at /agents/skills with filter chips (All /
Template / Custom / per-agent), search, and a SkillCardComponent-based
grid. Whole cards link to /agents/skills/:slug (Task 14 target).
v0.67.0
Nouveauté
Meridian
Gettext + changelog entry for Weekly Digest
v0.67.0
Nouveauté
Meridian
Backfill task for existing orgs with templates
v0.67.0
Nouveauté
Meridian
Add Skill schema
v0.67.0
Nouveauté
Meridian
Seed template triggers bound to template skills
v0.67.0
Nouveauté
Meridian
Digest composer worker (email wired in Task 27)
v0.67.0
Nouveauté
Meridian
Add SkillRuns context with weekly rollup
v0.67.0
Nouveauté
Meridian
Thread skill_id into JidoAgent traces
v0.67.0
Nouveauté
Meridian
Skills/0 callback on all three templates
v0.67.0
Nouveauté
Meridian
Add SkillExecutor wrapping JidoAgent.submit_task
Bridges named Skills to JidoAgent: renders {{param}} templates in
instructions, submits the task to the agent GenServer (starting it via
AgentSupervisor if needed), and persists the result as a skill_runs row
with outcome, duration, tokens, and trace_ref. Wraps the GenServer call
in try/rescue/catch so a missing or misbehaving agent process still
produces a skill_run with outcome="error" instead of crashing the
caller. Broadcasts {:skill_run_completed, run} on the org topic and
enqueues the (stub) SkillRunJudgeWorker for Task 9.
Also adds the Noop test action and a stub judge worker using the
:default queue until the :agents queue is introduced in Task 9.
v0.67.0
Nouveauté
Meridian
Triggers table + skill_runs.trigger_id FK
v0.67.0
Nouveauté
Meridian
Gettext + changelog entry for Triggers
v0.67.0
Nouveauté
Meridian
Weekly_digests table + schema
v0.67.0
Nouveauté
Meridian
Weekly digest email
Adds Meridian.Agents.Emails.DigestEmail builder (Swoosh) and wires it
into DigestComposerWorker so the weekly digest is delivered to all org
users after the narrative skill runs. Marks the digest email_sent_at
stamp once after a successful pass.
v0.67.0
Nouveauté
Meridian
Wire @-mentions on CRM rich-text surfaces
Task 32 (Agents v1.0): hooks up the Phase 4 @-mention infrastructure
(AgentMention JS hook + AgentMentionComponent picker) to rich-text
surfaces across the CRM.
Wired with hook attributes (phx-hook + data-entity-type/id + .agent-ready wrapper):
agent_mention_run_skill → SkillExecutor.execute/3 with mention_context
The picker is conditionally mounted next to the opportunity detail view.
No-op catch-alls added to CRMClientsLive and MeetingDetailLive so
users typing @ in those notes fields don't crash the LV while their full
picker wiring is deferred to a future task. CRMProposalsLive already
has a broader catch-all that absorbs the events.
Skipped surfaces:
projects/detail_components.ex — no rich-text notes field to wire
public/discovery_live.ex — public-facing, no authenticated context
v0.67.0
Nouveauté
Meridian
Add skill_runs table and schema
v0.67.0
Nouveauté
Meridian
Seed template skills and attach to default agents
v0.67.0
Nouveauté
Meridian
Gettext + changelog entry for Skills
v0.67.0
Nouveauté
Meridian
EventBus + CRM event broadcasts for triggers
Adds Meridian.Agents.EventBus, a GenServer that subscribes to the
"crm:events" PubSub channel and fires matching crm_event triggers via
SkillExecutor. CRM contexts broadcast events on successful mutations:
invoice_paid (CRM.Billing.Payments.record_payment/1, only
when the status transitions to :paid)
v0.67.0
Nouveauté
Meridian
Triggers LiveView + drawer with natural-language cron
v0.67.0
Nouveauté
Meridian
Add skills table
v0.67.0
Nouveauté
Meridian
Telemetry events for skill runs, triggers, digest, mentions
v0.67.0
Correctif
Meridian
Address pre-merge review findings
Gate TriggerCronWorker + EventBus on agents_v1_enabled via Triggers query joins
Gate DigestComposerWorker on agents_v1_enabled
Zero reclaimed_minutes on error-outcome skill_runs
Parse digest narrative from AgentTrace.decision, not SkillRun.decision
Add from: :binary_id to skill_runs.trigger_id modify for rollback safety
Tenant-scope list_skills_for_agent and EventBus/TriggerCronWorker skill loads
Replace silent no-op with info flash on non-opportunity mention surfaces
v0.67.0
Nouveauté
Meridian
Reclaimed-minutes judge with Oban worker
v0.67.0
Nouveauté
Meridian
Agents_v1_enabled feature flag gates new UI surfaces
v0.67.0
Nouveauté
Meridian
Add /agents/skills routes and nav highlight
v0.67.0
Nouveauté
Meridian
TriggerCronWorker fires cron-kind triggers every minute
v0.67.0
Nouveauté
Meridian
AgentMentionHook + AgentMentionComponent picker
Adds the primitives for @-mention agent/skill picker in rich-text surfaces:
JS hook detects @ + partial slug in textareas / contentEditable and
pushes agent_mention_picker_open / _close to the host LiveView.
LiveComponent renders a popover listing active agents and their skills
filtered by query, with events targeted at the host LV.
Host wiring will follow in Task 32 (rich-text surfaces).
v0.67.0
Nouveauté
Meridian
Skill editor LiveView with Run now modal
Implements Task 14 of Agents v1.0: MeridianWeb.Agents.AgentSkillLive
editor for individual skills, supporting both create (slug == "new")
and edit flows. Includes a Run-now modal that lists the skill's
parameters_schema and dispatches SkillExecutor.execute/3 with the
collected params. Also supports attach/detach to agents, archiving,
and shows recent skill_runs.
Fixes a latent bug in Skills.update_skill/2 where the template→custom
source flip produced a mixed atom/string-key map (rejected by
Ecto.Changeset.cast) when invoked from LiveView forms.
v0.67.0
Nouveauté
Meridian
Agents v1.0 — Skills, Triggers, Weekly Digest, and @-mentions
Your agents just got four new powers:
Skills — reusable multi-step workflows. Each template ships with ~6 pre-built skills; add your own or tune the defaults.
Triggers — run skills on a cron schedule, on CRM events (new opportunity, proposal signed, invoice paid), or anticipatorily (30 min before a meeting, 7 days before an invoice is due). The CRM is the event source — no connectors needed.
Weekly Digest — every Monday, see how much time your agents saved you, written by an agent itself.
@-mentions — type @Scout in any opportunity, client, proposal, or meeting note. The agent picker opens inline; pick a quick-run skill to fire it with the surrounding entity as context.
Turn it on from Org settings → Agents v1.0.
v0.67.0
Nouveauté
Meridian
Triggers — fire skills on cron, CRM events, and anticipatory windows
Your skills now run on their own.
Cron triggers — schedule skills with natural-language or raw cron (Monday 9am, every weekday at 8am, etc.).
CRM event triggers — fire when a new opportunity lands, a proposal is signed, an invoice is paid, or a meeting is booked. Optional event filter DSL (e.g. "unless source is referral", "when score ≥ 80") narrows the fire condition.
Anticipatory triggers — pre-computed time-relative events like meeting_30m_before and invoice_due_in_7d fire on their own.
Each industry template ships with 5 seeded triggers wired to the default skills. Turn them off or tune them in /agents/triggers.
v0.67.0
Nouveauté
Meridian
Skills — reusable multi-step workflows for your agents
Agents now run Skills: named, reusable workflows that chain tool calls and LLM reasoning. Each industry template ships with a pre-built skill library — attach them to agents, tune them, or author your own.
Next up in this release: Triggers to fire them automatically, a weekly digest of reclaimed hours, and @-mentions to invoke them from any page.
v0.67.0
Nouveauté
Meridian
@-mention agents from any note — run skills in context
Type @ in any note, comment, or proposal draft to invoke an agent right where you're working.
Mention an agent — @Scout opens a picker with quick-run skills scoped to the current entity.
Run a skill with context — one click fires the skill with the surrounding opportunity/client/meeting as auto-context.
Stays in flow — no page jump, no tab switch. The agent replies inline.
Wired surfaces in v1: opportunity discovery notes, client notes, proposal notes, meeting notes. More surfaces land in v1.1.
v0.67.0
Nouveauté
Meridian
Weekly Digest — your agents' impact, every Monday morning
Every Monday morning, the Weekly Digest lands in your inbox — and on your Agents dashboard.
Reclaimed hours: how many minutes of human work your agents saved this week, LLM-judged per run.
Three wins: a short narrative of the biggest impact, written by an agent.
Needs attention: errors, escalations, and override spikes that deserve a look.
Per-agent rollup: who did what, in one table.
Tune the schedule or turn the digest off in Agents → Skills → compose-weekly-digest.
v0.65.1
Correctif
Meridian
One-shot popup via ETS + amount field on new invoice
changelog: stop auto-marking the popup seen on mount (previous fix
flashed the modal then dismissed it). Instead, an in-memory
ShownCache records {user_id, version} the first time the popup
renders, and subsequent LV mounts in the same BEAM run skip
recomputing entries. The DB flag (last_seen_app_version) is still
only written when the user explicitly dismisses, so a restart or
re-login without dismiss will surface the popup again.
invoices: add optional "Amount" field to the New Invoice modal. When
set, a single "Services" line item is created alongside the invoice
so users don't have to create the invoice first and then add a line
item. Field only shows on new invoices (not edit).
v0.65.1
Correctif
Meridian
Tiebreak same-day entries by version descending
Meridian.Changelog.all/0 sorted entries by date only, so on /changelog
a day with 20+ entries spanning multiple releases (like today's v0.64.4
through v0.65.0 burst) rendered in whatever order NimblePublisher handed
them back — versions appeared interleaved (v0.64.5 next to v0.65.0 next
to v0.64.2) which read as broken.
Use a (date desc, version desc) comparator. Within a day, unreleased
entries (nil :version) bubble above released ones so in-progress work
stays visible when a shipped version lands the same day.
Expose Changelog.sort/1 so the two filtered sort sites in Unseen
(filter_trigger/2 and all_unread/2) share the canonical ordering
instead of re-sorting by date alone and re-introducing the bug for
the login popup and avatar unread modal.
v0.65.0
Correctif
Meridian
One-shot popup + invoice form input bugs
changelog: mark last_seen_app_version as soon as the popup shows so it
doesn't re-appear on every page navigation. Dismiss button is now
strictly for closing the on-screen modal. Also short-circuit
trigger_entries when user is already caught up.
invoice modal: tax rate was exponentially growing on each phx-change
because validate_invoice cast the raw "13" percent value as a fraction,
then the re-render multiplied by 100 for display. Route validate_invoice
params through maybe_convert_tax_rate to match save_invoice.
line-item modal: unit_price wasn't a schema field (schema uses
unit_price_cents) so the changeset silently dropped it on validate,
making it impossible to type an amount. Route validate_line_item
through convert_line_item_params.
harden maybe_convert_to_cents / maybe_convert_tax_rate to use
Float.parse / Decimal.parse so partial/integer input doesn't crash.
v0.65.0
Nouveauté
Meridian
Add wrap_keys migration task for existing raw DEKs
v0.65.0
Nouveauté
Meridian
Write v2 (envelope-encrypted) backup files
v0.65.0
Nouveauté
Meridian
Add Encryptor.wrap_dek/unwrap_dek for envelope encryption
v0.65.0
Nouveauté
Meridian
Importer auto-detects v2 files and uses embedded DEK
v0.65.0
Nouveauté
Meridian
Add v2 file format helpers (encrypt_file_v2, decrypt_file_v2, file_version)
v0.65.0
Nouveauté
Meridian
Add MasterKey module for loading the master backup key
v0.65.0
Correctif
Meridian
Warn when user id collisions will silently drop backup users
v0.65.0
Correctif
Meridian
Rename leftover account_* constraints, indexes, and sequences
These survived the accounts -> organizations table rename. Postgres
identifies them by OID so they kept working, but they produced
misleading errors (account_users_user_id_fkey on FK violations) and
broke code that looked up names statically (e.g. pg_get_serial_sequence
still returned accounts_id_seq).
v0.65.0
Correctif
Meridian
Importer INSERTs missing org for DR; updates all fields
Adds an INSERT path when the target organization row is absent (bare-DB
disaster recovery). Looks up the sequence name via pg_get_serial_sequence
so it survives the legacy accounts_id_seq name.
Replaces the four-field hand-picked update with a full-attribute update
so slug and other fields are correctly restored onto an existing org.
v0.65.0
Nouveauté
Meridian
Add bootstrap_super_admin mix task for DR
v0.65.0
Nouveauté
Meridian
Route DEK through wrap/unwrap at context boundary
Wraps every per-org DEK with the master key at rest in backup_storage_configs
and exposes Backups.fetch_dek/1 for callers that need the raw DEK.
v0.65.0
Correctif
Meridian
Filter orphan organization_users and user_roles on restore
v0.65.0
Nouveauté
Meridian
Add DR restore mix task
Scans a directory of .enc files, groups by organization, applies the
configured strategy (latest-per-org or all-in-order), and restores each
through the importer. v1 files without the MRDN magic are logged and
skipped since they cannot be DR-recovered without the DB DEK.
v0.65.0
Nouveauté
Meridian
Require BACKUP_MASTER_KEY at boot in prod
v0.65.0
Correctif
Meridian
Reject non-integer organization_id at importer entry point
v0.64.6
Nouveauté
Meridian
Style agent errors/escalations with distinct colors
Previously every agent reply rendered with the same neutral sunken
bubble, even when the underlying task outcome was "error",
"rejected", "escalated", or "proposed". An insufficient_credits
failure landed as %{decision: %{"error" => "insufficient_credits"}, outcome: "error"} inspected into the chat, blending in with a
normal response.
ChatServer.spawn_agent_response now runs each JidoAgent result
through format_agent_result/1:
outcome: "error" → human-readable text + warning glyph, stamps
metadata.error = true, metadata.error_reason.
Known reasons (insufficient_credits,
ai_disabled, budget_exceeded) get friendly
copy; others fall through.
outcome: "rejected" → same, carries the guardrail reason.
The drawer's message_classes/2 now reads that metadata: error/rejected
render in the danger soft surface, escalated/proposed in warning soft,
everything else keeps the neutral sunken look. Helpers tolerate both
atom and string keys because we serialize the map through the DB and
back.
v0.64.6
Amélioration
Meridian
Realistic reservation estimate instead of flat $5 floor
estimate_reservation_cents used a max(cost_cad, 500) floor — $5 CAD
reserved on every LLM call regardless of model or prompt size. Nano
models actually cost 1-2¢ per call, so the reservation was 500× the
settlement. With parallel agents (suggest_actions runs async_stream
with concurrency 4) this effectively locked $20 of credit during a
burst for calls that settled to pennies, starving anything else on
the same org balance.
Keep the worst-case estimate (prompt + max_tokens × pricing) and
apply a 1.5× safety buffer for tokenizer drift, then clamp to a
sensible $0.10–$100 range. Per-call overhead like ledger writes and
markup rounding still has headroom, but we stop over-reserving by
three orders of magnitude.
chat_server: match raw map returned by JidoAgent.submit_task so successful
responses run through format_agent_result instead of inspect-dumping the
decision map into the drawer
ai-drawer: humanize legacy raw inspect dumps already persisted in
conversations and apply error/escalated colors to content-sniffed matches
ai-router: drop reservation estimate from 1.5× to 1.25×, floor 10¢ → 2¢,
and assume 300 completion tokens by default (was 1000) so short chats
reserve a few cents instead of ~$0.50
v0.64.6
Correctif
Meridian
Emit OpenAI-shaped tools for the chat LLM call
Two wire-format mistakes caused the streamed chat completion to crash
with "Jason.Encoder not implemented for type Function":
build_tools/1 passed Jido.Action.Tool.to_tool/1's raw map through
to the router. That map embeds function: &execute_action/3 — a
captured handler used for local dispatch, not for serialization.
Jason choked on the function reference when encoding the request
body. Project the Jido shape into OpenAI's
{"type": "function", "function": {name, description, parameters}}
envelope and drop the handler.
HandoffManager.handoff_tools/1 built a flat map with name/
description/parameters at the top level. OpenAI/OpenRouter require
those under a nested "function" key alongside "type" — without the
wrapper the API would reject the call even if Jason had succeeded.
Tool execution on our side still happens via the module lookup
(build_tools knows the Elixir module behind each tool). The LLM only
needs the schema, so exposing just the schema is correct and safe.
v0.64.5
Correctif
Meridian
Avoid DynamicSupervisor deadlock on first drawer open
AgentSupervisor.start_agent/1 starts the JidoAgent via the same
DynamicSupervisor that owns the ChatServer. Calling it from inside
ChatServer.init/1 means the supervisor is already busy servicing the
ChatServer's own start_child request and can't accept the nested
JidoAgent start — GenServer.call times out after 5s (the supervisor
start is blocked waiting for init to return, which is blocked waiting
for the supervisor). The first AI drawer open hit this and killed the
LiveView before the panel could render.
Move the start_agent call to ensure_started/1, which runs in the
caller's process BEFORE we ask the supervisor to start the ChatServer.
Idempotent for already-running JidoAgents. Removes the temporary
toggle diagnostic.
v0.64.5
Correctif
Meridian
Forward PubSub chat messages from LV to component
LiveComponents don't have their own mailbox — Phoenix.PubSub.subscribe
called from the component's initialize/1 actually subscribes the
parent LiveView process. When the agent ChatServer broadcast
{:chat_message, msg} or {:stream_token, tok}, the messages landed on
DashboardLive's handle_info and fell through unhandled, so the drawer
never rendered the agent's response.
Add two forwarding clauses in AgentInteractionHooks.handle_agent_info/2
that re-dispatch the events to the component via send_update. New
update/2 clauses on GlobalAiDrawerComponent receive the relayed
:pubsub_event assign and apply it to the messages / streaming_content
state (with dedup on message id to guard against duplicates).
v0.64.5
Correctif
Meridian
Use remote captures so hot-reload doesn't break drawer
attach_hook was receiving local captures (&handle_drawer_event/3). Each
LiveView mount froze a closure pointing at the current bytecode
version of the function, so editing this module made existing sessions
silently route events to stale code — the AI right drawer never opened
because the toggle event ended in a dead reference (BadFunctionError or
unhandled fallthrough).
Remote captures (&MODULE.fn/arity) resolve the function via its
module on every call. Elixir's hot code reload swaps the module in
place, so existing sessions immediately see the latest clauses.
All hook callbacks (handle_agent_info, handle_drawer_event, and a
newly-extracted handle_context_params) are now public so they can be
captured remotely. Behaviour is otherwise unchanged.
v0.64.5
Correctif
Meridian
Answer chat tasks via LLM instead of escalating
Two defects in the chat path:
run_agent_loop/4 read task.action (absent on chat tasks, defaulted
to "unknown") and looked up its autonomy level. Unknown actions
resolve to :escalate, so a plain "Hello" in the AI drawer routed
to the human inbox with a serialized decision map — the operator
saw something like %{outcome: "escalated", ...} instead of a reply.
Now tasks with type: "chat" bypass the autonomy gate and go
straight to run_llm_loop/5 at the :silent level. Autonomy still
governs declared actions.
build_messages/1 flattened the task down to a single user turn,
dropping task.messages. ChatServer sends the full conversation
history, so without this the LLM had no context beyond the latest
prompt. Use the history when present, skipping the "system"
welcome row (PromptBuilder already owns the system prompt) and
mapping our "agent" role to OpenAI's "assistant".
v0.64.5
Correctif
Meridian
Stop merging git-cliff stderr into --context stdout
System.cmd was called with stderr_to_stdout: true, so git-cliff's
"X commit(s) were skipped due to parse error(s)" WARN line got
prefixed onto the --context JSON and Jason.decode failed at position 1.
Result: mix changelog.release 0.64.4 stamped the version bump but
auto-generated zero priv/changelog entries, so v0.64.4 went out with
no in-app popup trigger.
Drop the merge — stderr flows to the user's terminal naturally, which
is what we want for diagnostic WARN output, and stdout stays as clean
JSON.
Also add priv/changelog/2026-04-22-v0.64.4-summary.md (pre-stamped
with version: "0.64.4") to retroactively cover the 9d25ecb multi-area
commit the failed auto-generate should have captured — unified public
page branding, email localization + org timezone, "Modifications
demandées" proposal workflow, invoice-from-project, agent locale
handling, etc. Kind :improvement so users get the catch-up popup.
v0.64.4
Amélioration
Meridian
Pages publiques unifiées, emails localisés, nouveau workflow de modifications demandées
Polish multi-zones pour pages publiques, emails, agents et CRM.
🎨 Pages publiques avec branding d'organisation
Composant org_brand_header unifié sur booking, contact, issues, discovery, proposal et invoice_payment — le logo et les couleurs primaire/accent de l'org se propagent jusqu'aux gradients et tokens de fond.
Les titres de page publiques suivent le format {Org} — {Page}.
Page de proposition publique : logo + en-tête revus, salutation de secours en « Valued Client » au lieu de répéter le nom de la compagnie.
Le bouton « Retour à l'accueil » est retiré des pages de confirmation de booking et de contact.
📧 Emails dans la bonne timezone et la bonne langue
Les dates et heures dans les emails de réunion utilisent désormais le fuseau horaire de l'organisation (fini les décalages UTC vs. local).
Signature, sujet et corps par défaut basculent vers les variantes gettext FR/EN quand les overrides de l'org correspondent aux valeurs anglaises seedées.
L'email de proposition utilise branding.primary_color pour l'en-tête et le CTA, et affiche le logo.
📅 Disponibilités corrigées
AvailabilityService génère maintenant les créneaux dans la timezone de l'organisation et groupe les dates dans cette zone (corrige le bug « seul le vendredi s'affiche »). La page de réservation affiche les heures via in_timezone/2.
📝 Questionnaire de découverte
Salutation corrigée (« Aidez-nous à mieux nous préparer »).
Libellés et questions standard traduites via gettext ; fallback automatique sur la version localisée quand text_fr est vide.
Le footer affiche « Des questions? Contactez-nous » quand aucun reply-to n'est configuré (fini les doublons « Contactez-nous à Contactez-nous »).
Nouvelle étape « Modifications demandées » dans le stepper, avec callout ambre en haut du détail quand le statut est :changes_requested.
Section dédiée dans le drawer listant les change requests, avec lien dans la sidebar.
Appuyé par un nouveau type d'activité proposal_change_request (plus fallback legacy sur le sujet des notes).
Le flow d'envoi de proposition distingue maintenant clairement :approval_required au lieu d'un « Failed to send » générique.
💼 CRM — navigation et actions
Le nom de la compagnie est cliquable (<.link navigate>) dans les en-têtes et sidebars des opportunités et des propositions.
Les panneaux latéraux passent à 480/520 px et la largeur par défaut du drawer est doublée.
Bouton « Créer une facture » dans le dropdown d'un projet : ouvre une modale pré-remplie selon le contract_type de la proposition (sélecteur de milestone en fixed_fee ou plage de dates en T&M), puis route vers la nouvelle facture.
« Créer un projet » depuis une proposition navigue directement vers le projet créé.
🤖 Agents et suggestions contextuelles
Les suggestions d'actions IA apparaissent dans la locale de l'opérateur, mais le client_locale est transmis jusqu'à l'exécution pour que l'agent rédige le livrable dans la langue du client.
Seules les suggestions LLM contextuelles (contraintes aux actions permises de l'agent) sont affichées — les actions statiques ont été retirées.
ActionMapping découplée du vocabulaire hardcodé : la propriété d'action est résolue à l'exécution depuis les autonomy_rules de chaque agent.
🐛 Correctifs divers
Les réunions futures ne sont plus auto-marquées « Terminée » — le flag « déjà eu lieu » est respecté, et l'heure est parsée dans la tz de l'org.
Fix crash en mode stream sur la liste des projets (unwrap de {dom_id, item} dans les callbacks row_click).
:type sur les activités CRM casté en string "note" et non en atom :note.
Projects.add_project_phase normalise la clé position pour éviter les maps mixtes atom/string rejetées par Ecto.
FR/EN ajoutées pour toutes les nouvelles chaînes via gettext.
v0.64.3
Nouveauté
Meridian
Show version chip on /changelog entries
Each entry on the public /changelog page now displays its version
alongside the date and kind badge. Released entries get a dark
monospaced "v0.64.2" chip; unreleased entries (no :version stamp
yet) get a subtle muted "À venir" chip so readers can tell the
difference.
v0.64.2
Nouveauté
Meridian
Auto-generate changelog entries from unreleased commits
mix changelog.release X.Y.Z now runs git cliff --unreleased --context,
parses the JSON, and writes one priv/changelog/--.md
per conventional commit whose group maps to a user-facing :kind:
Docs/style/chore/ci/build are skipped (not user-facing). Dedup is by
short SHA in the filename, so hand-authored entries override auto-gen
and re-runs are idempotent. If git-cliff is missing or fails, the task
prints a warning and still stamps any hand-authored entries — the
release doesn't break.
Also renames the hand-authored "in-app changelog" entry to include its
SHA so the dedup will respect it on future releases.
v0.64.1
Nouveauté
Meridian
Changelog + documentation accessibles depuis l'app
L'app montre désormais un popup à la connexion quand une nouvelle version a été publiée depuis ta dernière visite. Le menu avatar gagne deux entrées : Documentation (ouvre /docs dans un nouvel onglet) et Changelog (ouvre un modal résumant les nouveautés, ou la page complète si tu es à jour).
Les nouveautés sont groupées par version dans le popup — si tu as sauté plusieurs releases, tu vois le rattrapage complet d'un coup, pas seulement la dernière version. Seules les entrées de type :feature, :improvement et :security déclenchent le popup ; les :fix et :refactor restent silencieux mais sont visibles dans le modal manuel et sur /changelog.
Actually default to 'fr' (previous commit only applied mix format)
Default locale is 'fr' (not 'en') for consistency with other controllers
♻️ Refactorisations
Merge Observability + Models into one catalog section
Merge V11+V9 into unified trace + Observability light band
Remove hero chips, V12 back to /router Guard, V9 trace to API
Query-param locale routing for show + thank-you
Query-param locale routing for show + thank-you
Query-param locale routing for login/forgot/reset
Query-param locale routing for /proposal + /pay
Query-param locale routing for /book + /discover
Migrate /router content to RouterContent struct
Migrate / to HomeContent struct + navigation locale switcher
v0.63.0
Nouveauté
Meridian
Hero switcher + wayfinding + footer traduit
Nouvelle page d'accueil avec bascule entre angle « entreprise » et angle « développeur ». Ajout d'une navigation à points (dot-nav) pour les pages longues. Le footer est désormais complètement traduit FR/EN via des structs de contenu avec parité enforced par tests.
v0.63.0
Refactorisation
Meridian · Router
Contenu marketing migré vers des structs HomeContent / RouterContent
Tout le contenu FR/EN des pages / et /router est désormais consommé via des structs typées. La parité entre les locales est vérifiée par un test automatique (ParityTest). Zéro gettext dans les templates marketing.
v0.63.0
Nouveauté
Router
Observability + Models fusionnés dans le catalogue unifié
La section Observability et la liste des modèles sont désormais présentées comme un seul tableau avec filtres. Plus facile de voir quel modèle est recommandé pour quel usage, avec latence et coût moyen par token.
v0.63.0
Amélioration
Meridian
Nouveau diagramme V12 : flux Router sur la home
Visualisation du flux Router (4 branches fan-out vers les fournisseurs, Guard central, fallback automatique) directement sur la page d'accueil. Montre en un coup d'œil comment Meridian route les requêtes IA.
v0.62.0
Nouveauté
Meridian
Version 0.62.0
🚀 Nouveautés
Configurable default view mode per user (board vs table)
Inline-editable notes column on clients table + include on_hold projects in stages
Client dashboard enrichment — last contact, stages, suggested actions
Wire client enrichment and add display components to clients list
Add client enrichment module with action suggestion rules
Migrate all public pages to design system tokens
Migrate public LiveView pages to design system tokens
Migrate auth, contact, and issue pages to design system tokens
Use correct key :average instead of :avg_deal in opp stats
Use Float.parse in maybe_convert_budget to handle integer strings
Halt :fetch_dynamic_suggestions in AgentInteractionHooks to prevent FunctionClauseError in LiveViews
v0.63.0
Correctif
Meridian
Locale par défaut « fr » pour tous les flows publics
Harmonisation : /login, /forgot, /reset, /contact, /book, /discover, /proposal et /pay utilisent désormais tous le français par défaut, avec bascule via ?locale=en.
v0.60.0
Nouveauté
Meridian
Version 0.60.0
🚀 Nouveautés
Upgrade pills, view toggle, and KPI strip inline
Migrate ActionsDropdownComponent to design system
Migrate all buttons to design system components/tokens
Add subtle depth to colored buttons
World-class 3D action buttons + declutter proposal detail
Redesign project detail with Pattern B + drawer
Redesign proposal detail with Pattern B + 'Ouvrir l'éditeur' CTA
Migrate hardcoded colors to design tokens in 10 pages
Add EN/FR translations for all new design system strings
Add persistent timer widget in global header
Apply settings sidebar nav to all 8 remaining settings pages
Add breadcrumbs to all remaining pages
Simplify sidebar to flat grouped navigation
Add settings sidebar nav and apply to user settings
Upgrade time tracking with breadcrumb and design tokens
Add Pattern D elements to invoice editor
Redesign opportunity detail with Pattern B + drawer
Upgrade pipeline list views to Pattern A
Redesign client detail with Pattern B + drawer
Redesign dashboard with action-first layout (Pattern C)
Add idempotency index, fix TOCTOU in credit_org, add resolve_model tests
Add default 30 to billing_markup_percentage on organization schema
Pass cost_usd_cents/exchange_rate/metadata through debit_org, fix opts access pattern
Address 10 spec review gaps in agent interaction layer
Update ChatServer test to account for welcome message
v0.63.0
Sécurité
Plateforme
Argon2id pour tous les mots de passe + rotation des clés AES
Migration transparente de bcrypt vers Argon2id pour tous les hashs de mots de passe (re-hash à la prochaine connexion). Rotation des clés AES-256 de chiffrement au repos effectuée sans interruption de service.
v0.56.33
Correctif
Meridian
Version 0.56.33
🐛 Correctifs
Handle tuple entries in AgentConstitutionLive render to prevent Access.get crash
v0.56.30
Correctif
Meridian
Version 0.56.30
🐛 Correctifs
Use env vars for uploads/backup dirs to decouple from release version paths
v0.56.26
Correctif
Meridian
Version 0.56.26
🐛 Correctifs
Remove is_super_admin from User.changeset/2 to prevent privilege escalation
v0.56.9
Correctif
Meridian
Version 0.56.9
🐛 Correctifs
Build broken after merging #541 CRMProposalsLive switch_tab crashes — missing assigns for notes/tasks/activity tabs (#563)
v0.56.8
Correctif
Meridian
Version 0.56.8
🐛 Correctifs
Build broken after merging #543 Pandoc PDF text extraction fails — Pandoc does not support PDF as input format (#566)
v0.56.5
Correctif
Meridian
Version 0.56.5
🐛 Correctifs
Use pdftotext instead of Pandoc for PDF text extraction
v0.56.4
Correctif
Meridian
Version 0.56.4
🐛 Correctifs
Remove unused alias and function to pass --warnings-as-errors
v0.56.1
Correctif
Meridian
Version 0.56.1
🐛 Correctifs
Use pdftotext instead of Pandoc for PDF text extraction
Proposition title invisible in light mode — add dark: variant
v0.56.0
Sécurité
Meridian
Version 0.56.0
🚀 Nouveautés
Add mix meridian.migrate_document_files task for physical file migration
Implement Notes, Tasks, and Activity tabs for proposal detail view
Add DocumentContent JS hook for Build Draft flow
Add shared DocumentsComponent for unified document tab UI
Add documents and document_links schemas and migration
🔒 Sécurité
Sanitize extracted HTML with HtmlSanitizeEx before raw rendering
Three-panel proposal editor layout with LiveView integration
Expanded slash commands (22 cmds), proposal editor factory and hook
Add custom Tiptap nodes for proposal sections and data blocks
Add ProposalDocumentSync for document_content ↔ sections_content
Add document_content and sections_order fields to proposals
Add EN/FR translations for products and issue categories
Add category to dogfooding issue modal and auto-detect product
Add product filter and category display to issues LiveView
Add Products management LiveView with CRUD
Add product and category selection to public issue form
Add PATCH and resolve endpoints for issues API
Add Product API controller with product-scoped issue endpoints
Add optional product_id FK to CRM projects
Add product_id and category fields to issues
Add Products context with CRUD operations
Update Meeting schema with company/proposal associations and subject field
Add products table and schema
Add company_id, proposal_id, subject to crm_meetings; make opportunity_id nullable
🐛 Correctifs
Add font-src and blob: to CSP, bump to v0.46.4
Issue report modal not opening due to JS.show/phx-click-away race condition
Yjs sync plugin crash blocking entire editor mount
Resolve 21 findings from deep audit of half-implemented features
Resolve all 11 issues from final review (3 blocking + 5 UX + 3 minor)
Resolve all 6 remaining non-blocking review items
Resolve 4 blocking issues and 8 UX gaps from editor review
v0.45.8
Correctif
Meridian
Version 0.45.8
🐛 Correctifs
Build broken after merging #27 System logs are not streaming (#32)
v0.45.1
Correctif
Meridian
Version 0.45.1
🐛 Correctifs
Resolve formatter infinite loop with em dash character in agents_inbox_live.ex
v0.41.2
Correctif
Meridian
Version 0.41.2
🐛 Correctifs
Build broken after merging #8 Software Agents (#22)
v0.41.1
Correctif
Meridian
Version 0.41.1
🐛 Correctifs
Build broken after merging #7 Agents tempalte (#21)
v0.38.1
Correctif
Meridian
Version 0.38.1
🐛 Correctifs
Build broken after merging #6 Agents architecture (#20)
v0.63.0
Nouveauté
Router
Guard anti-exfiltration : détection des clés API et variables .env
Guard filtre désormais automatiquement les clés API (GitHub, Stripe, AWS, etc.) et les variables d'environnement avant d'envoyer la requête aux modèles externes. Aucune donnée sensible ne quitte plus Montréal.