Changelog

Évolution de Meridian au fil du temps.

Nouveautés, améliorations, correctifs et mises à jour de sécurité, par ordre chronologique. Couvre la plateforme Meridian et l'API Router.

Suivez les mises à jour importantes par courriel — s'abonner — ou consultez l'état des services en temps réel.

v0.109.0 Nouveauté
Meridian

Report_meridian_issue tool for autonomous agent issue reports

v0.109.0 Nouveauté
Meridian

Issue.created event and body-signature header

v0.109.0 Nouveauté
Meridian

Report_platform_issue with fingerprint de-duplication

v0.109.0 Correctif
Meridian

Harden agent issue reporting (length, reopen, payload, trial path)

v0.109.0 Refactorisation
Meridian

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.

v0.108.0 Refactorisation
Meridian

Ai_enabled entitlement is the single AI switch

v0.108.0 Correctif
Meridian

Agents skip module_mcp_api gate, map tasks to projects, tighten 403 tests

v0.108.0 Correctif
Meridian

Platform-org admin access requires platform org membership

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.

v0.107.19 Nouveauté
Meridian

Fetch main_content, structured_data, highlights, summary

v0.107.19 Nouveauté
Meridian

Local main-content extraction

v0.107.19 Correctif
Meridian

Lazy page-reader text, Exa highlights/text correctness

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.

v0.107.19 Correctif
Meridian

Validate JSON Schema union types

v0.107.19 Nouveauté
Meridian

Schema.org product extraction for fetch

v0.107.19 Nouveauté
Meridian

Schema-validated fetch summary with one retry

v0.107.19 Correctif
Meridian

Main-content scoring ignores indentation whitespace

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.

v0.107.14 Correctif
Router

Jev self-recursion hang, blank SEARCH_URL crash, null-content 500

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

v0.107.12 Correctif
Router

Bedrock schema-downgrade retry, models perf, upstream deadline, loud search config

  • 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.
  • Unconfigured web_search answers 503 search_not_configured JSON; blank keys rejected; boot log shows effective backend (secret-free); compose/.env document + pass SEARCH_* explicitly.
v0.107.11 Correctif
Router

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).
  • Unconfigured web_search answers 503 search_not_configured JSON; explicit stub keeps 200 []. Blank keys rejected as misconfigured.
  • 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.
  • virtual_alias rows excluded from chat auto-resolution/fallbacks (listed + explicitly addressable only).
  • 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.

v0.107.5 Nouveauté
Meridian

Router API: catalogue OpenRouter synchronisé quotidiennement

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

v0.107.5 Correctif
Router

JSON errors everywhere, truthful models catalog, /openapi.json

  • 401 Router (incl. SSE frame) -> OpenAI envelope code invalid_api_key.
  • Malformed JSON / oversize bodies under /api/* -> JSON 400/413 (ApiParsers wrapper; browser behavior unchanged).
  • /openapi.json serves the Router spec on both hosts (host-plug allowlist).
  • supported_parameters: native json_schema matrix fallback (openai/, anthropic/) + classify:true for typesafe/jev-router.
  • Reject negative catalog prices (jev showed -$1.9M/M); pricing_for already nils unpriced models.
  • 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

v0.107.4 Correctif
Meridian

FR + EN for "Plan not available."

v0.107.4 Nouveauté
Router

Tools debit ledger like chat + dynamic fetch cost

  • AiGateway.check_tool_spend_allowed/1 (balance/budget 402 gate) and debit_tool_usage/3 (same ledger path as chat: prepaid millicents + retry, postpaid 1c floor; source llm_usage, description web_search/fetch).
  • 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

v0.107.0 Correctif
Meridian

Reject forged plan_id in LiveView and provision

v0.107.0 Nouveauté
Meridian

Email verification

v0.107.0 Nouveauté
Router

Artemis enrichment — precise billing, web_search/fetch tools, classify with scores, json_schema

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.

v0.101.0 Nouveauté
Meridian

MCP finance: accounts, expense/invoice details, tax periods, voids

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

v0.100.0 Refactorisation
Meridian

Extract proposal line-item LiveView event handlers

v0.100.0 Refactorisation
Meridian

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).

v0.99.0 Refactorisation
Meridian

Meridian.Proposals owns lifecycle; CRM façade delegates

v0.99.0 Refactorisation
Meridian

Finance.ClientBilling owns client billing; CRM façade

v0.99.0 Refactorisation
Meridian

Proposal lifecycle transition table

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:

  • Accounts (operating, tax reserve, savings, credit card, per-employee expense)
  • Expenses, invoices, transfers, reimbursements, tax periods
  • Cash position with available cash (not just bank balance)
  • Excel export (multi-sheet workbook)
  • MCP read/write tools under /api/meridian/v1/finance/*, including approve_expense (finance_approve) for pending expenses
  • LiveViews at /finance (dashboard, transfers, tax period, shareholder, settings)
  • Quick expense entry: operating, credit card, or employee expense + receipt upload

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.

Changements

  • Elixir / OTP — 1.20.4 / OTP 29.0.5 (.tool-versions, image Docker)
  • Phoenix LiveView 1.1 → 1.2, Req 0.5 → 0.7, nimble_publisher 1 → 2
  • Typst 0.14.2 → 0.15.1 (NIF Rust adapté aux nouvelles APIs)
  • npm — Tiptap 3.30, FullCalendar 6.1.21, pdfjs-dist 5.7, oxlint 1.80
  • Vendored — swagger-ui 5.32.14, topbar 3.0.1
  • Docker — PostgreSQL 17.11-bookworm
v0.96.0 Nouveauté
Meridian

Approver picker and pending-approval proposal filter.

Submit-for-approval modal selects an org member; the list filter and approval banner use the assigned approver instead of only the org default.

v0.96.0 Correctif
Meridian

Complete version restore, diff UI, portal toggle, and acceptance snapshots.

Restore line items from version snapshots, improve section diffs, CRM portal visibility toggle, PDF badges, LiveView tests, and LOGBOOK/ideas hygiene.

v0.96.0 Nouveauté
Meridian

Show win rate by Flow 2 proposal template.

Surfaces accepted/rejected outcomes on the proposal templates settings page with grouped stats from template_id.

v0.96.0 Nouveauté
Meridian

Phase B hardening: version restore, diff, portal toggle, acceptance snapshot

  • Versions : restauration complète des lignes depuis le snapshot; diff de sections avec extraits de texte.
  • Portail : toggle CRM « afficher le statut projet » (portal_status_visible).
  • Acceptation : snapshot de configuration (accepted_configuration_snapshot + signature).
  • PDF : badges optionnel / mensuel / annuel sur les lignes incluses.
v0.96.0 Nouveauté
Meridian

Quote builder, portal project status, and proposal version diff

  • Quote builder : lignes optionnelles, groupes (Gold/Silver), intervalles récurrents; sélection client sur la page publique et le portail.
  • Statut projet portail : phases, jalons, santé et dates sur les cartes projet du portail client.
  • Diff versions proposition : comparer deux snapshots depuis le tiroir Versions CRM.
v0.96.0 Nouveauté
Meridian

Employee expense reports and Phase A finance gaps

  • Comptes de dépenses employés : soumission, approbation, remboursement, export CSV (/comptabilite/depenses-employes).
  • 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.

v0.96.0 Nouveauté
Meridian

Ship Quebec depth, MSP rails, GEO, and win/loss

Complete Phase 1: TPS/TVQ remittance, project budgets, pipeline config, M365 CSP catalog+GDAP, Cloudflare rail phase 1, GEO discoverability, and win/loss stale-deal alerts. Archive shipped LOGBOOK dossiers and promote Agent Platform enablers to 2-next.

v0.96.0 Nouveauté
Meridian

Add shared tool registry, executor, and loop

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.

v0.96.0 Nouveauté
Meridian

Configurable invoice numbering (prefix, padding, year)

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.

security Fixes #13 Fixes #14 Fixes #15 Fixes #35 Fixes #46

v0.93.0 Correctif
Meridian

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).

v0.92.0 Nouveauté
Meridian

Catalogues Produits / Services / Besoins bilingues

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.

v0.89.0 Nouveauté
Meridian

MCP document tools (list/get-text/download-url/create/upload handshake/finalize)

v0.89.0 Amélioration
Meridian

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.

v0.89.0 Nouveauté
Meridian

Token issuance, refresh rotation, validation, revoke

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.

v0.89.0 Correctif
Meridian

Resolve adversarial-review findings (security + correctness + tests)

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

v0.89.0 Nouveauté
Meridian

Add documents_view/manage permissions + backfill roles

v0.89.0 Correctif
Meridian

Enforce https/loopback + no-fragment redirect URIs; correct token 401 www-authenticate challenge

v0.89.0 Nouveauté
Meridian

Access + refresh token schemas + migrations

v0.89.0 Nouveauté
Meridian

Token endpoint (authorization_code + refresh rotation)

v0.89.0 Nouveauté
Meridian

Oauth_clients schema + migration

v0.89.0 Nouveauté
Meridian

Token/PKCE crypto helpers

v0.89.0 Refactorisation
Meridian

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.

v0.89.0 Refactorisation
Meridian

Delete .mcpb Desktop bundle (Node server, DesktopBundle builder, :desktop build target)

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.

v0.87.0 Amélioration
Meridian

UX hardening: safer saves, clearer feedback, better accessibility

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
  • Shared org legal-footer HTML helper
  • Add legal/contact fields (legal_name, address, NEQ, TPS/TVQ)
  • Route Stripe writes through breaker with idempotency keys
  • Add StripeClient with breaker + idempotency-gated backoff
  • Guard OpenRouter streaming with circuit breaker
  • Circuit-break OpenRouter chat + embeddings
  • Configure circuit breaker thresholds
  • Org-admin settings page with self-serve AI module toggle
  • Add term-keyed CircuitBreaker

🐛 Correctifs

  • Resolve adversarial review findings
  • Admin org form pre-populates from satellites + regression test
  • Defensively preload satellites in Emails (password reset, welcome, test email)
  • Defensive router preload + remaining caller/test stragglers
  • Consistent 422 details shape + fill validation test gaps
  • OpenAI-compat validation errors return 400, not 422
  • Health probe stays up on 3rd-party outage; embeddings 503; no retry on open circuit; drop dead open_keys
  • Restore breaker config in half_open test to stop cross-test threshold leak
  • T&M invoice preview snapshots org tax_config (TPS/TVQ), matching generation
  • Log the real callback failure reason
  • Dead-letter handler logs only; avoid duplicate ErrorTracker reports
  • Handle SMTP circuit-open honestly in LowBalanceNotifierWorker batch loop
  • Fill FR translations and use token for AI toggle knob
  • Wrap maybe_migrate/0 in with_repo so it works before the tree
  • Wrap maybe_migrate/0 in with_repo so it works before the tree
  • Soften trust marquee to aspirational, non-legal copy
  • Run migrations before supervision tree, supervise M365 JWKS strategy
  • Run migrations before supervision tree, supervise M365 JWKS strategy
  • Exclude paid invoices by semantic_type not code
  • Truncate next_run_at to usec so scheduler stops crashing

♻️ Refactorisations

  • Satisfy credo --strict (mailer complexity, aliases)
  • Shape the mcp/tools ok-response schema
  • 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
  • Add calendar FK to Subscription
  • Per-calendar delta links
  • Add calendar FK and provenance to CalendarEvent
  • Add MailboxCalendar schema and factory
  • Migration for multi-calendar sync schema

🐛 Correctifs

  • Address multi-calendar review findings
v0.83.1 Correctif
Meridian

Version 0.83.1

🐛 Correctifs

  • Wire dashboard into settings nav + respect theme
v0.83.0 Nouveauté
Meridian

Version 0.83.0

🚀 Nouveautés

  • Register Graph and sync metrics with Prometheus
  • Add MicrosoftConnectionLive and route
  • Add MicrosoftStatus component
  • Add routes for auth and webhooks
  • Add Webhooks.MicrosoftController
  • Add Auth.MicrosoftController (start, callback, disconnect)
  • Schedule token refresher and subscription renewer crons
  • Add MicrosoftNotificationProcessor worker
  • Add MicrosoftInitialSync worker
  • Add MicrosoftSubscriptionRenewer worker
  • Add MicrosoftTokenRefresher worker
  • Add WebhookHandler (clientState + lifecycle)
  • Implement Meetings (standalone Teams online meetings)
  • Implement Mail context and MailSync
  • Implement Calendar context (list/create/update/delete)
  • Add CalendarSync delta handler
  • Implement Subscriptions context (create, renew, delete)
  • Add facade and sub-context stubs
  • Add Accounts context
  • Emit Graph request telemetry events
  • Graph supports POST/PATCH/DELETE/paginate/delta
  • 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.
  • Stack Docker docker-compose.observability.yml — Prometheus
    • 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.

Configuration Docker (optionnelle)

export GF_ADMIN_PASSWORD=<mot-de-passe-grafana>
echo "<clé-api-super-admin>" > docker/prometheus/meridian_token
docker compose -f docker-compose.observability.yml up

Grafana : http://localhost:3000 (admin / $GF_ADMIN_PASSWORD) Prometheus : http://localhost:9090

v0.81.0 Correctif
Meridian

Version 0.81.0

🐛 Correctifs

  • 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
  • /settings/statuses admin page + fix missed milestone query
  • StatusReorder JS hook for drag-reorder status admin
  • Milestone.status → organization_statuses FK
  • ProjectPhase.status → organization_statuses FK
  • Company.qualification_status → organization_statuses FK
  • Meeting.status → organization_statuses FK
  • Deliverable.status → organization_statuses FK
  • Project.status + health_status → organization_statuses FK
  • Invoice.status → organization_statuses FK (invoice_status)
  • Proposal.status → organization_statuses FK (proposal_status)
  • Opportunity.status → organization_statuses FK (opportunity_status)
  • Task.priority → organization_statuses FK (task_priority)
  • Task.status → organization_statuses FK with semantic_type branching
  • Live preview + help for 12 status field_kinds
  • Status_pill component with color palette
  • Seed 12 default status sets per org + backfill existing
  • Organization_statuses table, schema, and context
  • Company.service_interests org-configurable with admin tab + live preview
  • Contact.role org-configurable with admin tab + live preview
  • Company.tax_id_type org-configurable with admin tab + live preview
  • Company.manual_last_contact_kind org-configurable with admin tab + live preview
  • Payment.payment_method org-configurable with admin tab + live preview
  • ServiceBlock.pricing_type org-configurable (shared catalog_pricing_types)
  • Invoice.invoice_type org-configurable (shared catalog_pricing_types)
  • Add billing_mode canonical field — decouple billing logic from catalog labels
  • Project.contract_type org-configurable (shared catalog_pricing_types)
  • Proposal.pricing_type org-configurable with shared pricing_types tab
  • Opportunity.deal_type org-configurable with admin tab + live preview
  • Seed default flat catalogs on org creation
  • Add 7 flat catalog columns with French defaults
  • Field_help and field_preview components with deal_types renderer
  • Gate /settings/services behind catalogs_edit permission
  • Add catalogs_edit permission auto-attached to all roles

🐛 Correctifs

  • Resolve final test failures from Phase 2 status FK migration
  • Resolve remaining test failures from Phase 2 status FK migration
  • Bulk-update source code and tests for Phase 2 status FK requirements
  • Resolve merge conflict in skill/build.ex — use main's version
  • Enumerate writable fields on clients + proposals request bodies
  • Assemble bundles in-memory at runtime, drop Mix from request path
  • Catalog_previews use declared surface-sunken CSS var
  • Align catalogs_edit flash with team_live convention
v0.78.0 Correctif
Meridian

Per-org Desktop key + simplified single-button flow

v0.78.0 Nouveauté
Meridian

Get/generate/revoke_desktop_key helpers

v0.78.0 Correctif
Meridian

Address review findings (manifest_version, polish, hardening)

  • manifest.json: bump manifest_version 0.2 → 0.3 (current MCPB spec)
  • 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 :

<iframe src="https://app.meridian.dev/embed/contact/votre-slug?locale=fr"
        style="width:100%;border:0;min-height:600px"
        title="Contact"></iframe>
<script src="https://app.meridian.dev/embed.js" async></script>

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.

Détails techniques

  • Nouvelles routes /embed/contact/:slug, /embed/contact/:slug/thank-you
  • 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.

v0.78.0 Correctif
Meridian

Polish — branding, target=_blank, copy feedback, preview

Four gaps from review:

  1. 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.

  2. 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.

  3. "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.

  4. 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.

v0.78.0 Correctif
Meridian

Per-org display name, entry-point detection, hidden card

Three user-reported issues from the first local install attempt:

  1. 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.

  2. 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".

  3. 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
  • Règles d'escalade · déclencheur, destinataire, contexte
  • Garde-fous · risque + garde-fou à appliquer
  • 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

v0.74.1 Nouveauté
Meridian

Editable string lists (product types, categories, client statuses)

v0.74.1 Nouveauté
Meridian

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
v0.74.1 Nouveauté
Meridian

Create opportunity_presets table

v0.74.1 Nouveauté
Meridian

Set_opportunity_services/2 — replace-set semantics

v0.74.1 Nouveauté
Meridian

Create project_service_allocations table

v0.74.1 Nouveauté
Meridian

Client_status setter + manual contact + effective_last_contact resolver

v0.74.1 Nouveauté
Meridian

Tag service_blocks with product_types and essential bit

v0.74.1 Nouveauté
Meridian

Link time_entries to project_service_allocations

v0.74.1 Nouveauté
Meridian

Add per-org catalog lists (product types, service categories, client statuses)

v0.74.1 Nouveauté
Meridian

Create_proposal_from_opportunity/2 snapshots services as line items

v0.74.1 Nouveauté
Meridian

Add client_status + manual contact fields to Company

v0.74.1 Nouveauté
Meridian

Wire associations for project_service_allocations

v0.74.1 Nouveauté
Meridian

Drop hardcoded Opportunity.known_product_types in favor of org catalog

v0.74.1 Nouveauté
Meridian

Opportunity_presets CRUD with soft-ref load

v0.74.1 Nouveauté
Meridian

Add OpportunityPreset schema

v0.74.1 Nouveauté
Meridian

Create_project_from_proposal materializes allocations and tasks

v0.74.1 Nouveauté
Meridian

Add client_status + manual contact fields on crm_companies

v0.74.1 Nouveauté
Meridian

Create opportunity_services join table

v0.74.1 Nouveauté
Meridian

Add OpportunityService schema

v0.74.1 Nouveauté
Meridian

Convert service_block.category atom values to human form

v0.74.1 Nouveauté
Meridian

Add catalog_* string-array fields to Organization schema

v0.74.1 Nouveauté
Meridian

List_service_blocks_for_opportunity/2 (catalog query)

v0.74.1 Nouveauté
Meridian

Add ProjectServiceAllocation schema

v0.74.1 Nouveauté
Meridian

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
  • skill_card gets shadow-surface + hover:shadow-raised
v0.73.1 Correctif
Meridian

Wrap triggers table in <.card> for proper visual frame

v0.73.1 Correctif
Meridian

Card depth in non-Constitution tabs (kpi_tile, activity_row, trace_row, decision_card, chat panel)

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

v0.72.0 Amélioration
meridian

Page agent : layout pills, recommandations, chat embarqué

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.

v0.72.0 Nouveauté
Meridian

Constitution tab — 4 grouped sections + prompt drawer

12 existing sections regrouped into 4 logical groups (Identity & Voice / Authority & Autonomy / Behavior & Memory / Measurement). Per-section edit-in-place flows preserved untouched. Actions section removed (Capabilities tab covers it now). "View the prompt" button opens AgentPromptDrawerComponent; section anchors deep-link into the matching edit panel.

v0.72.0 Nouveauté
Meridian

Announce agent page redesign

v0.72.0 Nouveauté
Meridian

Kpi_tile, activity_row, decision_card components

Three new function components in AgentDetailComponents for the Overview tab.

v0.72.0 Nouveauté
Meridian

Overview tab — decision cards, KPI tiles, activity feed

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.
  • EN/FR gettext entries for the new strings.
v0.72.0 Nouveauté
Meridian

Activity tab — 7d chart + filterable list + trace drawer

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

v0.72.0 Nouveauté
Meridian

Skill_card, capability_chip, capability_row, constitution_group

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

v0.72.0 Correctif
Meridian

Strip Markdown code fences from LLM JSON output

v0.72.0 Nouveauté
Meridian

DecisionSupport — demote_autonomy heuristic

v0.72.0 Correctif
Meridian

Surface analysis crashes + tolerate unexpected Router shapes

v0.72.0 Nouveauté
Meridian

DecisionSupport — inbox/idle/trust recs + dismiss snooze

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.

v0.72.0 Nouveauté
Meridian

DecisionSupport module — promote_autonomy heuristic

v0.72.0 Correctif
Meridian

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

v0.71.0 Nouveauté
meridian

Éditeur Flow 2 — validations, commentaires, approbation

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.
  • Configuration Router (/router/settings) — fuses Guard + API Keys + Modèles LLM (super-admin).

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.
  • Configuration Router (/router/settings) — fusionne Guard + API Keys + Modèles LLM (super-admin).

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
  • Add 20 new tests: cross-org auth, update/delete happy paths, get_article! isolation, invalid-transition guards
v0.71.0 Nouveauté
Meridian

EditorLive handles chip + prompt + focus_section

v0.71.0 Nouveauté
Meridian

Approve/reject pending knowledge articles

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.

v0.70.0 Correctif
Meridian

Wizard upload race condition + defensive AST error mapping

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.
  • Jido actions. GenerateProposal, ProposeProposalEdit (with AST
    • compile retry), RecompileProposalTypst, ExportProposalPdf, ValidateProposalConsistency (3 Elixir-pure + 3 Router-driven validators, :elixir_only / :router_only / :all scopes).
  • 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.

v0.69.0 Nouveauté
Meridian

Elixir-pure validations (required_sections, date_consistency, completeness)

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)

  • Add :proposal_compile Oban queue (concurrency 4) alongside the existing :proposals queue.
  • 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:

  1. 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.

  2. 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).

  3. 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
  • proposal_validations — cross-source validation results
  • proposal_templates — Flow 2 (Typst) templates, distinct from legacy crm_proposal_templates (Flow 1 / DOCX)
  • proposal_template_versions
  • proposal_template_assets

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.

v0.69.0 Nouveauté
Meridian

Router-driven validations (pricing, scope, language)

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:

  1. Extract section body (Parser.extract_section/2).
  2. Ask Router (use_case proposal_edit) for a new fragment.
  3. 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.
  4. 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.
  5. 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.
v0.69.0 Nouveauté
Meridian

Coming-soon skills, setup-pending alerts, per-key ledger audit

  • 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.

mix precommit green: 2228 tests, 0 failures (was 2199 baseline).

v0.69.0 Correctif
Meridian

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
  • D13: agents sub-nav exposing Overview/Skills/Triggers/Inbox/Traces; removed redundant Inbox/Traces buttons from page header
  • 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

Big-bang reorg + safety pass.

REORG (Option 2):

  • Move Meridian.AI.Router → Meridian.Router (lib/meridian/router.ex)
  • Move Meridian.AI.LLMClient → Meridian.Router.LLMClient
  • Move Meridian.Billing.* → Meridian.Router.Billing.*
  • Move Meridian.Guard.* → Meridian.Router.Guard.*
  • 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.

mix precommit green: 2194 tests, 0 failures (baseline 2187 + 7 new).

v0.69.0 Correctif
Meridian

Repair 56 leftover failing tests + struct access bug

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).
  • misc: targeted fixes across time_live, user_dropdown, backup_download_controller, tax_service, agents_jido, send_agent_message, opportunity_product_types, invoices_live, page_controller.

mix precommit green (2208 tests, 0 failures).

v0.69.0 Refactorisation
Meridian

Remove OpenAIClient + ModelCache + BYOK + AgentProcess; standardize JidoAgent registry key

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

v0.67.0 Nouveauté
Meridian

Anticipatory events (meeting_30m_before, invoice_due_in_7d)

v0.67.0 Nouveauté
Meridian

Add Skills context with agent attach validation

v0.67.0 Nouveauté
Meridian

Gettext + changelog entry for @-mentions

v0.67.0 Nouveauté
Meridian

Weekly digest hero card on agents dashboard

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):

  • Opportunities discovery Q&A textareas (inline + drawer versions)
  • Client company note body
  • Proposal note body
  • Meeting internal notes
  • Meeting qualification-override notes (opportunity surface)

Fully wired (picker + 4 event handlers) on the opportunity detail LV (CRMOpportunitiesLive):

  • agent_mention_picker_open/close → toggles @mention_picker assign
  • agent_mention_insert → push_event mention-inserted
  • 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:

  • opportunity_created (CRM.Sales.create_opportunity/1)
  • proposal_sent (CRM.Proposals.send_proposal/2)
  • proposal_signed (CRM.Proposals.accept_proposal/1)
  • meeting_scheduled (CRM.Meetings.book_meeting/3)
  • 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.
  • outcome: "escalated" / "proposed" → inbox hand-off message, metadata.escalated = true.

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.

v0.64.6 Correctif
Meridian

Render agent results + tighten credit reservations

  • 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":

  1. 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.

  2. 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:

  1. 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.

  2. 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 »).

📋 Propositions — workflow « Modifications demandées »

  • 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:

🚀 Nouveautés → :feature ⚡ Performance → :improvement 🔒 Sécurité → :security 🐛 Correctifs → :fix ♻️ Refactorisations → :refactor

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.

v0.64.0 Nouveauté
Meridian

Version 0.64.0

🚀 Nouveautés

  • Add FR + EN strings for changelog popup + badges
  • Avatar dropdown adds Documentation + Changelog + dot indicator
  • Assign pending changelog entries + wire dismiss/open events
  • ChangelogPopupComponent — grouped-by-version modal
  • Add changelog_kind_badge component
  • Modal_wrapper supports optional subtitle and header_icon
  • Add changelog.release task for versioned releases
  • Add Unseen module for per-user diff logic
  • Add mark_changelog_seen/2
  • Expose last_seen_app_version in schema + changeset
  • Add last_seen_app_version column
  • Add since/2 and unreleased/0 queries
  • Add optional :version to Entry schema
  • Iteration 13 — low_balance trigger + deliveries sweeper + completion log
  • Iteration 12 — vision multimodal + /v1/models alias
  • Iteration 11 — outbound webhooks with HMAC + retry
  • Iteration 10 — API keys self-service API
  • Iteration 9 — cost estimate endpoint + strict fallback override
  • Iteration 8 — Guard audit API (GET /router/audit)
  • Iteration 7 — per-org /settings/guard configuration LiveView
  • Iteration 6 — wire Guard into Router end-to-end
  • Iteration 5 — entity detectors + unified Pipeline
  • Iteration 4 — built-in regex detectors (15 patterns)
  • Iteration 3 — schemas, context, audit sweeper
  • Iteration 2 — Idempotency-Key + embeddings endpoint
  • Iteration 1 — streaming SSE, JSON mode, tools/tool_choice
  • /router/docs custom OpenAPI viewer
  • Migrate /docs and /changelog to Meridian with NimblePublisher
  • SignalOrange breadcrumb nav + mobile menu + footer URLs
  • Hero switcher + wayfinding + refined copy + translatable footer
  • Home hero uses shared flow_diagram + design audit fixes
  • V12 block diagram on home + V8/V9/V11 on /router
  • Router flow — passes central, blocked ejected, 4-branch fork
  • 2/3-1/3 hero grid + simpler vertical Router flow
  • Enlarge hero cards + richer Router fan-in/fan-out flow
  • Visual mocks in dual-product hero cards
  • Dual-product hero (Meridian + Router) replaces standalone band
  • Revert hero + new Router standalone band + Router features
  • Redesign /contact/:slug with login-style split layout
  • Home hero split + CRM features + drop chapter chips

🐛 Correctifs

  • Manual "Changelog" click falls back to /changelog when caught up
  • Forward changelog assigns through Layouts.app
  • Phase 4 β — second-pass hardening bundle
  • Streaming path now uses reservation + model allowlist (phase 4 α)
  • Phase 3 bundle B — idempotency + vision URL validation
  • Phase 3 bundle A — trivial one-liner hardening
  • Phase 2 medium-severity hardening
  • Phase 1 medium-severity hardening
  • Per-api-key rate limiting on /api/v1 (H-1, H-2)
  • Atomic reservation billing + error sanitization + model allowlist + SSE chunk
  • Idempotency first-writer-wins + async api_key usage + SSE reauth
  • ReDoS validator + input size cap + precompile patterns
  • SSRF + HTTPS + HMAC timestamp + perm gate + Req hardening
  • Resolve multiple CRM & contact-form bugs
  • 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
  • Settings reorganization — sidebar consolidation + approver toggle
  • Add default approver toggle on users management page
  • Reorganize sidebar — consolidate settings, add system section for super-admins

🐛 Correctifs

  • Replace phx-click on tr with navigate link on company name
  • Stop click propagation on note cell to prevent row navigation
  • Move phx-click for note editing to inner div, remove phx-click-away
  • Word templates page uses settings layout, approver toggle only in modal
  • Settings nav active state, role creation timestamps, approver in modal, docm mime
  • Minor adjustments from worktree merges
  • Datetime diff, docm mime type, role creation org_id
  • Client enrichment data key consistency and stage display
  • Single settings entry in sidebar, all navigation in settings sub-sidebar
  • Word template upload modal and allow .docm files
  • Handle validate_settings event in EmailTemplatesLive
v0.61.0 Nouveauté
Meridian

Version 0.61.0

🚀 Nouveautés

  • Proposal document generation pipeline with approval workflow
  • Add pending approvals badge in navbar for approvers
  • Add proposal agent actions for docx generation and approval
  • Add EN/FR translations for docx generation and approval workflow
  • Add docx download controller and word templates management page
  • Add docx generation and approval UI components
  • Add approval stamp to PDF generation
  • Add approval workflow, template CRUD, AI docx drafter, and notifications
  • Add Docx module as Pythonx wrapper for python-docx
  • Add proposal approval settings to organization
  • Add word template, approval schemas, update proposal and uploads
  • Add database tables for word templates and proposal approvals
  • Add pythonx dependency with python-docx for proposal document generation

🐛 Correctifs

  • Migrate all proposal UI components to design system tokens
  • Async docx generation, approval UX, design tokens, accessibility
  • Address critical review issues — approval guards, notifications, security
  • Remove duplicate breadcrumb on projects page
  • 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 filter_pills, kpi_strip_inline, contact_chip, action_item
  • Add drawer slide-over component
  • Add aside_panel, aside_link, activity_timeline components
  • Add ai_insight and progress_stepper components
  • Add breadcrumb and entity_header components
  • Add drawer and stepper CSS animations
  • Restyle flash notifications as toast cards
  • Restyle global search as command palette
  • Refresh sidebar with active pill indicator and design tokens
  • Glass header, dynamic branding, design token header buttons
  • Add badge, skeleton, and progress_bar components
  • Refresh modal_wrapper and action_button with design tokens
  • Refresh card, page_header, kpi_strip, empty_state components
  • Add design system tokens, remove daisyUI

🐛 Correctifs

  • Multiple bugs + UI component upgrades
  • Migrate remaining hardcoded button colors to design tokens
  • Restore original design system button styles
  • Unified Stripe-clean button depth for all buttons
  • Remove btn-highlight from generic button component
  • Apply surface-base background to body + fix dark mode
  • Use outstanding_balance_cents instead of outstanding_count
  • Use primary_contact instead of contact on opportunity
  • Restore Pipeline and Facturation sub-items in sidebar
  • Critical crash + responsive layouts + aside panel mobile
  • Migrate 6 shared components to design tokens
  • Resolve all review issues — tokens, print styles, unmigrated components
  • Replace dead daisyUI classes in layouts.ex and home.html.heex

♻️ Refactorisations

  • Replace daisyUI classes with design token equivalents in core_components
v0.58.4 Correctif
Meridian

Version 0.58.4

🐛 Correctifs

  • Use Float.parse in maybe_convert_budget to handle integer strings
v0.58.3 Correctif
Meridian

Version 0.58.3

🐛 Correctifs

  • Halt :fetch_dynamic_suggestions in AgentInteractionHooks to prevent FunctionClauseError in LiveViews
v0.58.1 Nouveauté
Meridian

Version 0.58.1

🚀 Nouveautés

  • Fix FR translations for actions dropdown and fuzzy entries

🐛 Correctifs

  • Add :last_activity handler to ChatServer for IdleAgentChecker compatibility
v0.58.0 Nouveauté
Meridian

Version 0.58.0

🚀 Nouveautés

  • Add ActionsDropdown to calendar event detail
  • Add ActionsDropdown to meeting detail
  • Add ActionsDropdown to service blocks list
  • Add ActionsDropdown to invoices list and detail views
  • Add ActionsDropdown to projects list and detail views
  • Add ActionsDropdown to proposal detail, replace action buttons
  • Add ActionsDropdown to proposals list
  • Add AI action mappings for proposal, project, invoice, meeting, service_block
  • Add sent email history, test email sending, fix remaining ECL issues
  • Add EN/FR translations for email control layer
  • Add email type settings section to email templates page
  • Integrate email preview modal into invoice and proposal send flows
  • Add EmailPreviewModal component and EmailEditorHook
  • Add EmailDispatch service — send_automatic, prepare_preview, send_prepared
  • Add email_type_settings and sent_emails tables, remove follow_up_enabled
  • Add Phase 4 EN/FR translations and setup documentation
  • Add PDF download link to public payment page
  • Add PDF download button to invoices and file download handler
  • Send invoice email with PDF on status transition to sent
  • Add InvoiceMailer for sending invoice emails with PDF and Pay Online link
  • Add InvoicePDF for branded invoice PDF generation
  • Add Phase 4 webhook stubs — tax.settings.updated, reporting.report_run.succeeded
  • Add TaxService for Stripe Tax API calculations on CRM invoices
  • Add tax ID fields to companies and tax_auto_calculated to invoices
  • Add <.action_button> shared component with variant support
  • Add <.modal_wrapper> shared component with a11y and focus trap
  • Add <.card> shared component to core_components
  • Add Phase 3 EN/FR translations and Connect setup documentation
  • Add Connect webhook handlers — CRM invoice payments, account.updated, disputes
  • Add Settings/PaymentsLive for Stripe Connect onboarding
  • Add public InvoicePaymentLive at /pay/:token with Stripe Elements
  • Add /settings/payments and /pay/:token routes
  • Auto-generate payment_token on invoice send when Connect enabled
  • Add StripeElements JS hook for embedded payment forms
  • Add ConnectService for Stripe Connect account management and destination charges
  • Add Stripe Connect fields to organizations, invoices, and payments
  • Add FocusTrap JS hook to all custom modals for WCAG compliance
  • Add Phase 2 EN/FR translations and update setup documentation
  • Add postpaid billing toggle and usage display to admin organizations page
  • Add postpaid budget enforcement, fix Stripe.Billing.MeterEvent to use Stripe.Request directly
  • Add postpaid budget enforcement using metered_usage_cache_cents
  • Invoice.paid resets postpaid cache, invoice.payment_failed auto-reverts postpaid orgs
  • Branch AI Router billing on org.billing_mode — prepaid debit vs postpaid meter
  • Add create/cancel metered subscription and make ensure_stripe_customer public
  • Add MeterEventWorker for retrying failed Stripe meter events
  • Add MeterService for postpaid Stripe meter event reporting
  • Add STRIPE_METERED_PRICE_ID configuration
  • Add metered_usage_cache_cents to organizations for postpaid budget tracking
  • Add EN/FR translations for billing portal and pricing table strings
  • Add Manage Billing portal button to billing dashboard
  • Embed Stripe Pricing Table in billing credits page with fallback
  • Add missing FR translations for AI assistant and actions dropdown
  • Add STRIPE_PUBLISHABLE_KEY and STRIPE_PRICING_TABLE_ID config
  • Add StripePricingTable JS hook for embedded pricing table
  • Add command palette (⌘J) with agent autocomplete and drawer integration
  • Add webhook handlers for invoice.paid, invoice.payment_failed, subscription lifecycle
  • Enable Stripe Tax on checkout sessions
  • Add billing_mode, postpaid_eligible, stripe_subscription_id to organizations
  • Add ActionsDropdown, replace header buttons in opportunity + client detail views
  • Add AI header button, wire drawer into layout with context tracking
  • Add GlobalAiDrawerComponent with persistent chat, agent switching, context banner
  • Add ContextResolver for page-to-agent mapping and context extraction
  • Enable response-healing plugin for JSON mode requests
  • Add automatic model fallbacks via OpenRouter models array
  • Add HTTP-Referer, X-Title headers and user tracking to OpenRouter requests
  • Add ai_access permission, fix starts_at column, make gather_org_snapshot resilient

🐛 Correctifs

  • Address ECL gap analysis — stale test, resend regression, modal UX, validation
  • Final gap analysis — PaymentIntent retrieve arity, tax service, mailer preload, UI accessibility
  • Standardize border-radius per design system (lg/xl/full)
  • Address Phase 3 gap analysis — PaymentIntent idempotency, multi-tenant scoping, webhook routing, UI fixes
  • Standardize transitions and icon sizes per design system
  • Standardize z-index layers per 4-tier design system
  • Add focus-visible styles to clickable non-button elements for keyboard a11y
  • Replace raw select elements with <.input type=select> component
  • Standardize slate→gray color palette and add dark mode to public pages
  • Add data-confirm to destructive remove actions
  • Address Phase 2 gap analysis — atomic cache, check_balance postpaid, Stripe API compat, confirmations
  • Add role=dialog, aria-modal, aria-labelledby to all custom modals
  • Use Integer.parse instead of String.to_integer for user input safety
  • Quick UI/UX polish — badge, period selector, package cards, toggle a11y
  • Define custom neutral-750 color for Tailwind v4
  • Address Phase 1 gap analysis — theme, loading states, error handling, docs
  • Context tracking, ChatServer safety, dropdown perf, mobile, accessibility
  • Context tracking, ChatServer safety, dropdown perf, mobile, accessibility
  • Propagate Repo.update errors in webhook handlers, remove inconsistent nil org_id guard
  • Read cost from response body usage.cost, fix streaming cost from final chunk
  • Extract x-openrouter-cost from Req header list format
  • Add handle_info catch-all to CRM LiveViews, improve agent actions UX
  • Wire AgentActionsComponent properly with is_admin, add catch-all error handling

♻️ Refactorisations

  • Rewrite workers to use EmailDispatch, remove ProposalSentEmailWorker
  • Strip sending logic from InvoiceMailer, remove maybe_send_invoice_email
  • Strip sending logic from CRM.Emails, keep template rendering only
  • Adopt <.modal_wrapper> in billing and misc LiveViews
  • Adopt <.modal_wrapper> in public LiveViews
  • Adopt <.modal_wrapper> in CRM LiveViews
  • Adopt <.modal_wrapper> in settings and org LiveViews
  • Adopt <.modal_wrapper> in admin LiveViews
  • Adopt <.card> component across all LiveViews
  • Extract shared format_cad helper, use integer arithmetic
v0.57.2 Nouveauté
Meridian

Version 0.57.2

🚀 Nouveautés

  • LLM metered billing & multi-provider model routing
  • Add LLM billing API (OpenAI-compatible chat completions + billing endpoints)
  • Add volume discounts and model performance tracking
  • Add credit expiry and receipt generation
  • Add budget/quota system and cost estimation
  • Add usage breakdown page with per-model, per-agent, per-feature views
  • Add rate limiting, custom alert thresholds, and debit retry mechanism
  • Add balance reconciliation worker and cost estimation fallback
  • Add BillingStartupWorker and document production env vars
  • Add Billing.Seed module for packages, models, and initial credit grants
  • Add usage charts, weekly digest worker, and sort order controls
  • Update EN/FR translations for all billing and admin UI strings
  • Add per-org billing config to admin organizations page
  • Add super admin billing analytics dashboard and settings page
  • Add super admin LLM model registry and credit packages CRUD
  • Replace agent model selector with tier-grouped curated model picker
  • Add AI settings page with model selection and use case overrides
  • Add org billing dashboard with balance, quick buy, auto-replenish, history
  • Add billing analytics context with usage aggregation queries
  • Add background workers (exchange rate, model sync, low balance notifier)
  • Add streaming support to AI.Router, wire JidoAgent streaming
  • Wire remaining OpenAIClient callers through AI.Router
  • Wire all AI modules through AI.Router (OpenRouter gateway)
  • Implement AutoReplenishWorker for Stripe off-session charges
  • Add Stripe webhook controller with signature verification
  • Add StripeService for checkout, auto-replenish, and webhook handling
  • Add AI.Router for OpenRouter integration with cost calculation and balance checks
  • Add Billing context with ledger operations, package/model CRUD, model resolution
  • Add billing fields to organization and agent schemas
  • Add billing schemas (ledger, packages, models, use cases, settings)
  • Add billing infrastructure migration (ledger, models, packages, org fields)
  • Add stripity_stripe dependency and Stripe/OpenRouter config
  • Add EN/FR translations for Phase 2 agent features
  • Add AI model selector to agent constitution page
  • LLM welcome messages with org data scan and action pills
  • Hook-driven action handlers and suggest_actions backend
  • Wire streaming from JidoAgent through ChatServer to LiveView
  • Add OpenAI streaming, model listing, and model cache
  • Add EN/FR translations for agent interaction layer
  • Add agent interaction layer UI components
  • Broadcast agent_activated event on agent startup
  • Add granular streaming PubSub events to JidoAgent
  • Add ChatServer GenServer for agent conversations
  • Add conversation and chat message context functions
  • Add ActionMapping config for entity-type agent actions
  • Add Conversation and ChatMessage schemas
  • Add agent_conversations and agent_chat_messages tables

🐛 Correctifs

  • Remove stale model references, add AgentActionsComponent to detail views
  • Stop passing stale model string to Router in action context
  • Use correct crm_ table names in gather_org_snapshot
  • Only seed LLM models when table is empty, respect admin deletions
  • Switch exchange rate API from exchangerate.host to Bank of Canada
  • Dark mode on admin pages, page titles, startup worker safety, DB-side filtering, model performance latency tracking
  • Add real email notifications for low balance and payment failure tracking
  • Add transaction filters, cost indicators, pricing display, permission checks, payment method section
  • 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

🐛 Correctifs

  • Review round 3 — public_download guard, modal events, preview_tab reset
  • Review round 2 — legacy file paths, extraction notifications, test fixes
  • Address code review issues — stale preload, tenant scoping, filename sanitization

♻️ Refactorisations

  • Combine all document migrations into single atomic migration
v0.47.4 Nouveauté
Meridian

Version 0.47.4

🚀 Nouveautés

  • Calendar hub — unified calendar, time tracking & availability
  • Localized date/time formatting, layout fallback, and code cleanup
  • Add EN/FR translations for calendar hub
  • Add client-side timer elapsed display and entry buttons in stats bar
  • Inline availability editing with drag-to-create, fill week, and repeat
  • Add timer, log time, and drag interactions for calendar events
  • Render time entries and running timer as calendar events
  • Add stats bar with unified view toggle and period-aware metrics
  • Extend FullCalendar hook with selectable, drag, view sync, and timer tracking
  • Add upsert_user_availability and scope availability queries by organization
  • Add organization_id to user_availabilities for multi-tenant scoping

🐛 Correctifs

  • Agent constitution view crashes and add actions management
  • API key scope and expiration selects not firing phx-change events
  • Calendar hub modal crashes and interaction issues

♻️ Refactorisations

  • Extract format_elapsed_time to shared TimeHelpers module
v0.47.2 Nouveauté
Meridian

Version 0.47.2

🚀 Nouveautés

  • Add public questionnaire link to discovery card

🐛 Correctifs

  • Apply AI suggestion text to editor on accept, bump to v0.47.2
  • Handle nil primary_contact on public discovery page
  • Booking_token is on Opportunity, not Discovery
  • Add Start Discovery button when no discovery exists
  • Add discovery questions and BANT link to opportunity detail card
  • Proposal create link using non-existent /proposals/new route
v0.47.1 Nouveauté
Meridian

Version 0.47.1

🚀 Nouveautés

  • Dynamic page titles with org name, favicon from branding logo, fix booking stage error, bump to v0.47.1
  • Wire flowing dashboard layout replacing old opportunity detail view
  • Add pharma consulting agent template, template picker, and fix future meeting creation
  • Add flowing dashboard components (header, actions, intelligence, bottom row)
v0.47.0 Nouveauté
Meridian

Version 0.47.0

🚀 Nouveautés

  • Rewrite research flow with Jido agent + PubSub
  • Add ResearchCompany Jido action with web search
  • Add submit_action/3 for direct Jido action execution
  • Add get_agent_for_action/2 for action-based agent lookup
  • Add TaskSupervisor for async agent actions

🐛 Correctifs

  • Group handle_event/handle_async/handle_info clauses in proposals live
  • Handle web_search output in OpenAI extract_content
v0.46.5 Nouveauté
Meridian

Version 0.46.5

🚀 Nouveautés

  • Replace textareas with rich editors on branding & email templates pages, bump to v0.46.5
v0.46.4 Nouveauté
Meridian

Version 0.46.4

🚀 Nouveautés

  • Wire real-time collaboration for proposal editor
  • Jido proposal writer agent, task extraction, renderer updates, translations
  • 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.

v0.3.0 Nouveauté
Meridian

Version 0.3.0

🚀 Nouveautés

  • Complete qualification checklist - locale-aware labels, disqualify action, auto-seed on org creation
v0.2.0 Nouveauté
Meridian

Version 0.2.0

🚀 Nouveautés

  • Update CRMClientsLive to use dynamic qualification criteria
  • Add qualification criteria schema, context, settings UI, and navigation
  • Update CRMClientsLive to use dynamic qualification criteria
  • Add qualification criteria schema, context, settings UI, and navigation
  • Add tenant branding settings (#59)
v0.1.7 Sécurité
Meridian

Version 0.1.7

🚀 Nouveautés

  • Add tenant branding settings (#59)

🔒 Sécurité

  • Enable database SSL with peer verification in production

🐛 Correctifs

  • Format and fix flaky audit event ordering test
v0.1.6 Correctif
Meridian

Version 0.1.6

🐛 Correctifs

  • Align discovery_question tests with DB constraints
v0.1.5 Nouveauté
Meridian

Version 0.1.5

🚀 Nouveautés

  • Extract CRM.Meetings sub-context (meetings, transcripts, availability)
  • Extract CRM.Billing sub-context (invoices, payments, time entries)
  • Extract CRM.Projects sub-context (projects, phases, milestones, deliverables, tasks)
  • Extract CRM.Proposals sub-context (proposals, line items, service blocks, templates)
  • Extract CRM.Sales sub-context (pipeline, opportunities, discovery)
  • Extract CRM.Companies sub-context (companies, contacts, activities)

♻️ Refactorisations

  • Update CRM sub-modules to use sub-contexts directly
  • Replace CRM context with pure delegation layer
v0.1.4 Nouveauté
Meridian

Version 0.1.4

🚀 Nouveautés

  • Unify CRM kanban boards, merge projects route, clean up pipeline stages
  • Add EN/FR translations for unified CRM views
  • Refresh stats and board data after mutations
  • Add board view and stats bar to Projects
  • Add stats bar to Clients view
  • Standardize Proposals view with pill toggle and enriched cards
  • Normalize Opportunities toggle to pill style
  • Add CRM stats and group-by-status functions for clients, projects, invoices
  • Add analytics dashboard, revenue queries, and fix i18n across all pages
  • Replace billing placeholder with revenue dashboard
  • Replace projects placeholder with real data table and apply unified header
  • Wire dashboard to real database data with KPI strip and activity feed
  • Add page_header, kpi_strip, and empty_state reusable components

🐛 Correctifs

  • Format CRM clients and invoices views
  • Formatting in release.ex and correct switch-org redirect path
  • Set organization_id on BackupJob struct and add sidebar version footer

♻️ Refactorisations

  • Fix all credo --strict issues across codebase
  • Apply unified header to settings and admin pages
  • Apply unified header to table and time tracking pages
  • Apply unified header pattern to CRM pages
v0.1.3 Nouveauté
Meridian

Version 0.1.3

🚀 Nouveautés

  • Add CSV import tool for legacy data migration
  • Auto-run migrations and seeds on production startup
  • Add Release module for production migrations and seeding
  • Add custom domain support for organizations
  • Add comprehensive backup system with S3 support and bulk operations
  • Add in-app notification system with real-time delivery
  • Rename accounts to organizations, add email templates & SMTP improvements

♻️ Refactorisations

  • Consolidate sidebar navigation from 10 to 7 sections
v0.1.2 Nouveauté
Meridian

Version 0.1.2

🚀 Nouveautés

  • Implement comprehensive localization system (EN/FR)
  • Complete pipeline revamp with discovery, meetings, and email config
  • Implement Pipeline section enhancements
  • Implement Phase 6 & 7 - AI Drafting and Client Proposal View
  • Implement Phase 4 - Meeting Management & Transcripts
  • Implement Phase 3 - User Availability & Meeting Scheduling
  • Implement Phase 2 & 5 - Contact form, lead scoring, and proposal templates
  • Phase 1 - Foundation for Pipeline Revamp
  • Complete CRM Phase 1-5 with bug fixes
  • Add structured contact role field with data migration
  • Add company qualification, service interests, and AI fields

🐛 Correctifs

  • Handle Decimal and NaiveDateTime types in dashboard
  • Update page controller test for login redirect
Légende

Types d'entrées

Chaque changement est étiqueté pour vous aider à repérer ce qui vous concerne.

Nouveauté Nouvelle fonctionnalité accessible à tous les utilisateurs.
Amélioration Changement qui améliore une fonctionnalité existante.
Correctif Bogue corrigé sans changement de comportement.
Refactorisation Changement technique sans impact utilisateur visible.
Sécurité Mise à jour de sécurité ou correction d'une vulnérabilité.