robodev 0.47.3 → 0.49.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 (175) hide show
  1. package/package.json +3 -3
  2. package/src/dev-inspect.test.ts +15 -0
  3. package/src/dev-inspect.ts +10 -3
  4. package/src/dev-server.ts +6 -0
  5. package/src/emit-starter.test.ts +6 -3
  6. package/templates/auth-chat/ROBODEV.md +7 -1
  7. package/templates/auth-chat/package.json +2 -2
  8. package/templates/backend/ROBODEV.md +7 -1
  9. package/templates/backend/package.json +2 -2
  10. package/templates/catalog.json +5 -0
  11. package/templates/empty/ROBODEV.md +7 -1
  12. package/templates/empty/package.json +2 -2
  13. package/templates/marketplace/ROBODEV.md +7 -1
  14. package/templates/marketplace/package.json +2 -2
  15. package/templates/povio/.config/local.spa.template.yml +27 -0
  16. package/templates/povio/.oxlint-base.json +29 -0
  17. package/templates/povio/.oxlintrc.json +78 -0
  18. package/templates/povio/.rulesync/rules/frontend-api-boundary.md +36 -0
  19. package/templates/povio/.rulesync/rules/frontend-component-structure.md +40 -0
  20. package/templates/povio/.rulesync/rules/frontend-forms.md +27 -0
  21. package/templates/povio/.rulesync/rules/frontend-notifications.md +24 -0
  22. package/templates/povio/.rulesync/rules/frontend-povio-components.md +42 -0
  23. package/templates/povio/.rulesync/rules/frontend-povio-ui.md +45 -0
  24. package/templates/povio/.rulesync/rules/frontend-query-autocomplete.md +24 -0
  25. package/templates/povio/.rulesync/rules/frontend-tables-and-lists.md +26 -0
  26. package/templates/povio/.rulesync/rules/frontend-translations.md +25 -0
  27. package/templates/povio/.rulesync/rules/project-overview.md +32 -0
  28. package/templates/povio/.rulesync/rules/robodev-api.md +30 -0
  29. package/templates/povio/.rulesync/rules/robodev-auth.md +40 -0
  30. package/templates/povio/.rulesync/rules/robodev-database.md +22 -0
  31. package/templates/povio/.rulesync/rules/role-based-app-structure.md +36 -0
  32. package/templates/povio/.rulesync/skills/media-feature/SKILL.md +21 -0
  33. package/templates/povio/.rulesync/skills/povio-ui-styling/SKILL.md +211 -0
  34. package/templates/povio/.rulesync/skills/povio-ui-styling/agents/openai.yaml +4 -0
  35. package/templates/povio/.rulesync/skills/robodev-api-route/SKILL.md +13 -0
  36. package/templates/povio/.rulesync/skills/robodev-table/SKILL.md +12 -0
  37. package/templates/povio/README.md +40 -0
  38. package/templates/povio/ROBODEV.md +84 -0
  39. package/templates/povio/apps/fe/index.html +24 -0
  40. package/templates/povio/apps/fe/openapi-codegen.config.ts +72 -0
  41. package/templates/povio/apps/fe/package.json +71 -0
  42. package/templates/povio/apps/fe/public/apple-touch-icon.png +0 -0
  43. package/templates/povio/apps/fe/public/favicon-96x96.png +0 -0
  44. package/templates/povio/apps/fe/public/favicon.ico +0 -0
  45. package/templates/povio/apps/fe/public/favicon.svg +3 -0
  46. package/templates/povio/apps/fe/public/site.webmanifest +21 -0
  47. package/templates/povio/apps/fe/public/web-app-manifest-192x192.png +0 -0
  48. package/templates/povio/apps/fe/public/web-app-manifest-512x512.png +0 -0
  49. package/templates/povio/apps/fe/src/assets/locales/en/translation.json +166 -0
  50. package/templates/povio/apps/fe/src/clients/app-rest-client.ts +15 -0
  51. package/templates/povio/apps/fe/src/clients/auth-token-store.ts +101 -0
  52. package/templates/povio/apps/fe/src/clients/rest/app-error-handler.ts +31 -0
  53. package/templates/povio/apps/fe/src/clients/rest/interceptors/authorization-header.interceptor.ts +15 -0
  54. package/templates/povio/apps/fe/src/clients/rest/interceptors/refresh-token.interceptor.ts +45 -0
  55. package/templates/povio/apps/fe/src/clients/rest/interceptors/response.interceptor.ts +17 -0
  56. package/templates/povio/apps/fe/src/components/404.tsx +18 -0
  57. package/templates/povio/apps/fe/src/components/features/auth/AuthBrandPanel.tsx +60 -0
  58. package/templates/povio/apps/fe/src/components/features/auth/AuthLayout.tsx +23 -0
  59. package/templates/povio/apps/fe/src/components/features/auth/LoginPage.tsx +111 -0
  60. package/templates/povio/apps/fe/src/components/features/auth/RegisterPage.tsx +143 -0
  61. package/templates/povio/apps/fe/src/components/features/home/HomePage.tsx +21 -0
  62. package/templates/povio/apps/fe/src/components/features/profile/ProfilePage.tsx +96 -0
  63. package/templates/povio/apps/fe/src/components/layout/AppLayout.tsx +19 -0
  64. package/templates/povio/apps/fe/src/components/layout/app-header/AppHeader.tsx +91 -0
  65. package/templates/povio/apps/fe/src/components/layout/app-header/MobileNavigation.tsx +51 -0
  66. package/templates/povio/apps/fe/src/components/layout/app-header/NavLink.tsx +29 -0
  67. package/templates/povio/apps/fe/src/components/shared/branding/BrandLogo.tsx +13 -0
  68. package/templates/povio/apps/fe/src/components/shared/error/ErrorFallback.tsx +43 -0
  69. package/templates/povio/apps/fe/src/components/shared/error/ErrorText.tsx +20 -0
  70. package/templates/povio/apps/fe/src/components/shared/error/NotFound.tsx +36 -0
  71. package/templates/povio/apps/fe/src/components/shared/forms/RequiredLabel.tsx +21 -0
  72. package/templates/povio/apps/fe/src/components/shared/forms/RowInputWrapper.tsx +50 -0
  73. package/templates/povio/apps/fe/src/components/shared/head/AppHead.tsx +32 -0
  74. package/templates/povio/apps/fe/src/components/shared/head/DefaultAppHead.tsx +34 -0
  75. package/templates/povio/apps/fe/src/components/shared/layout/LoadingState.tsx +9 -0
  76. package/templates/povio/apps/fe/src/components/shared/layout/ThinPageWrapper.tsx +5 -0
  77. package/templates/povio/apps/fe/src/components/shared/page/PageHeader.tsx +69 -0
  78. package/templates/povio/apps/fe/src/components/shared/ui/Card.tsx +60 -0
  79. package/templates/povio/apps/fe/src/components/shared/ui/GoogleLoginButton.tsx +19 -0
  80. package/templates/povio/apps/fe/src/components/shared/ui/RequiredLabel.tsx +22 -0
  81. package/templates/povio/apps/fe/src/components/shared/ui/TableActions.tsx +22 -0
  82. package/templates/povio/apps/fe/src/config/app.config.ts +23 -0
  83. package/templates/povio/apps/fe/src/config/i18n.ts +37 -0
  84. package/templates/povio/apps/fe/src/config/inits/logger.ts +7 -0
  85. package/templates/povio/apps/fe/src/config/jwt.config.ts +2 -0
  86. package/templates/povio/apps/fe/src/config/query.config.ts +20 -0
  87. package/templates/povio/apps/fe/src/hooks/useAuth.ts +5 -0
  88. package/templates/povio/apps/fe/src/main.tsx +52 -0
  89. package/templates/povio/apps/fe/src/pages/(guest)/login.tsx +23 -0
  90. package/templates/povio/apps/fe/src/pages/(guest)/register.tsx +23 -0
  91. package/templates/povio/apps/fe/src/pages/(guest)/route.tsx +18 -0
  92. package/templates/povio/apps/fe/src/pages/(private)/index.tsx +23 -0
  93. package/templates/povio/apps/fe/src/pages/(private)/profile.tsx +23 -0
  94. package/templates/povio/apps/fe/src/pages/(private)/route.tsx +18 -0
  95. package/templates/povio/apps/fe/src/pages/(public)/auth.tsx +37 -0
  96. package/templates/povio/apps/fe/src/pages/(public)/route.tsx +9 -0
  97. package/templates/povio/apps/fe/src/pages/__root.tsx +133 -0
  98. package/templates/povio/apps/fe/src/providers/AppErrorBoundary.tsx +44 -0
  99. package/templates/povio/apps/fe/src/providers/OpenApiRuntimeProvider.tsx +31 -0
  100. package/templates/povio/apps/fe/src/providers/index.tsx +44 -0
  101. package/templates/povio/apps/fe/src/providers/jwt.provider.tsx +95 -0
  102. package/templates/povio/apps/fe/src/routeTree.gen.ts +225 -0
  103. package/templates/povio/apps/fe/src/styles/base.css +84 -0
  104. package/templates/povio/apps/fe/src/styles/fonts/fonts.tsx +10 -0
  105. package/templates/povio/apps/fe/src/styles/globals.css +26 -0
  106. package/templates/povio/apps/fe/src/styles/overrides/defaults/button.override.ts +536 -0
  107. package/templates/povio/apps/fe/src/styles/overrides/defaults/checkbox.override.ts +71 -0
  108. package/templates/povio/apps/fe/src/styles/overrides/defaults/input.override.ts +252 -0
  109. package/templates/povio/apps/fe/src/styles/overrides/defaults/label.override.ts +91 -0
  110. package/templates/povio/apps/fe/src/styles/overrides/defaults/modal.override.ts +62 -0
  111. package/templates/povio/apps/fe/src/styles/overrides/defaults/radio.override.ts +46 -0
  112. package/templates/povio/apps/fe/src/styles/overrides/defaults/table.override.ts +104 -0
  113. package/templates/povio/apps/fe/src/styles/overrides/defaults/tag.override.ts +66 -0
  114. package/templates/povio/apps/fe/src/styles/overrides/defaults/typography.override.ts +115 -0
  115. package/templates/povio/apps/fe/src/styles/overrides/outline.clsx.ts +10 -0
  116. package/templates/povio/apps/fe/src/styles/overrides/uiOverrides.override.ts +60 -0
  117. package/templates/povio/apps/fe/src/styles/theme.css +2177 -0
  118. package/templates/povio/apps/fe/src/types/i18next.d.ts +12 -0
  119. package/templates/povio/apps/fe/src/types/table.d.ts +17 -0
  120. package/templates/povio/apps/fe/src/types/ui.d.ts +26 -0
  121. package/templates/povio/apps/fe/src/types/vite-env.d.ts +13 -0
  122. package/templates/povio/apps/fe/src/utils/date.utils.ts +17 -0
  123. package/templates/povio/apps/fe/src/utils/image-fallback.ts +9 -0
  124. package/templates/povio/apps/fe/src/utils/number.utils.ts +12 -0
  125. package/templates/povio/apps/fe/src/utils/string.utils.ts +5 -0
  126. package/templates/povio/apps/fe/src/vite-env.d.ts +1 -0
  127. package/templates/povio/apps/fe/tsconfig.app.json +32 -0
  128. package/templates/povio/apps/fe/tsconfig.json +9 -0
  129. package/templates/povio/apps/fe/tsconfig.node.json +31 -0
  130. package/templates/povio/apps/fe/vite.config.ts +150 -0
  131. package/templates/povio/openapi.json +911 -0
  132. package/templates/povio/oxfmt.config.js +23 -0
  133. package/templates/povio/package.json +19 -0
  134. package/templates/povio/robodev/api/_lib.ts +99 -0
  135. package/templates/povio/robodev/api/health.ts +7 -0
  136. package/templates/povio/robodev/database.ts +28 -0
  137. package/templates/povio/robodev/package.json +4 -0
  138. package/templates/povio/rulesync.jsonc +18 -0
  139. package/templates/povio/tsconfig.json +11 -0
  140. package/templates/shadcn/.rulesync/rules/frontend-api-boundary.md +29 -0
  141. package/templates/shadcn/.rulesync/rules/frontend-component-structure.md +19 -0
  142. package/templates/shadcn/.rulesync/rules/frontend-hosted-ui.md +38 -0
  143. package/templates/shadcn/.rulesync/rules/project-overview.md +29 -0
  144. package/templates/shadcn/.rulesync/rules/robodev-api.md +22 -0
  145. package/templates/shadcn/.rulesync/rules/robodev-auth.md +47 -0
  146. package/templates/shadcn/.rulesync/rules/robodev-database.md +21 -0
  147. package/templates/shadcn/.rulesync/skills/robodev-crud-page/SKILL.md +181 -0
  148. package/templates/shadcn/README.md +9 -4
  149. package/templates/shadcn/ROBODEV.md +14 -6
  150. package/templates/shadcn/package.json +4 -6
  151. package/templates/shadcn/rulesync.jsonc +18 -0
  152. package/templates/shadcn/src/App.tsx +12 -3
  153. package/templates/shadcn/src/app.css +359 -0
  154. package/templates/shadcn/src/components/auth/AuthCard.tsx +29 -0
  155. package/templates/shadcn/src/components/ui/badge.tsx +17 -0
  156. package/templates/shadcn/src/components/ui/card.tsx +28 -0
  157. package/templates/shadcn/src/components/ui/dialog.tsx +38 -0
  158. package/templates/shadcn/src/components/ui/empty-state.tsx +17 -0
  159. package/templates/shadcn/src/components/ui/input.tsx +8 -0
  160. package/templates/shadcn/src/components/ui/label.tsx +8 -0
  161. package/templates/shadcn/src/components/ui/skeleton.tsx +6 -0
  162. package/templates/shadcn/src/components/ui/spinner.tsx +3 -0
  163. package/templates/shadcn/src/components/ui/table.tsx +30 -0
  164. package/templates/shadcn/src/components/ui/textarea.tsx +8 -0
  165. package/templates/shadcn/src/lib/auth.tsx +72 -0
  166. package/templates/shadcn/src/lib/client.ts +8 -0
  167. package/templates/shadcn/src/pages/Home.tsx +15 -0
  168. package/templates/shadcn/src/pages/Login.tsx +70 -0
  169. package/templates/shadcn/src/pages/NotFound.tsx +14 -0
  170. package/templates/shadcn/src/pages/Register.tsx +82 -0
  171. package/templates/space/ROBODEV.md +7 -1
  172. package/templates/space/package.json +2 -2
  173. package/templates/shadcn/components.json +0 -21
  174. package/templates/shadcn/postcss.config.js +0 -6
  175. package/templates/shadcn/tailwind.config.ts +0 -42
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "robodev",
3
- "version": "0.47.3",
3
+ "version": "0.49.0",
4
4
  "description": "CLI for Robodev Starbase — create, auth, link, deploy, load, and run a project locally with robodev dev",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -26,8 +26,8 @@
26
26
  "embedded-postgres": "17.10.0-beta.17",
27
27
  "fastify": "^5.12.1",
28
28
  "tsx": "^4.20.5",
29
- "@robodev-ai/runtime": "0.7.2",
30
- "@robodev-ai/sdk": "0.13.0"
29
+ "@robodev-ai/sdk": "0.15.0",
30
+ "@robodev-ai/runtime": "0.9.0"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/node": "^24.3.0",
@@ -62,6 +62,10 @@ test("shouldCountRequestHistogram counts Auth and matched file routes only", ()
62
62
  assert.equal(shouldCountRequestHistogram("/_robodev/scalar", fileRuntime, "GET"), false);
63
63
  assert.equal(shouldCountRequestHistogram("/_robodev/ready", fileRuntime, "GET"), false);
64
64
  assert.equal(shouldCountRequestHistogram("/openapi.json", fileRuntime, "GET"), false);
65
+ assert.equal(
66
+ shouldCountRequestHistogram("/robodev-enterprise-spec.json", fileRuntime, "GET"),
67
+ false,
68
+ );
65
69
  assert.equal(shouldCountRequestHistogram("/docs", fileRuntime, "GET"), false);
66
70
  assert.equal(shouldCountRequestHistogram("/swagger", fileRuntime, "GET"), false);
67
71
  assert.equal(isHistogramExcludedPath("/scalar"), true);
@@ -278,6 +282,17 @@ test("inspect HTML has nav labels and polls state.json", () => {
278
282
  assert.doesNotMatch(html, /fetch\("\/_robodev\/logs\.json"\)/);
279
283
  assert.doesNotMatch(html, /@xyflow|React\.createElement|react-dom/);
280
284
  assert.match(html, /setInterval\(poll, 1000\)/);
285
+ assert.match(html, /state\.overview\.links\.enterprise/);
286
+ assert.match(html, /label: "Enterprise spec"/);
287
+ });
288
+
289
+ test("dashboard state includes enterprise spec link after openapi", async () => {
290
+ const state = await buildDashboardState({
291
+ inspect: createDevInspect(),
292
+ runtime: { routes: [], jobs: [] },
293
+ });
294
+ assert.equal(state.overview.links.openapi, "/openapi.json");
295
+ assert.equal(state.overview.links.enterprise, "/robodev-enterprise-spec.json");
281
296
  });
282
297
 
283
298
  test("storageActivityMatchesKey uses exact key except list prefixes", () => {
@@ -40,6 +40,7 @@ const HISTOGRAM_EXCLUDED_PATHS = new Set([
40
40
  "/_robodev/scalar",
41
41
  "/scalar",
42
42
  "/openapi.json",
43
+ "/robodev-enterprise-spec.json",
43
44
  "/_robodev/ready",
44
45
  ]);
45
46
 
@@ -213,7 +214,7 @@ export type DashboardState = {
213
214
  google: DashboardGoogle;
214
215
  requestHistogram: RequestHistogramBucket[];
215
216
  jobHistogram: JobHistogramBucket[];
216
- links: { swagger: string; scalar: string; openapi: string };
217
+ links: { swagger: string; scalar: string; openapi: string; enterprise: string };
217
218
  };
218
219
  routes: Array<{ method: string; path: string; file: string }>;
219
220
  calls: Array<{ at: number; method: string; path: string; status: number; durationMs: number }>;
@@ -596,7 +597,12 @@ export async function buildDashboardState(input: {
596
597
  google,
597
598
  requestHistogram: input.inspect.requestHistogram(),
598
599
  jobHistogram: input.inspect.jobHistogram(),
599
- links: { swagger: "/_robodev/docs", scalar: "/_robodev/scalar", openapi: "/openapi.json" },
600
+ links: {
601
+ swagger: "/_robodev/docs",
602
+ scalar: "/_robodev/scalar",
603
+ openapi: "/openapi.json",
604
+ enterprise: "/robodev-enterprise-spec.json",
605
+ },
600
606
  },
601
607
  routes,
602
608
  calls,
@@ -1067,7 +1073,8 @@ export function inspectHtml(): string {
1067
1073
  var items = [
1068
1074
  { href: state.overview.links.swagger, label: "Swagger" },
1069
1075
  { href: state.overview.links.scalar, label: "Scalar" },
1070
- { href: state.overview.links.openapi, label: "openapi.json" }
1076
+ { href: state.overview.links.openapi, label: "openapi.json" },
1077
+ { href: state.overview.links.enterprise, label: "Enterprise spec" }
1071
1078
  ];
1072
1079
  for (var i = 0; i < items.length; i++) {
1073
1080
  var a = document.createElement("a");
package/src/dev-server.ts CHANGED
@@ -11,9 +11,11 @@ import {
11
11
  browseRows,
12
12
  browseSchema,
13
13
  buildOpenApi,
14
+ buildEnterpriseSpec,
14
15
  handleLocalAuth,
15
16
  isLocalAuthPath,
16
17
  isReservedStoragePath,
18
+ ENTERPRISE_SPEC_PATH,
17
19
  matchProjectRoute,
18
20
  matchSocketRoute,
19
21
  parseLogicalKey,
@@ -624,6 +626,10 @@ export async function startDevServer(
624
626
  await reply.send(runtime.openapi);
625
627
  return;
626
628
  }
629
+ if (pathname === ENTERPRISE_SPEC_PATH) {
630
+ await reply.send(buildEnterpriseSpec(runtime.openapi));
631
+ return;
632
+ }
627
633
 
628
634
  if (isLocalAuthPath(pathname)) {
629
635
  const result = await handleLocalAuth(
@@ -218,9 +218,12 @@ test("collectFiles for shadcn starter includes hosted Welcome and tooling config
218
218
  assert.ok(paths.has("src/api/generated/endpoints.ts"));
219
219
  assert.ok(paths.has("src/api/openapi.json"));
220
220
  assert.ok(paths.has("orval.config.ts"));
221
- assert.ok(paths.has("components.json"));
222
- assert.ok(paths.has("tailwind.config.ts"));
223
- assert.ok(paths.has("postcss.config.js"));
221
+ assert.ok(paths.has("src/lib/client.ts"));
222
+ assert.ok(paths.has("src/lib/auth.tsx"));
223
+ assert.ok(paths.has("src/pages/Login.tsx"));
224
+ assert.ok(!paths.has("components.json"));
225
+ assert.ok(!paths.has("tailwind.config.ts"));
226
+ assert.ok(!paths.has("postcss.config.js"));
224
227
  assert.ok(!paths.has("robodev/api/planets.ts"));
225
228
  assert.ok([...paths].every((path) => !path.startsWith("apps/")));
226
229
  assert.ok(files.length < 200);
@@ -22,6 +22,12 @@ export const get = defineApi({
22
22
  });
23
23
  ```
24
24
 
25
+ Method exports: one export per method — `get` / `post` / `put` / `patch` / `delete`. `delete` is a reserved word — write `export const del = ...` or `export { remove as delete }`; both serve DELETE.
26
+
27
+ `ctx.user.id` is a string like `usr_abc123`, not a UUID. Type user id columns as `text`, never `uuid`.
28
+
29
+ Throw an Error with an integer `statusCode` (400-599) to answer with that status: `throw Object.assign(new Error("Not found"), { statusCode: 404 })`. Any other throw is a generic 500.
30
+
25
31
  ## Hard rules
26
32
 
27
33
  - Do not run npm, pnpm, or yarn install.
@@ -34,7 +40,7 @@ export const get = defineApi({
34
40
 
35
41
  ## Auth and product data
36
42
 
37
- Persist primary product data with `defineApi` and `robodev-publish be`. Do not use localStorage as the product store unless the user asked for a public, static, or no-account page. Auth is on by default: add login and register and protect routes unless the product is public or unauthenticated. Use `auth: "required"` and `ctx.user.id`. Call reserved `/api/user/auth/*` — do not implement `api/user/**`. Tiny: reuse seed login/register and AuthGuard. Shadcn, Empty, and legacy: create login/register with `@robodev-ai/client` tokens. A missing `.rulesync` skill is not a reason to skip APIs. Do not require `robodev-auth set` every run.
43
+ Persist primary product data with `defineApi` and `robodev-publish be`. Do not use localStorage as the product store unless the user asked for a public, static, or no-account page. Auth is on by default: add login and register and protect routes unless the product is public or unauthenticated. Use `auth: "required"` and `ctx.user.id`. Call reserved `/api/user/auth/*` — do not implement `api/user/**`. Tiny and Shadcn: reuse seed login/register and AuthGuard. Empty and legacy: create login/register with `@robodev-ai/client` tokens. A missing `.rulesync` skill is not a reason to skip APIs. Do not require `robodev-auth set` every run.
38
44
 
39
45
  ## Backend
40
46
 
@@ -9,10 +9,10 @@
9
9
  "rules:gen": "rulesync generate"
10
10
  },
11
11
  "dependencies": {
12
- "@robodev-ai/sdk": "^0.13.0"
12
+ "@robodev-ai/sdk": "^0.15.0"
13
13
  },
14
14
  "devDependencies": {
15
- "robodev": "^0.47.3",
15
+ "robodev": "^0.49.0",
16
16
  "rulesync": "^8.18.0",
17
17
  "typescript": "^5.9.2"
18
18
  }
@@ -22,6 +22,12 @@ export const get = defineApi({
22
22
  });
23
23
  ```
24
24
 
25
+ Method exports: one export per method — `get` / `post` / `put` / `patch` / `delete`. `delete` is a reserved word — write `export const del = ...` or `export { remove as delete }`; both serve DELETE.
26
+
27
+ `ctx.user.id` is a string like `usr_abc123`, not a UUID. Type user id columns as `text`, never `uuid`.
28
+
29
+ Throw an Error with an integer `statusCode` (400-599) to answer with that status: `throw Object.assign(new Error("Not found"), { statusCode: 404 })`. Any other throw is a generic 500.
30
+
25
31
  ## Hard rules
26
32
 
27
33
  - Do not run npm, pnpm, or yarn install.
@@ -34,7 +40,7 @@ export const get = defineApi({
34
40
 
35
41
  ## Auth and product data
36
42
 
37
- Persist primary product data with `defineApi` and `robodev-publish be`. Do not use localStorage as the product store unless the user asked for a public, static, or no-account page. Auth is on by default: add login and register and protect routes unless the product is public or unauthenticated. Use `auth: "required"` and `ctx.user.id`. Call reserved `/api/user/auth/*` — do not implement `api/user/**`. Tiny: reuse seed login/register and AuthGuard. Shadcn, Empty, and legacy: create login/register with `@robodev-ai/client` tokens. A missing `.rulesync` skill is not a reason to skip APIs. Do not require `robodev-auth set` every run.
43
+ Persist primary product data with `defineApi` and `robodev-publish be`. Do not use localStorage as the product store unless the user asked for a public, static, or no-account page. Auth is on by default: add login and register and protect routes unless the product is public or unauthenticated. Use `auth: "required"` and `ctx.user.id`. Call reserved `/api/user/auth/*` — do not implement `api/user/**`. Tiny and Shadcn: reuse seed login/register and AuthGuard. Empty and legacy: create login/register with `@robodev-ai/client` tokens. A missing `.rulesync` skill is not a reason to skip APIs. Do not require `robodev-auth set` every run.
38
44
 
39
45
  ## Backend
40
46
 
@@ -8,10 +8,10 @@
8
8
  "deploy": "robodev deploy"
9
9
  },
10
10
  "dependencies": {
11
- "@robodev-ai/sdk": "^0.13.0"
11
+ "@robodev-ai/sdk": "^0.15.0"
12
12
  },
13
13
  "devDependencies": {
14
- "robodev": "^0.47.3",
14
+ "robodev": "^0.49.0",
15
15
  "typescript": "^5.9.2"
16
16
  }
17
17
  }
@@ -30,6 +30,11 @@
30
30
  "id": "shadcn",
31
31
  "title": "Shadcn",
32
32
  "description": "Blank database.ts and GET /api/health plus a hosted Welcome page with shadcn and an orval client. No sample schema."
33
+ },
34
+ {
35
+ "id": "povio",
36
+ "title": "Povio UI",
37
+ "description": "Blank seed with the real @povio/ui in apps/fe: empty schema, GET /api/health, seeded auth. No sample features."
33
38
  }
34
39
  ]
35
40
  }
@@ -22,6 +22,12 @@ export const get = defineApi({
22
22
  });
23
23
  ```
24
24
 
25
+ Method exports: one export per method — `get` / `post` / `put` / `patch` / `delete`. `delete` is a reserved word — write `export const del = ...` or `export { remove as delete }`; both serve DELETE.
26
+
27
+ `ctx.user.id` is a string like `usr_abc123`, not a UUID. Type user id columns as `text`, never `uuid`.
28
+
29
+ Throw an Error with an integer `statusCode` (400-599) to answer with that status: `throw Object.assign(new Error("Not found"), { statusCode: 404 })`. Any other throw is a generic 500.
30
+
25
31
  ## Hard rules
26
32
 
27
33
  - Do not run npm, pnpm, or yarn install.
@@ -34,7 +40,7 @@ export const get = defineApi({
34
40
 
35
41
  ## Auth and product data
36
42
 
37
- Persist primary product data with `defineApi` and `robodev-publish be`. Do not use localStorage as the product store unless the user asked for a public, static, or no-account page. Auth is on by default: add login and register and protect routes unless the product is public or unauthenticated. Use `auth: "required"` and `ctx.user.id`. Call reserved `/api/user/auth/*` — do not implement `api/user/**`. Tiny: reuse seed login/register and AuthGuard. Shadcn, Empty, and legacy: create login/register with `@robodev-ai/client` tokens. A missing `.rulesync` skill is not a reason to skip APIs. Do not require `robodev-auth set` every run.
43
+ Persist primary product data with `defineApi` and `robodev-publish be`. Do not use localStorage as the product store unless the user asked for a public, static, or no-account page. Auth is on by default: add login and register and protect routes unless the product is public or unauthenticated. Use `auth: "required"` and `ctx.user.id`. Call reserved `/api/user/auth/*` — do not implement `api/user/**`. Tiny and Shadcn: reuse seed login/register and AuthGuard. Empty and legacy: create login/register with `@robodev-ai/client` tokens. A missing `.rulesync` skill is not a reason to skip APIs. Do not require `robodev-auth set` every run.
38
44
 
39
45
  ## Backend
40
46
 
@@ -10,13 +10,13 @@
10
10
  "build": "vite build"
11
11
  },
12
12
  "dependencies": {
13
- "@robodev-ai/sdk": "^0.13.0",
13
+ "@robodev-ai/sdk": "^0.15.0",
14
14
  "@robodev-ai/client": "^0.5.0",
15
15
  "react": "^18.3.1",
16
16
  "react-dom": "^18.3.1"
17
17
  },
18
18
  "devDependencies": {
19
- "robodev": "^0.47.3",
19
+ "robodev": "^0.49.0",
20
20
  "typescript": "^5.9.2",
21
21
  "vite": "^6.0.0"
22
22
  }
@@ -22,6 +22,12 @@ export const get = defineApi({
22
22
  });
23
23
  ```
24
24
 
25
+ Method exports: one export per method — `get` / `post` / `put` / `patch` / `delete`. `delete` is a reserved word — write `export const del = ...` or `export { remove as delete }`; both serve DELETE.
26
+
27
+ `ctx.user.id` is a string like `usr_abc123`, not a UUID. Type user id columns as `text`, never `uuid`.
28
+
29
+ Throw an Error with an integer `statusCode` (400-599) to answer with that status: `throw Object.assign(new Error("Not found"), { statusCode: 404 })`. Any other throw is a generic 500.
30
+
25
31
  ## Hard rules
26
32
 
27
33
  - Do not run npm, pnpm, or yarn install.
@@ -34,7 +40,7 @@ export const get = defineApi({
34
40
 
35
41
  ## Auth and product data
36
42
 
37
- Persist primary product data with `defineApi` and `robodev-publish be`. Do not use localStorage as the product store unless the user asked for a public, static, or no-account page. Auth is on by default: add login and register and protect routes unless the product is public or unauthenticated. Use `auth: "required"` and `ctx.user.id`. Call reserved `/api/user/auth/*` — do not implement `api/user/**`. Tiny: reuse seed login/register and AuthGuard. Shadcn, Empty, and legacy: create login/register with `@robodev-ai/client` tokens. A missing `.rulesync` skill is not a reason to skip APIs. Do not require `robodev-auth set` every run.
43
+ Persist primary product data with `defineApi` and `robodev-publish be`. Do not use localStorage as the product store unless the user asked for a public, static, or no-account page. Auth is on by default: add login and register and protect routes unless the product is public or unauthenticated. Use `auth: "required"` and `ctx.user.id`. Call reserved `/api/user/auth/*` — do not implement `api/user/**`. Tiny and Shadcn: reuse seed login/register and AuthGuard. Empty and legacy: create login/register with `@robodev-ai/client` tokens. A missing `.rulesync` skill is not a reason to skip APIs. Do not require `robodev-auth set` every run.
38
44
 
39
45
  ## Backend
40
46
 
@@ -9,10 +9,10 @@
9
9
  "rules:gen": "rulesync generate"
10
10
  },
11
11
  "dependencies": {
12
- "@robodev-ai/sdk": "^0.13.0"
12
+ "@robodev-ai/sdk": "^0.15.0"
13
13
  },
14
14
  "devDependencies": {
15
- "robodev": "^0.47.3",
15
+ "robodev": "^0.49.0",
16
16
  "rulesync": "^8.18.0",
17
17
  "typescript": "^5.9.2"
18
18
  }
@@ -0,0 +1,27 @@
1
+ STAGE: "local"
2
+ OUTPUT: "export"
3
+
4
+ ANALYZE: "false"
5
+ NEXT_TELEMETRY_DISABLED: "1"
6
+
7
+ VITE_PUBLIC_RELEASE: ${env:RELEASE}
8
+ VITE_PUBLIC_STAGE: ${func:stage}
9
+
10
+ APP_PUBLIC_API_URL: &APP_PUBLIC_API_URL "http://localhost:4000"
11
+ APP_PUBLIC_API_MODE: &APP_PUBLIC_API_MODE "real"
12
+ VITE_PUBLIC_API_URL: *APP_PUBLIC_API_URL
13
+ VITE_PUBLIC_API_MODE: *APP_PUBLIC_API_MODE
14
+
15
+ VITE_PUBLIC_LOG_LEVEL: "trace"
16
+
17
+ VITE_PUBLIC_SENTRY_DSN: ""
18
+ VITE_PUBLIC_SENTRY_ENVIRONMENT: ${func:stage}
19
+ VITE_PUBLIC_SENTRY_TRACES_SAMPLE_RATE: "0"
20
+ VITE_PUBLIC_SENTRY_REPLAYS_SESSION_SAMPLE_RATE: "0"
21
+ VITE_PUBLIC_SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE: "0"
22
+
23
+ VITE_PUBLIC_AUTH_CUSTOM_JWT_ENABLE_MAGIC_LINK: "true"
24
+
25
+ VITE_PUBLIC_GOOGLE_ANALYTICS_MEASUREMENT_ID: ""
26
+
27
+ VITE_DEV_PORT: "3000"
@@ -0,0 +1,29 @@
1
+ {
2
+ "$schema": "apps/fe/node_modules/oxlint/configuration_schema.json",
3
+ "plugins": ["eslint", "typescript", "unicorn", "import", "oxc", "promise", "vitest"],
4
+ "categories": {
5
+ "correctness": "error",
6
+ "perf": "error",
7
+ "pedantic": "off",
8
+ "style": "off",
9
+ "restriction": "off",
10
+ "suspicious": "off",
11
+ "nursery": "off"
12
+ },
13
+ "env": {
14
+ "builtin": true,
15
+ "node": true,
16
+ "shared-node-browser": true
17
+ },
18
+ "rules": {
19
+ "eslint/eqeqeq": [
20
+ "error",
21
+ "always",
22
+ {
23
+ "null": "ignore"
24
+ }
25
+ ],
26
+ "typescript/no-floating-promises": "off",
27
+ "eslint/capitalized-comments": "off"
28
+ }
29
+ }
@@ -0,0 +1,78 @@
1
+ {
2
+ "$schema": "apps/fe/node_modules/oxlint/configuration_schema.json",
3
+ "extends": [".oxlint-base.json"],
4
+ "plugins": [
5
+ "eslint",
6
+ "typescript",
7
+ "unicorn",
8
+ "import",
9
+ "vitest",
10
+ "react",
11
+ "react-perf",
12
+ "jsx-a11y"
13
+ ],
14
+ "categories": {
15
+ "style": "error"
16
+ },
17
+ "ignorePatterns": [
18
+ "openapi-codegen.config.ts",
19
+ "postcss.config.js",
20
+ "out",
21
+ "dist",
22
+ "public",
23
+ "scripts",
24
+ ".vscode",
25
+ ".turbo",
26
+ "node_modules",
27
+ "apps/fe/src/routeTree.gen.ts",
28
+ "apps/fe/src/openapi",
29
+ "apps/fe/public"
30
+ ],
31
+ "overrides": [
32
+ {
33
+ "files": ["vite-plugin-*.ts", "apps/fe/vite-plugin-*.ts"],
34
+ "rules": {
35
+ "import/no-nodejs-modules": "off"
36
+ }
37
+ }
38
+ ],
39
+ "rules": {
40
+ "eslint/no-implicit-coercion": "off",
41
+ "no-map-spread": "off",
42
+ "eslint/sort-keys": "off",
43
+ "eslint/sort-imports": "off",
44
+ "eslint/no-ternary": "off",
45
+ "eslint/id-length": "off",
46
+ "eslint/no-magic-numbers": "off",
47
+ "eslint/arrow-body-style": "off",
48
+ "eslint/max-params": "off",
49
+ "eslint/func-style": "off",
50
+ "eslint/new-cap": "off",
51
+ "eslint/no-continue": "off",
52
+ "eslint/max-statements": "off",
53
+ "eslint/no-duplicate-imports": [
54
+ "error",
55
+ {
56
+ "allowSeparateTypeImports": true
57
+ }
58
+ ],
59
+ "react/exhaustive-deps": "off",
60
+ "react/jsx-props-no-spreading": "off",
61
+ "react/jsx-max-depth": "off",
62
+ "react-perf/jsx-no-new-object-as-prop": "off",
63
+ "react-perf/jsx-no-new-function-as-prop": "off",
64
+ "react-perf/jsx-no-new-array-as-prop": "off",
65
+ "react-perf/jsx-no-jsx-as-prop": "off",
66
+ "typescript/no-empty-interface": "off",
67
+ "import/no-named-export": "off",
68
+ "import/group-exports": "off",
69
+ "import/prefer-default-export": "off",
70
+ "import/exports-last": "off",
71
+ "import/consistent-type-specifier-style": "off",
72
+ "jest/require-hook": "off",
73
+ "unicorn/filename-case": "off",
74
+ "unicorn/prefer-global-this": "off",
75
+ "unicorn/no-await-expression-member": "off",
76
+ "unicorn/no-null": "off"
77
+ }
78
+ }
@@ -0,0 +1,36 @@
1
+ ---
2
+ root: false
3
+ targets: ["claudecode", "codexcli", "cursor"]
4
+ description: "Frontend must consume generated OpenAPI queries and models, not backend internals."
5
+ globs: ["apps/fe/src/**/*.{ts,tsx}"]
6
+ cursor:
7
+ alwaysApply: false
8
+ description: "Apply when editing frontend components, hooks, providers, pages, or clients that call the API."
9
+ globs: ["apps/fe/src/**/*.{ts,tsx}"]
10
+ ---
11
+
12
+ # Frontend API Boundary
13
+
14
+ Frontend application code must consume the API through generated files in `apps/fe/src/openapi`.
15
+
16
+ Use generated modules such as:
17
+
18
+ - `@/openapi/<domain>/<domain>.queries`
19
+ - `@/openapi/<domain>/<domain>.models`
20
+ - `@/openapi/queryModules`
21
+
22
+ For generated mutations, pass invalidation through the mutation options instead of importing `queryClient` or calling `invalidateQueries` with generated query keys. The current module is invalidated by default through `invalidateCurrentModule: true`; invalidate dependent modules explicitly with `invalidateModules: [QueryModule.someModule]`.
23
+
24
+ After mutations, derive follow-up UI state from canonical API response or query state instead of leaving action controls unchanged. Disable duplicate submissions when the API state already represents a pending or completed action, and surface mutation errors through the default generated-client error handler or a feature-specific message.
25
+
26
+ Do not import `@robodev-ai/sdk`, `robodev/database.ts`, Drizzle tables, or API helper modules into frontend features.
27
+
28
+ `apps/fe/src/openapi` is generated by `@povio/openapi-codegen-cli` from root `openapi.json` (or a live project `/openapi.json` when `OPENAPI_LIVE=true`). Do not hand-edit generated OpenAPI client files.
29
+
30
+ When API contracts change:
31
+
32
+ 1. Update `api/` handlers and `openapi.json` if the documented contract changed.
33
+ 2. Run `bun openapi:gen` from `apps/fe`.
34
+ 3. Update frontend code to use the regenerated queries and models.
35
+
36
+ Point `VITE_PUBLIC_API_URL` at the Starbase project host origin only. Do not append `/api`.
@@ -0,0 +1,40 @@
1
+ ---
2
+ root: false
3
+ targets: ["claudecode", "codexcli", "cursor"]
4
+ description: "Frontend component extraction and feature subcomponent structure conventions."
5
+ globs: ["apps/fe/src/**/*.{ts,tsx}"]
6
+ cursor:
7
+ alwaysApply: false
8
+ description: "Apply when organizing frontend feature components, page sections, mapped items, or reusable UI."
9
+ globs: ["apps/fe/src/**/*.{ts,tsx}"]
10
+ ---
11
+
12
+ # Frontend Component Structure
13
+
14
+ Extract repeatable UI into subcomponents. Every named React component should live in its own file, even when it is currently used only once. Keep the component file near the feature, layout, page, or shared UI area that owns it.
15
+
16
+ Extract large or complex sections of pages into named components so route and page components stay readable. Anything mapped from an array should usually be a component, such as cards, table row actions, repeated sections, or list items.
17
+
18
+ For a `todos` feature that means:
19
+
20
+ - `TodoCard` for mapped grid cards.
21
+ - `TodosFilters` for shared filter controls.
22
+ - `TodosTableActions` for repeated row actions.
23
+ - `TodosTable` and `TodosTableInfinite` for table wrappers.
24
+ - `TodoDetailsPage` and `TodoEditPage` for large route-owned views.
25
+
26
+ The seeded `auth`, `home`, and `profile` features show the structure.
27
+
28
+ Add each new product page to the navigation in `apps/fe/src/components/layout/app-header/AppHeader.tsx` and `MobileNavigation.tsx` so it is reachable.
29
+
30
+ Route files should own routing, document metadata, and route data boundaries. Feature components should own the page UI and interaction details.
31
+
32
+ Exception: route-local wrappers such as `PageComponent` or layout guard components may stay in route files when they only connect routing primitives to feature components.
33
+
34
+ ## Shared Utilities
35
+
36
+ Keep generic formatting, parsing, calculation, and data-shaping helpers in `apps/fe/src/utils/*.utils.ts` files instead of defining them inside component files. Export helpers through namespaces such as `DateUtils.formatDate(...)` or `NumberUtils.formatInteger(...)` so call sites stay explicit and related helpers stay grouped.
37
+
38
+ Component files may keep UI-local glue helpers only when the logic is tightly coupled to that component's JSX, such as adapting one component's prop shape or handling a local event. If the helper describes dates, numbers, arrays, strings, IDs, or other domain-neutral data, move it into a shared utility file.
39
+
40
+ For apps with multiple user roles that require distinct UI or business workflows, also apply the role-based app structure rule.
@@ -0,0 +1,27 @@
1
+ ---
2
+ root: false
3
+ targets: ["claudecode", "codexcli", "cursor"]
4
+ description: "Frontend form patterns with Povio UI useForm, generated schemas, and formControl wiring."
5
+ globs: ["apps/fe/src/**/*.{ts,tsx}"]
6
+ cursor:
7
+ alwaysApply: false
8
+ description: "Apply when building or changing frontend forms, modals, edit pages, or input components."
9
+ globs: ["apps/fe/src/**/*.{ts,tsx}"]
10
+ ---
11
+
12
+ # Frontend Forms
13
+
14
+ Use `useForm` and form-aware inputs from `@povio/ui/tanstack` with generated OpenAPI Zod schemas for API-backed forms. The seeded login and register forms (`apps/fe/src/components/features/auth/LoginPage.tsx`, `RegisterPage.tsx`) show the pattern. Prefer this shape:
15
+
16
+ ```tsx
17
+ const form = useForm({
18
+ zodSchema: TodosModels.TodosCreateInputSchema,
19
+ defaultValues: { name: "" },
20
+ });
21
+ ```
22
+
23
+ Pass form state into Povio UI inputs with `field={{ form, name: "fieldName" }}`. Use `form.handleSubmit`, `form.reset`, and `form.setFieldValue` for form actions, and `useFormValue(form, selector)` for reactive field reads.
24
+
25
+ Avoid local `useState`, custom `value`, and custom `onChange` plumbing for fields that belong to the form. Use TanStack Form's `form.Field` adapter only when a component cannot accept the Povio UI `field` binding.
26
+
27
+ Use generated OpenAPI queries and mutations for submit handlers. Keep toast feedback and navigation close to the feature interaction that owns them.
@@ -0,0 +1,24 @@
1
+ ---
2
+ root: false
3
+ targets: ["claudecode", "codexcli", "cursor"]
4
+ description: "Frontend notification inbox, preferences, push permission, service worker, and token registration boundaries."
5
+ globs: ["apps/fe/src/**/*.{ts,tsx}", "apps/fe/public/**/*.{js,ts}"]
6
+ cursor:
7
+ alwaysApply: false
8
+ description: "Apply when frontend work handles notifications, push permission, service workers, push tokens, unread counts, or notification preferences."
9
+ globs: ["apps/fe/src/**/*.{ts,tsx}", "apps/fe/public/**/*.{js,ts}"]
10
+ ---
11
+
12
+ # Frontend Notifications
13
+
14
+ Use generated `@/openapi` queries, mutations, and models for notification history, preferences, and push-token registration. Do not import `@robodev-ai/sdk` or `robodev/database.ts` into frontend feature code.
15
+
16
+ Request push permission only after an explanatory UI and explicit user gesture. Never request it automatically during initial application load. Handle unsupported, default, denied, granted, registered, expired, and failed-registration states.
17
+
18
+ Register the service worker and provider subscription through a small browser integration, then persist the token/subscription through the generated authenticated user API. Clean up or detach the current device registration on logout when required by the security model.
19
+
20
+ Keep push payloads minimal and privacy-safe. Validate internal deep links before navigation. Never depend on push as the only record of an important event; provide a paginated in-app notification list and unread state.
21
+
22
+ Use generated mutation invalidation options for unread counts, mark-read actions, preferences, and token changes. Do not access the query client directly for generated API state.
23
+
24
+ Use `@povio/ui` for permission prompts, notification lists, menus/popovers, tags, forms, confirmations, and toasts. Use `povio-ui-styling` for styling-layer decisions.
@@ -0,0 +1,42 @@
1
+ ---
2
+ root: false
3
+ targets: ["claudecode", "codexcli", "cursor"]
4
+ description: "Frontend interactive controls and typography must use Povio UI primitives instead of native replacements."
5
+ globs: ["apps/fe/src/**/*.{ts,tsx}"]
6
+ cursor:
7
+ alwaysApply: false
8
+ description: "Apply when creating or editing React components, controls, forms, tables, overlays, or user-facing text."
9
+ globs: ["apps/fe/src/**/*.{ts,tsx}"]
10
+ ---
11
+
12
+ # Use Povio UI Components
13
+
14
+ Use a component from `@povio/ui` whenever it provides the required primitive. Do not recreate an available Povio component with a native element plus Tailwind or custom CSS.
15
+
16
+ Required replacements include:
17
+
18
+ - `Button`, `TextButton`, or the appropriate Povio action component instead of a styled `<button>`.
19
+ - `TextInput`, `PasswordInput`, `TextArea`, checkbox, radio, select, autocomplete, and other Povio form controls instead of native form controls.
20
+ - `Typography` instead of directly styling user-facing headings, paragraphs, labels, or spans.
21
+ - `Table` or `InfiniteTable` instead of a hand-built native data table.
22
+ - `Modal`, `Confirmation`, `Drawer`, `BottomSheet`, `Menu`, `Tooltip`, or `ResponsivePopover` instead of custom overlay primitives.
23
+ - `FileUpload` instead of a directly exposed file input.
24
+ - Povio hooks such as `useForm` and `useToast` instead of parallel custom infrastructure.
25
+
26
+ Before creating a control:
27
+
28
+ 1. Search `@povio/ui` usage in the repository.
29
+ 2. Inspect existing feature components for the same primitive.
30
+ 3. Use the existing Povio props and variants.
31
+ 4. Apply the `povio-ui-styling` skill when choosing between local Tailwind, `UIConfig`, `UIOverrides`, a shared wrapper, or scoped CSS.
32
+
33
+ Native semantic and structural elements such as `<main>`, `<section>`, `<article>`, `<nav>`, `<form>`, `<div>`, and list elements remain appropriate for document structure and layout. Use TanStack Router navigation primitives for routing. This rule prohibits native replacements for available Povio UI behavior; it does not prohibit semantic HTML.
34
+
35
+ If Povio UI has no suitable primitive:
36
+
37
+ - Compose existing Povio components first.
38
+ - Put a reusable project-specific primitive under `apps/fe/src/components/shared/ui`.
39
+ - Preserve keyboard behavior, focus visibility, accessible names, disabled state, validation state, and loading state.
40
+ - Keep the exception narrow; do not introduce another general-purpose UI library.
41
+
42
+ When touching an existing native control that has a Povio equivalent, migrate it when the change is safely within scope. Do not expand a narrowly requested fix into a broad unrelated rewrite.