Build an app with sign-in and AI #
Prompt:
Build a web app where people sign in, keep their own notes, and ask an AI questions. I don't have an AI provider key.
This worked example uses the complete web-app source. The browser signs people in, the backend verifies each session, and the signed-in user can ask an AI a question. Each question stands alone; the example sends no earlier questions to the model.
At a glance:
- Example:
web-app, with all its files on one source page. - Sign-in:
/__account/signin; the Account package verifies the session insrc/session.mjs. - AI route:
POST /api/ask;src/ai.mjscalls the AI Allowance package after the server verifies the user. - Server settings:
TURNZERO_CLOUD_API,TURNZERO_CLOUD_APP_TOKEN,TURNZERO_CLOUD_REALM_KEYS, andTURNZERO_CLOUD_GATEWAY_URLwhere set. - Packages: Account, AI Allowance, and Database. The example includes the database so each user can keep private notes.
What your AI tool does #
Your AI tool starts from the complete example, creates the application, submits its manifest, and deploys it. It checks that an anonymous request cannot reach the AI route and that a signed-in user can get an answer. It reports which checks it completed.
What you need #
- A connected AI coding tool.
- A plan with room for the application and an available AI allowance. Your AI tool reads the allowance; the creation call refuses a plan that is full.
- A sign-in method to try, such as an emailed code, Google, or GitHub.
You need no separate AI provider account or key.
Before your AI starts #
Read the deploy, add-sign-in, and use-ai-allowance skills through read_context. Keep their approval and verification rules. Read the complete web-app example, following the response's continuation fields if it arrives in parts.
With a shell, check that the turnzero command is installed and this computer is authorized, as Connect your AI coding tool describes. Without a usable command, use the file route below.
Steps #
1. Create the application #
Read read_plan_quotas for the plans and their AI allowances. Use the plan the person named, or ask them to choose one. With nobody to ask, use Free and report that choice. Call create_application without a separate capacity check, and keep its identifier. If the chosen plan is full, follow Create the application. A new application has production only.
2. Take the complete example #
With an installed, authorized command, run this from an empty project folder, replacing <application id> with the identifier from step 1:
turnzero scaffold --template web-app --application <application id>
The command writes the app in app/, takes its three library packages, installs dependencies, and runs the tests. Keep the generated files together.
Without a usable command, read every file on the web-app source page, using its application paths. Its text downloads end in .txt; remove that suffix when naming a file. Keep package.json, the client files, server modules, and migration. Read the tests too, even if your tools cannot run them.
For the file route, read list_library and put the current names and versions of account, ai_allowance, and database in the manifest's packages list. Keep the example's file:lib/… dependencies. Leave the three library folders out of deploy_files; Cloud fills them from the submitted manifest. The manifest's package rows explains this route.
3. Follow the sign-in and AI request together #
The complete app already connects these parts:
| File | What happens |
|---|---|
client/index.html |
The Sign in link opens the platform's sign-in page on the app's own hostname. |
client/app.js |
The page reads /__account/me. After sign-in, its question form sends { question } to /api/ask; the browser sends its session cookie. |
src/session.mjs |
The Account client verifies the cookie or bearer token and the router's session header. It returns the verified user's id, or no user. |
src/server.mjs |
The AI route returns 401 with sign_in_required without a verified user. Otherwise it passes the question to src/ai.mjs. |
src/ai.mjs |
generateText sends the question through the platform gateway under the app's credential. The route returns the answer or a named fallback. |
Keep the platform credential in the backend. The browser receives the answer, never that credential. The example's AI call uses the plan's allowance, so it needs no stored provider key or external-host declaration.
4. Submit the manifest and deploy #
Submit the example's complete manifest with submit_manifest. It declares the database and accounts services. Use the application identifier from step 1. For the file route, include the current package rows you prepared in step 2; the source template's empty list is a starting point.
Check read_realm and keep the sign-in methods the person chose. Follow Deploy from your computer with a usable command, or Deploy from a chat with files. Run the required deployment checks before starting the deploy, then read status until it ends.
With a shell, run the app's tests again after any code change. Without one, report that local tests were not run. File checks and a successful health check do not verify sign-in or an AI answer.
5. Verify the combined flow #
Check the deployed home page and /health. An anonymous request to /api/ask must return 401 with sign_in_required.
Open the app's deployed address, choose Sign in, and complete the selected method. On returning to the app, the page shows the signed-in user and the question form. Ask, “What are three ways to organize my notes?” The page should display an AI answer. Sign out and confirm that the signed-in controls disappear.
For an automated run, use Test sign-in with test end users, including the approvals required by the chosen environment and tools. Check a signed-in POST /api/ask as well as the anonymous refusal. Ask before writing test data to production, and remove temporary users and data after the test.
Use the example name web-app sign-in and AI when reporting a test. Record the environment, whether browser sign-in completed, whether the protected route refused an anonymous request, and whether a signed-in question received an answer. State any untested part explicitly.
Expected result #
One deployed app lets a person sign in, keep private notes, and ask an AI a question. Anonymous requests cannot use its AI route. The source and tests stay in the project, and the verification report distinguishes local tests from checks on the deployed app.
Refusals #
These are the example's common failures. The Account, AI Allowance, and platform refusal reference cover the rest.
| Code | Cause | Remedy |
|---|---|---|
sign_in_required |
The app received no verified session. | Sign in on the deployed app's hostname, or follow the test-user guide for an automated request. This response is expected in the anonymous check. |
library_entry_not_served |
A package row names a version the library cannot fill. | Read list_library again, correct the row, and resubmit the manifest before retrying the file deployment. |
allowance_drawn |
The example caught allowance_exhausted: the month's AI allowance is used up. |
Keep the fallback and wait for the allowance reset, or choose another approved source of AI answers. Do not retry the exhausted allowance. |
allowance_unavailable |
The platform cannot serve the included allowance now. | Keep the fallback and report the failure if it persists. |
upstream_quota |
The model provider is out of capacity. | Keep the fallback and try later. |
Related #
- web-app example holds the complete app and its tests.
- Add sign-in to your app explains session verification and the sign-in methods.
- Call an AI model under the allowance explains the AI request, conversation history, and fallbacks.
- Test your application locally explains tests over the package doubles.