forgecad 0.9.14 → 0.9.16

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 (239) hide show
  1. package/LICENSE +6 -4
  2. package/README.md +8 -4
  3. package/dist/assets/{AdminPage-eWGs2K6H.js → AdminPage-CXvls4-J.js} +2 -2
  4. package/dist/assets/{BenchmarkPage-CTrLKfpo.js → BenchmarkPage-B27zk8xL.js} +4 -15
  5. package/dist/assets/{BlogPage-5nPesyds.js → BlogPage-CMAVvgQL.js} +2 -2
  6. package/dist/assets/{DocsPage-C4Y3nbYc.js → DocsPage-knf4I4h7.js} +9 -3
  7. package/dist/assets/EditorApp-BHMQlJ-D.js +14686 -0
  8. package/dist/assets/{EditorApp-BAnckbsk.css → EditorApp-BpjZgzk0.css} +846 -0
  9. package/dist/assets/{EmbedViewer-C8fB4n5U.js → EmbedViewer-D7ZGlFjx.js} +3 -3
  10. package/dist/assets/{LandingPageProofDriven-jSz0LaMM.js → LandingPageProofDriven-CnevhTE8.js} +36 -38
  11. package/dist/assets/LegalPage-BPTUmqeg.js +39 -0
  12. package/dist/assets/LegalPage-BRlScr9A.css +91 -0
  13. package/dist/assets/{PricingPage-B83B90zh.js → PricingPage-B0D4goG_.js} +19 -19
  14. package/dist/assets/{PricingPage-BMedqFef.css → PricingPage-BPF6HKyO.css} +25 -0
  15. package/dist/assets/{SettingsPage-DY889pcu.js → SettingsPage-CFF-UgjI.js} +2 -2
  16. package/dist/assets/app-CE3sYcV7.css +3890 -0
  17. package/dist/assets/{app-bEww1ic4.js → app-T0pDcSX4.js} +3382 -1069
  18. package/dist/assets/cli/{render-Cho2uKG_.js → render-C5pcIISc.js} +477 -29
  19. package/dist/assets/{constructionHistoryWorker-HYwzJY4m.js → constructionHistoryWorker-Ba2Hm58b.js} +928 -243
  20. package/dist/assets/{evalWorker-CjQwJSE-.js → evalWorker-vkx310U2.js} +8883 -6040
  21. package/dist/assets/{forgecad_geometry-CH2nvuLA.js → forgecad_geometry-Dgceylq9.js} +43 -1
  22. package/dist/assets/forgecad_geometry_bg-dD4RNQF1.wasm +0 -0
  23. package/dist/assets/{inspectWorker-DeRnMVv1.js → inspectWorker-BuTJDVX6.js} +1179 -273
  24. package/dist/assets/{javascript-70-4uGcz.js → javascript-1kQXfVaz.js} +1 -1
  25. package/dist/assets/{targets-D6PWsv6X.js → jointPose-B_Cgedn9.js} +71 -3
  26. package/dist/assets/landing-proof-driven-DiGqdtWa.js +18 -0
  27. package/dist/assets/{landing-proof-driven-oFYW6mjz.css → landing-proof-driven-ORyigZ6p.css} +13 -7
  28. package/dist/assets/legalContent-ZfFGMmi4.js +251 -0
  29. package/dist/assets/{manifold-rmfAcdwF.js → manifold-BWgsjmAM.js} +1 -1
  30. package/dist/assets/{manifold-uRzgk5O8.js → manifold-D6IFSkhH.js} +2 -2
  31. package/dist/assets/{manifold-CG9Fokx-.js → manifold-rZexZI0G.js} +1 -1
  32. package/dist/assets/{reportWorker-4cW_ZpoS.js → reportWorker-0AGij1Ru.js} +8659 -12771
  33. package/dist/assets/{scalar-sampling-budget-CfDiFvh7.js → scalar-sampling-budget-J5cuzxT1.js} +8050 -6203
  34. package/dist/assets/{scanProxyWorker-Bs2TDgLw.js → scanProxyWorker-Vl4Wxa1y.js} +50 -6
  35. package/dist/assets/{solver-DuJAO8S6.js → solver-BZ9LPTHs.js} +1 -1
  36. package/dist/assets/solver_bg-DAHZJ_rw.wasm +0 -0
  37. package/dist/assets/{vendor-react-Da3A2QmU.js → vendor-react-6j1Kke-Y.js} +6 -5
  38. package/dist/cli/render.html +1 -1
  39. package/dist/docs/index.html +2 -2
  40. package/dist/docs-raw/AI/ai-native-cad.md +50 -0
  41. package/dist/docs-raw/AI/usage.md +5 -12
  42. package/dist/docs-raw/CLI.md +34 -10
  43. package/dist/docs-raw/component-model.md +27 -11
  44. package/dist/docs-raw/generated/assembly.md +374 -187
  45. package/dist/docs-raw/generated/concepts.md +245 -237
  46. package/dist/docs-raw/generated/core.md +283 -6
  47. package/dist/docs-raw/generated/curves.md +274 -361
  48. package/dist/docs-raw/generated/lib.md +9 -19
  49. package/dist/docs-raw/generated/output.md +29 -4
  50. package/dist/docs-raw/generated/runtime-names.md +49 -0
  51. package/dist/docs-raw/generated/sdf.md +31 -0
  52. package/dist/docs-raw/generated/sheet-metal.md +9 -0
  53. package/dist/docs-raw/generated/sketch.md +44 -1
  54. package/dist/docs-raw/generated/viewport.md +11 -3
  55. package/dist/docs-raw/guides/coordinate-system.md +20 -16
  56. package/dist/docs-raw/guides/geometry-conventions.md +2 -2
  57. package/dist/docs-raw/guides/inspection-bundles.md +2 -1
  58. package/dist/docs-raw/guides/joint-design.md +24 -0
  59. package/dist/docs-raw/guides/positioning.md +13 -3
  60. package/dist/docs-raw/legal/privacy.md +63 -0
  61. package/dist/docs-raw/legal/software-license.md +55 -0
  62. package/dist/docs-raw/legal/terms.md +87 -0
  63. package/dist/docs-raw/skills/forgecad-3d-reconstruction.md +1 -1
  64. package/dist/docs-raw/skills/forgecad-blockout-model.md +1 -1
  65. package/dist/docs-raw/skills/forgecad-component-model.md +11 -2
  66. package/dist/docs-raw/skills/forgecad-high-level-spec.md +1 -1
  67. package/dist/docs-raw/skills/forgecad-image-replicator.md +8 -8
  68. package/dist/docs-raw/skills/forgecad-lld.md +1 -1
  69. package/dist/docs-raw/skills/forgecad-make-a-model.md +40 -39
  70. package/dist/docs-raw/skills/forgecad-model-grader.md +2 -2
  71. package/dist/docs-raw/skills/forgecad-prepare-prompt.md +2 -2
  72. package/dist/docs-raw/skills/forgecad-project.md +3 -1
  73. package/dist/docs-raw/skills/forgecad-reconstruction-benchmark.md +1 -1
  74. package/dist/docs-raw/skills/forgecad-render-inspect.md +4 -2
  75. package/dist/docs-raw/skills/forgecad-visual-spec.md +1 -1
  76. package/dist/docs-raw/skills/forgecad.md +4 -3
  77. package/dist/docs-raw/welcome.md +2 -0
  78. package/dist/index.html +40 -12
  79. package/dist/llms.txt +8 -0
  80. package/dist/site.webmanifest +1 -1
  81. package/dist/sitemap.xml +49 -13
  82. package/dist-cli/{check-compiler-U5SOPN7X.js → check-compiler-SYQ2PWOB.js} +1 -2
  83. package/dist-cli/{check-query-propagation-XOKNSSYU.js → check-query-propagation-HIAGV62W.js} +1 -2
  84. package/dist-cli/{chunk-EXWGNL6K.js → chunk-SPZE3DUY.js} +20659 -17930
  85. package/dist-cli/forgecad.js +3568 -1250
  86. package/dist-cli/{forgecad_geometry-GYVNKPIE.js → forgecad_geometry-QOQIIP53.js} +42 -1
  87. package/dist-cli/forgecad_geometry_bg.wasm +0 -0
  88. package/dist-cli/{solver-46FFSK2U.js → solver-OK4HECRH.js} +0 -1
  89. package/dist-cli/solver_bg.wasm +0 -0
  90. package/dist-skill/CONTEXT.md +1192 -725
  91. package/dist-skill/SKILL.md +3 -2
  92. package/dist-skill/docs/API/core/concepts.md +64 -1
  93. package/dist-skill/docs/CLI.md +34 -10
  94. package/dist-skill/docs/generated/assembly.md +339 -213
  95. package/dist-skill/docs/generated/core.md +283 -6
  96. package/dist-skill/docs/generated/curves.md +272 -362
  97. package/dist-skill/docs/generated/lib.md +9 -19
  98. package/dist-skill/docs/generated/output.md +29 -4
  99. package/dist-skill/docs/generated/runtime-names.md +40 -0
  100. package/dist-skill/docs/generated/sdf.md +31 -0
  101. package/dist-skill/docs/generated/sheet-metal.md +9 -0
  102. package/dist-skill/docs/generated/sketch.md +44 -2
  103. package/dist-skill/docs/generated/viewport.md +2 -87
  104. package/dist-skill/docs/guides/coordinate-system.md +20 -16
  105. package/dist-skill/docs/guides/geometry-conventions.md +2 -2
  106. package/dist-skill/docs/guides/inspection-bundles.md +2 -1
  107. package/dist-skill/docs/guides/joint-design.md +24 -0
  108. package/dist-skill/docs/guides/positioning.md +13 -3
  109. package/dist-skill/library/forgecad-component-model/SKILL.md +10 -1
  110. package/dist-skill/library/forgecad-image-replicator/SKILL.md +6 -6
  111. package/dist-skill/library/forgecad-image-replicator/scripts/compare_images.py +166 -0
  112. package/dist-skill/library/forgecad-make-a-model/SKILL.md +39 -38
  113. package/dist-skill/library/forgecad-model-grader/SKILL.md +1 -1
  114. package/dist-skill/library/forgecad-prepare-prompt/SKILL.md +1 -1
  115. package/dist-skill/library/forgecad-project/SKILL.md +2 -0
  116. package/dist-skill/library/forgecad-render-inspect/SKILL.md +3 -1
  117. package/examples/api/assembly-kinematics-foundation.forge.js +65 -0
  118. package/examples/api/assembly-kinematics-four-bar.forge.js +115 -0
  119. package/examples/api/assembly-kinematics-limb.forge.js +116 -0
  120. package/examples/api/connector-frame-rig-chain.forge.js +102 -0
  121. package/examples/api/exact-sheet-shell-assembly.forge.js +0 -2
  122. package/examples/api/exact-surface-studio.forge.js +6 -8
  123. package/examples/api/helix-basics.forge.js +8 -8
  124. package/examples/api/lean-foundations/README.md +12 -0
  125. package/examples/api/lean-foundations/curve-blend-exact.forge.js +22 -0
  126. package/examples/api/lean-foundations/curve-fit-interpolation.forge.js +18 -0
  127. package/examples/api/lean-foundations/curve-helix-canonicalization.forge.js +27 -0
  128. package/examples/api/lean-foundations/curve-route-canonicalization.forge.js +16 -0
  129. package/examples/api/lean-foundations/curve-trim-reverse.forge.js +24 -0
  130. package/examples/api/lean-foundations/exact-curve-arc.forge.js +36 -0
  131. package/examples/api/mixed-edge-finishes-proof.forge.js +8 -11
  132. package/examples/api/route3d-elbow.forge.js +71 -0
  133. package/examples/api/transition-curves.forge.js +44 -15
  134. package/examples/api/variable-sweep-test.forge.js +3 -1
  135. package/examples/api/y-blend-corner-showcase.forge.js +0 -2
  136. package/examples/generative/coral-vase.forge.js +1 -1
  137. package/examples/nurbs-tube.forge.js +1 -1
  138. package/package.json +17 -13
  139. package/dist/assets/EditorApp-lXv53A1m.js +0 -13610
  140. package/dist/assets/app-CsHnaBWt.css +0 -1789
  141. package/dist/assets/forgecad_geometry_bg-C5_E9Oa9.wasm +0 -0
  142. package/dist/assets/solver_bg-CWvv4lnN.wasm +0 -0
  143. package/dist/docs-raw/API/README.md +0 -16
  144. package/dist/docs-raw/API/core/concepts.md +0 -118
  145. package/dist/docs-raw/INDEX.md +0 -138
  146. package/dist/docs-raw/RELEASING.md +0 -87
  147. package/dist/docs-raw/agent-native-api.md +0 -27
  148. package/dist/docs-raw/beta-deployment.md +0 -304
  149. package/dist/docs-raw/beta-operations.md +0 -325
  150. package/dist/docs-raw/blueprint-first.md +0 -145
  151. package/dist/docs-raw/cli-monetization.md +0 -112
  152. package/dist/docs-raw/coding-best-practices.md +0 -120
  153. package/dist/docs-raw/coding.md +0 -340
  154. package/dist/docs-raw/deployment.md +0 -374
  155. package/dist/docs-raw/guides/skill-maintenance.md +0 -161
  156. package/dist/docs-raw/guides/surface-members.md +0 -82
  157. package/dist/docs-raw/harbor-cli.md +0 -854
  158. package/dist/docs-raw/internals/backend-vocabulary.md +0 -35
  159. package/dist/docs-raw/internals/compiler.md +0 -307
  160. package/dist/docs-raw/internals/constraint-solver-quality.md +0 -161
  161. package/dist/docs-raw/internals/constraint-solver.md +0 -176
  162. package/dist/docs-raw/internals/shape-from-slices.md +0 -152
  163. package/dist/docs-raw/internals/sketch-2d-pipeline.md +0 -108
  164. package/dist/docs-raw/platform/admin.md +0 -45
  165. package/dist/docs-raw/platform/architecture.md +0 -82
  166. package/dist/docs-raw/platform/auth.md +0 -139
  167. package/dist/docs-raw/platform/email.md +0 -67
  168. package/dist/docs-raw/platform/google-oauth-setup.md +0 -88
  169. package/dist/docs-raw/platform/observability.md +0 -197
  170. package/dist/docs-raw/platform/projects.md +0 -111
  171. package/dist/docs-raw/platform/sharing.md +0 -90
  172. package/dist/docs-raw/product/README.md +0 -39
  173. package/dist/docs-raw/product/api-as-product-language.md +0 -13
  174. package/dist/docs-raw/product/business-model.md +0 -15
  175. package/dist/docs-raw/product/competitive-positioning.md +0 -17
  176. package/dist/docs-raw/product/creative-manufacturing.md +0 -15
  177. package/dist/docs-raw/product/founder-story.md +0 -11
  178. package/dist/docs-raw/product/manufacturing-workflows.md +0 -15
  179. package/dist/docs-raw/product/onboarding-first-experience.md +0 -256
  180. package/dist/docs-raw/product/product-loop.md +0 -17
  181. package/dist/docs-raw/product/strategic-decisions.md +0 -22
  182. package/dist/docs-raw/product/user-outreach-email-templates.md +0 -161
  183. package/dist/docs-raw/product/user-segments.md +0 -15
  184. package/dist/docs-raw/product/vision.md +0 -26
  185. package/dist/docs-raw/rl-environments.md +0 -350
  186. package/dist/docs-raw/runbook.md +0 -611
  187. package/dist-cli/check-compiler-U5SOPN7X.js.map +0 -1
  188. package/dist-cli/check-query-propagation-XOKNSSYU.js.map +0 -1
  189. package/dist-cli/chunk-EXWGNL6K.js.map +0 -1
  190. package/dist-cli/forgecad.js.map +0 -1
  191. package/dist-cli/forgecad_geometry-GYVNKPIE.js.map +0 -1
  192. package/dist-cli/solver-46FFSK2U.js.map +0 -1
  193. package/dist-skill/SKILL-dev.md +0 -145
  194. package/dist-skill/docs-dev/API/core/concepts.md +0 -118
  195. package/dist-skill/docs-dev/CLI.md +0 -677
  196. package/dist-skill/docs-dev/agent-native-api.md +0 -27
  197. package/dist-skill/docs-dev/blueprint-first.md +0 -145
  198. package/dist-skill/docs-dev/coding-best-practices.md +0 -120
  199. package/dist-skill/docs-dev/coding.md +0 -340
  200. package/dist-skill/docs-dev/component-model.md +0 -164
  201. package/dist-skill/docs-dev/generated/assembly.md +0 -794
  202. package/dist-skill/docs-dev/generated/core.md +0 -2117
  203. package/dist-skill/docs-dev/generated/curves.md +0 -2583
  204. package/dist-skill/docs-dev/generated/lib.md +0 -169
  205. package/dist-skill/docs-dev/generated/output.md +0 -247
  206. package/dist-skill/docs-dev/generated/sdf.md +0 -446
  207. package/dist-skill/docs-dev/generated/sheet-metal.md +0 -504
  208. package/dist-skill/docs-dev/generated/sketch.md +0 -1811
  209. package/dist-skill/docs-dev/generated/viewport.md +0 -585
  210. package/dist-skill/docs-dev/generated/wood.md +0 -108
  211. package/dist-skill/docs-dev/guides/coordinate-system.md +0 -46
  212. package/dist-skill/docs-dev/guides/geometry-conventions.md +0 -52
  213. package/dist-skill/docs-dev/guides/inspection-bundles.md +0 -485
  214. package/dist-skill/docs-dev/guides/joint-design.md +0 -78
  215. package/dist-skill/docs-dev/guides/modeling-recipes.md +0 -78
  216. package/dist-skill/docs-dev/guides/positioning.md +0 -161
  217. package/dist-skill/docs-dev/guides/skill-maintenance.md +0 -161
  218. package/dist-skill/docs-dev/internals/backend-vocabulary.md +0 -35
  219. package/dist-skill/docs-dev/internals/compiler.md +0 -307
  220. package/dist-skill/docs-dev/internals/constraint-solver-quality.md +0 -161
  221. package/dist-skill/docs-dev/internals/constraint-solver.md +0 -176
  222. package/dist-skill/docs-dev/internals/sketch-2d-pipeline.md +0 -108
  223. package/dist-skill/library/forgecad-image-replicator/scripts/compare_images.mjs +0 -289
  224. package/examples/api/bolted-service-cover.forge.js +0 -17
  225. package/examples/api/cable-gland-anchor.forge.js +0 -14
  226. package/examples/api/captured-cartridge-guide.forge.js +0 -14
  227. package/examples/api/captured-linear-slide.forge.js +0 -13
  228. package/examples/api/clevis-pin-joint.forge.js +0 -13
  229. package/examples/api/datum-enclosure.forge.js +0 -16
  230. package/examples/api/hose-barb-port.forge.js +0 -14
  231. package/examples/api/knuckled-hinge-assembly.forge.js +0 -15
  232. package/examples/api/living-hinge-cover.forge.js +0 -14
  233. package/examples/api/pcb-terminal-block.forge.js +0 -22
  234. package/examples/api/pinned-lever-pivot-stack.forge.js +0 -14
  235. package/examples/api/retained-shaft-knob-stack.forge.js +0 -15
  236. package/examples/api/routed-tube-clip.forge.js +0 -15
  237. package/examples/api/seated-bearing-stack.forge.js +0 -30
  238. package/examples/api/snap-latch-cover.forge.js +0 -14
  239. package/examples/api/thumb-screw-clamp.forge.js +0 -15
@@ -1,139 +0,0 @@
1
- # Authentication
2
-
3
- ForgeCAD uses JWT-based authentication with refresh token rotation. Tokens are delivered via `httpOnly` cookies -- never exposed to client-side JavaScript.
4
-
5
- ---
6
-
7
- ## Token Architecture
8
-
9
- - **Access token**: JWT signed with HMAC (HS256). Default lifetime: 15 minutes.
10
- - **Refresh token**: Opaque token stored in the database. Default lifetime: 7 days.
11
- - **Rotation**: Each refresh request issues a new refresh token and invalidates the old one. If a previously-used refresh token is replayed, all sessions for that user are revoked (replay detection).
12
-
13
- Both tokens are set as `httpOnly`, `Secure`, `SameSite=Strict` cookies.
14
-
15
- ---
16
-
17
- ## User Roles
18
-
19
- | Role | Access |
20
- |-------|--------|
21
- | `user` | Standard account, can use `/app` and all editor features |
22
- | `admin` | Full access including `/admin` dashboard |
23
-
24
- Middleware:
25
-
26
- - `requireAuth` -- extracts the user from the JWT access token. Returns 401 if the token is missing or expired.
27
- - `requireAdmin` -- calls `requireAuth`, then checks `role === 'admin'`. Returns 403 otherwise.
28
-
29
- ---
30
-
31
- ## Registration and Login
32
-
33
- 1. **Register** (`POST /api/auth/register`) -- accepts email and password. Creates the account and sends a verification email. See [email delivery](email.md) for delivery configuration.
34
- 2. **Verify email** (`GET /api/auth/verify-email`) -- confirms the address using the token from the email link.
35
- 3. **Login** (`POST /api/auth/login`) -- validates credentials, sets access and refresh token cookies.
36
-
37
- Password reset:
38
-
39
- 1. `POST /api/auth/forgot-password` -- sends a reset email with a single-use token (1-hour expiry).
40
- 2. `POST /api/auth/reset-password` -- applies the new password using the reset token.
41
-
42
- ---
43
-
44
- ## OAuth
45
-
46
- GitHub and Google are supported as optional OAuth providers. They are enabled by setting the corresponding environment variables (see below). When not configured, the provider is omitted from the login UI.
47
-
48
- - `GET /api/auth/providers` -- returns the list of configured OAuth providers and their authorization URLs.
49
- - `POST /api/auth/callback/:provider` -- handles the OAuth redirect, creates or links the account, and sets token cookies.
50
-
51
- ---
52
-
53
- ## CLI Auth for OAuth Accounts
54
-
55
- The web app and CLI use different sign-in mechanics:
56
-
57
- - Browser sign-in uses cookies. Email/password login and OAuth login both end with `httpOnly` cookies that the browser sends back to ForgeCAD.
58
- - CLI sign-in uses bearer tokens. The CLI cannot reuse a browser-only OAuth cookie, and a Google OAuth redirect flow is awkward for a terminal.
59
-
60
- That difference is why a Google-only user needs an API token in the CLI: there is no terminal password to submit for a browser-only OAuth account.
61
-
62
- The normal CLI path is now one interactive command:
63
-
64
- ```bash
65
- forgecad login
66
- ```
67
-
68
- Choose **API token** when prompted, then paste a token created from the signed-in web app at **Settings > API Tokens**. The CLI validates the token with `GET /api/auth/session`, stores it in `~/.forgecad/auth.json` as `authType: "token"`, and sends it as `Authorization: Bearer ...` on project, publish, license, and token-management requests.
69
-
70
- For CI/CD and one-off automation, skip local storage and set:
71
-
72
- ```bash
73
- FORGECAD_TOKEN=fc_pat_... forgecad project push
74
- ```
75
-
76
- Passing the token directly as `forgecad login --token fc_pat_...` is accepted for non-interactive setup, but the interactive prompt is preferred so tokens do not land in shell history.
77
-
78
- For local development or self-hosted experiments, `forgecad login --server <url>` accepts a clean server origin only. Use HTTPS for remote servers; plain HTTP is accepted only for localhost. License activation remains tied to forgecad.io accounts.
79
-
80
- ---
81
-
82
- ## API Endpoints
83
-
84
- | Method | Route | Purpose |
85
- |--------|-------|---------|
86
- | `POST` | `/api/auth/register` | Create account |
87
- | `POST` | `/api/auth/login` | Login (sets cookies) |
88
- | `POST` | `/api/auth/refresh` | Rotate refresh token, issue new access token |
89
- | `POST` | `/api/auth/logout` | Clear session cookies, invalidate refresh token |
90
- | `GET` | `/api/auth/session` | Return current user info (requires valid access token) |
91
- | `GET` | `/api/auth/providers` | List available OAuth providers |
92
- | `POST` | `/api/auth/callback/:provider` | OAuth callback |
93
- | `POST` | `/api/auth/forgot-password` | Request password reset email |
94
- | `POST` | `/api/auth/reset-password` | Apply password reset |
95
- | `GET` | `/api/auth/verify-email` | Confirm email address |
96
- | `POST` | `/api/auth/resend-verification` | Resend verification email |
97
-
98
- ---
99
-
100
- ## Rate Limiting
101
-
102
- Auth endpoints are rate-limited to **10 requests per 15 minutes per IP**. This applies to login, registration, password reset, and token refresh. Exceeding the limit returns HTTP 429.
103
-
104
- ---
105
-
106
- ## Environment Variables
107
-
108
- | Variable | Required | Default | Purpose |
109
- |----------|----------|---------|---------|
110
- | `FORGE_JWT_SECRET` | Yes | -- | HMAC signing key for JWT access tokens |
111
- | `FORGE_JWT_ACCESS_EXPIRES` | No | `15m` | Access token lifetime (e.g. `15m`, `1h`) |
112
- | `FORGE_JWT_REFRESH_EXPIRES` | No | `7d` | Refresh token lifetime |
113
- | `GITHUB_CLIENT_ID` | No | -- | GitHub OAuth application ID |
114
- | `GITHUB_CLIENT_SECRET` | No | -- | GitHub OAuth secret |
115
- | `GOOGLE_CLIENT_ID` | No | -- | Google OAuth client ID |
116
- | `GOOGLE_CLIENT_SECRET` | No | -- | Google OAuth secret |
117
- | `FORGE_ALLOWED_ORIGINS` | No | `localhost` | Comma-separated list of allowed CORS origins |
118
-
119
- See [deployment.md](../deployment.md) for the full environment variable reference.
120
-
121
- ---
122
-
123
- ## Troubleshooting
124
-
125
- **500 on login** -- `FORGE_JWT_SECRET` is not set. The server cannot sign tokens without it.
126
-
127
- **401 on authenticated endpoints** -- the access token has expired. The client should call `POST /api/auth/refresh` to obtain a new one. If refresh also returns 401, the session has expired entirely and the user must log in again.
128
-
129
- **CORS errors** -- `FORGE_ALLOWED_ORIGINS` does not include the frontend's origin. Add the correct domain (e.g. `https://forgecad.io`).
130
-
131
- ---
132
-
133
- ## Source Files
134
-
135
- | File | Purpose |
136
- |------|---------|
137
- | `server/routes/auth.ts` | All auth route handlers |
138
- | `server/middleware/auth.ts` | `requireAuth` and `requireAdmin` middleware |
139
- | `server/db/schema.ts` | User and refresh token table definitions |
@@ -1,67 +0,0 @@
1
- # Email Delivery
2
-
3
- ForgeCAD uses [Resend](https://resend.com) for transactional email. The free tier covers 3,000 emails/month and 100/day — more than enough for early production.
4
-
5
- Emails are sent for:
6
- - Email address verification (on register + resend)
7
- - Password reset links
8
-
9
- See [auth.md](auth.md) for the authentication flows that trigger these emails.
10
-
11
- ## Environment Variables
12
-
13
- | Variable | Required | Default | Notes |
14
- |---|---|---|---|
15
- | `RESEND_API_KEY` | Yes (in prod) | — | From Resend dashboard |
16
- | `FORGE_EMAIL_FROM` | No | `ForgeCAD <noreply@forgecad.io>` | Must match a verified domain |
17
- | `FORGE_APP_URL` | No | `http://localhost:5173` | Base URL used in email links |
18
-
19
- Without `RESEND_API_KEY`, emails fall back to `console.log` — fine for local dev.
20
-
21
- See [../deployment.md](../deployment.md) for the full environment variable reference.
22
-
23
- ## First-Time Setup
24
-
25
- ### 1. Create a Resend account
26
-
27
- Sign up at [resend.com](https://resend.com). No credit card required for the free tier.
28
-
29
- ### 2. Verify your sending domain
30
-
31
- In the Resend dashboard: **Domains** > **Add Domain** > enter `forgecad.io`.
32
-
33
- Resend will show you DNS records to add (typically a few TXT/MX entries). If your DNS is on **Cloudflare**, Resend can auto-configure the records — just connect your Cloudflare account in the Resend dashboard. It takes a few minutes to propagate.
34
-
35
- ### 3. Create an API key
36
-
37
- In the Resend dashboard: **API Keys** > **Create API Key**.
38
-
39
- Use **Send access only** — no need for full access on the server.
40
-
41
- ### 4. Set env vars
42
-
43
- In production secrets (`.kamal/secrets`) or your local `.env`:
44
-
45
- ```
46
- RESEND_API_KEY=re_...
47
- FORGE_EMAIL_FROM=ForgeCAD <noreply@forgecad.io>
48
- FORGE_APP_URL=https://forgecad.io
49
- ```
50
-
51
- ## Local Development
52
-
53
- Leave `RESEND_API_KEY` unset. The `send()` function detects the missing key and logs the email content and token to the console instead of sending. Token links are printed so you can copy them directly into the browser.
54
-
55
- ## Code Layout
56
-
57
- | File | Purpose |
58
- |---|---|
59
- | `server/email/send.ts` | Resend client + `sendVerificationEmail` / `sendPasswordResetEmail` helpers |
60
- | `server/env.ts` | `resendApiKey`, `emailFrom`, `appUrl` env vars |
61
- | `server/routes/auth.ts` | Calls into `send.ts` from register, forgot-password, resend-verification routes |
62
-
63
- ## Adding a New Email Type
64
-
65
- 1. Add a new `send*Email(to, ...)` export in `server/email/send.ts`
66
- 2. Call it from the relevant route in `server/routes/auth.ts` (or wherever)
67
- 3. No new infrastructure needed — same Resend client and `send()` helper
@@ -1,88 +0,0 @@
1
- # Google OAuth Setup Guide
2
-
3
- Step-by-step guide to configure Google Sign-In for ForgeCAD.
4
-
5
- ## Prerequisites
6
-
7
- - A Google account
8
- - Access to [Google Cloud Console](https://console.cloud.google.com)
9
-
10
- ## 1. Create a Google Cloud Project
11
-
12
- 1. Go to [console.cloud.google.com](https://console.cloud.google.com)
13
- 2. Click the project dropdown at the top left (might say "Select a project")
14
- 3. Click **New Project**
15
- 4. Name it **ForgeCAD**, click **Create**
16
- 5. Make sure it's selected in the project dropdown
17
-
18
- ## 2. Configure the OAuth Consent Screen
19
-
20
- This is what users see when they click "Sign in with Google."
21
-
22
- 1. In the left sidebar: **APIs & Services → OAuth consent screen**
23
- 2. Click **Get started** (or **Configure consent screen**)
24
- 3. Choose **External** (anyone with a Google account can sign in) → **Create**
25
- 4. Fill in:
26
- - **App name**: `ForgeCAD`
27
- - **User support email**: your email
28
- - **Developer contact email**: your email
29
- - Logo is optional (can add later)
30
- 5. Click **Save and Continue**
31
- 6. **Scopes** screen → click **Add or Remove Scopes**
32
- - Add these three:
33
- - `openid`
34
- - `email` (or `.../auth/userinfo.email`)
35
- - `profile` (or `.../auth/userinfo.profile`)
36
- - Click **Update** → **Save and Continue**
37
- 7. **Test users** → skip for now (only matters while in "Testing" status) → **Save and Continue**
38
- 8. Review and click **Back to Dashboard**
39
-
40
- ## 3. Create OAuth Credentials
41
-
42
- Use the Google Auth Platform / Credentials page for ForgeCAD web sign-in.
43
- The `gcloud iam oauth-clients` command is for IAM/IAP OAuth application
44
- resources and is not the right client type for this app's Google Sign-In flow.
45
-
46
- 1. In the left sidebar: **APIs & Services → Credentials**
47
- 2. Click **+ Create Credentials → OAuth client ID**
48
- 3. **Application type**: Web application
49
- 4. **Name**: `ForgeCAD Web` (just a label for you)
50
- 5. **Authorized JavaScript origins** — add your domain(s):
51
- - `https://forgecad.io` (production)
52
- - `http://localhost:5173` (local dev)
53
- 6. **Authorized redirect URIs** — must match exactly:
54
- - `https://forgecad.io/auth/callback/google`
55
- - `http://localhost:5173/auth/callback/google` (local dev)
56
- 7. Click **Create**
57
- 8. Copy the **Client ID** and **Client Secret** from the dialog
58
-
59
- ## 4. Add Credentials to `.env`
60
-
61
- On your server (or local `.env`):
62
-
63
- ```bash
64
- GOOGLE_CLIENT_ID=123456789-xxxxxxx.apps.googleusercontent.com
65
- GOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxxxxxxxxxxx
66
- ```
67
-
68
- ## 5. Publish the App
69
-
70
- While the consent screen is in **Testing** mode, only explicitly added test users can sign in.
71
-
72
- 1. Go to **OAuth consent screen**
73
- 2. Click **Publish App**
74
- 3. For apps requesting only `email`, `profile`, and `openid` scopes, Google does not require a full verification review — just confirm the prompt.
75
-
76
- ## 6. Restart and Test
77
-
78
- Restart the server so it picks up the new env vars, then click the Google button on the login page.
79
-
80
- ## Troubleshooting
81
-
82
- | Problem | Cause | Fix |
83
- |---------|-------|-----|
84
- | `redirect_uri_mismatch` error | Redirect URI in Google Console doesn't exactly match the one your app sends | Check scheme (`http` vs `https`), domain, port, path, and trailing slashes |
85
- | "Access blocked: This app's request is invalid" | Consent screen not configured or missing scopes | Complete the OAuth consent screen setup (step 2) |
86
- | "This app isn't verified" warning | App is published but not verified by Google | Normal for `openid`/`email`/`profile` scopes — users can click "Advanced → Go to ForgeCAD" to proceed |
87
- | Google button doesn't appear on login page | `GOOGLE_CLIENT_ID` env var not set | Add it to `.env` and restart the server |
88
- | Sign-in works but no email returned | Missing `email` scope | Re-check scopes in consent screen (step 2.6) |
@@ -1,197 +0,0 @@
1
- # Observability
2
-
3
- ForgeCAD uses a self-hosted observability stack on Hetzner:
4
-
5
- - Grafana for dashboards and Explore
6
- - Prometheus for metrics
7
- - Loki for logs
8
- - Alloy for Docker log collection
9
- - node-exporter and cAdvisor for host and container metrics
10
- - Uptime Kuma for black-box uptime checks
11
-
12
- ## Why this setup
13
-
14
- We explicitly do **not** use the app admin page as the primary operational surface.
15
-
16
- The goals are:
17
-
18
- - Tailscale-first private operator workflow
19
- - real dashboards and query UIs
20
- - logs and metrics on the same box
21
- - no paid SaaS requirement
22
- - minimal public exposure
23
-
24
- ## Access model
25
-
26
- Operator-facing observability ports bind only to the Hetzner host's Tailscale address, defaulting to `100.118.68.93`.
27
- Reach them directly from any authorized device on the tailnet:
28
-
29
- - Grafana: `http://100.118.68.93:3000`
30
- - Uptime Kuma: `http://100.118.68.93:3001`
31
- - Prometheus: `http://100.118.68.93:9090`
32
- - Loki: `http://100.118.68.93:3100`
33
- - Alloy UI: `http://100.118.68.93:12345`
34
-
35
- This keeps the stack private without adding a public reverse proxy or requiring an SSH tunnel for routine access.
36
- If the host's Tailscale IP changes, set `OBSERVABILITY_TAILSCALE_IP` in `/home/kostard/forgecad-observability/.env` before redeploying.
37
- The Compose file uses pinned image digests rather than floating `latest` tags so repeat deploys stay predictable.
38
-
39
- ## Deploy
40
-
41
- ```bash
42
- bash scripts/prod/observability-deploy.sh
43
- ```
44
-
45
- The deploy script:
46
-
47
- 1. syncs `ops/observability/` to `/home/kostard/forgecad-observability` on Hetzner
48
- 2. creates `/home/kostard/forgecad-observability/.env` if it does not already exist
49
- 3. pulls fresh images
50
- 4. starts the stack with `docker compose up -d`
51
-
52
- ## Check status
53
-
54
- ```bash
55
- bash scripts/prod/observability-status.sh
56
- ```
57
-
58
- ## Incident Workflow
59
-
60
- This stack is the primary way we debug production incidents.
61
-
62
- 1. Make sure your laptop is connected to Tailscale.
63
-
64
- 2. Check Uptime Kuma first:
65
-
66
- - `http://100.118.68.93:3001`
67
- - Use it to answer "is the site/API reachable from outside?" before diving into internals.
68
-
69
- 3. Check Grafana next:
70
-
71
- - `http://100.118.68.93:3000`
72
- - Start with the `ForgeCAD Host Overview` dashboard.
73
- - Then switch to `ForgeCAD Web Requests` for throughput, 4xx/5xx rate, latency, and top API routes.
74
- - Then switch to `Explore` for live investigation.
75
-
76
- 4. In Grafana Explore, use:
77
-
78
- - `Loki` when you want logs
79
- - `Prometheus` when you want metrics
80
-
81
- Useful Loki queries:
82
-
83
- ```text
84
- {container=~"forgecad-web-.*|forgecad-backend-web-.*"}
85
- {container=~"forgecad-web-.*|forgecad-backend-web-.*"} |= "error"
86
- {container=~"forgecad-web-.*|forgecad-beta-web-.*"} |= "DB slow query"
87
- {container=~"forgecad-web-.*|forgecad-beta-web-.*"} | json | event="db.query"
88
- {container=~"forgecad-beta-.*"}
89
- {container="kamal-proxy"}
90
- ```
91
-
92
- Useful Prometheus queries:
93
-
94
- ```text
95
- up
96
- node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes
97
- 100 * (1 - node_filesystem_avail_bytes{mountpoint="/",fstype!~"tmpfs|overlay"} / node_filesystem_size_bytes{mountpoint="/",fstype!~"tmpfs|overlay"})
98
- sum by (container) (rate(container_cpu_usage_seconds_total{container!=""}[5m]))
99
- sum(rate(forge_http_request_total[$__rate_interval]))
100
- sum(rate(forge_http_request_total{surface="api",status_class="5xx"}[$__rate_interval]))
101
- histogram_quantile(0.95, sum by (le) (rate(forge_http_request_duration_seconds_bucket[$__rate_interval])))
102
- topk(10, sum by (forge_env, method, route) (rate(forge_http_request_total{surface="api"}[$__rate_interval])))
103
- sum by (forge_env, operation) (rate(forge_db_query_total[$__rate_interval]))
104
- histogram_quantile(0.95, sum by (forge_env, operation, le) (rate(forge_db_query_duration_seconds_bucket[$__rate_interval])))
105
- sum by (forge_env, relation) (rate(forge_db_slow_query_total[$__rate_interval]))
106
- ```
107
-
108
- 5. Use the `ForgeCAD Web Requests` dashboard when the issue smells app-level traffic, request failures, or latency:
109
-
110
- - overall request rate
111
- - API-only request rate
112
- - 4xx and 5xx rates
113
- - P95 request latency
114
- - request concurrency
115
- - top API routes by throughput, 4xx rate, 5xx rate, and latency
116
-
117
- Health probes to `/api/health` are intentionally excluded so low-traffic charts stay focused on real user traffic instead of uptime polling.
118
-
119
- 6. Use the `ForgeCAD DB Queries` dashboard when the issue smells database-related:
120
-
121
- - Query rate by operation
122
- - P95 query latency by operation
123
- - Slow-query rate
124
- - Error-query rate
125
- - Top relations by average latency
126
- - Queries currently in flight
127
-
128
- The dashboard is backed by app-native metrics from the ForgeCAD web service, not host-level guesses.
129
-
130
- 6. Re-check prod explicitly after any restart or deploy:
131
-
132
- ```bash
133
- curl -fsS https://forgecad.io/api/health
134
- ```
135
-
136
- 7. If observability itself is degraded, fall back to SSH and direct Docker inspection:
137
-
138
- ```bash
139
- ssh hetzner
140
- docker ps --format "{{.Names}}\t{{.Status}}"
141
- docker logs --tail 200 <container>
142
- df -h /
143
- free -h
144
- ```
145
-
146
- ## Tool Roles
147
-
148
- - `Grafana`: main operator UI for dashboards, Explore, and datasource-backed queries
149
- - `Loki`: log backend queried through Grafana Explore
150
- - `Prometheus`: metrics backend and alert rule evaluation
151
- - `Uptime Kuma`: external uptime/status checks
152
-
153
- ## Credentials
154
-
155
- Grafana admin credentials live on Hetzner in `/home/kostard/forgecad-observability/.env`.
156
-
157
- ## What phase 1 covers
158
-
159
- - host CPU, memory, and disk metrics
160
- - container CPU and memory metrics
161
- - Docker stdout/stderr logs in Loki
162
- - app-native HTTP request metrics from the ForgeCAD web app
163
- - app-native DB query metrics from the ForgeCAD web app
164
- - Grafana data sources and a starter host dashboard
165
- - a provisioned `ForgeCAD Web Requests` dashboard
166
- - a provisioned `ForgeCAD DB Queries` dashboard
167
- - starter Prometheus alert rules for target health, memory, disk, and observability restarts
168
- - Uptime Kuma for health checks and notifications
169
-
170
- Prometheus reaches the web app metrics listener over the private `kamal` Docker network. The app exposes `/metrics` on an internal metrics port, not through the public Cloudflare route.
171
-
172
- ## What phase 1 does not cover
173
-
174
- - distributed Loki storage
175
- - Postgres-native query stats such as `pg_stat_statements`
176
- - tracing / Tempo
177
- - public Grafana hostnames
178
- - automatic provisioning of Uptime Kuma monitors
179
-
180
- Those can be added later once the basic operator loop is working.
181
-
182
- ## First Alerts
183
-
184
- Phase 1 ships starter Prometheus rules for:
185
-
186
- - observability targets going down
187
- - host memory staying below 10% available
188
- - root disk staying below 15% free
189
- - observability containers restarting
190
-
191
- These are intentionally conservative. Let them bake before wiring noisy notifications.
192
-
193
- ## Rollback and Safety
194
-
195
- - Stop the stack with `cd /home/kostard/forgecad-observability && docker compose down` if it causes unexpected pressure.
196
- - The observability services bind only to the host's Tailscale address, so they stay off the public internet and do not compete with Kamal for `80/443`.
197
- - Prod health should always be rechecked with `curl -fsS https://forgecad.io/api/health` after any observability deploy or restart.
@@ -1,111 +0,0 @@
1
- # Projects and File Management
2
-
3
- Projects are the top-level container for user work in ForgeCAD. Each project groups related scripts and output files under a single name with access controls.
4
-
5
- ## Project Model
6
-
7
- Each project has:
8
-
9
- | Field | Type | Description |
10
- |-------|------|-------------|
11
- | `id` | UUID | Primary key |
12
- | `slug` | string | URL-safe identifier, unique per owner |
13
- | `name` | string | Display name |
14
- | `visibility` | `private` \| `public` | Controls unauthenticated access |
15
- | `ownerId` | UUID | Foreign key to the user who created the project |
16
-
17
- Source: `server/db/schema.ts`
18
-
19
- ## Member Roles
20
-
21
- Projects support collaborative access through membership:
22
-
23
- | Role | Capabilities |
24
- |------|-------------|
25
- | **owner** | Full control: rename, delete, manage members, read/write files |
26
- | **editor** | Read and write files (save, delete, mkdir) |
27
- | **viewer** | Read files, watch for changes |
28
-
29
- The owner is always the user who created the project. Ownership cannot be transferred through the membership API.
30
-
31
- ## File Storage
32
-
33
- Project files are stored on disk, not in the database. The storage root is configured by the `FORGE_STORAGE_ROOT` environment variable (default: `/data/projects` in Docker). Each project gets an isolated directory under this root.
34
-
35
- See [deployment.md](../deployment.md) for Docker volume and storage configuration.
36
-
37
- ### Supported File Types
38
-
39
- | Extension | Purpose |
40
- |-----------|---------|
41
- | `.forge.js` | ForgeCAD model scripts |
42
- | `.js` | Utility modules (imported by scripts) |
43
- | `.svg` | Vector assets |
44
- | `.dxf` | 2D CAD profile assets |
45
- | `.stl`, `.3mf` | Exported mesh files |
46
-
47
- ### Path Traversal Protection
48
-
49
- All file operations validate resolved paths against the project's storage directory. Any path that escapes the project root (via `..` segments or symlinks) is rejected. This check runs in `server/storage.ts` before any read or write reaches the filesystem.
50
-
51
- ### Storage Quotas
52
-
53
- Each user has a storage quota tracked via `storage_used_bytes` on the user record.
54
-
55
- | Limit | Value |
56
- |-------|-------|
57
- | Storage per user | 50 MB |
58
- | Projects per user | 20 |
59
-
60
- The quota is checked before every file write. Storage counters are adjusted atomically and clamped to zero to prevent negative drift from race conditions or deleted files.
61
-
62
- Source: `server/quotas.ts`
63
-
64
- ## Real-Time File Watching
65
-
66
- Clients can subscribe to file changes via Server-Sent Events:
67
-
68
- ```
69
- GET /api/projects/:id/watch
70
- ```
71
-
72
- This endpoint streams events whenever files in the project are created, modified, or deleted. The editor uses this to stay in sync when multiple clients have the same project open.
73
-
74
- ## API Endpoints
75
-
76
- ### Projects
77
-
78
- | Method | Route | Min Role | Purpose |
79
- |--------|-------|----------|---------|
80
- | GET | `/api/projects` | -- | List the authenticated user's projects |
81
- | POST | `/api/projects` | -- | Create a new project |
82
- | GET | `/api/projects/:id` | viewer | Get project details |
83
- | PATCH | `/api/projects/:id` | owner | Update project name, slug, or visibility |
84
- | DELETE | `/api/projects/:id` | owner | Delete project and all its files |
85
-
86
- ### Members
87
-
88
- | Method | Route | Min Role | Purpose |
89
- |--------|-------|----------|---------|
90
- | GET | `/api/projects/:id/members` | viewer | List project members |
91
- | POST | `/api/projects/:id/members` | owner | Add a member by user ID |
92
- | PATCH | `/api/projects/:id/members/:userId` | owner | Change a member's role |
93
- | DELETE | `/api/projects/:id/members/:userId` | owner | Remove a member |
94
-
95
- ### Files
96
-
97
- | Method | Route | Min Role | Purpose |
98
- |--------|-------|----------|---------|
99
- | GET | `/api/projects/:id/watch` | viewer | SSE stream of file changes |
100
- | POST | `/api/projects/:id/save` | editor | Write file contents to disk |
101
- | POST | `/api/projects/:id/delete` | editor | Delete a file |
102
- | POST | `/api/projects/:id/mkdir` | editor | Create a directory |
103
- | GET | `/api/projects/:id/read-binary` | viewer | Download a binary file (meshes, assets) |
104
-
105
- Source: `server/routes/projects.ts`, `server/routes/files.ts`
106
-
107
- ## Related
108
-
109
- - [Architecture](architecture.md) -- system overview and deployment topology
110
- - [Sharing](sharing.md) -- model publishing and public URLs
111
- - [Deployment](../deployment.md) -- storage volume configuration, Docker setup