robodev 0.47.2 → 0.48.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.
- package/package.json +3 -3
- package/src/emit-starter.test.ts +6 -3
- package/templates/auth-chat/ROBODEV.md +7 -1
- package/templates/auth-chat/package.json +2 -2
- package/templates/backend/ROBODEV.md +7 -1
- package/templates/backend/package.json +2 -2
- package/templates/catalog.json +5 -0
- package/templates/empty/ROBODEV.md +7 -1
- package/templates/empty/package.json +2 -2
- package/templates/marketplace/ROBODEV.md +7 -1
- package/templates/marketplace/package.json +2 -2
- package/templates/povio/.config/local.spa.template.yml +27 -0
- package/templates/povio/.oxlint-base.json +29 -0
- package/templates/povio/.oxlintrc.json +78 -0
- package/templates/povio/.rulesync/rules/frontend-api-boundary.md +36 -0
- package/templates/povio/.rulesync/rules/frontend-component-structure.md +40 -0
- package/templates/povio/.rulesync/rules/frontend-forms.md +27 -0
- package/templates/povio/.rulesync/rules/frontend-notifications.md +24 -0
- package/templates/povio/.rulesync/rules/frontend-povio-components.md +42 -0
- package/templates/povio/.rulesync/rules/frontend-povio-ui.md +45 -0
- package/templates/povio/.rulesync/rules/frontend-query-autocomplete.md +24 -0
- package/templates/povio/.rulesync/rules/frontend-tables-and-lists.md +26 -0
- package/templates/povio/.rulesync/rules/frontend-translations.md +25 -0
- package/templates/povio/.rulesync/rules/project-overview.md +32 -0
- package/templates/povio/.rulesync/rules/robodev-api.md +30 -0
- package/templates/povio/.rulesync/rules/robodev-auth.md +40 -0
- package/templates/povio/.rulesync/rules/robodev-database.md +22 -0
- package/templates/povio/.rulesync/rules/role-based-app-structure.md +36 -0
- package/templates/povio/.rulesync/skills/media-feature/SKILL.md +21 -0
- package/templates/povio/.rulesync/skills/povio-ui-styling/SKILL.md +211 -0
- package/templates/povio/.rulesync/skills/povio-ui-styling/agents/openai.yaml +4 -0
- package/templates/povio/.rulesync/skills/robodev-api-route/SKILL.md +13 -0
- package/templates/povio/.rulesync/skills/robodev-table/SKILL.md +12 -0
- package/templates/povio/README.md +40 -0
- package/templates/povio/ROBODEV.md +84 -0
- package/templates/povio/apps/fe/index.html +24 -0
- package/templates/povio/apps/fe/openapi-codegen.config.ts +72 -0
- package/templates/povio/apps/fe/package.json +71 -0
- package/templates/povio/apps/fe/public/apple-touch-icon.png +0 -0
- package/templates/povio/apps/fe/public/favicon-96x96.png +0 -0
- package/templates/povio/apps/fe/public/favicon.ico +0 -0
- package/templates/povio/apps/fe/public/favicon.svg +3 -0
- package/templates/povio/apps/fe/public/site.webmanifest +21 -0
- package/templates/povio/apps/fe/public/web-app-manifest-192x192.png +0 -0
- package/templates/povio/apps/fe/public/web-app-manifest-512x512.png +0 -0
- package/templates/povio/apps/fe/src/assets/locales/en/translation.json +166 -0
- package/templates/povio/apps/fe/src/clients/app-rest-client.ts +15 -0
- package/templates/povio/apps/fe/src/clients/auth-token-store.ts +101 -0
- package/templates/povio/apps/fe/src/clients/rest/app-error-handler.ts +31 -0
- package/templates/povio/apps/fe/src/clients/rest/interceptors/authorization-header.interceptor.ts +15 -0
- package/templates/povio/apps/fe/src/clients/rest/interceptors/refresh-token.interceptor.ts +45 -0
- package/templates/povio/apps/fe/src/clients/rest/interceptors/response.interceptor.ts +17 -0
- package/templates/povio/apps/fe/src/components/404.tsx +18 -0
- package/templates/povio/apps/fe/src/components/features/auth/AuthBrandPanel.tsx +60 -0
- package/templates/povio/apps/fe/src/components/features/auth/AuthLayout.tsx +23 -0
- package/templates/povio/apps/fe/src/components/features/auth/LoginPage.tsx +111 -0
- package/templates/povio/apps/fe/src/components/features/auth/RegisterPage.tsx +143 -0
- package/templates/povio/apps/fe/src/components/features/home/HomePage.tsx +21 -0
- package/templates/povio/apps/fe/src/components/features/profile/ProfilePage.tsx +96 -0
- package/templates/povio/apps/fe/src/components/layout/AppLayout.tsx +19 -0
- package/templates/povio/apps/fe/src/components/layout/app-header/AppHeader.tsx +91 -0
- package/templates/povio/apps/fe/src/components/layout/app-header/MobileNavigation.tsx +51 -0
- package/templates/povio/apps/fe/src/components/layout/app-header/NavLink.tsx +29 -0
- package/templates/povio/apps/fe/src/components/shared/branding/BrandLogo.tsx +13 -0
- package/templates/povio/apps/fe/src/components/shared/error/ErrorFallback.tsx +43 -0
- package/templates/povio/apps/fe/src/components/shared/error/ErrorText.tsx +20 -0
- package/templates/povio/apps/fe/src/components/shared/error/NotFound.tsx +36 -0
- package/templates/povio/apps/fe/src/components/shared/forms/RequiredLabel.tsx +21 -0
- package/templates/povio/apps/fe/src/components/shared/forms/RowInputWrapper.tsx +50 -0
- package/templates/povio/apps/fe/src/components/shared/head/AppHead.tsx +32 -0
- package/templates/povio/apps/fe/src/components/shared/head/DefaultAppHead.tsx +34 -0
- package/templates/povio/apps/fe/src/components/shared/layout/LoadingState.tsx +9 -0
- package/templates/povio/apps/fe/src/components/shared/layout/ThinPageWrapper.tsx +5 -0
- package/templates/povio/apps/fe/src/components/shared/page/PageHeader.tsx +69 -0
- package/templates/povio/apps/fe/src/components/shared/ui/Card.tsx +60 -0
- package/templates/povio/apps/fe/src/components/shared/ui/GoogleLoginButton.tsx +19 -0
- package/templates/povio/apps/fe/src/components/shared/ui/RequiredLabel.tsx +22 -0
- package/templates/povio/apps/fe/src/components/shared/ui/TableActions.tsx +22 -0
- package/templates/povio/apps/fe/src/config/app.config.ts +23 -0
- package/templates/povio/apps/fe/src/config/i18n.ts +37 -0
- package/templates/povio/apps/fe/src/config/inits/logger.ts +7 -0
- package/templates/povio/apps/fe/src/config/jwt.config.ts +2 -0
- package/templates/povio/apps/fe/src/config/query.config.ts +20 -0
- package/templates/povio/apps/fe/src/hooks/useAuth.ts +5 -0
- package/templates/povio/apps/fe/src/main.tsx +52 -0
- package/templates/povio/apps/fe/src/pages/(guest)/login.tsx +23 -0
- package/templates/povio/apps/fe/src/pages/(guest)/register.tsx +23 -0
- package/templates/povio/apps/fe/src/pages/(guest)/route.tsx +18 -0
- package/templates/povio/apps/fe/src/pages/(private)/index.tsx +23 -0
- package/templates/povio/apps/fe/src/pages/(private)/profile.tsx +23 -0
- package/templates/povio/apps/fe/src/pages/(private)/route.tsx +18 -0
- package/templates/povio/apps/fe/src/pages/(public)/auth.tsx +37 -0
- package/templates/povio/apps/fe/src/pages/(public)/route.tsx +9 -0
- package/templates/povio/apps/fe/src/pages/__root.tsx +133 -0
- package/templates/povio/apps/fe/src/providers/AppErrorBoundary.tsx +44 -0
- package/templates/povio/apps/fe/src/providers/OpenApiRuntimeProvider.tsx +31 -0
- package/templates/povio/apps/fe/src/providers/index.tsx +44 -0
- package/templates/povio/apps/fe/src/providers/jwt.provider.tsx +95 -0
- package/templates/povio/apps/fe/src/routeTree.gen.ts +225 -0
- package/templates/povio/apps/fe/src/styles/base.css +84 -0
- package/templates/povio/apps/fe/src/styles/fonts/fonts.tsx +10 -0
- package/templates/povio/apps/fe/src/styles/globals.css +26 -0
- package/templates/povio/apps/fe/src/styles/overrides/defaults/button.override.ts +536 -0
- package/templates/povio/apps/fe/src/styles/overrides/defaults/checkbox.override.ts +71 -0
- package/templates/povio/apps/fe/src/styles/overrides/defaults/input.override.ts +252 -0
- package/templates/povio/apps/fe/src/styles/overrides/defaults/label.override.ts +91 -0
- package/templates/povio/apps/fe/src/styles/overrides/defaults/modal.override.ts +62 -0
- package/templates/povio/apps/fe/src/styles/overrides/defaults/radio.override.ts +46 -0
- package/templates/povio/apps/fe/src/styles/overrides/defaults/table.override.ts +104 -0
- package/templates/povio/apps/fe/src/styles/overrides/defaults/tag.override.ts +66 -0
- package/templates/povio/apps/fe/src/styles/overrides/defaults/typography.override.ts +115 -0
- package/templates/povio/apps/fe/src/styles/overrides/outline.clsx.ts +10 -0
- package/templates/povio/apps/fe/src/styles/overrides/uiOverrides.override.ts +60 -0
- package/templates/povio/apps/fe/src/styles/theme.css +2177 -0
- package/templates/povio/apps/fe/src/types/i18next.d.ts +12 -0
- package/templates/povio/apps/fe/src/types/table.d.ts +17 -0
- package/templates/povio/apps/fe/src/types/ui.d.ts +26 -0
- package/templates/povio/apps/fe/src/types/vite-env.d.ts +13 -0
- package/templates/povio/apps/fe/src/utils/date.utils.ts +17 -0
- package/templates/povio/apps/fe/src/utils/image-fallback.ts +9 -0
- package/templates/povio/apps/fe/src/utils/number.utils.ts +12 -0
- package/templates/povio/apps/fe/src/utils/string.utils.ts +5 -0
- package/templates/povio/apps/fe/src/vite-env.d.ts +1 -0
- package/templates/povio/apps/fe/tsconfig.app.json +32 -0
- package/templates/povio/apps/fe/tsconfig.json +9 -0
- package/templates/povio/apps/fe/tsconfig.node.json +31 -0
- package/templates/povio/apps/fe/vite.config.ts +150 -0
- package/templates/povio/openapi.json +911 -0
- package/templates/povio/oxfmt.config.js +23 -0
- package/templates/povio/package.json +19 -0
- package/templates/povio/robodev/api/_lib.ts +99 -0
- package/templates/povio/robodev/api/health.ts +7 -0
- package/templates/povio/robodev/database.ts +28 -0
- package/templates/povio/robodev/package.json +4 -0
- package/templates/povio/rulesync.jsonc +18 -0
- package/templates/povio/tsconfig.json +11 -0
- package/templates/shadcn/.rulesync/rules/frontend-api-boundary.md +29 -0
- package/templates/shadcn/.rulesync/rules/frontend-component-structure.md +19 -0
- package/templates/shadcn/.rulesync/rules/frontend-hosted-ui.md +38 -0
- package/templates/shadcn/.rulesync/rules/project-overview.md +29 -0
- package/templates/shadcn/.rulesync/rules/robodev-api.md +22 -0
- package/templates/shadcn/.rulesync/rules/robodev-auth.md +47 -0
- package/templates/shadcn/.rulesync/rules/robodev-database.md +21 -0
- package/templates/shadcn/.rulesync/skills/robodev-crud-page/SKILL.md +181 -0
- package/templates/shadcn/README.md +9 -4
- package/templates/shadcn/ROBODEV.md +14 -6
- package/templates/shadcn/package.json +4 -6
- package/templates/shadcn/rulesync.jsonc +18 -0
- package/templates/shadcn/src/App.tsx +12 -3
- package/templates/shadcn/src/app.css +359 -0
- package/templates/shadcn/src/components/auth/AuthCard.tsx +29 -0
- package/templates/shadcn/src/components/ui/badge.tsx +17 -0
- package/templates/shadcn/src/components/ui/card.tsx +28 -0
- package/templates/shadcn/src/components/ui/dialog.tsx +38 -0
- package/templates/shadcn/src/components/ui/empty-state.tsx +17 -0
- package/templates/shadcn/src/components/ui/input.tsx +8 -0
- package/templates/shadcn/src/components/ui/label.tsx +8 -0
- package/templates/shadcn/src/components/ui/skeleton.tsx +6 -0
- package/templates/shadcn/src/components/ui/spinner.tsx +3 -0
- package/templates/shadcn/src/components/ui/table.tsx +30 -0
- package/templates/shadcn/src/components/ui/textarea.tsx +8 -0
- package/templates/shadcn/src/lib/auth.tsx +72 -0
- package/templates/shadcn/src/lib/client.ts +8 -0
- package/templates/shadcn/src/pages/Home.tsx +15 -0
- package/templates/shadcn/src/pages/Login.tsx +70 -0
- package/templates/shadcn/src/pages/NotFound.tsx +14 -0
- package/templates/shadcn/src/pages/Register.tsx +82 -0
- package/templates/space/ROBODEV.md +7 -1
- package/templates/space/package.json +2 -2
- package/templates/shadcn/components.json +0 -21
- package/templates/shadcn/postcss.config.js +0 -6
- package/templates/shadcn/tailwind.config.ts +0 -42
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
root: true
|
|
3
|
+
targets: ["claudecode", "codexcli", "cursor"]
|
|
4
|
+
description: "Project overview and Rulesync source-of-truth guidance."
|
|
5
|
+
globs: ["**/*"]
|
|
6
|
+
cursor:
|
|
7
|
+
alwaysApply: true
|
|
8
|
+
description: "Project overview and Rulesync source-of-truth guidance."
|
|
9
|
+
globs: ["**/*"]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Povio UI starter AI rules
|
|
13
|
+
|
|
14
|
+
This project is a Vite React frontend in `apps/fe` plus a Robodev backend under **`robodev/`** (`robodev/database.ts` + `robodev/api/**/*.ts` using `@robodev-ai/sdk`). There is no Expo / mobile app in this starter. End-user auth is reserved on the project host at `/api/user/*`. There is no in-browser fake backend.
|
|
15
|
+
|
|
16
|
+
`robodev deploy` from this root uploads schema, APIs, and (when `.robodev` has a `frontend` block) the local Vite build as a hosted static SPA. Use bun in `apps/fe` to iterate locally.
|
|
17
|
+
|
|
18
|
+
Shared AI rules and skills are authored in `.rulesync/`. Generated files for Codex, Claude Code, and Cursor are local outputs and should be regenerated with `bun rules:gen`.
|
|
19
|
+
|
|
20
|
+
This is a blank seed: no sample features. The backend ships `robodev/database.ts` (placeholder `items` table + `media`) and `GET /api/health`; the frontend ships auth (login/register), a Home page, and a profile page built with `@povio/ui`. Build product features on these seams instead of restructuring them.
|
|
21
|
+
|
|
22
|
+
When an app has multiple user roles with distinct UI or business workflows, use the conditional role-based app structure rule. Do not apply role splitting to simple single-role apps or small permission differences.
|
|
23
|
+
|
|
24
|
+
Use the more specific generated rules for:
|
|
25
|
+
|
|
26
|
+
- Robodev `defineDatabase` tables in `robodev/database.ts`.
|
|
27
|
+
- Robodev `defineApi` routes in `api/`.
|
|
28
|
+
- Reserved `/api/user/*` auth contracts (do not implement `api/user/**` in the project).
|
|
29
|
+
- Frontend API boundaries around generated `@/openapi` queries and models.
|
|
30
|
+
- Povio UI and semantic Tailwind token usage.
|
|
31
|
+
- Frontend forms, tables/lists, `QueryAutocomplete`, translations, and component structure.
|
|
32
|
+
- Role-based frontend structure when the app has multiple distinct user roles.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
root: false
|
|
3
|
+
targets: ["claudecode", "codexcli", "cursor"]
|
|
4
|
+
description: "Robodev defineApi file routes and handler conventions."
|
|
5
|
+
globs: ["robodev/api/**/*.ts"]
|
|
6
|
+
cursor:
|
|
7
|
+
alwaysApply: false
|
|
8
|
+
description: "Apply when editing Starbase API routes."
|
|
9
|
+
globs: ["robodev/api/**/*.ts"]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Robodev API
|
|
13
|
+
|
|
14
|
+
Project APIs live in `robodev/api/`. `robodev/api/todos.ts` would be served at `/todos` and `/api/todos`. Prefer the `/api/...` path in OpenAPI and frontend clients.
|
|
15
|
+
|
|
16
|
+
## File layout
|
|
17
|
+
|
|
18
|
+
- `robodev/api/foo.ts` → `/api/foo`
|
|
19
|
+
- `robodev/api/foo/[id].ts` → `/api/foo/:id`
|
|
20
|
+
- Export `get` / `post` / `put` / `patch` / `delete` as `defineApi(...)`.
|
|
21
|
+
- Shared helpers belong in `robodev/api/_lib.ts`. Do not export `defineApi` from `_lib.ts`.
|
|
22
|
+
- Do not add `robodev/api/user/**`. Those paths are reserved for Robodev Auth.
|
|
23
|
+
|
|
24
|
+
## Handlers
|
|
25
|
+
|
|
26
|
+
- Use `auth: "required"` on routes that Tiny marked authenticated.
|
|
27
|
+
- Handler context includes `db`, `user`, `email`, `storage`, `params`, `query`, `body`.
|
|
28
|
+
- Return JSON for 200, or `{ status, body }` for errors (404/403/400).
|
|
29
|
+
- Keep request/response shapes compatible with `openapi.json` so OpenAPI codegen stays stable.
|
|
30
|
+
- After changing public contracts, update `openapi.json` if needed and run `bun openapi:gen` from `apps/fe`.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
root: false
|
|
3
|
+
targets: ["claudecode", "codexcli", "cursor"]
|
|
4
|
+
description: "Reserved Robodev /api/user auth contracts."
|
|
5
|
+
globs: ["**/*.ts", "apps/fe/src/**/*.{ts,tsx}"]
|
|
6
|
+
cursor:
|
|
7
|
+
alwaysApply: false
|
|
8
|
+
description: "Apply when touching auth, login, register, or /api/user clients."
|
|
9
|
+
globs:
|
|
10
|
+
[
|
|
11
|
+
"robodev/database.ts",
|
|
12
|
+
"robodev/api/**/*.ts",
|
|
13
|
+
"apps/fe/src/components/features/auth/**/*.{ts,tsx}",
|
|
14
|
+
"apps/fe/src/clients/**/*.ts",
|
|
15
|
+
]
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Robodev Auth
|
|
19
|
+
|
|
20
|
+
End-user auth is reserved on the project host. Do not implement `api/user/**` in this project.
|
|
21
|
+
|
|
22
|
+
## Contracts
|
|
23
|
+
|
|
24
|
+
| Method | Path | Notes |
|
|
25
|
+
| ------- | ----------------------------------------- | ------------------------------------------------------- |
|
|
26
|
+
| POST | `/api/user/auth/login` | `{ email, password }` → `{ accessToken, refreshToken }` |
|
|
27
|
+
| POST | `/api/user/auth/register` | password min 12, 201, token pair |
|
|
28
|
+
| POST | `/api/user/auth/refresh` | `{ refreshToken }` → new pair |
|
|
29
|
+
| GET | `/api/user/auth/magic-link` | query `email`, generic status |
|
|
30
|
+
| GET | `/api/user/auth/magic-link/callback` | query `code` → tokens |
|
|
31
|
+
| POST | `/api/user/auth/forgot-password` | `{ email }` |
|
|
32
|
+
| POST | `/api/user/auth/forgot-password/callback` | `{ code, password }` |
|
|
33
|
+
| GET | `/api/user/auth/google` | start OAuth; `redirect_uri` required |
|
|
34
|
+
| GET/PUT | `/api/user/me` | flat `{ id, name, email }` |
|
|
35
|
+
|
|
36
|
+
Access tokens last 15 minutes. Refresh tokens last 30 days. Frontend stores both and refreshes on 401 via `UserAuthApi.accessToken`.
|
|
37
|
+
|
|
38
|
+
Error `code` is top-level: `invalid-credentials`, `identity-already-exists`, `identity-not-found`, `nonce-invalid`.
|
|
39
|
+
|
|
40
|
+
Codegen operationIds stay Tiny-shaped (`UserAuthLocalPasswordController_login`, `UserMeController_get`, …) in `openapi.json`.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
root: false
|
|
3
|
+
targets: ["claudecode", "codexcli", "cursor"]
|
|
4
|
+
description: "Robodev database.ts Drizzle schema and deploy sync."
|
|
5
|
+
globs: ["robodev/database.ts"]
|
|
6
|
+
cursor:
|
|
7
|
+
alwaysApply: false
|
|
8
|
+
description: "Apply when editing the Starbase database schema."
|
|
9
|
+
globs: ["robodev/database.ts"]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Robodev Database
|
|
13
|
+
|
|
14
|
+
The backend schema lives in `robodev/database.ts`. Default-export `defineDatabase` with Drizzle `pgTable` definitions. `robodev deploy` from this root creates or syncs the named Postgres database. There are no migration files.
|
|
15
|
+
|
|
16
|
+
## Rules
|
|
17
|
+
|
|
18
|
+
- Import table helpers from `@robodev-ai/sdk` (`pgTable`, `uuid`, `text`, `timestamp`, `integer`, and query helpers).
|
|
19
|
+
- Do not recreate User or auth tables. End users live in platform `robodev_auth`. Store `userId` as `text` matching `ctx.user.id`.
|
|
20
|
+
- Prefer scalar columns and foreign keys. Destructive drops need deploy confirmation or `--force`.
|
|
21
|
+
- Export named tables so API files can import them from `../database` or `robodev/api/_lib.ts`.
|
|
22
|
+
- Seed demo rows in API handlers on first read (see `robodev/api/_lib.ts` `ensureSeed`), not with a separate seed runner.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
root: false
|
|
3
|
+
targets: ["claudecode", "codexcli", "cursor"]
|
|
4
|
+
description: "Conditional role-based frontend and API structure for apps with distinct user roles."
|
|
5
|
+
globs: ["apps/fe/src/**/*.{ts,tsx}", "robodev/api/**/*.ts"]
|
|
6
|
+
cursor:
|
|
7
|
+
alwaysApply: false
|
|
8
|
+
description: "Apply only when an app has multiple user roles with distinct UI surfaces or business workflows."
|
|
9
|
+
globs: ["apps/fe/src/**/*.{ts,tsx}", "robodev/api/**/*.ts"]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Role-Based App Structure
|
|
13
|
+
|
|
14
|
+
Apply this rule only when the app has multiple user roles with meaningfully different UI surfaces or business workflows. For single-role apps or small permission differences, keep normal feature-based structure and express authorization in handlers, ACL metadata, or UI affordances.
|
|
15
|
+
|
|
16
|
+
## Frontend Structure
|
|
17
|
+
|
|
18
|
+
Split role-specific frontend code by role first:
|
|
19
|
+
|
|
20
|
+
- `apps/fe/src/components/features/<role>/<feature>/...` for role-owned feature UI, such as `admin/companies`, `manager/projects`, or `worker/timesheets`.
|
|
21
|
+
- `apps/fe/src/pages/(private)/(<role>)/...` for role-owned private routes and layout guards.
|
|
22
|
+
- Shared auth, profile, layout, and role-neutral UI should stay outside role folders.
|
|
23
|
+
|
|
24
|
+
When two roles touch the same entity with different screens or permissions, prefer separate role-owned feature components over a single component with many role branches.
|
|
25
|
+
|
|
26
|
+
## API Structure
|
|
27
|
+
|
|
28
|
+
Create role-prefixed `defineApi` files for role-owned behavior even when the backing table is shared. For example, use `api/manager/projects.ts` and `api/worker/projects.ts` when managers can create projects while workers can only list assigned ones.
|
|
29
|
+
|
|
30
|
+
Role-prefixed routes should keep the role visible across the API surface:
|
|
31
|
+
|
|
32
|
+
- Files: `api/<role>/<resource>.ts`, such as `api/manager/projects.ts`.
|
|
33
|
+
- HTTP paths: `/api/<role>/<resource>`, such as `/api/manager/projects/paginate`.
|
|
34
|
+
- Generated client modules should follow the same names.
|
|
35
|
+
|
|
36
|
+
Keep shared auth, user, and media contracts role-neutral. Auth stays reserved at `/api/user/*`.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: media-feature
|
|
3
|
+
description: "Use when adding or changing feature-level media/file upload support or frontend FileUpload handling."
|
|
4
|
+
targets: ["claudecode", "codexcli", "cursor"]
|
|
5
|
+
codexcli:
|
|
6
|
+
short-description: Add or update media upload support for features.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Media Feature Skill
|
|
10
|
+
|
|
11
|
+
Preserve the upload contract:
|
|
12
|
+
|
|
13
|
+
1. Frontend selects a `File` and keeps it local until submit. Do not call `/api/files/*`.
|
|
14
|
+
2. Feature create/update is one `multipart/form-data` request (`POST` / `PUT`) with text fields and an optional `file`.
|
|
15
|
+
3. The handler validates text fields, optionally calls `saveImage` from `robodev/api/_lib.ts` (`ctx.storage.upload` public), and writes the feature row.
|
|
16
|
+
4. Update may send `clearImage=true` when the user cleared an existing image and picked nothing new. A new `file` wins over `clearImage`.
|
|
17
|
+
5. Feature reads resolve the stored media ID to `image: { id, url }`.
|
|
18
|
+
|
|
19
|
+
Never use a standalone files API. File bytes stay on the device until submit.
|
|
20
|
+
|
|
21
|
+
Media metadata lives in the `media` table in `robodev/database.ts`. Bytes live in Robodev storage.
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: povio-ui-styling
|
|
3
|
+
description: Mandatory first skill for any Tiny Template web frontend UI work in apps/fe. Load and apply it before other frontend, design, UX, accessibility, responsive, animation, or performance skills when creating, changing, reviewing, debugging, polishing, or refactoring pages and React components. It requires checking and using @povio/ui primitives before raw HTML or custom controls, and governs UIConfig defaults, UIOverrides, Tailwind utilities, semantic tokens, shared UI wrappers, and dedicated CSS files.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Povio UI Styling
|
|
7
|
+
|
|
8
|
+
Apply the narrowest styling layer that expresses the intended scope. Preserve one source of truth for each visual rule.
|
|
9
|
+
|
|
10
|
+
## Priority and Coordination
|
|
11
|
+
|
|
12
|
+
This is the foundation skill for every UI task under `apps/fe`. Apply it first, before broader design, UX, accessibility, animation, responsive, or React performance skills. Those skills may improve the result, but they must preserve the component and styling decisions defined here.
|
|
13
|
+
|
|
14
|
+
Use this skill for all work that creates, changes, reviews, or diagnoses visible or interactive frontend UI, including:
|
|
15
|
+
|
|
16
|
+
- Pages, layouts, navigation, dashboards, cards, lists, and empty states
|
|
17
|
+
- Forms, filters, search, inputs, validation, uploads, and settings
|
|
18
|
+
- Buttons, links, menus, dialogs, drawers, popovers, tooltips, and toasts
|
|
19
|
+
- Tables, pagination, tags, badges, typography, icons, and loading states
|
|
20
|
+
- Responsive behavior, theming, accessibility, motion, and visual polish
|
|
21
|
+
- Component extraction, shared wrappers, design-system alignment, and Figma implementation
|
|
22
|
+
|
|
23
|
+
This skill does not replace feature-specific skills. Apply the relevant feature skill as well, after establishing the Povio UI component and styling layer.
|
|
24
|
+
|
|
25
|
+
## Inspect Before Styling
|
|
26
|
+
|
|
27
|
+
1. Read the target component and nearby feature components.
|
|
28
|
+
2. Inspect existing `@povio/ui` usage in `apps/fe` for the relevant primitive.
|
|
29
|
+
3. Inspect `apps/fe/src/styles/overrides/uiOverrides.override.ts` and the matching file under `styles/overrides/defaults` before changing a Povio primitive.
|
|
30
|
+
4. Inspect `apps/fe/src/styles/theme.css` for available generated tokens, but never edit that file manually.
|
|
31
|
+
5. Inspect `apps/fe/src/styles/base.css` and `globals.css` before adding global rules or tokens.
|
|
32
|
+
|
|
33
|
+
## Use This Decision Order
|
|
34
|
+
|
|
35
|
+
### 1. Use an Existing Povio UI Component
|
|
36
|
+
|
|
37
|
+
Use `@povio/ui` whenever it provides the semantic control or presentation primitive. This includes buttons, links, typography, icons, inputs, textareas, selects, checkboxes, radios, switches, forms, uploads, tags, badges, tables, pagination, menus, tooltips, modals, confirmations, drawers, popovers, toasts, loading indicators, and empty or feedback states.
|
|
38
|
+
|
|
39
|
+
Prefer the component's supported props and variants over restyling its internals. Do not recreate a primitive with a raw HTML element merely to get a different appearance.
|
|
40
|
+
|
|
41
|
+
Before introducing a native interactive element, a custom control, or a third-party UI component, search `@povio/ui` exports and existing feature usage for an existing equivalent. Native structural elements such as `main`, `section`, `article`, `nav`, and layout containers remain appropriate when no Povio semantic component exists.
|
|
42
|
+
|
|
43
|
+
### 2. Use `UIConfig` for Application-Wide Defaults
|
|
44
|
+
|
|
45
|
+
Use the root `UIConfig.Provider` when an existing Povio variant or option is correct and only its default should change across the application.
|
|
46
|
+
|
|
47
|
+
Examples:
|
|
48
|
+
|
|
49
|
+
- Make all inputs default to `small`.
|
|
50
|
+
- Set the default table-cell typography size.
|
|
51
|
+
- Set the default tag text size.
|
|
52
|
+
|
|
53
|
+
Do not use `UIConfig` for a one-off screen or to invent a new variant.
|
|
54
|
+
|
|
55
|
+
### 3. Use Tailwind for Composition and Local Presentation
|
|
56
|
+
|
|
57
|
+
Use Tailwind classes in JSX for:
|
|
58
|
+
|
|
59
|
+
- Page and component layout
|
|
60
|
+
- Grid and flex behavior
|
|
61
|
+
- Width, height, spacing, alignment, and overflow
|
|
62
|
+
- Responsive composition
|
|
63
|
+
- A one-instance surface, border, or text treatment
|
|
64
|
+
- State selectors that remain short and readable
|
|
65
|
+
|
|
66
|
+
Use semantic project utilities such as `bg-elevation-fill-default-1`, `text-text-default-1`, and `border-elevation-outline-default-1`. Do not use removed default palette utilities such as `bg-blue-500`, and do not repeat raw hex values in components.
|
|
67
|
+
|
|
68
|
+
Keep Povio component `className` additions focused on outer layout or a genuinely local treatment. Do not pile conflicting utilities onto a component to fight its configured CVA variants. If the same correction is required on most instances, move it to `UIConfig` or `UIOverrides`.
|
|
69
|
+
|
|
70
|
+
### 4. Use `UIOverrides` for Design-System-Level Povio Changes
|
|
71
|
+
|
|
72
|
+
Use `UIOverrides.defineOverride(...)` when a Povio primitive must change consistently throughout the application:
|
|
73
|
+
|
|
74
|
+
- Change the base classes of every instance.
|
|
75
|
+
- Add or change supported variants.
|
|
76
|
+
- Change compound-variant behavior.
|
|
77
|
+
- Change internal slots not exposed by ordinary component props.
|
|
78
|
+
- Align a primitive with the application's Figma design system.
|
|
79
|
+
|
|
80
|
+
Place overrides under `apps/fe/src/styles/overrides/defaults/<component>.override.ts` and register them in `uiOverrides.override.ts`. Use the existing `mode`, `base`, `config`, variant, and compound-variant patterns.
|
|
81
|
+
|
|
82
|
+
Update `apps/fe/src/types/ui.d.ts` when a new override variant must augment public Povio component types.
|
|
83
|
+
|
|
84
|
+
Do not use `UIOverrides` for:
|
|
85
|
+
|
|
86
|
+
- Page layout
|
|
87
|
+
- One feature's special card
|
|
88
|
+
- One exceptional component instance
|
|
89
|
+
- A workaround that can be expressed through an existing prop
|
|
90
|
+
|
|
91
|
+
Changing an override affects every consumer. Search all uses of the primitive and verify representative screens before finishing.
|
|
92
|
+
|
|
93
|
+
### 5. Use a Shared Wrapper for Repeated Product Semantics
|
|
94
|
+
|
|
95
|
+
Create a component under `apps/fe/src/components/shared` when several features need the same product-specific composition but the base Povio primitive should remain unchanged.
|
|
96
|
+
|
|
97
|
+
Examples:
|
|
98
|
+
|
|
99
|
+
- `StatusTag` mapping domain statuses to Povio `Tag` variants
|
|
100
|
+
- `WalkSchedule` composing typography, icons, and layout
|
|
101
|
+
- `PageCard` applying a repeated application surface
|
|
102
|
+
|
|
103
|
+
Expose semantic props rather than forwarding a growing collection of styling flags.
|
|
104
|
+
|
|
105
|
+
### 6. Use Dedicated CSS for Selector-Heavy or Browser-Level Behavior
|
|
106
|
+
|
|
107
|
+
Create or extend a `.css` file when CSS communicates the rule more clearly than Tailwind:
|
|
108
|
+
|
|
109
|
+
- Pseudo-elements used for connected timelines or route lines
|
|
110
|
+
- Multi-step keyframes
|
|
111
|
+
- Complex descendant, sibling, or state selectors
|
|
112
|
+
- Calendar grids and overlapping appointments
|
|
113
|
+
- Map-library markers, popups, or third-party DOM overrides
|
|
114
|
+
- Print styles
|
|
115
|
+
- Browser-global behavior such as scrollbars
|
|
116
|
+
- Rules driven by CSS custom properties that many descendants consume
|
|
117
|
+
|
|
118
|
+
Co-locate feature CSS with its owning component and import it there. Use a narrow, feature-prefixed class namespace, for example `walk-route__marker`. Keep truly global rules in `globals.css` or `base.css`.
|
|
119
|
+
|
|
120
|
+
Do not create a CSS file for ordinary spacing, flex/grid layout, a simple hover, or a semantic color already expressible with a short Tailwind class list.
|
|
121
|
+
|
|
122
|
+
## Scope Guide
|
|
123
|
+
|
|
124
|
+
| Desired scope | Styling layer |
|
|
125
|
+
| -------------------------------------------------------------- | --------------------------- |
|
|
126
|
+
| Existing primitive behavior | Povio UI props/variants |
|
|
127
|
+
| Default for every instance | `UIConfig` |
|
|
128
|
+
| One page or component composition | Tailwind |
|
|
129
|
+
| Every instance or internal Povio slot | `UIOverrides` |
|
|
130
|
+
| Repeated product-specific composition | Shared wrapper |
|
|
131
|
+
| Pseudo-elements, keyframes, complex selectors, third-party DOM | Scoped `.css` |
|
|
132
|
+
| Generated design tokens | Figma-generated `theme.css` |
|
|
133
|
+
| Handwritten global token or browser rule | `base.css` or `globals.css` |
|
|
134
|
+
|
|
135
|
+
Retheming the app means overriding tokens in `globals.css`, in `@layer base`, after the
|
|
136
|
+
`theme.css` import — nowhere else redeclares them, so the last declaration in that layer wins.
|
|
137
|
+
|
|
138
|
+
## Guardrails
|
|
139
|
+
|
|
140
|
+
- Use `@povio/ui` before creating a custom primitive.
|
|
141
|
+
- Do not let guidance from a general frontend or design skill replace an available `@povio/ui` primitive with raw HTML, a local reimplementation, or another component library.
|
|
142
|
+
- Use semantic Tailwind tokens from the project theme.
|
|
143
|
+
- Never manually edit `apps/fe/src/styles/theme.css`.
|
|
144
|
+
- Avoid `!important`; resolve ownership or specificity instead.
|
|
145
|
+
- Avoid inline `style` except for truly runtime numeric values such as map coordinates or calculated dimensions. Prefer CSS custom properties when descendants need the value.
|
|
146
|
+
- Avoid Sass, CSS-in-JS, and a second styling system.
|
|
147
|
+
- Preserve visible focus, disabled, hover, pressed, error, and loading states.
|
|
148
|
+
- Respect `prefers-reduced-motion` for nonessential animation.
|
|
149
|
+
- Keep touch targets at least 44 by 44 CSS pixels where practical.
|
|
150
|
+
- Verify changes at mobile and desktop breakpoints.
|
|
151
|
+
|
|
152
|
+
## Examples
|
|
153
|
+
|
|
154
|
+
Use Tailwind for local layout:
|
|
155
|
+
|
|
156
|
+
```tsx
|
|
157
|
+
<section className="grid gap-4 rounded-modal-rounding-default border border-elevation-outline-default-1 bg-elevation-fill-default-1 p-4">
|
|
158
|
+
<Typography size="title-4">{title}</Typography>
|
|
159
|
+
{children}
|
|
160
|
+
</section>
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Use `UIConfig` for an existing global default:
|
|
164
|
+
|
|
165
|
+
```tsx
|
|
166
|
+
<UIConfig.Provider
|
|
167
|
+
config={{
|
|
168
|
+
input: { size: "small" },
|
|
169
|
+
}}
|
|
170
|
+
>
|
|
171
|
+
{children}
|
|
172
|
+
</UIConfig.Provider>
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Use a scoped CSS file for a connected route line:
|
|
176
|
+
|
|
177
|
+
```css
|
|
178
|
+
.walk-route__marker::after {
|
|
179
|
+
content: "";
|
|
180
|
+
position: absolute;
|
|
181
|
+
inset-block: 1.25rem -0.75rem;
|
|
182
|
+
inset-inline-start: 50%;
|
|
183
|
+
width: 0.125rem;
|
|
184
|
+
background: rgb(var(--elevation-outline-default-1-base));
|
|
185
|
+
transform: translateX(-50%);
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Use `UIOverrides` only when the same primitive-level change is intentionally global:
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
export const tagOverride = UIOverrides.defineOverride("tag.cva", {
|
|
193
|
+
mode: "overrideCva",
|
|
194
|
+
base: ["inline-flex items-center border"],
|
|
195
|
+
config: {
|
|
196
|
+
variants: {
|
|
197
|
+
color: {
|
|
198
|
+
success: "border-interactive-subtle-success-idle bg-interactive-subtle-success-idle",
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Verification
|
|
206
|
+
|
|
207
|
+
1. Run formatting, linting, and TypeScript checks relevant to `apps/fe`.
|
|
208
|
+
2. Inspect at least one representative use for every globally changed primitive.
|
|
209
|
+
3. Check keyboard focus and disabled/error states.
|
|
210
|
+
4. Check mobile and desktop layouts.
|
|
211
|
+
5. Confirm no raw default-palette classes or duplicated design values were introduced.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: robodev-api-route
|
|
3
|
+
description: Add a defineApi route under robodev/api/.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Add a Robodev API route
|
|
7
|
+
|
|
8
|
+
1. Create `robodev/api/<path>.ts` or `robodev/api/<path>/[id].ts`.
|
|
9
|
+
2. Export HTTP methods with `defineApi` from `@robodev-ai/sdk`.
|
|
10
|
+
3. Use `auth: "required"` unless the route is public.
|
|
11
|
+
4. Keep JSON shapes aligned with `openapi.json`.
|
|
12
|
+
5. Do not create `robodev/api/user/**` files.
|
|
13
|
+
6. Deploy from the project root (`robodev deploy`), then `bun openapi:gen` in `apps/fe` if the contract changed.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: robodev-table
|
|
3
|
+
description: Add a Drizzle table to robodev/database.ts and wire it into defineApi handlers.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Add a Robodev table
|
|
7
|
+
|
|
8
|
+
1. Add a `pgTable` to `robodev/database.ts` and include it in `defineDatabase({ tables })`.
|
|
9
|
+
2. Do not add a User table. Auth users are platform-managed; store `userId` as text.
|
|
10
|
+
3. Import the table in `api/_lib.ts` or the route file that needs it.
|
|
11
|
+
4. Deploy from the project root with `robodev deploy`. Destructive drops need confirmation or `--force`.
|
|
12
|
+
5. If the frontend needs the new fields, update `openapi.json` and run `bun openapi:gen` from `apps/fe`.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# {{NAME}}
|
|
2
|
+
|
|
3
|
+
Blank starter with the real `@povio/ui` kit: empty schema (placeholder `items` + `media`), `GET /api/health`, file-based APIs in `robodev/api/`, and a Povio UI frontend in `apps/fe` with seeded auth (login/register), Home, and profile — no sample features. Agents: read `ROBODEV.md`.
|
|
4
|
+
|
|
5
|
+
After a CLI create or deploy with `.robodev` `frontend` set (the default for this starter), the project host serves the built SPA at `GET /`. APIs and Swagger still win over static files.
|
|
6
|
+
|
|
7
|
+
Local Starbase occupies FE **:3000** and BE **:4000**. Point the CLI at it, then run starter Vite on **3001** so it does not steal the dashboard port:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
STARBASE_URL=http://localhost:4000 STARBASE_FE_URL=http://localhost:3000
|
|
11
|
+
# from starter root: auth / link / deploy as today
|
|
12
|
+
cd apps/fe
|
|
13
|
+
bun install
|
|
14
|
+
bun openapi:gen
|
|
15
|
+
bunx --bun vite --port 3001
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`bun` is required for `apps/fe`.
|
|
19
|
+
|
|
20
|
+
Auth, link, and deploy from this **root**:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx robodev auth
|
|
24
|
+
npx robodev link
|
|
25
|
+
npx robodev deploy
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`robodev create` / `robodev link` write `VITE_API_URL`, `VITE_PUBLIC_API_URL`, and `APP_PUBLIC_API_URL` in `.env`, rewrite `.config/local.spa.yml` so the FE talks to the project host, and (when `apps/fe/package.json` exists) add a `frontend` block to `.robodev`. `robodev deploy` then runs the local Vite build and uploads the static output.
|
|
29
|
+
|
|
30
|
+
Dashboard create deploys schema + APIs only. The FE tree is copied by `robodev create`; a later CLI deploy hosts the SPA.
|
|
31
|
+
|
|
32
|
+
Auth stays reserved at `/api/user/*`. Do not add `robodev/api/user/**`.
|
|
33
|
+
|
|
34
|
+
Regenerate AI rules after editing `.rulesync/`:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
bun rules:gen
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Docs: https://robodev.povio.dev/docs
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Robodev
|
|
2
|
+
|
|
3
|
+
Use this file for Robodev and SDK facts. Do not web-search the SDK.
|
|
4
|
+
|
|
5
|
+
## defineApi (copy-paste)
|
|
6
|
+
|
|
7
|
+
`db`, `email`, `storage`, and `env` are injected. Never `import { db } from "@robodev-ai/sdk"`.
|
|
8
|
+
The SDK is not installed in the runner. Do not `import("@robodev-ai/sdk")`. Do not search `/opt`, `node_modules`, or grok/gemini home for it.
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { defineApi, z } from "@robodev-ai/sdk";
|
|
12
|
+
|
|
13
|
+
export const get = defineApi({
|
|
14
|
+
response: z.object({ ok: z.literal(true) }),
|
|
15
|
+
handler: async ({ db, email, storage, env }) => {
|
|
16
|
+
void db;
|
|
17
|
+
void email;
|
|
18
|
+
void storage;
|
|
19
|
+
void env;
|
|
20
|
+
return { ok: true as const };
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
```
|
|
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
|
+
|
|
31
|
+
## Hard rules
|
|
32
|
+
|
|
33
|
+
- Do not run npm, pnpm, or yarn install.
|
|
34
|
+
- Do not start npm run dev, vite, or any local server.
|
|
35
|
+
- Do not run tsc (node_modules is not installed in this runner).
|
|
36
|
+
- Do not port-scan or curl/fetch localhost.
|
|
37
|
+
- Preview is the WebContainer. Live APIs exist only after `robodev-publish be`.
|
|
38
|
+
- Publish backend after a batch of file edits, not after every file.
|
|
39
|
+
- Do not publish the frontend.
|
|
40
|
+
|
|
41
|
+
## Auth and product data
|
|
42
|
+
|
|
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.
|
|
44
|
+
|
|
45
|
+
## Backend
|
|
46
|
+
|
|
47
|
+
- Auth: robodev-auth get / set / users / users-delete. Do not invent control-plane HTTP.
|
|
48
|
+
- Secrets: robodev-secret list / set / delete. Use env.NAME in defineApi. List names only.
|
|
49
|
+
- SQL: psql or robodev-sql for DML, SELECT, and seed only. Never print DATABASE_URL. Never run DDL.
|
|
50
|
+
- Publish backend only with robodev-publish be. Do not publish the frontend.
|
|
51
|
+
- Email settings: robodev-email get / set / validate / logs.
|
|
52
|
+
|
|
53
|
+
## Email templates
|
|
54
|
+
|
|
55
|
+
Hosted mail is the Email page. Changes apply immediately through these helpers — no Code save or deploy.
|
|
56
|
+
|
|
57
|
+
- `robodev-email templates list`
|
|
58
|
+
- `robodev-email templates get --slug <slug>`
|
|
59
|
+
- `robodev-email templates set --slug <slug> [--subject] [--html] [--text]`
|
|
60
|
+
|
|
61
|
+
`set` edits an existing slug. If the slug is missing and is a custom slug (`^[a-z][a-z0-9-]{0,62}$`, not `auth.*`), `set` creates it.
|
|
62
|
+
|
|
63
|
+
System slugs: `auth.welcome` (`{{email}}`, `{{name}}`), `auth.magic-link` (`{{link}}`, `{{email}}`, `{{name}}`, `{{appUrl}}`), `auth.forgot-password` (`{{link}}`, `{{code}}`, `{{email}}`, `{{name}}`, `{{appUrl}}`). Keep placeholders exact. Do not delete system templates. Do not invent `auth.*` slugs.
|
|
64
|
+
|
|
65
|
+
Send with `ctx.email.send({ template: "<slug>", to, vars })`.
|
|
66
|
+
|
|
67
|
+
Do not write `robodev/emails/*.html` or `robodev/emails/*.json` for hosted templates. Those files do not update the live project.
|
|
68
|
+
|
|
69
|
+
Never write `.env` or secrets. Never write `.robodev`.
|
|
70
|
+
|
|
71
|
+
## Layout
|
|
72
|
+
|
|
73
|
+
CLI Tiny-family: `robodev/database.ts` + `robodev/api/**`, Povio UI in `apps/fe`. Keep that layout. This is a blank seed — no sample features.
|
|
74
|
+
|
|
75
|
+
- Schema: `robodev/database.ts` (`defineDatabase` from `@robodev-ai/sdk`; placeholder `items` table + `media`)
|
|
76
|
+
- HTTP handlers: `robodev/api/**/*.ts` (`GET /api/health` is seeded; shared helpers in `robodev/api/_lib.ts`)
|
|
77
|
+
- Optional jobs / sockets / hooks under `robodev/`
|
|
78
|
+
- Frontend: `apps/fe` (real `@povio/ui` kit, TanStack Router + Query, generated `@/openapi` client). Seeded: login/register (`(guest)`), Home and profile (`(private)`). Reuse the seeded auth — never rebuild token handling.
|
|
79
|
+
- After schema or API changes, update root `openapi.json` and regenerate the client (`cd apps/fe && bun openapi:gen`), then `robodev-publish be`.
|
|
80
|
+
- Add new pages under `apps/fe/src/pages/(private)/` and link them in `AppHeader.tsx` / `MobileNavigation.tsx`.
|
|
81
|
+
- Auth is reserved at `/api/user/*`. Do not add `robodev/api/user/**`.
|
|
82
|
+
- AI rules live in `.rulesync/` — read `.rulesync/rules/project-overview.md` first.
|
|
83
|
+
|
|
84
|
+
Allowed paths: `robodev/database.ts`, `robodev/api/**/*.ts`, `robodev/jobs/**/*.ts`, `robodev/sockets/**/*.ts`, `robodev/hooks/**/*.ts`, `robodev/package.json`, `apps/fe/**`, `.rulesync/**`, `openapi.json`, `package.json`, `README.md`, `ROBODEV.md`, `.gitignore`.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link
|
|
6
|
+
rel="icon"
|
|
7
|
+
type="image/svg+xml"
|
|
8
|
+
href="/favicon.svg"
|
|
9
|
+
/>
|
|
10
|
+
<meta
|
|
11
|
+
name="viewport"
|
|
12
|
+
content="width=device-width, initial-scale=1.0"
|
|
13
|
+
/>
|
|
14
|
+
<title>Povio UI</title>
|
|
15
|
+
</head>
|
|
16
|
+
|
|
17
|
+
<body class="bg-elevation-fill-default-2 text-text-default-1">
|
|
18
|
+
<div id="app"></div>
|
|
19
|
+
<script
|
|
20
|
+
type="module"
|
|
21
|
+
src="/src/main.tsx"
|
|
22
|
+
></script>
|
|
23
|
+
</body>
|
|
24
|
+
</html>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/* oxlint-disable import/no-nodejs-modules */
|
|
2
|
+
import type { OpenAPICodegenConfig } from "@povio/openapi-codegen-cli";
|
|
3
|
+
import { resolveConfigSync } from "@povio/resolve-config";
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
5
|
+
import { join, resolve } from "node:path";
|
|
6
|
+
|
|
7
|
+
const COMPACT_OPENAPI_INPUT = "../../openapi.json";
|
|
8
|
+
const repoRoot = resolve(process.cwd(), "../..");
|
|
9
|
+
|
|
10
|
+
function readDotEnvKey(root: string, key: string): string | undefined {
|
|
11
|
+
try {
|
|
12
|
+
const content = readFileSync(join(root, ".env"), "utf8");
|
|
13
|
+
const line = content.split(/\r?\n/).find((row) => row.startsWith(`${key}=`));
|
|
14
|
+
const value = line?.slice(key.length + 1).trim();
|
|
15
|
+
return value || undefined;
|
|
16
|
+
} catch {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function loadResolvedSpaEnv(cwd: string): Record<string, string | undefined> {
|
|
22
|
+
try {
|
|
23
|
+
const resolved = resolveConfigSync({ cwd, module: "spa", target: "resolved" });
|
|
24
|
+
if (resolved && typeof resolved === "object") {
|
|
25
|
+
return resolved as Record<string, string | undefined>;
|
|
26
|
+
}
|
|
27
|
+
} catch {
|
|
28
|
+
// unnamed or missing spa manifest
|
|
29
|
+
}
|
|
30
|
+
return {};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const env = loadResolvedSpaEnv(repoRoot);
|
|
34
|
+
|
|
35
|
+
function fallbackApiUrl(): string {
|
|
36
|
+
return (
|
|
37
|
+
env.VITE_PUBLIC_API_URL ||
|
|
38
|
+
process.env.VITE_PUBLIC_API_URL ||
|
|
39
|
+
readDotEnvKey(repoRoot, "VITE_PUBLIC_API_URL") ||
|
|
40
|
+
"http://localhost:4000"
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function resolveLiveOpenApiInput(apiUrl = fallbackApiUrl()) {
|
|
45
|
+
const usable = apiUrl.trim();
|
|
46
|
+
if (!usable) return COMPACT_OPENAPI_INPUT;
|
|
47
|
+
return `${usable.replace(/\/+$/, "")}/openapi.json`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function resolveOpenApiInput() {
|
|
51
|
+
if (process.env.OPENAPI_INPUT) return process.env.OPENAPI_INPUT;
|
|
52
|
+
if (process.env.OPENAPI_LIVE === "true") return resolveLiveOpenApiInput();
|
|
53
|
+
return COMPACT_OPENAPI_INPUT;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const config: OpenAPICodegenConfig = {
|
|
57
|
+
input: resolveOpenApiInput(),
|
|
58
|
+
output: "src/openapi",
|
|
59
|
+
tsPath: "@/openapi",
|
|
60
|
+
restClientImportPath: "@/clients/app-rest-client",
|
|
61
|
+
clearOutput: true,
|
|
62
|
+
excludeRedundantZodSchemas: false,
|
|
63
|
+
checkAcl: false,
|
|
64
|
+
acl: false,
|
|
65
|
+
replaceOptionalWithNullish: true,
|
|
66
|
+
infiniteQueries: true,
|
|
67
|
+
mutationDefaultOnError: true,
|
|
68
|
+
modelsInCommon: true,
|
|
69
|
+
axiosRequestConfig: true,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export default config;
|