Use this mode when the backend is already developed or being developed in parallel and is deployed with an accessible OpenAPI specification endpoint.
-
Initialize project in Bolt: http://bolt.new/github.com/poviolabs/bolt-template/tree/external-be
-
Configure environment
- Create a
.envfile in the project root - Set the API URL:
VITE_PUBLIC_API_URL=https://api.dev.pov.io/
- Note: Include the trailing slash
- Create a
-
Configure OpenAPI codegen
- Open
openapi-codegen.config.ts - Update the
inputURL to point to your OpenAPI spec endpoint:const config: OpenAPICodegenConfig = { input: "https://api.dev.pov.io/api/docs-json", // ... rest of config };
- Open
-
Generate data layer
npm run openapi:gen
Configure Bolt's Package Knowledge
To ensure Bolt follows our conventions, add these package rules to your team's Packages knowledge:
| Package Name | Package Prompt |
|---|---|
@povio/ui |
rules/povio-ui-rules.md |
@tanstack/react-query |
rules/react-query-rules.md |
@tanstack/react-router |
rules/tanstack-router-rules.md |
clsx |
rules/clsx-rules.md |
lucide-react |
rules/lucide-rules.md |
tailwindcss |
rules/tailwind-rules.md |
react-hook-form |
rules/react-hook-form-rules.md |
These are common pitfalls and bugs you might encounter. Click to jump to detailed explanations:
- Bolt tries to setup and use Supabase - In your first prompt, explicitly tell it to use the external API
- Newly added pages not working - AI creates a folder with the same name as an existing route file
- Submitting a form does nothing - Required data appended during submission causes validation errors
- File upload resourceName errors - Backend doesn't accept the specified resourceName
For general prompting tips, AI model selection, and planning mode, see the Prompting Guide.
Give a rough overview of the app and tell it to only implement user authentication in the first prompt. Tell it explicitly that it must use the provided external API!
Build me an app named ... which will have the features ... Start with the user authentication - add a login and register page. Logged in users should be redirected to...
Use the provided external REST API - all queries and mutations were generated inside src/openapi.
Bolt should automatically update jwt.provider.tsx and refresh-token.interceptor.ts and also switch to the JWT authentication provider in main.tsx. Make sure it did these steps correctly (check Authentication section).
Routing is done via Tanstack React Router. The template comes with two pre-defined route groups:
(private)- Routes that require the user to be logged in(public-only)- Routes that require the user to NOT be logged in (e.g. login)- Adding routes outside of these two folders makes them public - accessible by all users
- The guard logic of the groups can be modified in their corresponding
route.tsxfiles
Possible bug: if the AI agent creates a new folder inside pages with the same name as an existing route component, one of these routes will not be generated by Tanstack Router. Example:
src/pages/
├── posts/
│ ├── create.tsx
│ └── $postId.tsx
├── posts.tsx // Either this route or the nested posts routes will not be generated
└── index.ts
--- Solution: ---
src/pages/
├── posts/
│ ├── index.tsx // Moved inside folder and renamed to index.tsx
│ ├── create.tsx
│ └── $postId.tsx
└── index.ts
The data layer is generated from the OpenAPI specification using @povio/openapi-codegen-cli. Bolt should automatically be able to find and use the correct queries and models for specific features assuming they are named and documented well enough. Otherwise point it to the correct hooks it needs to use in your prompts.
Updating Data Layer:
When backend changes are deployed:
npm run openapi:gen- The template uses JWT-based authentication with the external backend
- Bolt should automatically set up the JWT provider when implementing authentication
- Uses
src/providers/jwt.provider.tsxfor authentication logic - Make sure Bolt correctly updates all the necessary files:
src/providers/jwt.provider.tsx- user query and typesrc/clients/rest/interceptors/refresh-token.interceptor.ts- token refresh logicsrc/main.tsx- switched to use JWTProvidersrc/hooks/useAuth.ts- correct user type
Bolt should by default use either useForm or useFormAutosave from @povio/ui, which uses react-hook-form behind the scenes.
Validation is done through the zodSchema parameter, where Bolt passes the appropriate Zod schema from src/openapi/*.models.ts.
Possible bug: if some required data only gets appended during the form submission, the form validation can fail and your onSubmit handler will not trigger. To avoid this, make sure that all required data in the Zod schema is actually added to the form hook's state.
- Check
src/pages/code-examples/file-upload.tsx - Tell Bolt to follow this file's example
- The example useUploadRequest mutation hook may be named or work differently on your specific backend
- General file upload flow:
- Get upload instructions from Backend (receive back instructions and the media ID)
- Upload file following the instructions
- Set the media ID to the resource which uses the uploaded file (create or update mutation)
Possible bug: When fetching upload instructions, resourceName must be set to a value the Backend accepts. Below is a list of defaults from the monorepo template, contact Backend if they were changed:
| resourceName | Accepted mimeTypes | Max size |
|---|---|---|
| small-image | image/jpeg, image/png | 2 MB |
| large-image | image/jpeg, image/png | 20 MB |
| compressed-file | application/zip, application/x-rar-compressed, application/gzip, etc. | 50 MB |
| document | document files | 50 MB |
| any | */* | 100 MB |
- Inside the Bolt project, click "Publish" on the top right
- Bolt will give you a URL to the published app
- You must re-publish the app manually after making changes (app URL stays the same)
When moving from Bolt to the monorepo:
-
Export Project
- Click on the chat/project name on top left
- Export > Download
-
Override Monorepo Frontend App
- Replace the entire content of
apps/fewith the exported project - Copy
turbo.jsonfrom admin app - Copy and replace
.oxlintrc.jsonfrom admin app - Copy and replace
tsconfig.jsonfrom admin app- Remove
tsconfig.app.jsonandtsconfig.node.jsonfrom within fe
- Remove
- Copy and replace
biome.jsonfrom admin app - Copy and replace
.vscode/settings.jsonfrom admin app- Remove
.vscode/extensions.jsonfrom within fe
- Remove
- Copy and replace
.gitignoreand.gitattributesfrom admin app - Remove
.boltfolder
- Replace the entire content of
-
Update scripts in package.json
- Switch to zx scripts - refer to admin app. Example:
{ "scripts": { "dev": "zx scripts/execute.mjs dev", "build": "zx scripts/execute.mjs build", "clean": "rimraf .turbo out src/openapi", "lint": "oxlint --type-aware . --fix", "lint:check": "oxlint --type-aware . --quiet", "format": "biome check --write .", "format:check": "biome check .", "typecheck": "tsgo --noEmit", "generate": "zx scripts/execute.mjs generate", "script": "zx scripts/execute.mjs --", "openapi:gen": "openapi-codegen generate --prettier false", "openapi:check": "openapi-codegen check", "svg": "npx @svgr/cli --config-file ./svg/.svgrrc.js -- svg/icons && biome format --write ./src/assets/icons", "i18n:missing": "npx tsx scripts/i18n/find-missing-translations.ts" } }
- Switch to zx scripts - refer to admin app. Example:
-
Update environment variables in .config
- Set backend API URL:
dev.spa.template.yml: "http://localhost:4000/"local.spa.template.yml: "http://localhost:4000/"monorepo-dev.spa.template.yml(deployment): "https://api.dev.pov.io/" (Put your actual deployed app's URL)
- Add any additional environment variables (analytics, sentry, etc.)
- Set backend API URL:
-
UI Updates
- Change @povio/ui dependency from npm to local package
{ "dependencies": { "@povio/ui": "workspace:*" } } - Change Tailwind source inside
globals.cssto point to the local UI package@source "../../../../packages/ui/src";
- Remove
scripts/copy-ui-source.mjs - Remove
.povio-ui-source
- Change @povio/ui dependency from npm to local package
-
Verify Backend Connection
- Update
openapi-codegen.config.tsOpenAPI spec input pathconst config: OpenAPICodegenConfig = { input: "../be/resources/openapi-main.json", /// ... }
- Generate data layer:
yarn generate
- Test all API endpoints and authentication flows
- Update