@cloudgrid-io/mcp 0.12.0 → 0.14.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 (390) hide show
  1. package/package.json +1 -1
  2. package/src/corpus/capability-map.md +82 -2
  3. package/src/corpus/examples/crm/index.md +273 -0
  4. package/src/corpus/examples/kanban/index.md +256 -0
  5. package/src/corpus/templates/_cloudgrid.yaml.reference +228 -0
  6. package/src/corpus/templates/admin-dashboard/README.md +75 -0
  7. package/src/corpus/templates/admin-dashboard/cloudgrid.yaml +233 -0
  8. package/src/corpus/templates/admin-dashboard/index.md +81 -0
  9. package/src/corpus/templates/admin-dashboard/services/web/app/api/orders/route.js +64 -0
  10. package/src/corpus/templates/admin-dashboard/services/web/app/api/users/route.js +63 -0
  11. package/src/corpus/templates/admin-dashboard/services/web/app/layout.js +39 -0
  12. package/src/corpus/templates/admin-dashboard/services/web/app/page.js +73 -0
  13. package/src/corpus/templates/admin-dashboard/services/web/app/resource-table.js +94 -0
  14. package/src/corpus/templates/admin-dashboard/services/web/lib/db.js +32 -0
  15. package/src/corpus/templates/admin-dashboard/services/web/package.json +16 -0
  16. package/src/corpus/templates/ai-app/cloudgrid.yaml +225 -11
  17. package/src/corpus/templates/ai-app/index.md +3 -11
  18. package/src/corpus/templates/ai-knowledge-base/AGENTS.md +254 -0
  19. package/src/corpus/templates/ai-knowledge-base/README.md +28 -0
  20. package/src/corpus/templates/ai-knowledge-base/cloudgrid.yaml +238 -0
  21. package/src/corpus/templates/ai-knowledge-base/index.md +81 -0
  22. package/src/corpus/templates/analytics-dashboard/README.md +85 -0
  23. package/src/corpus/templates/analytics-dashboard/cloudgrid.yaml +232 -0
  24. package/src/corpus/templates/analytics-dashboard/index.md +316 -0
  25. package/src/corpus/templates/analytics-dashboard/services/web/app/api/events/route.js +60 -0
  26. package/src/corpus/templates/analytics-dashboard/services/web/app/event-form.js +100 -0
  27. package/src/corpus/templates/analytics-dashboard/services/web/app/layout.js +41 -0
  28. package/src/corpus/templates/analytics-dashboard/services/web/app/page.js +54 -0
  29. package/src/corpus/templates/analytics-dashboard/services/web/lib/db.js +32 -0
  30. package/src/corpus/templates/analytics-dashboard/services/web/package.json +16 -0
  31. package/src/corpus/templates/api-dashboard/README.md +84 -0
  32. package/src/corpus/templates/api-dashboard/cloudgrid.yaml +233 -0
  33. package/src/corpus/templates/api-dashboard/index.md +310 -0
  34. package/src/corpus/templates/api-dashboard/services/web/app/api/requests/route.js +62 -0
  35. package/src/corpus/templates/api-dashboard/services/web/app/dashboard.js +156 -0
  36. package/src/corpus/templates/api-dashboard/services/web/app/layout.js +42 -0
  37. package/src/corpus/templates/api-dashboard/services/web/app/page.js +39 -0
  38. package/src/corpus/templates/api-dashboard/services/web/lib/db.js +32 -0
  39. package/src/corpus/templates/api-dashboard/services/web/package.json +16 -0
  40. package/src/corpus/templates/api-docs/README.md +28 -0
  41. package/src/corpus/templates/api-docs/cloudgrid.yaml +228 -0
  42. package/src/corpus/templates/api-docs/index.html +136 -0
  43. package/src/corpus/templates/api-docs/index.md +28 -0
  44. package/src/corpus/templates/api-service/cloudgrid.yaml +224 -9
  45. package/src/corpus/templates/api-service/index.md +3 -11
  46. package/src/corpus/templates/app-with-data/cloudgrid.yaml +226 -8
  47. package/src/corpus/templates/app-with-data/index.md +3 -8
  48. package/src/corpus/templates/appointment-booking/AGENTS.md +223 -0
  49. package/src/corpus/templates/appointment-booking/README.md +16 -0
  50. package/src/corpus/templates/appointment-booking/cloudgrid.yaml +250 -0
  51. package/src/corpus/templates/appointment-booking/index.md +72 -0
  52. package/src/corpus/templates/approval-workflow/AGENTS.md +170 -0
  53. package/src/corpus/templates/approval-workflow/README.md +12 -0
  54. package/src/corpus/templates/approval-workflow/cloudgrid.yaml +237 -0
  55. package/src/corpus/templates/approval-workflow/index.md +58 -0
  56. package/src/corpus/templates/billing-dashboard/AGENTS.md +199 -0
  57. package/src/corpus/templates/billing-dashboard/README.md +18 -0
  58. package/src/corpus/templates/billing-dashboard/cloudgrid.yaml +235 -0
  59. package/src/corpus/templates/billing-dashboard/index.md +87 -0
  60. package/src/corpus/templates/blog-cms/README.md +94 -0
  61. package/src/corpus/templates/blog-cms/cloudgrid.yaml +233 -0
  62. package/src/corpus/templates/blog-cms/index.md +358 -0
  63. package/src/corpus/templates/blog-cms/services/web/app/admin/admin-editor.js +133 -0
  64. package/src/corpus/templates/blog-cms/services/web/app/admin/page.js +33 -0
  65. package/src/corpus/templates/blog-cms/services/web/app/api/posts/route.js +84 -0
  66. package/src/corpus/templates/blog-cms/services/web/app/layout.js +47 -0
  67. package/src/corpus/templates/blog-cms/services/web/app/page.js +56 -0
  68. package/src/corpus/templates/blog-cms/services/web/app/posts/[slug]/page.js +45 -0
  69. package/src/corpus/templates/blog-cms/services/web/lib/db.js +32 -0
  70. package/src/corpus/templates/blog-cms/services/web/package.json +16 -0
  71. package/src/corpus/templates/booking-system/AGENTS.md +189 -0
  72. package/src/corpus/templates/booking-system/README.md +17 -0
  73. package/src/corpus/templates/booking-system/cloudgrid.yaml +248 -0
  74. package/src/corpus/templates/booking-system/index.md +86 -0
  75. package/src/corpus/templates/calendar-scheduler/AGENTS.md +226 -0
  76. package/src/corpus/templates/calendar-scheduler/README.md +25 -0
  77. package/src/corpus/templates/calendar-scheduler/cloudgrid.yaml +259 -0
  78. package/src/corpus/templates/calendar-scheduler/index.md +85 -0
  79. package/src/corpus/templates/changelog/README.md +27 -0
  80. package/src/corpus/templates/changelog/cloudgrid.yaml +228 -0
  81. package/src/corpus/templates/changelog/index.html +80 -0
  82. package/src/corpus/templates/changelog/index.md +28 -0
  83. package/src/corpus/templates/company-website/README.md +54 -0
  84. package/src/corpus/templates/company-website/cloudgrid.yaml +233 -0
  85. package/src/corpus/templates/company-website/index.html +309 -0
  86. package/src/corpus/templates/company-website/index.md +29 -0
  87. package/src/corpus/templates/course-platform/AGENTS.md +161 -0
  88. package/src/corpus/templates/course-platform/README.md +26 -0
  89. package/src/corpus/templates/course-platform/cloudgrid.yaml +237 -0
  90. package/src/corpus/templates/course-platform/index.md +70 -0
  91. package/src/corpus/templates/crm/README.md +72 -0
  92. package/src/corpus/templates/crm/cloudgrid.yaml +233 -0
  93. package/src/corpus/templates/crm/index.md +71 -0
  94. package/src/corpus/templates/crm/services/web/app/api/contacts/route.js +80 -0
  95. package/src/corpus/templates/crm/services/web/app/contact-manager.js +102 -0
  96. package/src/corpus/templates/crm/services/web/app/layout.js +35 -0
  97. package/src/corpus/templates/crm/services/web/app/page.js +34 -0
  98. package/src/corpus/templates/crm/services/web/lib/db.js +32 -0
  99. package/src/corpus/templates/crm/services/web/package.json +16 -0
  100. package/src/corpus/templates/dashboard/cloudgrid.yaml +228 -4
  101. package/src/corpus/templates/dashboard/index.md +3 -5
  102. package/src/corpus/templates/deck/cloudgrid.yaml +228 -4
  103. package/src/corpus/templates/deck/index.md +3 -5
  104. package/src/corpus/templates/directory/README.md +75 -0
  105. package/src/corpus/templates/directory/cloudgrid.yaml +233 -0
  106. package/src/corpus/templates/directory/index.md +334 -0
  107. package/src/corpus/templates/directory/services/web/app/api/entries/route.js +63 -0
  108. package/src/corpus/templates/directory/services/web/app/directory-list.js +146 -0
  109. package/src/corpus/templates/directory/services/web/app/layout.js +44 -0
  110. package/src/corpus/templates/directory/services/web/app/page.js +38 -0
  111. package/src/corpus/templates/directory/services/web/lib/db.js +32 -0
  112. package/src/corpus/templates/directory/services/web/package.json +16 -0
  113. package/src/corpus/templates/docs-site/README.md +28 -0
  114. package/src/corpus/templates/docs-site/cloudgrid.yaml +228 -0
  115. package/src/corpus/templates/docs-site/index.html +122 -0
  116. package/src/corpus/templates/docs-site/index.md +28 -0
  117. package/src/corpus/templates/erp/AGENTS.md +116 -0
  118. package/src/corpus/templates/erp/README.md +17 -0
  119. package/src/corpus/templates/erp/cloudgrid.yaml +235 -0
  120. package/src/corpus/templates/erp/index.md +81 -0
  121. package/src/corpus/templates/event-board/README.md +74 -0
  122. package/src/corpus/templates/event-board/cloudgrid.yaml +233 -0
  123. package/src/corpus/templates/event-board/index.md +299 -0
  124. package/src/corpus/templates/event-board/services/web/app/api/events/route.js +61 -0
  125. package/src/corpus/templates/event-board/services/web/app/event-form.js +118 -0
  126. package/src/corpus/templates/event-board/services/web/app/layout.js +39 -0
  127. package/src/corpus/templates/event-board/services/web/app/page.js +34 -0
  128. package/src/corpus/templates/event-board/services/web/lib/db.js +32 -0
  129. package/src/corpus/templates/event-board/services/web/package.json +16 -0
  130. package/src/corpus/templates/expense-tracker/README.md +76 -0
  131. package/src/corpus/templates/expense-tracker/cloudgrid.yaml +233 -0
  132. package/src/corpus/templates/expense-tracker/index.md +305 -0
  133. package/src/corpus/templates/expense-tracker/services/web/app/api/expenses/route.js +61 -0
  134. package/src/corpus/templates/expense-tracker/services/web/app/expense-form.js +145 -0
  135. package/src/corpus/templates/expense-tracker/services/web/app/layout.js +42 -0
  136. package/src/corpus/templates/expense-tracker/services/web/app/page.js +34 -0
  137. package/src/corpus/templates/expense-tracker/services/web/lib/db.js +32 -0
  138. package/src/corpus/templates/expense-tracker/services/web/package.json +16 -0
  139. package/src/corpus/templates/feature-request-board/README.md +87 -0
  140. package/src/corpus/templates/feature-request-board/cloudgrid.yaml +233 -0
  141. package/src/corpus/templates/feature-request-board/index.md +317 -0
  142. package/src/corpus/templates/feature-request-board/services/web/app/api/requests/route.js +92 -0
  143. package/src/corpus/templates/feature-request-board/services/web/app/board.js +91 -0
  144. package/src/corpus/templates/feature-request-board/services/web/app/layout.js +43 -0
  145. package/src/corpus/templates/feature-request-board/services/web/app/page.js +35 -0
  146. package/src/corpus/templates/feature-request-board/services/web/lib/db.js +32 -0
  147. package/src/corpus/templates/feature-request-board/services/web/package.json +16 -0
  148. package/src/corpus/templates/financial-dashboard/README.md +80 -0
  149. package/src/corpus/templates/financial-dashboard/cloudgrid.yaml +233 -0
  150. package/src/corpus/templates/financial-dashboard/index.md +326 -0
  151. package/src/corpus/templates/financial-dashboard/services/web/app/api/entries/route.js +63 -0
  152. package/src/corpus/templates/financial-dashboard/services/web/app/entry-board.js +130 -0
  153. package/src/corpus/templates/financial-dashboard/services/web/app/layout.js +46 -0
  154. package/src/corpus/templates/financial-dashboard/services/web/app/page.js +31 -0
  155. package/src/corpus/templates/financial-dashboard/services/web/lib/db.js +32 -0
  156. package/src/corpus/templates/financial-dashboard/services/web/package.json +16 -0
  157. package/src/corpus/templates/forum/AGENTS.md +196 -0
  158. package/src/corpus/templates/forum/README.md +12 -0
  159. package/src/corpus/templates/forum/cloudgrid.yaml +237 -0
  160. package/src/corpus/templates/forum/index.md +66 -0
  161. package/src/corpus/templates/hr-portal/AGENTS.md +174 -0
  162. package/src/corpus/templates/hr-portal/README.md +14 -0
  163. package/src/corpus/templates/hr-portal/cloudgrid.yaml +237 -0
  164. package/src/corpus/templates/hr-portal/index.md +56 -0
  165. package/src/corpus/templates/internal-tools-portal/AGENTS.md +201 -0
  166. package/src/corpus/templates/internal-tools-portal/README.md +17 -0
  167. package/src/corpus/templates/internal-tools-portal/cloudgrid.yaml +237 -0
  168. package/src/corpus/templates/internal-tools-portal/index.md +62 -0
  169. package/src/corpus/templates/inventory/README.md +71 -0
  170. package/src/corpus/templates/inventory/cloudgrid.yaml +233 -0
  171. package/src/corpus/templates/inventory/index.md +68 -0
  172. package/src/corpus/templates/inventory/services/web/app/api/items/route.js +88 -0
  173. package/src/corpus/templates/inventory/services/web/app/inventory-manager.js +101 -0
  174. package/src/corpus/templates/inventory/services/web/app/layout.js +36 -0
  175. package/src/corpus/templates/inventory/services/web/app/page.js +37 -0
  176. package/src/corpus/templates/inventory/services/web/lib/db.js +32 -0
  177. package/src/corpus/templates/inventory/services/web/package.json +16 -0
  178. package/src/corpus/templates/invoice/README.md +71 -0
  179. package/src/corpus/templates/invoice/cloudgrid.yaml +233 -0
  180. package/src/corpus/templates/invoice/index.md +68 -0
  181. package/src/corpus/templates/invoice/services/web/app/api/invoices/route.js +82 -0
  182. package/src/corpus/templates/invoice/services/web/app/invoice-manager.js +101 -0
  183. package/src/corpus/templates/invoice/services/web/app/layout.js +35 -0
  184. package/src/corpus/templates/invoice/services/web/app/page.js +34 -0
  185. package/src/corpus/templates/invoice/services/web/lib/db.js +32 -0
  186. package/src/corpus/templates/invoice/services/web/package.json +16 -0
  187. package/src/corpus/templates/job-board/README.md +71 -0
  188. package/src/corpus/templates/job-board/cloudgrid.yaml +233 -0
  189. package/src/corpus/templates/job-board/index.md +68 -0
  190. package/src/corpus/templates/job-board/services/web/app/api/jobs/route.js +66 -0
  191. package/src/corpus/templates/job-board/services/web/app/job-board.js +73 -0
  192. package/src/corpus/templates/job-board/services/web/app/layout.js +35 -0
  193. package/src/corpus/templates/job-board/services/web/app/page.js +32 -0
  194. package/src/corpus/templates/job-board/services/web/lib/db.js +32 -0
  195. package/src/corpus/templates/job-board/services/web/package.json +16 -0
  196. package/src/corpus/templates/kanban/README.md +72 -0
  197. package/src/corpus/templates/kanban/cloudgrid.yaml +233 -0
  198. package/src/corpus/templates/kanban/index.md +71 -0
  199. package/src/corpus/templates/kanban/services/web/app/api/cards/route.js +70 -0
  200. package/src/corpus/templates/kanban/services/web/app/board.js +93 -0
  201. package/src/corpus/templates/kanban/services/web/app/layout.js +37 -0
  202. package/src/corpus/templates/kanban/services/web/app/page.js +32 -0
  203. package/src/corpus/templates/kanban/services/web/lib/db.js +32 -0
  204. package/src/corpus/templates/kanban/services/web/package.json +16 -0
  205. package/src/corpus/templates/landing-page/cloudgrid.yaml +228 -4
  206. package/src/corpus/templates/landing-page/index.md +3 -5
  207. package/src/corpus/templates/lms/AGENTS.md +193 -0
  208. package/src/corpus/templates/lms/README.md +27 -0
  209. package/src/corpus/templates/lms/cloudgrid.yaml +237 -0
  210. package/src/corpus/templates/lms/index.md +79 -0
  211. package/src/corpus/templates/marketplace/AGENTS.md +208 -0
  212. package/src/corpus/templates/marketplace/README.md +22 -0
  213. package/src/corpus/templates/marketplace/cloudgrid.yaml +233 -0
  214. package/src/corpus/templates/marketplace/index.md +76 -0
  215. package/src/corpus/templates/membership-site/AGENTS.md +160 -0
  216. package/src/corpus/templates/membership-site/README.md +18 -0
  217. package/src/corpus/templates/membership-site/cloudgrid.yaml +236 -0
  218. package/src/corpus/templates/membership-site/index.md +66 -0
  219. package/src/corpus/templates/monitoring-dashboard/README.md +84 -0
  220. package/src/corpus/templates/monitoring-dashboard/cloudgrid.yaml +233 -0
  221. package/src/corpus/templates/monitoring-dashboard/index.md +328 -0
  222. package/src/corpus/templates/monitoring-dashboard/services/web/app/api/checks/route.js +76 -0
  223. package/src/corpus/templates/monitoring-dashboard/services/web/app/check-form.js +124 -0
  224. package/src/corpus/templates/monitoring-dashboard/services/web/app/layout.js +44 -0
  225. package/src/corpus/templates/monitoring-dashboard/services/web/app/page.js +49 -0
  226. package/src/corpus/templates/monitoring-dashboard/services/web/lib/db.js +32 -0
  227. package/src/corpus/templates/monitoring-dashboard/services/web/package.json +16 -0
  228. package/src/corpus/templates/online-store/AGENTS.md +153 -0
  229. package/src/corpus/templates/online-store/README.md +16 -0
  230. package/src/corpus/templates/online-store/cloudgrid.yaml +234 -0
  231. package/src/corpus/templates/online-store/index.md +81 -0
  232. package/src/corpus/templates/portfolio/README.md +29 -0
  233. package/src/corpus/templates/portfolio/cloudgrid.yaml +228 -0
  234. package/src/corpus/templates/portfolio/index.html +126 -0
  235. package/src/corpus/templates/portfolio/index.md +28 -0
  236. package/src/corpus/templates/product-catalog/README.md +74 -0
  237. package/src/corpus/templates/product-catalog/cloudgrid.yaml +232 -0
  238. package/src/corpus/templates/product-catalog/index.md +330 -0
  239. package/src/corpus/templates/product-catalog/services/web/app/api/products/route.js +69 -0
  240. package/src/corpus/templates/product-catalog/services/web/app/catalog.js +153 -0
  241. package/src/corpus/templates/product-catalog/services/web/app/layout.js +49 -0
  242. package/src/corpus/templates/product-catalog/services/web/app/page.js +36 -0
  243. package/src/corpus/templates/product-catalog/services/web/lib/db.js +32 -0
  244. package/src/corpus/templates/product-catalog/services/web/package.json +16 -0
  245. package/src/corpus/templates/product-launch/README.md +46 -0
  246. package/src/corpus/templates/product-launch/cloudgrid.yaml +234 -0
  247. package/src/corpus/templates/product-launch/index.html +320 -0
  248. package/src/corpus/templates/product-launch/index.md +34 -0
  249. package/src/corpus/templates/project-management/README.md +83 -0
  250. package/src/corpus/templates/project-management/cloudgrid.yaml +233 -0
  251. package/src/corpus/templates/project-management/index.md +346 -0
  252. package/src/corpus/templates/project-management/services/web/app/api/projects/route.js +48 -0
  253. package/src/corpus/templates/project-management/services/web/app/api/tasks/route.js +85 -0
  254. package/src/corpus/templates/project-management/services/web/app/board.js +182 -0
  255. package/src/corpus/templates/project-management/services/web/app/layout.js +45 -0
  256. package/src/corpus/templates/project-management/services/web/app/page.js +49 -0
  257. package/src/corpus/templates/project-management/services/web/lib/db.js +32 -0
  258. package/src/corpus/templates/project-management/services/web/package.json +16 -0
  259. package/src/corpus/templates/property-listings/README.md +76 -0
  260. package/src/corpus/templates/property-listings/cloudgrid.yaml +233 -0
  261. package/src/corpus/templates/property-listings/index.md +335 -0
  262. package/src/corpus/templates/property-listings/services/web/app/api/properties/route.js +73 -0
  263. package/src/corpus/templates/property-listings/services/web/app/layout.js +45 -0
  264. package/src/corpus/templates/property-listings/services/web/app/listings.js +152 -0
  265. package/src/corpus/templates/property-listings/services/web/app/page.js +53 -0
  266. package/src/corpus/templates/property-listings/services/web/lib/db.js +32 -0
  267. package/src/corpus/templates/property-listings/services/web/package.json +16 -0
  268. package/src/corpus/templates/quiz-platform/README.md +84 -0
  269. package/src/corpus/templates/quiz-platform/cloudgrid.yaml +233 -0
  270. package/src/corpus/templates/quiz-platform/index.md +313 -0
  271. package/src/corpus/templates/quiz-platform/services/web/app/api/questions/route.js +69 -0
  272. package/src/corpus/templates/quiz-platform/services/web/app/layout.js +47 -0
  273. package/src/corpus/templates/quiz-platform/services/web/app/page.js +37 -0
  274. package/src/corpus/templates/quiz-platform/services/web/app/quiz.js +188 -0
  275. package/src/corpus/templates/quiz-platform/services/web/lib/db.js +32 -0
  276. package/src/corpus/templates/quiz-platform/services/web/package.json +16 -0
  277. package/src/corpus/templates/report/cloudgrid.yaml +228 -4
  278. package/src/corpus/templates/report/index.md +3 -5
  279. package/src/corpus/templates/restaurant-reservations/AGENTS.md +258 -0
  280. package/src/corpus/templates/restaurant-reservations/README.md +17 -0
  281. package/src/corpus/templates/restaurant-reservations/cloudgrid.yaml +258 -0
  282. package/src/corpus/templates/restaurant-reservations/index.md +62 -0
  283. package/src/corpus/templates/revenue-dashboard/README.md +75 -0
  284. package/src/corpus/templates/revenue-dashboard/cloudgrid.yaml +233 -0
  285. package/src/corpus/templates/revenue-dashboard/index.md +307 -0
  286. package/src/corpus/templates/revenue-dashboard/services/web/app/api/sales/route.js +60 -0
  287. package/src/corpus/templates/revenue-dashboard/services/web/app/layout.js +40 -0
  288. package/src/corpus/templates/revenue-dashboard/services/web/app/page.js +87 -0
  289. package/src/corpus/templates/revenue-dashboard/services/web/app/sale-form.js +63 -0
  290. package/src/corpus/templates/revenue-dashboard/services/web/lib/db.js +32 -0
  291. package/src/corpus/templates/revenue-dashboard/services/web/package.json +16 -0
  292. package/src/corpus/templates/saas-marketing/README.md +30 -0
  293. package/src/corpus/templates/saas-marketing/cloudgrid.yaml +228 -0
  294. package/src/corpus/templates/saas-marketing/index.html +212 -0
  295. package/src/corpus/templates/saas-marketing/index.md +28 -0
  296. package/src/corpus/templates/status-page/README.md +28 -0
  297. package/src/corpus/templates/status-page/cloudgrid.yaml +228 -0
  298. package/src/corpus/templates/status-page/index.html +117 -0
  299. package/src/corpus/templates/status-page/index.md +28 -0
  300. package/src/corpus/templates/subscription-management/AGENTS.md +191 -0
  301. package/src/corpus/templates/subscription-management/README.md +21 -0
  302. package/src/corpus/templates/subscription-management/cloudgrid.yaml +236 -0
  303. package/src/corpus/templates/subscription-management/index.md +73 -0
  304. package/src/corpus/templates/task-manager/README.md +72 -0
  305. package/src/corpus/templates/task-manager/cloudgrid.yaml +233 -0
  306. package/src/corpus/templates/task-manager/index.md +71 -0
  307. package/src/corpus/templates/task-manager/services/web/app/api/tasks/route.js +77 -0
  308. package/src/corpus/templates/task-manager/services/web/app/layout.js +39 -0
  309. package/src/corpus/templates/task-manager/services/web/app/page.js +33 -0
  310. package/src/corpus/templates/task-manager/services/web/app/task-list.js +110 -0
  311. package/src/corpus/templates/task-manager/services/web/lib/db.js +32 -0
  312. package/src/corpus/templates/task-manager/services/web/package.json +16 -0
  313. package/src/corpus/templates/ticket-system/README.md +71 -0
  314. package/src/corpus/templates/ticket-system/cloudgrid.yaml +233 -0
  315. package/src/corpus/templates/ticket-system/index.md +68 -0
  316. package/src/corpus/templates/ticket-system/services/web/app/api/tickets/route.js +81 -0
  317. package/src/corpus/templates/ticket-system/services/web/app/layout.js +36 -0
  318. package/src/corpus/templates/ticket-system/services/web/app/page.js +35 -0
  319. package/src/corpus/templates/ticket-system/services/web/app/ticket-queue.js +112 -0
  320. package/src/corpus/templates/ticket-system/services/web/lib/db.js +32 -0
  321. package/src/corpus/templates/ticket-system/services/web/package.json +16 -0
  322. package/src/corpus/templates/time-tracking/README.md +81 -0
  323. package/src/corpus/templates/time-tracking/cloudgrid.yaml +233 -0
  324. package/src/corpus/templates/time-tracking/index.md +298 -0
  325. package/src/corpus/templates/time-tracking/services/web/app/api/entries/route.js +66 -0
  326. package/src/corpus/templates/time-tracking/services/web/app/entry-form.js +106 -0
  327. package/src/corpus/templates/time-tracking/services/web/app/layout.js +39 -0
  328. package/src/corpus/templates/time-tracking/services/web/app/page.js +30 -0
  329. package/src/corpus/templates/time-tracking/services/web/lib/db.js +32 -0
  330. package/src/corpus/templates/time-tracking/services/web/package.json +16 -0
  331. package/src/corpus/templates/travel-booking/AGENTS.md +207 -0
  332. package/src/corpus/templates/travel-booking/README.md +17 -0
  333. package/src/corpus/templates/travel-booking/cloudgrid.yaml +249 -0
  334. package/src/corpus/templates/travel-booking/index.md +88 -0
  335. package/src/corpus/templates/waitlist/README.md +38 -0
  336. package/src/corpus/templates/waitlist/cloudgrid.yaml +228 -0
  337. package/src/corpus/templates/waitlist/index.html +69 -0
  338. package/src/corpus/templates/waitlist/index.md +39 -0
  339. package/src/corpus/templates/web-app/cloudgrid.yaml +228 -4
  340. package/src/corpus/templates/web-app/index.md +3 -5
  341. package/src/corpus/workflows/admin-dashboard.md +102 -0
  342. package/src/corpus/workflows/ai-knowledge-base.md +137 -0
  343. package/src/corpus/workflows/analytics-dashboard.md +104 -0
  344. package/src/corpus/workflows/api-dashboard.md +102 -0
  345. package/src/corpus/workflows/api-docs.md +36 -0
  346. package/src/corpus/workflows/appointment-booking.md +143 -0
  347. package/src/corpus/workflows/approval-workflow.md +124 -0
  348. package/src/corpus/workflows/billing-dashboard.md +120 -0
  349. package/src/corpus/workflows/blog-cms.md +104 -0
  350. package/src/corpus/workflows/booking-system.md +116 -0
  351. package/src/corpus/workflows/calendar-scheduler.md +134 -0
  352. package/src/corpus/workflows/changelog.md +33 -0
  353. package/src/corpus/workflows/company-website.md +46 -0
  354. package/src/corpus/workflows/course-platform.md +126 -0
  355. package/src/corpus/workflows/crm.md +101 -0
  356. package/src/corpus/workflows/directory.md +101 -0
  357. package/src/corpus/workflows/docs-site.md +35 -0
  358. package/src/corpus/workflows/erp.md +125 -0
  359. package/src/corpus/workflows/event-board.md +102 -0
  360. package/src/corpus/workflows/expense-tracker.md +102 -0
  361. package/src/corpus/workflows/feature-request-board.md +105 -0
  362. package/src/corpus/workflows/financial-dashboard.md +103 -0
  363. package/src/corpus/workflows/forum.md +128 -0
  364. package/src/corpus/workflows/hr-portal.md +115 -0
  365. package/src/corpus/workflows/internal-tools-portal.md +125 -0
  366. package/src/corpus/workflows/inventory.md +101 -0
  367. package/src/corpus/workflows/invoice.md +101 -0
  368. package/src/corpus/workflows/job-board.md +101 -0
  369. package/src/corpus/workflows/kanban.md +102 -0
  370. package/src/corpus/workflows/lms.md +113 -0
  371. package/src/corpus/workflows/marketplace.md +123 -0
  372. package/src/corpus/workflows/membership-site.md +128 -0
  373. package/src/corpus/workflows/monitoring-dashboard.md +104 -0
  374. package/src/corpus/workflows/online-store.md +114 -0
  375. package/src/corpus/workflows/portfolio.md +35 -0
  376. package/src/corpus/workflows/product-catalog.md +105 -0
  377. package/src/corpus/workflows/product-launch.md +43 -0
  378. package/src/corpus/workflows/project-management.md +106 -0
  379. package/src/corpus/workflows/property-listings.md +101 -0
  380. package/src/corpus/workflows/quiz-platform.md +105 -0
  381. package/src/corpus/workflows/restaurant-reservations.md +123 -0
  382. package/src/corpus/workflows/revenue-dashboard.md +102 -0
  383. package/src/corpus/workflows/saas-marketing.md +37 -0
  384. package/src/corpus/workflows/status-page.md +35 -0
  385. package/src/corpus/workflows/subscription-management.md +141 -0
  386. package/src/corpus/workflows/task-manager.md +101 -0
  387. package/src/corpus/workflows/ticket-system.md +101 -0
  388. package/src/corpus/workflows/time-tracking.md +104 -0
  389. package/src/corpus/workflows/travel-booking.md +115 -0
  390. package/src/corpus/workflows/waitlist.md +42 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudgrid-io/mcp",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "description": "MCP server for CloudGrid. Three editions: a local stdio server (full toolset), a hosted web server (light, CLI-free toolset), and a public docs server (search_cloudgrid_documentation) over MCP Streamable HTTP.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,18 +13,50 @@ cloudgrid.yaml schema (every field, the `needs:` injection table, the
13
13
  requires-vs-needs caveat, validation rules), fetch the companion reference:
14
14
  `gridctl_fetch("doc", "cloudgrid-yaml")`.
15
15
 
16
- ## The 8 templates
16
+ ## The 58 templates
17
17
 
18
18
  | Intent (match on `when:`) | Template | `needs:` | Deploy | Edition |
19
19
  |---|---|---|---|---|
20
- | landing page, marketing/product/hero page, coming-soon, waitlist, pricing, portfolio, link-in-bio, event page | `landing-page` | none | inspiration (instant) | all |
20
+ | landing page, marketing/product/hero page, coming-soon, link-in-bio, event page — a single-section page | `landing-page` | none | inspiration (instant) | all |
21
+ | SaaS marketing site, product marketing page, features + pricing page — multi-section with pricing tiers, testimonials, FAQ | `saas-marketing` | none | inspiration (instant) | all |
22
+ | documentation site, docs, developer docs, guide, manual, knowledge base — prose docs with sidebar + search | `docs-site` | none | inspiration (instant) | all |
23
+ | API documentation, API reference, endpoint docs, REST API docs — method badges, params tables, request/response examples | `api-docs` | none | inspiration (instant) | all |
24
+ | status page, service status, uptime page, incident history, is-it-down page — display-only, status baked in | `status-page` | none | inspiration (instant) | all |
25
+ | changelog, release notes, what's new, product updates, version history | `changelog` | none | inspiration (instant) | all |
26
+ | portfolio, personal site, freelancer site, my work, showcase — projects grid + about + skills + contact | `portfolio` | none | inspiration (instant) | all |
27
+ | waitlist, coming soon, early access, join the list, launch page — email capture form (form is static; storing signups needs a runtime crud-app) | `waitlist` | none | inspiration (instant) | all |
21
28
  | calculator, converter, generator, timer, quiz, interactive tool, mini-app, widget — computed client-side, no saved data | `web-app` | none | inspiration (instant) | all |
22
29
  | dashboard, metrics, KPIs, stats page, status board, charts, analytics view — display-only, static data baked in | `dashboard` | none | inspiration (instant) | all |
23
30
  | report, one-pager, summary, brief, whitepaper, case study, formatted document | `report` | none | inspiration (instant) | all |
24
31
  | slides, deck, pitch, presentation, slideshow | `presentation` (dir: `deck`) | none | inspiration (instant) | all |
32
+ | product launch page, launch announcement, new product page, "we just launched" | `product-launch` | none | inspiration (instant) | all |
33
+ | company website, business site, corporate site, about-us site, small-business homepage | `company-website` | none | inspiration (instant) | all |
25
34
  | to-do, task list, notes app, guestbook, CRUD app, a form that SAVES/STORES submissions, anything that PERSISTS data or shares state across users/sessions, sign-in/accounts | `app-with-data` | `database: true` | runtime (async, poll) | local |
35
+ | CRM, contacts, leads, sales pipeline, customer manager, deal tracker | `crm` | `database: true` | runtime (async, poll) | local |
36
+ | kanban board, task board, trello-style board, workflow columns | `kanban` | `database: true` | runtime (async, poll) | local |
37
+ | task manager, to-do app (richer than the app-with-data starter), task list with due dates/priorities | `task-manager` | `database: true` | runtime (async, poll) | local |
38
+ | admin dashboard, admin panel, back-office, CRUD admin, manage records | `admin-dashboard` | `database: true` | runtime (async, poll) | local |
39
+ | invoice system, invoicing, billing invoices, send invoices, invoice tracker | `invoice` | `database: true` | runtime (async, poll) | local |
40
+ | inventory management, stock tracker, warehouse, product stock, SKU manager | `inventory` | `database: true` | runtime (async, poll) | local |
41
+ | job board, careers page, job listings, hiring board, open roles | `job-board` | `database: true` | runtime (async, poll) | local |
42
+ | ticket system, support tickets, helpdesk, issue tracker, support queue | `ticket-system` | `database: true` | runtime (async, poll) | local |
26
43
  | REST API, backend for X, API endpoint(s), CRUD API, JSON API, webhook receiver — a backend/service that stores data and isn't a full web UI | `api-service` | `database: true` | runtime (async, poll) | local |
27
44
  | chatbot, AI assistant, Q&A bot, conversational app, support bot, ask-me-anything, an app that talks to an LLM / generates text with AI | `ai-app` | `ai: true, database: true` | runtime (async, poll) | local |
45
+ | blog, CMS, content site with posts, publishing platform, articles | `blog-cms` | `database: true` | runtime (async, poll) | local |
46
+ | product catalog, product listings, catalog site, browse products (no checkout) | `product-catalog` | `database: true` | runtime (async, poll) | local |
47
+ | analytics dashboard, usage analytics, metrics from stored events | `analytics-dashboard` | `database: true` | runtime (async, poll) | local |
48
+ | monitoring dashboard, service health board, uptime/incident monitor (data-backed) | `monitoring-dashboard` | `database: true` | runtime (async, poll) | local |
49
+ | financial dashboard, finance metrics, P&L, cashflow board | `financial-dashboard` | `database: true` | runtime (async, poll) | local |
50
+ | expense tracker, spending log, budget tracker, expense report | `expense-tracker` | `database: true` | runtime (async, poll) | local |
51
+ | time tracking, timesheet, hours logger, billable hours | `time-tracking` | `database: true` | runtime (async, poll) | local |
52
+ | event board, events listing, community events, meetup board | `event-board` | `database: true` | runtime (async, poll) | local |
53
+ | directory, business directory, member directory, listings directory | `directory` | `database: true` | runtime (async, poll) | local |
54
+ | quiz, quiz platform, trivia, assessment, questionnaire | `quiz-platform` | `database: true` | runtime (async, poll) | local |
55
+ | API dashboard, API usage dashboard, API requests monitor | `api-dashboard` | `database: true` | runtime (async, poll) | local |
56
+ | feature request board, feedback board, roadmap voting, idea board | `feature-request-board` | `database: true` | runtime (async, poll) | local |
57
+ | revenue dashboard, sales dashboard, MRR/revenue view | `revenue-dashboard` | `database: true` | runtime (async, poll) | local |
58
+ | property listings, real estate site, rentals/homes listings | `property-listings` | `database: true` | runtime (async, poll) | local |
59
+ | project management, projects and tasks tracker, team project board | `project-management` | `database: true` | runtime (async, poll) | local |
28
60
 
29
61
  **Rule of thumb:** if the app must SAVE/remember data, share state across
30
62
  users/sessions, log in, or store submissions → it is persistent → runtime, local
@@ -32,6 +64,15 @@ edition. Pick by shape: a full web UI → `app-with-data`; a plain backend/JSON
32
64
  (no UI) → `api-service`; an app that talks to an LLM → `ai-app` (adds `ai:`).
33
65
  Otherwise a static template deploys instantly anywhere.
34
66
 
67
+ **The DB-CRUD family.** `crm`, `kanban`, `task-manager`, `admin-dashboard`,
68
+ `invoice`, `inventory`, `job-board`, and `ticket-system` all share the exact
69
+ `app-with-data` shape (nextjs + `needs: { database: true }`, app under
70
+ `services/web/`, lazy Mongo getter, force-dynamic App-Router routes) — they
71
+ differ only by domain schema + UI. Match the request to the closest one by its
72
+ `when:`; if it is a bare to-do or generic "save this data" with no specific
73
+ domain, use `app-with-data` (the minimal reference). Deploy path is identical for
74
+ all of them.
75
+
35
76
  ## Held / pending platform (not yet buildable)
36
77
 
37
78
  Two more archetypes are designed but blocked on platform work — the LLM should
@@ -42,6 +83,45 @@ know they are coming but must NOT author them yet:
42
83
  | scheduled task, cron job, "run every day/hour", periodic worker | a `type: cron` service (`schedule`, `timezone`) | **HELD** — platform issue #1543 (cron entities crash the online-check). Do not build. |
43
84
  | RAG chatbot, "answer over my own docs", semantic search, retrieval-augmented Q&A | `ai-app` + `needs: { vector: pgvector }` | **HELD** — platform issue #1545 (pgvector crashes the deploy). Ship the plain `ai-app` (no vector) for now. |
44
85
 
86
+ ## Blueprints (structure + cloudgrid.yaml; adapt the app — some pending platform support)
87
+
88
+ A **blueprint** is a heavier archetype that ships **structure + a correct
89
+ `cloudgrid.yaml` + an `AGENTS.md`** rather than fill-in-the-blanks app code
90
+ (`kind: blueprint` in the workflow frontmatter). Fetch the workflow, fetch the
91
+ template, **read its `AGENTS.md`** for the file tree / collections / CloudGrid
92
+ wiring (DB injection, `vault:` secrets for auth + Stripe, deploy), then BUILD the
93
+ app under `services/web/` following it. All are persistent Next.js + Mongo →
94
+ runtime, async build, **local edition only**. Auth/payment secrets map through a
95
+ `vault:` block → env vars (never `requires:`).
96
+
97
+ | Intent (match on `when:`) | Template | `needs:` | Deploy | Edition |
98
+ |---|---|---|---|---|
99
+ | online store, e-commerce store, shop with checkout, sell products online | `online-store` | `database: true` (+ Stripe via `vault:`) | runtime (async, poll) | local |
100
+ | marketplace, multi-vendor platform, two-sided marketplace | `marketplace` | `database: true` (+ Stripe/auth via `vault:`) | runtime (async, poll) | local |
101
+ | HR portal, employee portal, HR management, leave/PTO system | `hr-portal` | `database: true` (+ auth via `vault:`) | runtime (async, poll) | local |
102
+ | ERP, enterprise resource planning, integrated multi-module business system | `erp` | `database: true` (+ auth/Stripe via `vault:`) | runtime (async, poll) | local |
103
+ | forum, discussion board, community forum, threaded discussions | `forum` | `database: true` (+ auth via `vault:`) | runtime (async, poll) | local |
104
+ | membership site, paid community, subscriber content, gated content | `membership-site` | `database: true` (+ Stripe/auth via `vault:`) | runtime (async, poll) | local |
105
+ | course platform, sell online courses, Teachable-style | `course-platform` | `database: true` (+ Stripe/auth via `vault:`) | runtime (async, poll) | local |
106
+ | LMS, learning management system, training platform | `lms` | `database: true` (+ auth via `vault:`) | runtime (async, poll) | local |
107
+ | subscription management, manage subscriptions, self-serve plans/billing | `subscription-management` | `database: true` (+ Stripe via `vault:`) | runtime (async, poll) | local |
108
+ | billing dashboard, invoicing and payments dashboard, SaaS billing | `billing-dashboard` | `database: true` (+ Stripe via `vault:`) | runtime (async, poll) | local |
109
+ | internal tools portal, admin tools hub, back-office portal | `internal-tools-portal` | `database: true` (+ auth via `vault:`) | runtime (async, poll) | local |
110
+ | approval workflow, request approvals, multi-step approval system | `approval-workflow` | `database: true` (+ auth via `vault:`) | runtime (async, poll) | local |
111
+ | booking system, reservations, appointment booking, scheduling | `booking-system` | `database: true` (+ Stripe/auth via `vault:`); reminder **cron pending #1543** | runtime (async, poll) | local |
112
+ | calendar scheduler, team calendar, scheduling app, meeting scheduler | `calendar-scheduler` | `database: true` (+ optional auth/Stripe via `vault:`); reminder **cron pending #1543** | runtime (async, poll) | local |
113
+ | appointment booking, clinic/salon booking, appointment scheduler | `appointment-booking` | `database: true` (+ auth/Stripe via `vault:`); reminder **cron pending #1543** | runtime (async, poll) | local |
114
+ | restaurant website with reservations, table booking, restaurant site | `restaurant-reservations` | `database: true` (+ Stripe/email via `vault:`); reminder **cron pending #1543** | runtime (async, poll) | local |
115
+ | travel booking portal, trip booking, flights/hotels booking, travel reservations | `travel-booking` | `database: true` (+ Stripe/auth via `vault:`); reminder **cron pending #1543** | runtime (async, poll) | local |
116
+ | RAG, ask my docs, knowledge base chatbot, retrieval-augmented search over documents | `ai-knowledge-base` | `ai: true, database: true`; ideal `vector: pgvector` **pending #1545** (store embeddings in Mongo + cosine-rank until it lands) | runtime (async, poll) | local |
117
+
118
+ The booking family (`booking-system`, `calendar-scheduler`, `appointment-booking`,
119
+ `restaurant-reservations`, `travel-booking`) is fully buildable today **minus**
120
+ the reminder cron — a `type: cron` service is HELD on platform issue **#1543**, so
121
+ ship without it. `ai-knowledge-base` builds today on the AI Gateway + Mongo; its
122
+ ideal `needs: { vector: pgvector }` embedding store is HELD on **#1545**, so store
123
+ chunks in Mongo and cosine-rank in-app until it lands.
124
+
45
125
  ## The full `needs:` vocabulary (the whole menu)
46
126
 
47
127
  `needs:` is a MAP declaring infrastructure capabilities. Values are `true` or an
@@ -0,0 +1,273 @@
1
+ # Example: crm — "Sales Pipeline CRM"
2
+
3
+ A filled reference imitating the `crm` template: a persistent sales-pipeline CRM.
4
+ Same stack (Next.js App Router + the `mongodb` driver, grid-shared Mongo via
5
+ `process.env.DATABASE_MONGODB_URL`). Contacts have a `name`, `email`, `company`,
6
+ a `stage` (lead / qualified / customer) and a `note`; the table lets you add a
7
+ contact, change its stage inline, and delete it.
8
+
9
+ Data persists in the grid-shared Mongo, so the whole team sees the same pipeline
10
+ across sessions and refresh.
11
+
12
+ **Same three proven rules as the template:** (1) app code lives under
13
+ **`services/web/`** (the service name, NOT the repo root — `path:` is the URL
14
+ mount); (2) the DB connection string is read **lazily inside the `getDb`
15
+ getter**, never at module top level (a top-level read fails `next build`); (3)
16
+ the datastore is declared with the canonical **`needs: { database: true }`** —
17
+ the deployer provisions Mongo and injects `DATABASE_MONGODB_URL` (plus the legacy
18
+ `MONGODB_URL` alias). Don't use the deprecated `requires:` alias.
19
+
20
+ ## cloudgrid.yaml
21
+
22
+ ```yaml
23
+ # `needs: { database: true }` is canonical: the deployer provisions Mongo and
24
+ # injects DATABASE_MONGODB_URL (plus the legacy MONGODB_URL alias). `requires:`
25
+ # is the deprecated v1 alias — don't mix the two (the validator rejects it).
26
+ name: sales-pipeline-crm
27
+ services:
28
+ web:
29
+ type: nextjs
30
+ path: /
31
+ needs:
32
+ database: true
33
+ ```
34
+
35
+ ## services/web/package.json
36
+
37
+ ```json
38
+ {
39
+ "name": "sales-pipeline-crm",
40
+ "version": "0.1.0",
41
+ "private": true,
42
+ "scripts": { "dev": "next dev", "build": "next build", "start": "next start" },
43
+ "dependencies": {
44
+ "next": "^15.1.0",
45
+ "react": "^19.0.0",
46
+ "react-dom": "^19.0.0",
47
+ "mongodb": "^6.12.0"
48
+ }
49
+ }
50
+ ```
51
+
52
+ ## services/web/lib/db.js
53
+
54
+ ```js
55
+ // Cached Mongo client. The grid injects DATABASE_MONGODB_URL (plus the legacy
56
+ // MONGODB_URL alias) at dev + runtime. Read the canonical var first, fall back to
57
+ // the legacy alias. Resolve it LAZILY inside the getter — a top-level read fails
58
+ // `next build`.
59
+ import { MongoClient } from "mongodb";
60
+
61
+ function clientPromise() {
62
+ const uri = process.env.DATABASE_MONGODB_URL || process.env.MONGODB_URL;
63
+ if (!uri) {
64
+ throw new Error(
65
+ "DATABASE_MONGODB_URL is not set. The grid injects it — run `grid dev` " +
66
+ "locally or deploy with `grid plug`. Do not set it by hand.",
67
+ );
68
+ }
69
+ if (!globalThis.__mongoClientPromise) {
70
+ globalThis.__mongoClientPromise = new MongoClient(uri).connect();
71
+ }
72
+ return globalThis.__mongoClientPromise;
73
+ }
74
+
75
+ export async function getDb() {
76
+ return (await clientPromise()).db();
77
+ }
78
+ ```
79
+
80
+ ## services/web/app/api/contacts/route.js
81
+
82
+ ```js
83
+ import { NextResponse } from "next/server";
84
+ import { ObjectId } from "mongodb";
85
+ import { getDb } from "../../../lib/db.js";
86
+
87
+ export const dynamic = "force-dynamic";
88
+
89
+ const STAGES = ["lead", "qualified", "customer"];
90
+
91
+ async function contacts() {
92
+ return (await getDb()).collection("contacts");
93
+ }
94
+
95
+ function shape(c) {
96
+ return {
97
+ id: c._id.toString(),
98
+ name: c.name || "",
99
+ email: c.email || "",
100
+ company: c.company || "",
101
+ stage: STAGES.includes(c.stage) ? c.stage : "lead",
102
+ note: c.note || "",
103
+ };
104
+ }
105
+
106
+ // GET /api/contacts — list the pipeline.
107
+ export async function GET() {
108
+ const col = await contacts();
109
+ const items = await col.find({}).sort({ createdAt: -1 }).toArray();
110
+ return NextResponse.json(items.map(shape));
111
+ }
112
+
113
+ // POST /api/contacts — add a contact. Body: { name, email, company, note }.
114
+ export async function POST(request) {
115
+ const body = await request.json().catch(() => ({}));
116
+ const name = typeof body.name === "string" ? body.name.trim() : "";
117
+ if (!name) return NextResponse.json({ error: "name is required" }, { status: 400 });
118
+ const doc = {
119
+ name,
120
+ email: typeof body.email === "string" ? body.email.trim() : "",
121
+ company: typeof body.company === "string" ? body.company.trim() : "",
122
+ stage: "lead",
123
+ note: typeof body.note === "string" ? body.note.trim() : "",
124
+ createdAt: new Date(),
125
+ };
126
+ const col = await contacts();
127
+ const res = await col.insertOne(doc);
128
+ return NextResponse.json({ id: res.insertedId.toString(), ...doc }, { status: 201 });
129
+ }
130
+
131
+ // PATCH /api/contacts — move a contact along the pipeline. Body: { id, stage }.
132
+ export async function PATCH(request) {
133
+ const body = await request.json().catch(() => ({}));
134
+ const { id, stage } = body;
135
+ if (!id || !ObjectId.isValid(id) || !STAGES.includes(stage)) {
136
+ return NextResponse.json({ error: "valid id and stage required" }, { status: 400 });
137
+ }
138
+ const col = await contacts();
139
+ await col.updateOne({ _id: new ObjectId(id) }, { $set: { stage } });
140
+ return NextResponse.json({ ok: true });
141
+ }
142
+
143
+ // DELETE /api/contacts?id=<id>
144
+ export async function DELETE(request) {
145
+ const id = new URL(request.url).searchParams.get("id");
146
+ if (!id || !ObjectId.isValid(id)) {
147
+ return NextResponse.json({ error: "valid id is required" }, { status: 400 });
148
+ }
149
+ const col = await contacts();
150
+ await col.deleteOne({ _id: new ObjectId(id) });
151
+ return NextResponse.json({ ok: true });
152
+ }
153
+ ```
154
+
155
+ ## services/web/app/page.js
156
+
157
+ ```js
158
+ import { getDb } from "../lib/db.js";
159
+ import ContactManager from "./contact-manager.js";
160
+
161
+ export const dynamic = "force-dynamic";
162
+
163
+ const STAGES = ["lead", "qualified", "customer"];
164
+
165
+ async function listContacts() {
166
+ const items = await (await getDb())
167
+ .collection("contacts")
168
+ .find({})
169
+ .sort({ createdAt: -1 })
170
+ .toArray();
171
+ return items.map((c) => ({
172
+ id: c._id.toString(),
173
+ name: c.name || "",
174
+ email: c.email || "",
175
+ company: c.company || "",
176
+ stage: STAGES.includes(c.stage) ? c.stage : "lead",
177
+ note: c.note || "",
178
+ }));
179
+ }
180
+
181
+ export default async function Page() {
182
+ const contacts = await listContacts();
183
+ return (
184
+ <main>
185
+ <h1>Sales Pipeline</h1>
186
+ <p className="hint">Shared across the team — persisted in grid Mongo.</p>
187
+ <ContactManager initialContacts={contacts} />
188
+ </main>
189
+ );
190
+ }
191
+ ```
192
+
193
+ ## services/web/app/contact-manager.js
194
+
195
+ ```js
196
+ "use client";
197
+ import { useState } from "react";
198
+
199
+ const STAGES = ["lead", "qualified", "customer"];
200
+ const LABELS = { lead: "Lead", qualified: "Qualified", customer: "Customer" };
201
+
202
+ export default function ContactManager({ initialContacts }) {
203
+ const [contacts, setContacts] = useState(initialContacts);
204
+ const [name, setName] = useState("");
205
+ const [email, setEmail] = useState("");
206
+ const [company, setCompany] = useState("");
207
+
208
+ async function add(e) {
209
+ e.preventDefault();
210
+ if (!name.trim()) return;
211
+ const res = await fetch("/api/contacts", {
212
+ method: "POST",
213
+ headers: { "content-type": "application/json" },
214
+ body: JSON.stringify({ name, email, company }),
215
+ });
216
+ if (res.ok) { setContacts((p) => [await res.json(), ...p]); setName(""); setEmail(""); setCompany(""); }
217
+ }
218
+
219
+ async function setStage(id, stage) {
220
+ const res = await fetch("/api/contacts", {
221
+ method: "PATCH",
222
+ headers: { "content-type": "application/json" },
223
+ body: JSON.stringify({ id, stage }),
224
+ });
225
+ if (res.ok) setContacts((p) => p.map((c) => (c.id === id ? { ...c, stage } : c)));
226
+ }
227
+
228
+ async function remove(id) {
229
+ const res = await fetch(`/api/contacts?id=${encodeURIComponent(id)}`, { method: "DELETE" });
230
+ if (res.ok) setContacts((p) => p.filter((c) => c.id !== id));
231
+ }
232
+
233
+ return (
234
+ <div>
235
+ <form onSubmit={add} className="row">
236
+ <input value={name} onChange={(e) => setName(e.target.value)} placeholder="Name" />
237
+ <input value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" />
238
+ <input value={company} onChange={(e) => setCompany(e.target.value)} placeholder="Company" />
239
+ <button type="submit">Add</button>
240
+ </form>
241
+ <table>
242
+ <thead>
243
+ <tr><th>Name</th><th>Email</th><th>Company</th><th>Stage</th><th></th></tr>
244
+ </thead>
245
+ <tbody>
246
+ {contacts.map((c) => (
247
+ <tr key={c.id}>
248
+ <td>{c.name}</td>
249
+ <td>{c.email}</td>
250
+ <td>{c.company}</td>
251
+ <td>
252
+ <select value={c.stage} onChange={(e) => setStage(c.id, e.target.value)}>
253
+ {STAGES.map((s) => <option key={s} value={s}>{LABELS[s]}</option>)}
254
+ </select>
255
+ </td>
256
+ <td><button type="button" onClick={() => remove(c.id)}>Delete</button></td>
257
+ </tr>
258
+ ))}
259
+ </tbody>
260
+ </table>
261
+ </div>
262
+ );
263
+ }
264
+ ```
265
+
266
+ ## Notes
267
+
268
+ - Deploy the same way as the template: `grid dev` locally, `grid plug` to deploy
269
+ (async — poll status to a live URL). Re-plug the same entity to keep one URL.
270
+ - The only store this needs is Mongo (`needs: { database: true }`). Add
271
+ `cache: true` to `needs:` only for caching/sessions you actually use.
272
+ - All app code lives under `services/web/`; the connection is read lazily inside
273
+ `getDb`, never at module top level.
@@ -0,0 +1,256 @@
1
+ # Example: kanban — "Workflow Board"
2
+
3
+ A filled reference imitating the `kanban` template: a persistent trello-style
4
+ board. Same stack (Next.js App Router + the `mongodb` driver, grid-shared Mongo
5
+ via `process.env.DATABASE_MONGODB_URL`). Cards have a `title`, a `column` (todo /
6
+ doing / done) and an `order`; you add a card to the first column, move it between
7
+ columns, and delete it.
8
+
9
+ Data persists in the grid-shared Mongo, so the whole team sees the same board
10
+ across sessions and refresh.
11
+
12
+ **Same three proven rules as the template:** (1) app code lives under
13
+ **`services/web/`** (the service name, NOT the repo root — `path:` is the URL
14
+ mount); (2) the DB connection string is read **lazily inside the `getDb`
15
+ getter**, never at module top level (a top-level read fails `next build`); (3)
16
+ the datastore is declared with the canonical **`needs: { database: true }`** —
17
+ the deployer provisions Mongo and injects `DATABASE_MONGODB_URL` (plus the legacy
18
+ `MONGODB_URL` alias). Don't use the deprecated `requires:` alias.
19
+
20
+ ## cloudgrid.yaml
21
+
22
+ ```yaml
23
+ # `needs: { database: true }` is canonical: the deployer provisions Mongo and
24
+ # injects DATABASE_MONGODB_URL (plus the legacy MONGODB_URL alias). `requires:`
25
+ # is the deprecated v1 alias — don't mix the two (the validator rejects it).
26
+ name: workflow-board
27
+ services:
28
+ web:
29
+ type: nextjs
30
+ path: /
31
+ needs:
32
+ database: true
33
+ ```
34
+
35
+ ## services/web/package.json
36
+
37
+ ```json
38
+ {
39
+ "name": "workflow-board",
40
+ "version": "0.1.0",
41
+ "private": true,
42
+ "scripts": { "dev": "next dev", "build": "next build", "start": "next start" },
43
+ "dependencies": {
44
+ "next": "^15.1.0",
45
+ "react": "^19.0.0",
46
+ "react-dom": "^19.0.0",
47
+ "mongodb": "^6.12.0"
48
+ }
49
+ }
50
+ ```
51
+
52
+ ## services/web/lib/db.js
53
+
54
+ ```js
55
+ // Cached Mongo client. The grid injects DATABASE_MONGODB_URL (plus the legacy
56
+ // MONGODB_URL alias) at dev + runtime. Read the canonical var first, fall back to
57
+ // the legacy alias. Resolve it LAZILY inside the getter — a top-level read fails
58
+ // `next build`.
59
+ import { MongoClient } from "mongodb";
60
+
61
+ function clientPromise() {
62
+ const uri = process.env.DATABASE_MONGODB_URL || process.env.MONGODB_URL;
63
+ if (!uri) {
64
+ throw new Error(
65
+ "DATABASE_MONGODB_URL is not set. The grid injects it — run `grid dev` " +
66
+ "locally or deploy with `grid plug`. Do not set it by hand.",
67
+ );
68
+ }
69
+ if (!globalThis.__mongoClientPromise) {
70
+ globalThis.__mongoClientPromise = new MongoClient(uri).connect();
71
+ }
72
+ return globalThis.__mongoClientPromise;
73
+ }
74
+
75
+ export async function getDb() {
76
+ return (await clientPromise()).db();
77
+ }
78
+ ```
79
+
80
+ ## services/web/app/api/cards/route.js
81
+
82
+ ```js
83
+ import { NextResponse } from "next/server";
84
+ import { ObjectId } from "mongodb";
85
+ import { getDb } from "../../../lib/db.js";
86
+
87
+ export const dynamic = "force-dynamic";
88
+
89
+ const COLUMNS = ["todo", "doing", "done"];
90
+
91
+ async function cards() {
92
+ return (await getDb()).collection("cards");
93
+ }
94
+
95
+ function shape(c) {
96
+ return {
97
+ id: c._id.toString(),
98
+ title: c.title || "",
99
+ column: COLUMNS.includes(c.column) ? c.column : "todo",
100
+ order: typeof c.order === "number" ? c.order : 0,
101
+ };
102
+ }
103
+
104
+ // GET /api/cards — list the board, ordered.
105
+ export async function GET() {
106
+ const col = await cards();
107
+ const items = await col.find({}).sort({ order: 1, createdAt: 1 }).toArray();
108
+ return NextResponse.json(items.map(shape));
109
+ }
110
+
111
+ // POST /api/cards — add a card to the first column. Body: { title }.
112
+ export async function POST(request) {
113
+ const body = await request.json().catch(() => ({}));
114
+ const title = typeof body.title === "string" ? body.title.trim() : "";
115
+ if (!title) return NextResponse.json({ error: "title is required" }, { status: 400 });
116
+ const doc = { title, column: "todo", order: Date.now(), createdAt: new Date() };
117
+ const col = await cards();
118
+ const res = await col.insertOne(doc);
119
+ return NextResponse.json({ id: res.insertedId.toString(), ...doc }, { status: 201 });
120
+ }
121
+
122
+ // PATCH /api/cards — move a card to another column. Body: { id, column }.
123
+ export async function PATCH(request) {
124
+ const body = await request.json().catch(() => ({}));
125
+ const { id, column } = body;
126
+ if (!id || !ObjectId.isValid(id) || !COLUMNS.includes(column)) {
127
+ return NextResponse.json({ error: "valid id and column required" }, { status: 400 });
128
+ }
129
+ const col = await cards();
130
+ await col.updateOne({ _id: new ObjectId(id) }, { $set: { column } });
131
+ return NextResponse.json({ ok: true });
132
+ }
133
+
134
+ // DELETE /api/cards?id=<id>
135
+ export async function DELETE(request) {
136
+ const id = new URL(request.url).searchParams.get("id");
137
+ if (!id || !ObjectId.isValid(id)) {
138
+ return NextResponse.json({ error: "valid id is required" }, { status: 400 });
139
+ }
140
+ const col = await cards();
141
+ await col.deleteOne({ _id: new ObjectId(id) });
142
+ return NextResponse.json({ ok: true });
143
+ }
144
+ ```
145
+
146
+ ## services/web/app/page.js
147
+
148
+ ```js
149
+ import { getDb } from "../lib/db.js";
150
+ import Board from "./board.js";
151
+
152
+ export const dynamic = "force-dynamic";
153
+
154
+ const COLUMNS = ["todo", "doing", "done"];
155
+
156
+ async function listCards() {
157
+ const items = await (await getDb())
158
+ .collection("cards")
159
+ .find({})
160
+ .sort({ order: 1, createdAt: 1 })
161
+ .toArray();
162
+ return items.map((c) => ({
163
+ id: c._id.toString(),
164
+ title: c.title || "",
165
+ column: COLUMNS.includes(c.column) ? c.column : "todo",
166
+ order: typeof c.order === "number" ? c.order : 0,
167
+ }));
168
+ }
169
+
170
+ export default async function Page() {
171
+ const cards = await listCards();
172
+ return (
173
+ <main>
174
+ <h1>Workflow Board</h1>
175
+ <p className="hint">Shared across the team — persisted in grid Mongo.</p>
176
+ <Board initialCards={cards} />
177
+ </main>
178
+ );
179
+ }
180
+ ```
181
+
182
+ ## services/web/app/board.js
183
+
184
+ ```js
185
+ "use client";
186
+ import { useState } from "react";
187
+
188
+ const COLUMNS = ["todo", "doing", "done"];
189
+ const LABELS = { todo: "To do", doing: "Doing", done: "Done" };
190
+
191
+ export default function Board({ initialCards }) {
192
+ const [cards, setCards] = useState(initialCards);
193
+ const [title, setTitle] = useState("");
194
+
195
+ async function add(e) {
196
+ e.preventDefault();
197
+ if (!title.trim()) return;
198
+ const res = await fetch("/api/cards", {
199
+ method: "POST",
200
+ headers: { "content-type": "application/json" },
201
+ body: JSON.stringify({ title }),
202
+ });
203
+ if (res.ok) { setCards((p) => [...p, await res.json()]); setTitle(""); }
204
+ }
205
+
206
+ async function move(id, column) {
207
+ const res = await fetch("/api/cards", {
208
+ method: "PATCH",
209
+ headers: { "content-type": "application/json" },
210
+ body: JSON.stringify({ id, column }),
211
+ });
212
+ if (res.ok) setCards((p) => p.map((c) => (c.id === id ? { ...c, column } : c)));
213
+ }
214
+
215
+ async function remove(id) {
216
+ const res = await fetch(`/api/cards?id=${encodeURIComponent(id)}`, { method: "DELETE" });
217
+ if (res.ok) setCards((p) => p.filter((c) => c.id !== id));
218
+ }
219
+
220
+ return (
221
+ <div>
222
+ <form onSubmit={add} className="row">
223
+ <input value={title} onChange={(e) => setTitle(e.target.value)} placeholder="Add a card…" />
224
+ <button type="submit">Add</button>
225
+ </form>
226
+ <div className="board">
227
+ {COLUMNS.map((column) => (
228
+ <section key={column}>
229
+ <h2>{LABELS[column]}</h2>
230
+ {cards.filter((c) => c.column === column).map((c) => (
231
+ <article key={c.id} className="card">
232
+ <span className="title">{c.title}</span>
233
+ <div className="moves">
234
+ {COLUMNS.filter((o) => o !== column).map((o) => (
235
+ <button key={o} type="button" onClick={() => move(c.id, o)}>→ {LABELS[o]}</button>
236
+ ))}
237
+ <button type="button" onClick={() => remove(c.id)}>Delete</button>
238
+ </div>
239
+ </article>
240
+ ))}
241
+ </section>
242
+ ))}
243
+ </div>
244
+ </div>
245
+ );
246
+ }
247
+ ```
248
+
249
+ ## Notes
250
+
251
+ - Deploy the same way as the template: `grid dev` locally, `grid plug` to deploy
252
+ (async — poll status to a live URL). Re-plug the same entity to keep one URL.
253
+ - The only store this needs is Mongo (`needs: { database: true }`). Add
254
+ `cache: true` to `needs:` only for caching/sessions you actually use.
255
+ - All app code lives under `services/web/`; the connection is read lazily inside
256
+ `getDb`, never at module top level.