boondmanager-mcp-server 2.6.2 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +115 -4
  2. package/dist/schemas/index.d.ts +29 -3
  3. package/dist/schemas/index.d.ts.map +1 -1
  4. package/dist/schemas/index.js +90 -17
  5. package/dist/schemas/index.js.map +1 -1
  6. package/dist/services/boond-client.d.ts +8 -0
  7. package/dist/services/boond-client.d.ts.map +1 -1
  8. package/dist/services/boond-client.js +15 -14
  9. package/dist/services/boond-client.js.map +1 -1
  10. package/dist/services/logger.d.ts +8 -0
  11. package/dist/services/logger.d.ts.map +1 -1
  12. package/dist/services/logger.js +26 -1
  13. package/dist/services/logger.js.map +1 -1
  14. package/dist/tools/accounts.d.ts.map +1 -1
  15. package/dist/tools/accounts.js +9 -37
  16. package/dist/tools/accounts.js.map +1 -1
  17. package/dist/tools/actions.d.ts.map +1 -1
  18. package/dist/tools/actions.js +56 -2
  19. package/dist/tools/actions.js.map +1 -1
  20. package/dist/tools/agencies.d.ts.map +1 -1
  21. package/dist/tools/agencies.js +9 -37
  22. package/dist/tools/agencies.js.map +1 -1
  23. package/dist/tools/business-units.d.ts.map +1 -1
  24. package/dist/tools/business-units.js +9 -37
  25. package/dist/tools/business-units.js.map +1 -1
  26. package/dist/tools/calendars.d.ts.map +1 -1
  27. package/dist/tools/calendars.js +9 -37
  28. package/dist/tools/calendars.js.map +1 -1
  29. package/dist/tools/crud-factory.d.ts +33 -3
  30. package/dist/tools/crud-factory.d.ts.map +1 -1
  31. package/dist/tools/crud-factory.js +39 -18
  32. package/dist/tools/crud-factory.js.map +1 -1
  33. package/dist/tools/expenses.d.ts.map +1 -1
  34. package/dist/tools/expenses.js +25 -100
  35. package/dist/tools/expenses.js.map +1 -1
  36. package/dist/tools/flags.d.ts.map +1 -1
  37. package/dist/tools/flags.js +9 -37
  38. package/dist/tools/flags.js.map +1 -1
  39. package/dist/tools/invoices.d.ts.map +1 -1
  40. package/dist/tools/invoices.js +26 -80
  41. package/dist/tools/invoices.js.map +1 -1
  42. package/dist/tools/logs.d.ts.map +1 -1
  43. package/dist/tools/logs.js +9 -33
  44. package/dist/tools/logs.js.map +1 -1
  45. package/dist/tools/opportunities.d.ts.map +1 -1
  46. package/dist/tools/opportunities.js +28 -20
  47. package/dist/tools/opportunities.js.map +1 -1
  48. package/dist/tools/orders.d.ts.map +1 -1
  49. package/dist/tools/orders.js +22 -95
  50. package/dist/tools/orders.js.map +1 -1
  51. package/dist/tools/poles.d.ts.map +1 -1
  52. package/dist/tools/poles.js +9 -37
  53. package/dist/tools/poles.js.map +1 -1
  54. package/dist/tools/roles.d.ts.map +1 -1
  55. package/dist/tools/roles.js +9 -37
  56. package/dist/tools/roles.js.map +1 -1
  57. package/dist/tools/threads.d.ts.map +1 -1
  58. package/dist/tools/threads.js +9 -37
  59. package/dist/tools/threads.js.map +1 -1
  60. package/dist/tools/todolists.d.ts.map +1 -1
  61. package/dist/tools/todolists.js +9 -37
  62. package/dist/tools/todolists.js.map +1 -1
  63. package/dist/tools/webhooks.d.ts.map +1 -1
  64. package/dist/tools/webhooks.js +9 -37
  65. package/dist/tools/webhooks.js.map +1 -1
  66. package/dist/transports/http.d.ts.map +1 -1
  67. package/dist/transports/http.js +18 -9
  68. package/dist/transports/http.js.map +1 -1
  69. package/manifest.json +2 -2
  70. package/package.json +2 -2
package/README.md CHANGED
@@ -11,9 +11,21 @@
11
11
  [![GHCR](https://img.shields.io/badge/GHCR-fauguste%2Fboondmanager--mcp--server-181717?logo=github)](https://github.com/fauguste/boondmanager-mcp-server/pkgs/container/boondmanager-mcp-server)
12
12
  [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
13
13
 
14
+ **Installation 1-clic :**
15
+
16
+ [![Add to Cursor](https://img.shields.io/badge/Add%20to-Cursor-000000?logo=cursor&logoColor=white)](https://cursor.com/install-mcp?name=boondmanager&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsImJvb25kbWFuYWdlci1tY3Atc2VydmVyIl19)
17
+ [![Install in VS Code](https://img.shields.io/badge/Install-VS%20Code-0098FF?logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=boondmanager&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22boondmanager-mcp-server%22%5D%7D)
18
+ [![Install in VS Code Insiders](https://img.shields.io/badge/Install-VS%20Code%20Insiders-24bfa5?logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=boondmanager&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22boondmanager-mcp-server%22%5D%7D&quality=insiders)
19
+
20
+ <a href="https://glama.ai/mcp/servers/fauguste/boondmanager-mcp-server"><img src="https://glama.ai/mcp/servers/fauguste/boondmanager-mcp-server/badge" alt="Glama" width="180" /></a>
21
+
22
+ > **LM Studio**, **Goose** et **Gemini CLI** s'installent via leur procédure dédiée (deeplink natif ou commande) — voir la section [Installation](#installation). GitHub ne rend pas cliquables les liens à schéma non-HTTP (`lmstudio://`, `goose://`), c'est pourquoi ils n'ont pas de bouton 1-clic ici.
23
+
14
24
  Serveur MCP (Model Context Protocol) pour l'API BoondManager, permettant a Claude (Desktop, Cowork, Code) de rechercher, consulter, creer et modifier des enregistrements dans votre instance BoondManager.
15
25
 
16
- **175 outils** couvrant **38 domaines** de l'API BoondManager. Voir [TOOLS.md](./TOOLS.md) pour le catalogue auto-généré (outils + prompts + ressources).
26
+ **176 outils** couvrant **38 domaines** de l'API BoondManager. Voir [TOOLS.md](./TOOLS.md) pour le catalogue auto-généré (outils + prompts + ressources).
27
+
28
+ > **Sorties structurées.** En plus du texte lisible, les outils `search`, `create`, `update` et `delete` renvoient un `structuredContent` conforme à un `outputSchema` MCP : `search` → `{ total?, count, items[] }` (résumés compacts, pas les ressources JSON:API complètes), `create`/`update` → `{ id?, type? }`, `delete` → `{ id, deleted, reason? }`. Les clients MCP qui exploitent les sorties structurées obtiennent une référence d'entité fiable pour chaîner les appels. Les outils `get` restent en texte seul (leur texte est déjà du JSON exploitable).
17
29
 
18
30
  ## Domaines couverts
19
31
 
@@ -61,7 +73,7 @@ Serveur MCP (Model Context Protocol) pour l'API BoondManager, permettant a Claud
61
73
 
62
74
  | Domaine | Outils | Operations |
63
75
  |---------|--------|------------|
64
- | **Actions** | 4 | search, get, create, delete |
76
+ | **Actions** | 5 | search, get, create, update, delete |
65
77
  | **Validations** | 2 | search, get |
66
78
  | **Todolists** | 2 | search, get |
67
79
 
@@ -357,6 +369,85 @@ Le serveur est listé sur le [marketplace MCP de LobeHub](https://lobehub.com/mc
357
369
 
358
370
  Ou utiliser le transport HTTP (voir section [Transports](#transports)) pour un deploiement partage en mode gateway.
359
371
 
372
+ ### Cursor
373
+
374
+ Cliquez sur le badge **[Add to Cursor](https://cursor.com/install-mcp?name=boondmanager&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsImJvb25kbWFuYWdlci1tY3Atc2VydmVyIl19)** en haut du README (ou ajoutez le serveur manuellement dans **Settings > MCP > Add new MCP server**). Renseignez ensuite l'authentification en ajoutant un bloc `env` au serveur dans `~/.cursor/mcp.json` :
375
+
376
+ ```json
377
+ {
378
+ "mcpServers": {
379
+ "boondmanager": {
380
+ "command": "npx",
381
+ "args": ["-y", "boondmanager-mcp-server"],
382
+ "env": {
383
+ "BOOND_API_TOKEN": "votre_token_jwt"
384
+ }
385
+ }
386
+ }
387
+ }
388
+ ```
389
+
390
+ ### VS Code (GitHub Copilot / agent MCP)
391
+
392
+ Cliquez sur le badge **[Install in VS Code](https://insiders.vscode.dev/redirect/mcp/install?name=boondmanager&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22boondmanager-mcp-server%22%5D%7D)** en haut du README, ou ajoutez le serveur a `.vscode/mcp.json` (par projet) ou a votre `settings.json` utilisateur :
393
+
394
+ ```json
395
+ {
396
+ "servers": {
397
+ "boondmanager": {
398
+ "type": "stdio",
399
+ "command": "npx",
400
+ "args": ["-y", "boondmanager-mcp-server"],
401
+ "env": {
402
+ "BOOND_API_TOKEN": "${input:boond_api_token}"
403
+ }
404
+ }
405
+ }
406
+ }
407
+ ```
408
+
409
+ ### LM Studio
410
+
411
+ Dans LM Studio : **Program > Install > Edit `mcp.json`** et ajoutez :
412
+
413
+ ```json
414
+ {
415
+ "mcpServers": {
416
+ "boondmanager": {
417
+ "command": "npx",
418
+ "args": ["-y", "boondmanager-mcp-server"],
419
+ "env": {
420
+ "BOOND_API_TOKEN": "votre_token_jwt"
421
+ }
422
+ }
423
+ }
424
+ }
425
+ ```
426
+
427
+ ### Goose
428
+
429
+ Ajoutez une extension de type **STDIO** dans **Settings > Extensions > Add** avec la commande `npx -y boondmanager-mcp-server` et la variable d'environnement `BOOND_API_TOKEN`. En CLI :
430
+
431
+ ```bash
432
+ goose session --with-extension "npx -y boondmanager-mcp-server"
433
+ ```
434
+
435
+ ### Gemini CLI
436
+
437
+ Le depot embarque un manifeste d'extension Gemini CLI (`gemini-extension.json`). Installez l'extension directement depuis GitHub :
438
+
439
+ ```bash
440
+ gemini extensions install https://github.com/fauguste/boondmanager-mcp-server
441
+ ```
442
+
443
+ Definissez ensuite l'authentification dans votre environnement (Gemini interpole `${VAR}` au demarrage) :
444
+
445
+ ```bash
446
+ export BOOND_API_TOKEN="votre_token_jwt"
447
+ # ou le trio JWT auto :
448
+ export BOOND_USER_TOKEN="..." BOOND_CLIENT_TOKEN="..." BOOND_CLIENT_KEY="..."
449
+ ```
450
+
360
451
  ## Configuration
361
452
 
362
453
  ### Logs
@@ -424,6 +515,14 @@ Pour eviter qu'une boucle d'outils emballee n'inonde l'API (et n'enchaine les `4
424
515
  | `BOOND_HTTP_RATE_LIMIT_RPS` | `10` | Debit soutenu (requetes/seconde). `0` desactive completement. |
425
516
  | `BOOND_HTTP_RATE_LIMIT_BURST` | `20` | Capacite du bucket = taille maximale de rafale immediate. |
426
517
 
518
+ ### Cache du dictionnaire
519
+
520
+ L'API BoondManager n'expose qu'un seul endpoint `/application/dictionary` qui renvoie l'intégralité des libellés (états, types, pays…). Le serveur le met en cache en mémoire pour éviter de le re-télécharger à chaque résolution état/type → libellé.
521
+
522
+ | Variable | Defaut | Description |
523
+ |----------|--------|-------------|
524
+ | `BOOND_DICTIONARY_TTL_MS` | `3600000` (1 h) | Durée de vie du cache du dictionnaire, en millisecondes. Une valeur non numérique ou ≤ 0 retombe sur le défaut. |
525
+
427
526
  ### Restriction d'accès (domaines / lecture seule)
428
527
 
429
528
  Vous pouvez restreindre **ce que l'IA voit et peut faire**, entièrement par
@@ -593,6 +692,18 @@ docker compose logs -f mcp
593
692
 
594
693
  > **Securite** : le serveur HTTP est stateless et ne stocke aucun secret BoondManager. Chaque utilisateur authentifie le serveur via son propre token OAuth2 (issu de sa propre App BoondManager), et toutes les actions sont attribuees a son identite dans l'audit log Boond. Derriere un reverse proxy : terminez TLS (HTTPS), forwardez l'en-tete `Authorization`, et reglez `MCP_HTTP_PUBLIC_URL` sur l'URL publique pour que la discovery soit coherente.
595
694
 
695
+ ### Clients distants non-Claude (ChatGPT, OpenAI / Gemini Agents SDK)
696
+
697
+ MCP est un protocole **agnostique du modele** : le meme endpoint HTTP/OAuth2 est consomme tel quel par tout hote compatible MCP, pas seulement Claude. **Aucun package ni build specifique a un LLM n'est requis** — il suffit de pointer l'hote sur votre URL `MCP_HTTP_PUBLIC_URL`.
698
+
699
+ | Hote | Comment brancher le serveur |
700
+ |------|-----------------------------|
701
+ | **ChatGPT (connecteurs / Developer mode)** | Ajouter un connecteur MCP distant pointant sur l'URL HTTP ; l'OAuth2 est decouvert via la metadata `/.well-known/oauth-protected-resource`. |
702
+ | **OpenAI Agents SDK** | Declarer un `HostedMCPTool` / serveur MCP distant avec l'URL HTTP et le flux OAuth2. |
703
+ | **Google Gemini (Agents SDK / Vertex)** | Enregistrer le serveur MCP distant cote SDK ; en local, l'extension Gemini CLI (voir [Installation](#gemini-cli)) couvre le transport stdio. |
704
+
705
+ Le contrat est identique a celui de Claude Code en HTTP (voir l'exemple `claude mcp add --transport http` ci-dessus) : seule la maniere de declarer le serveur cote client change.
706
+
596
707
  ## Exemples d'utilisation
597
708
 
598
709
  Une fois configure, vous pouvez demander a Claude :
@@ -659,7 +770,7 @@ boondmanager-mcp-server/
659
770
  │ ├── companies.ts # 14 outils (CRUD + 9 onglets)
660
771
  │ ├── opportunities.ts # 10 outils (CRUD + 5 onglets)
661
772
  │ ├── projects.ts # 12 outils (CRUD + 7 onglets)
662
- │ ├── actions.ts # 4 outils
773
+ │ ├── actions.ts # 5 outils
663
774
  │ ├── timesheets.ts # 3 outils
664
775
  │ ├── invoices.ts # 5 outils
665
776
  │ ├── orders.ts # 5 outils
@@ -702,7 +813,7 @@ boondmanager-mcp-server/
702
813
 
703
814
  - Les credentials BoondManager (JWT ou BasicAuth) ne transitent jamais via le protocole MCP -- ils sont configures en variables d'environnement cote serveur uniquement
704
815
  - En mode **stdio**, le serveur tourne en local, aucun port reseau n'est expose
705
- - En mode **streamable HTTP**, protegez l'endpoint avec `MCP_HTTP_BEARER_TOKEN` + TLS (HTTPS via reverse proxy) et restreignez l'acces reseau a votre gateway
816
+ - En mode **streamable HTTP**, l'authentification est un **OAuth2 protected resource** : chaque requete MCP porte son propre `Authorization: Bearer <token>` (le serveur ne stocke aucun secret). Terminez TLS (HTTPS via reverse proxy), forwardez l'en-tete `Authorization`, reglez `MCP_HTTP_PUBLIC_URL` sur l'URL publique, et activez la protection anti DNS rebinding via `MCP_HTTP_ALLOWED_HOSTS`. Restreignez aussi l'acces reseau a votre gateway. Voir [docs/oauth.md](docs/oauth.md).
706
817
  - Compatible avec les exigences ISO 27001
707
818
  - L'API BoondManager est hebergee en France et conforme RGPD
708
819
  - Authentification BoondManager : JWT (recommande), BasicAuth, ou JWT construit automatiquement a partir des composants
@@ -474,21 +474,39 @@ export declare const CompanyUpdateSchema: z.ZodObject<{
474
474
  note: z.ZodOptional<z.ZodString>;
475
475
  }, z.core.$strict>;
476
476
  export declare const OpportunityCreateSchema: z.ZodObject<{
477
- name: z.ZodString;
477
+ typeOf: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
478
478
  companyId: z.ZodOptional<z.ZodString>;
479
479
  contactId: z.ZodOptional<z.ZodString>;
480
480
  state: z.ZodOptional<z.ZodPreprocess<z.ZodCoercedNumber<unknown>>>;
481
481
  startDate: z.ZodOptional<z.ZodString>;
482
482
  endDate: z.ZodOptional<z.ZodString>;
483
483
  note: z.ZodOptional<z.ZodString>;
484
+ criteria: z.ZodOptional<z.ZodString>;
485
+ expertiseArea: z.ZodOptional<z.ZodString>;
486
+ turnoverEstimatedExcludingTax: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
487
+ poleId: z.ZodOptional<z.ZodString>;
488
+ hrManagerId: z.ZodOptional<z.ZodString>;
489
+ mainManagerId: z.ZodOptional<z.ZodString>;
490
+ agencyId: z.ZodOptional<z.ZodString>;
491
+ name: z.ZodString;
484
492
  }, z.core.$strict>;
485
493
  export declare const OpportunityUpdateSchema: z.ZodObject<{
486
- id: z.ZodString;
487
- name: z.ZodOptional<z.ZodString>;
494
+ typeOf: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
495
+ companyId: z.ZodOptional<z.ZodString>;
496
+ contactId: z.ZodOptional<z.ZodString>;
488
497
  state: z.ZodOptional<z.ZodPreprocess<z.ZodCoercedNumber<unknown>>>;
489
498
  startDate: z.ZodOptional<z.ZodString>;
490
499
  endDate: z.ZodOptional<z.ZodString>;
491
500
  note: z.ZodOptional<z.ZodString>;
501
+ criteria: z.ZodOptional<z.ZodString>;
502
+ expertiseArea: z.ZodOptional<z.ZodString>;
503
+ turnoverEstimatedExcludingTax: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
504
+ poleId: z.ZodOptional<z.ZodString>;
505
+ hrManagerId: z.ZodOptional<z.ZodString>;
506
+ mainManagerId: z.ZodOptional<z.ZodString>;
507
+ agencyId: z.ZodOptional<z.ZodString>;
508
+ id: z.ZodString;
509
+ name: z.ZodOptional<z.ZodString>;
492
510
  }, z.core.$strict>;
493
511
  export declare const ActionSearchSchema: z.ZodObject<{
494
512
  keywords: z.ZodOptional<z.ZodString>;
@@ -513,6 +531,14 @@ export declare const ActionCreateSchema: z.ZodObject<{
513
531
  companyId: z.ZodOptional<z.ZodString>;
514
532
  positioningId: z.ZodOptional<z.ZodString>;
515
533
  }, z.core.$strict>;
534
+ export declare const ActionUpdateSchema: z.ZodObject<{
535
+ id: z.ZodString;
536
+ typeOf: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
537
+ title: z.ZodOptional<z.ZodString>;
538
+ text: z.ZodOptional<z.ZodString>;
539
+ startDate: z.ZodOptional<z.ZodString>;
540
+ endDate: z.ZodOptional<z.ZodString>;
541
+ }, z.core.$strict>;
516
542
  export declare const ResourceTimesheetSchema: z.ZodObject<{
517
543
  resourceId: z.ZodString;
518
544
  month: z.ZodOptional<z.ZodNumber>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schemas/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schemas/index.ts"],"names":[],"mappings":"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"}
@@ -49,6 +49,19 @@ const fieldsField = z
49
49
  "(ex: ['title', 'updateDate', 'numberOfActiveProjects']). Réduit fortement la taille de la réponse. " +
50
50
  "Absent = résumé standard (nom, email, ville, statut...). Les noms inconnus sont ignorés.");
51
51
  const strArray = (doc) => z.array(z.string()).optional().describe(doc);
52
+ // Shared `tools` (technologies/skills) filter. Centralised so every entity
53
+ // search exposes the same `#AND#` semantics to the model — previously the
54
+ // description ranged from the full explanation (resources) to a bare
55
+ // "IDs d'outils." (opportunities), so the model only learned about `#AND#`
56
+ // on some endpoints.
57
+ const toolsFilterField = strArray("IDs d'outils/technos (dictionnaire setting.tool). Logique OU par défaut. " +
58
+ "Pour ET, ajouter '#AND#' en 1er élément: tools=['#AND#','12','34'].");
59
+ // Action timestamps: ISO 8601 with timezone, e.g. 2026-06-05T10:00:00+0200.
60
+ // Accepts the colon-less (+0200) and colon (+02:00) offset styles, an optional
61
+ // fractional-seconds part, and a trailing Z. The timezone is optional so the
62
+ // API can apply the account default. Surfaces a malformed value at the schema
63
+ // boundary instead of as an opaque 422.
64
+ const actionDateTimeRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?([+-]\d{2}:?\d{2}|Z)?$/;
52
65
  // Shared "perimeter" filters available on every entity search (from RAML trait `searchable`).
53
66
  // These are the CORRECT filters for "my team / my agency / my N-1" — NOT the old `mainManagers`.
54
67
  const perimeterManagersField = intArray("IDs des managers (ressources). Conserve les entités dont le responsable est l'un de ces managers. " +
@@ -115,8 +128,7 @@ export const ResourceSearchSchema = z
115
128
  excludeResourceTypes: intArray("IDs de types de ressource à EXCLURE."),
116
129
  activityAreas: strArray("IDs de secteurs d'activité (dictionnaire setting.activityArea)."),
117
130
  expertiseAreas: strArray("IDs de domaines d'expertise (dictionnaire setting.expertiseArea)."),
118
- tools: strArray("IDs d'outils/technos (dictionnaire setting.tool). Logique OU par défaut. " +
119
- "Pour ET, ajouter '#AND#' en 1er élément: tools=['#AND#','12','34']."),
131
+ tools: toolsFilterField,
120
132
  experiences: intArray("IDs de niveaux d'expérience (dictionnaire setting.experience)."),
121
133
  trainings: strArray("IDs de formations (dictionnaire setting.training)."),
122
134
  mobilityAreas: strArray("IDs de zones de mobilité (dictionnaire setting.mobilityArea)."),
@@ -201,7 +213,7 @@ export const CandidateSearchSchema = z
201
213
  availabilityTypes: intArray("IDs de types de disponibilité (dictionnaire setting.availability)."),
202
214
  activityAreas: strArray("IDs de secteurs d'activité (dictionnaire setting.activityArea)."),
203
215
  expertiseAreas: strArray("IDs de domaines d'expertise."),
204
- tools: strArray("IDs d'outils/technos. Logique OU par défaut. Pour ET, ajouter '#AND#' en 1er élément."),
216
+ tools: toolsFilterField,
205
217
  experiences: intArray("IDs de niveaux d'expérience."),
206
218
  trainings: strArray("IDs de formations."),
207
219
  mobilityAreas: strArray("IDs de zones de mobilité."),
@@ -268,7 +280,7 @@ export const ContactSearchSchema = z
268
280
  origins: strArray("IDs d'origines (dictionnaire setting.origin)."),
269
281
  activityAreas: strArray("IDs de secteurs d'activité de la société."),
270
282
  expertiseAreas: strArray("IDs de domaines d'expertise de la société."),
271
- tools: strArray("IDs d'outils. Logique OU par défaut, '#AND#' en 1er pour ET."),
283
+ tools: toolsFilterField,
272
284
  influencers: intArray("IDs de contacts influenceurs."),
273
285
  flags: intArray("IDs de tags."),
274
286
  period: z
@@ -357,7 +369,7 @@ export const OpportunitySearchSchema = z
357
369
  positioningStates: strArray("IDs d'états de positionnement, ou 'none' pour les opportunités sans positionnement."),
358
370
  expertiseAreas: strArray("IDs de domaines d'expertise."),
359
371
  activityAreas: strArray("IDs de secteurs d'activité."),
360
- tools: strArray("IDs d'outils."),
372
+ tools: toolsFilterField,
361
373
  places: strArray("IDs de zones (dictionnaire setting.mobilityArea)."),
362
374
  durations: intArray("IDs de durées (dictionnaire setting.duration)."),
363
375
  origins: strArray("IDs d'origines."),
@@ -696,25 +708,61 @@ export const CompanyUpdateSchema = z
696
708
  })
697
709
  .strict();
698
710
  // ---- Opportunity schemas ----
711
+ // Writable fields shared by create and update. The attribute/relationship
712
+ // names mirror the official RAML (schemas/opportunities/information.json):
713
+ // - `note` → /data/attributes/description (the API has no `note` attribute,
714
+ // so the old direct pass-through was silently dropped — see issue #124)
715
+ // - `typeOf`, `criteria`, `expertiseArea`, `turnoverEstimatedExcludingTax`
716
+ // are plain attributes
717
+ // - `companyId`/`contactId`/`poleId`/`hrManagerId`/`mainManagerId`/`agencyId`
718
+ // become JSON:API relationships (resource types: company, contact, pole,
719
+ // resource, resource, agency)
720
+ const opportunityWritableShape = {
721
+ typeOf: z.coerce
722
+ .number()
723
+ .int()
724
+ .min(1)
725
+ .optional()
726
+ .describe("Type d'opportunité : ID numérique du dictionnaire setting.typeOf.project (ex: 1, 3), via boond_application_dictionary"),
727
+ companyId: z.string().optional().describe("ID de la société cliente (relation company)"),
728
+ contactId: z.string().optional().describe("ID du contact associé (relation contact)"),
729
+ state: stateField("opportunity", "État de l'opportunité"),
730
+ startDate: z.string().optional().describe("Date de début prévue (YYYY-MM-DD ou 'immediate')"),
731
+ endDate: z.string().optional().describe("Date de fin prévue (YYYY-MM-DD)"),
732
+ note: z
733
+ .string()
734
+ .max(65000)
735
+ .optional()
736
+ .describe("Description de l'opportunité (mappée sur /data/attributes/description)"),
737
+ criteria: z
738
+ .string()
739
+ .max(5000)
740
+ .optional()
741
+ .describe("Critères / compétences recherchées (texte libre). Alimente le matching de boond_workflow_candidats_pour_opportunite."),
742
+ expertiseArea: z
743
+ .string()
744
+ .optional()
745
+ .describe("Domaine d'expertise : ID du dictionnaire setting.expertiseArea (via boond_application_dictionary)"),
746
+ turnoverEstimatedExcludingTax: z.coerce.number().optional().describe("Chiffre d'affaires estimé HT (montant)"),
747
+ poleId: z.string().optional().describe("ID du pôle (relation pole)"),
748
+ hrManagerId: z.string().optional().describe("ID de la ressource responsable RH (relation hrManager)"),
749
+ mainManagerId: z
750
+ .string()
751
+ .optional()
752
+ .describe("ID de la ressource responsable principal / commercial (relation mainManager)"),
753
+ agencyId: z.string().optional().describe("ID de l'agence (relation agency)"),
754
+ };
699
755
  export const OpportunityCreateSchema = z
700
756
  .object({
701
757
  name: z.string().min(1).describe("Nom / titre de l'opportunité"),
702
- companyId: z.string().optional().describe("ID de la société cliente"),
703
- contactId: z.string().optional().describe("ID du contact associé"),
704
- state: stateField("opportunity", "État de l'opportunité"),
705
- startDate: z.string().optional().describe("Date de début prévue (YYYY-MM-DD)"),
706
- endDate: z.string().optional().describe("Date de fin prévue (YYYY-MM-DD)"),
707
- note: z.string().optional().describe("Notes / description"),
758
+ ...opportunityWritableShape,
708
759
  })
709
760
  .strict();
710
761
  export const OpportunityUpdateSchema = z
711
762
  .object({
712
763
  id: z.string().min(1).describe("ID de l'opportunité à modifier"),
713
764
  name: z.string().optional().describe("Nom / titre"),
714
- state: stateField("opportunity", "État"),
715
- startDate: z.string().optional().describe("Date de début (YYYY-MM-DD)"),
716
- endDate: z.string().optional().describe("Date de fin (YYYY-MM-DD)"),
717
- note: z.string().optional().describe("Notes"),
765
+ ...opportunityWritableShape,
718
766
  })
719
767
  .strict();
720
768
  // ---- Action schemas ----
@@ -743,9 +791,10 @@ export const ActionCreateSchema = z
743
791
  text: z.string().optional().describe("Contenu / notes de l'action"),
744
792
  startDate: z
745
793
  .string()
794
+ .regex(actionDateTimeRegex)
746
795
  .optional()
747
- .describe("Date de début au format ISO avec timezone (ex: 2026-06-05T10:00:00+0200)"),
748
- endDate: z.string().optional().describe("Date de fin (même format que startDate)"),
796
+ .describe("Date de début au format ISO 8601 avec timezone (ex: 2026-06-05T10:00:00+0200)"),
797
+ endDate: z.string().regex(actionDateTimeRegex).optional().describe("Date de fin (même format que startDate)"),
749
798
  candidateId: z.string().optional().describe("ID du candidat auquel rattacher l'action (dependsOn)"),
750
799
  resourceId: z.string().optional().describe("ID de la ressource à laquelle rattacher l'action (dependsOn)"),
751
800
  contactId: z.string().optional().describe("ID du contact auquel rattacher l'action (dependsOn)"),
@@ -758,6 +807,30 @@ export const ActionCreateSchema = z
758
807
  .describe("ID du positionnement à lier à l'action (relation positioning). Requis par l'API pour les types d'action liés aux positionnements (ex. RQ) — sans lui, erreur 422 « 1002 - Wrong or missing attribute (/data/relationships/positioning) »."),
759
808
  })
760
809
  .strict();
810
+ // PUT /actions/{id} (PATCH renvoie 405). Mise à jour partielle des seuls
811
+ // attributs : aucune relation n'est envoyée, ce qui préserve le rattachement
812
+ // `dependsOn`/`positioning` et la synchronisation calendrier (event Outlook /
813
+ // Teams). `typeOf` accepte uniquement l'ID numérique du dictionnaire ici (pas
814
+ // de résolution de libellé, faute d'entité `dependsOn` connue sur l'update).
815
+ export const ActionUpdateSchema = z
816
+ .object({
817
+ id: z.string().min(1).describe("ID de l'action à modifier"),
818
+ typeOf: z.coerce
819
+ .number()
820
+ .int()
821
+ .min(0)
822
+ .optional()
823
+ .describe("Nouveau type : ID numérique du dictionnaire setting.action.* (via boond_application_dictionary)"),
824
+ title: z.string().optional().describe("Nouveau titre de l'action"),
825
+ text: z.string().optional().describe("Nouveau contenu / notes (HTML accepté). Remplace l'existant (pas d'ajout)."),
826
+ startDate: z
827
+ .string()
828
+ .regex(actionDateTimeRegex)
829
+ .optional()
830
+ .describe("Date de début au format ISO 8601 avec timezone (ex: 2026-06-05T10:00:00+0200)"),
831
+ endDate: z.string().regex(actionDateTimeRegex).optional().describe("Date de fin (même format que startDate)"),
832
+ })
833
+ .strict();
761
834
  // ---- Timesheet schemas ----
762
835
  export const ResourceTimesheetSchema = z
763
836
  .object({