page.tsx166 lines · main
| 1 | import Link from 'next/link'; |
| 2 | |
| 3 | import { DocsShell } from '../../components/shell'; |
| 4 | |
| 5 | export const metadata = { title: 'ai schema generator' }; |
| 6 | |
| 7 | export default function AiPage() { |
| 8 | return ( |
| 9 | <DocsShell> |
| 10 | <h1 className="font-mono text-2xl tracking-tight">ai schema generator</h1> |
| 11 | <p className="mt-2 font-mono text-sm text-[var(--color-text-muted)]"> |
| 12 | describe your app in plain english, get a draft <code>schema.ts</code> back. powered |
| 13 | by a self-hosted Qwen 2.5-coder 32B running on briven infrastructure — your prompt |
| 14 | never leaves briven's network. |
| 15 | </p> |
| 16 | |
| 17 | <Section title="how to use it"> |
| 18 | <ol className="list-decimal space-y-2 pl-5"> |
| 19 | <li> |
| 20 | open the <em>ai schema</em> tab on any project at{' '} |
| 21 | <code>/dashboard/projects/<p_id>/ai-schema</code> |
| 22 | </li> |
| 23 | <li>type a description of your data model in the textarea (up to 4000 chars)</li> |
| 24 | <li> |
| 25 | click <strong>generate schema</strong>. expect 5-15 seconds for a typical |
| 26 | response — Qwen runs on a single DGX so larger prompts take longer |
| 27 | </li> |
| 28 | <li> |
| 29 | click <strong>copy</strong> on the result, paste into your project's{' '} |
| 30 | <code>briven/schema.ts</code>, and review every column before committing |
| 31 | </li> |
| 32 | <li> |
| 33 | run <code>briven deploy</code> as usual — the AI output goes through the same |
| 34 | schema-diff + migration path as a hand-written change |
| 35 | </li> |
| 36 | </ol> |
| 37 | </Section> |
| 38 | |
| 39 | <Section title="what makes a good prompt"> |
| 40 | <ul className="list-disc space-y-2 pl-5"> |
| 41 | <li> |
| 42 | <strong>be specific about relationships</strong>: "users have many posts, posts |
| 43 | have many comments, comments can reply to other comments" ports cleanly. "a blog" |
| 44 | doesn't. |
| 45 | </li> |
| 46 | <li> |
| 47 | <strong>name your domain entities</strong>: "projects, tasks, time-tracking |
| 48 | entries" beats "a productivity app" |
| 49 | </li> |
| 50 | <li> |
| 51 | <strong>call out denormalised fields</strong>: "each post stores its current |
| 52 | comment count alongside the comment rows" saves a follow-up query |
| 53 | </li> |
| 54 | <li> |
| 55 | <strong>mention indexes you know you'll need</strong>: "most queries are by |
| 56 | user_id and created_at descending" signals the right index |
| 57 | </li> |
| 58 | </ul> |
| 59 | </Section> |
| 60 | |
| 61 | <Section title="what the AI knows about briven"> |
| 62 | <p> |
| 63 | the model is primed with a system prompt that: |
| 64 | </p> |
| 65 | <ul className="list-disc space-y-2 pl-5"> |
| 66 | <li> |
| 67 | pins the available column helpers: <code>text()</code>, <code>bigint()</code>,{' '} |
| 68 | <code>boolean()</code>, <code>timestamp()</code>, <code>jsonb<T>()</code>,{' '} |
| 69 | <code>uuid()</code> |
| 70 | </li> |
| 71 | <li> |
| 72 | pins the modifiers: <code>.primaryKey()</code>, <code>.notNull()</code>,{' '} |
| 73 | <code>.default(...)</code>, <code>.nullable()</code>,{' '} |
| 74 | <code>.references(table, column)</code>, <code>.unique()</code> |
| 75 | </li> |
| 76 | <li> |
| 77 | insists on a primary-key column per table; prefers <code>text()</code> for |
| 78 | ULIDs; uses <code>bigint()</code> only for counters |
| 79 | </li> |
| 80 | <li>adds indexes only where a non-trivial query would scan — no over-indexing</li> |
| 81 | <li> |
| 82 | returns only the code (no markdown fences, no explanation) so it pastes cleanly |
| 83 | into your editor |
| 84 | </li> |
| 85 | </ul> |
| 86 | </Section> |
| 87 | |
| 88 | <Section title="what it can't do"> |
| 89 | <ul className="list-disc space-y-2 pl-5"> |
| 90 | <li> |
| 91 | <strong>write your functions</strong> — schema only. function bodies are too app- |
| 92 | specific to template |
| 93 | </li> |
| 94 | <li> |
| 95 | <strong>guess your auth model</strong> — every table that needs per-user scoping |
| 96 | still needs an explicit <code>user_id</code> column and the function-level guard |
| 97 | </li> |
| 98 | <li> |
| 99 | <strong>refactor an existing schema</strong> — the prompt assumes you're |
| 100 | generating from scratch. for incremental changes, edit the schema by hand and let{' '} |
| 101 | <code>briven deploy</code> compute the diff |
| 102 | </li> |
| 103 | <li> |
| 104 | <strong>understand your data privacy constraints</strong> — review the output for |
| 105 | anything you wouldn't store; the AI doesn't know your jurisdiction |
| 106 | </li> |
| 107 | </ul> |
| 108 | </Section> |
| 109 | |
| 110 | <Section title="privacy"> |
| 111 | <p> |
| 112 | your prompt and the generated schema are <strong>not</strong> logged. only the |
| 113 | prompt length, response length, model name, and elapsed milliseconds are recorded |
| 114 | for operational monitoring. the request never leaves briven's infrastructure |
| 115 | — the Ollama instance runs on a dedicated DGX VPS in EU-Central. |
| 116 | </p> |
| 117 | <p> |
| 118 | we do not train or fine-tune the model on your prompts. there is no "telemetry to |
| 119 | improve the service" pipeline. |
| 120 | </p> |
| 121 | </Section> |
| 122 | |
| 123 | <Section title="when it's offline"> |
| 124 | <p> |
| 125 | if the dashboard shows "AI assistant offline", the operator has not configured |
| 126 | the Ollama endpoint (BRIVEN_OLLAMA_URL is unset on the api container). this is the |
| 127 | default state on self-hosted briven — the feature is opt-in. self-hosters who want |
| 128 | it should: |
| 129 | </p> |
| 130 | <ol className="list-decimal space-y-2 pl-5"> |
| 131 | <li> |
| 132 | run Ollama on a machine with at least 24GB GPU VRAM (qwen2.5-coder:32b |
| 133 | quantized fits in ~22GB) |
| 134 | </li> |
| 135 | <li> |
| 136 | <code>ollama pull qwen2.5-coder:32b</code> |
| 137 | </li> |
| 138 | <li> |
| 139 | set <code>BRIVEN_OLLAMA_URL=http://your-ollama-host:11434</code> on the api |
| 140 | container |
| 141 | </li> |
| 142 | <li>restart the api</li> |
| 143 | </ol> |
| 144 | </Section> |
| 145 | |
| 146 | <p className="mt-12 font-mono text-xs text-[var(--color-text-subtle)]"> |
| 147 | more AI features (function bodies, query suggestions, performance review) are{' '} |
| 148 | <Link href="/roadmap" className="underline hover:text-[var(--color-text)]"> |
| 149 | on the roadmap |
| 150 | </Link>{' '} |
| 151 | for year-two. |
| 152 | </p> |
| 153 | </DocsShell> |
| 154 | ); |
| 155 | } |
| 156 | |
| 157 | function Section({ title, children }: { title: string; children: React.ReactNode }) { |
| 158 | return ( |
| 159 | <section className="mt-10"> |
| 160 | <h2 className="font-mono text-lg">{title}</h2> |
| 161 | <div className="mt-2 space-y-3 font-mono text-sm text-[var(--color-text-muted)]"> |
| 162 | {children} |
| 163 | </div> |
| 164 | </section> |
| 165 | ); |
| 166 | } |