Matthewmasturbation commited on
Commit
6c9e61c
·
verified ·
1 Parent(s): 0911e55

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +355 -178
app.py CHANGED
@@ -3,8 +3,47 @@ import gradio as gr
3
 
4
  TITLE = "AppDraft"
5
 
6
-
7
- def slugify(value):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  value = (value or "my-app").strip().lower()
9
  out = []
10
  for ch in value:
@@ -19,56 +58,68 @@ def slugify(value):
19
 
20
 
21
  def build_pack(app_idea, stack, platform, style, auth, database, extras):
22
- app_name = (app_idea or "My App").strip().split("\n")[0][:60] or "My App"
 
 
 
 
 
 
23
  slug = slugify(app_name)
24
  extras = extras or []
25
 
26
  feature_pool = [
27
  "Authentication and user onboarding" if auth != "No auth" else "Guest-friendly onboarding and local session flow",
28
  "Dashboard or home view with quick actions",
29
- "Create, edit, delete core records",
30
  "Search, filter, and sort data",
31
  "Responsive mobile-friendly UI",
32
- "Error, loading, and empty states",
33
- "Analytics or activity history",
34
  ]
35
-
36
  if "Payments" in extras:
37
  feature_pool.append("Subscriptions, billing, and checkout flow")
38
  if "Notifications" in extras:
39
- feature_pool.append("Email or in-app notification system")
40
  if "Admin panel" in extras:
41
  feature_pool.append("Role-based admin panel and moderation tools")
42
  if "AI features" in extras:
43
- feature_pool.append("AI-powered generation, summarization, or recommendation flow")
44
  if "File uploads" in extras:
45
  feature_pool.append("Secure file upload and storage pipeline")
46
  if "Realtime" in extras:
47
  feature_pool.append("Realtime collaboration or live activity updates")
 
 
 
 
48
 
49
  pages = [
50
  "Landing / marketing page",
51
  "Sign in / sign up" if auth != "No auth" else "Welcome / guest entry",
52
  "Main dashboard",
53
- "List view",
54
- "Detail view",
55
- "Create / edit form",
56
- "Settings page",
57
  ]
58
-
59
  if "Admin panel" in extras:
60
- pages.append("Admin dashboard")
61
  if "Payments" in extras:
62
- pages.append("Billing page")
 
 
63
 
64
  components = [
65
- "Navbar / app shell",
66
  "Sidebar or tab navigation",
67
- "Hero / empty state block",
68
- "Cards and data tables",
69
- "Modal / drawer for quick actions",
70
- "Toast / alert system",
71
- "Form inputs with validation",
 
 
72
  ]
73
 
74
  tables = [
@@ -84,67 +135,52 @@ def build_pack(app_idea, stack, platform, style, auth, database, extras):
84
  },
85
  {
86
  "table": "items",
87
- "fields": ["id", "project_id", "title", "content", "type", "created_at", "updated_at"],
88
  },
89
  {
90
  "table": "activity_logs",
91
- "fields": ["id", "user_id", "action", "entity_type", "entity_id", "created_at"],
92
  },
93
  ]
94
-
95
  if "Payments" in extras:
96
- tables.append(
97
- {
98
- "table": "subscriptions",
99
- "fields": ["id", "user_id", "plan", "status", "provider_customer_id", "renewal_date"],
100
- }
101
- )
102
  if "Notifications" in extras:
103
- tables.append(
104
- {
105
- "table": "notifications",
106
- "fields": ["id", "user_id", "type", "title", "body", "read_at", "created_at"],
107
- }
108
- )
109
  if "File uploads" in extras:
110
- tables.append(
111
- {
112
- "table": "files",
113
- "fields": ["id", "owner_id", "project_id", "filename", "mime_type", "storage_url", "created_at"],
114
- }
115
- )
116
 
117
  endpoints = [
118
- "POST /api/auth/register" if auth != "No auth" else "POST /api/session/start",
119
- "POST /api/auth/login" if auth != "No auth" else "GET /api/session",
120
- "GET /api/projects",
121
- "POST /api/projects",
122
- "GET /api/projects/:id",
123
- "PUT /api/projects/:id",
 
124
  "DELETE /api/projects/:id",
125
- "GET /api/items?projectId=:id",
126
- "POST /api/items",
 
 
127
  ]
128
-
129
  if "Payments" in extras:
130
- endpoints += [
131
- "POST /api/billing/create-checkout-session",
132
- "GET /api/billing/subscription",
133
- ]
134
  if "Notifications" in extras:
135
- endpoints += [
136
- "GET /api/notifications",
137
- "POST /api/notifications/mark-read",
138
- ]
139
  if "File uploads" in extras:
140
- endpoints += [
141
- "POST /api/files/upload",
142
- "DELETE /api/files/:id",
143
- ]
144
 
145
  folder_tree = f"""{slug}/
146
  ├── app/
147
  │ ├── components/
 
 
 
148
  │ ├── pages/
149
  │ ├── hooks/
150
  │ ├── services/
@@ -157,104 +193,247 @@ def build_pack(app_idea, stack, platform, style, auth, database, extras):
157
  │ └── models/
158
  ├── database/
159
  │ ├── schema.sql
 
160
  │ └── seed.sql
161
  ├── public/
 
162
  ├── tests/
 
 
163
  ├── .env.example
 
164
  ├── README.md
165
  └── package.json"""
166
 
167
- starter_code = f"""# {app_name}
168
 
169
- ## Suggested stack
170
  - Frontend: {stack}
171
  - Platform: {platform}
172
- - UI style: {style}
173
  - Auth: {auth}
174
  - Database: {database}
 
 
 
175
 
176
- ## Core app shell
177
  ```tsx
178
- export default function AppShell() {{
 
179
  return (
180
- <main>
181
- <h1>{app_name}</h1>
182
- <p>Build the main workflow here.</p>
183
- </main>
 
 
 
 
 
 
184
  );
185
  }}
186
  ```
187
 
188
- ## Example API contract
189
  ```ts
190
- export async function getProjects() {{
191
- const res = await fetch('/api/projects');
 
 
 
192
  if (!res.ok) throw new Error('Failed to load projects');
193
  return res.json();
194
  }}
 
 
 
 
 
 
 
 
 
 
195
  ```
196
 
197
- ## SQL starter
198
  ```sql
 
199
  CREATE TABLE projects (
200
- id UUID PRIMARY KEY,
201
- owner_id UUID NOT NULL,
202
- title TEXT NOT NULL,
203
  description TEXT,
204
- status TEXT DEFAULT 'draft',
 
 
 
 
 
 
 
 
 
 
 
205
  created_at TIMESTAMP DEFAULT NOW(),
206
  updated_at TIMESTAMP DEFAULT NOW()
207
  );
208
- ```"""
209
 
210
- prd = f"""# Product Brief
 
 
 
 
 
 
 
 
 
 
211
 
212
  ## App Name
213
- {app_name}
214
 
215
- ## One-line idea
216
  {app_idea}
217
 
218
- ## Target platform
 
 
219
  {platform}
220
 
221
- ## Tech stack
222
  {stack}
223
 
224
- ## Experience goal
225
- Create a {style.lower()} product that feels fast, clear, and easy to expand in an IDE.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
 
227
- ## Must-have features
228
- """ + "\n".join(f"- {item}" for item in feature_pool[:8])
229
 
230
- ui_plan = "# UI Plan\n\n## Pages\n" + "\n".join(f"- {p}" for p in pages)
231
- ui_plan += "\n\n## Components\n" + "\n".join(f"- {c}" for c in components)
 
 
 
 
 
 
 
 
 
 
 
 
232
 
233
  db_plan = "# Database Plan\n\n" + "\n\n".join(
234
- f"## {t['table']}\n" + "\n".join(f"- {field}" for field in t["fields"])
235
  for t in tables
236
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
 
238
- api_plan = "# API Routes\n\n" + "\n".join(f"- {route}" for route in endpoints)
239
-
240
- system_prompt = f"""You are a senior product engineer and UX architect.
241
- Generate implementation-ready output for this app idea: {app_idea}
242
- Stack: {stack}
243
- Platform: {platform}
244
- Style: {style}
245
- Auth: {auth}
246
- Database: {database}
247
- Extras: {', '.join(extras) if extras else 'None'}
248
- Return:
249
- 1. Product requirements
250
- 2. User stories
251
- 3. Information architecture
252
- 4. Components
253
- 5. Database schema
254
- 6. API routes
255
- 7. Folder structure
256
- 8. Starter code
257
- Keep output concise, structured, and copy-paste ready."""
 
 
 
 
 
 
 
258
 
259
  json_export = json.dumps(
260
  {
@@ -269,7 +448,7 @@ Keep output concise, structured, and copy-paste ready."""
269
  "features": feature_pool,
270
  "pages": pages,
271
  "components": components,
272
- "tables": tables,
273
  "endpoints": endpoints,
274
  "folder_tree": folder_tree,
275
  },
@@ -279,77 +458,75 @@ Keep output concise, structured, and copy-paste ready."""
279
  return prd, ui_plan, db_plan, api_plan, folder_tree, starter_code, system_prompt, json_export
280
 
281
 
282
- with gr.Blocks(title=TITLE) as demo:
283
- gr.Markdown(
284
- """
285
  # AppDraft
286
- ### Turn an app idea into a copy-paste build pack for your IDE.
287
- Describe the app once, then generate a product brief, UI plan, schema, API routes, folder structure, and starter code.
 
 
 
 
 
 
 
 
 
 
 
288
  """
289
- )
290
 
291
- with gr.Row():
292
- app_idea = gr.Textbox(
293
- label="App idea",
294
- lines=5,
295
- placeholder="Example: A local service marketplace for last-minute movers with quotes, scheduling, reviews, Stripe payments, and an admin dashboard.",
296
- )
297
 
298
- with gr.Column():
299
- stack = gr.Dropdown(
300
- ["Next.js + TypeScript", "React + Vite", "FastAPI + React", "Flask + HTMX", "Electron + React", "React Native + Expo"],
301
- value="Next.js + TypeScript",
302
- label="Target stack",
303
- )
304
- platform = gr.Dropdown(
305
- ["Web app", "Mobile app", "Desktop app", "Marketplace", "SaaS dashboard", "Landing page + app"],
306
- value="Web app",
307
- label="Platform",
308
- )
309
- style = gr.Dropdown(
310
- ["Minimal modern", "Dark SaaS", "Bold startup", "Playful consumer", "Enterprise clean", "Mobile-first utility"],
311
- value="Dark SaaS",
312
- label="Design style",
313
- )
314
- auth = gr.Dropdown(
315
- ["Email + password", "Magic link", "OAuth", "No auth"],
316
- value="Email + password",
317
- label="Auth",
318
- )
319
- database = gr.Dropdown(
320
- ["PostgreSQL", "Supabase", "SQLite", "MongoDB", "Firebase"],
321
- value="PostgreSQL",
322
- label="Database",
323
- )
324
- extras = gr.CheckboxGroup(
325
- ["Payments", "Notifications", "Admin panel", "AI features", "File uploads", "Realtime"],
326
- label="Extras",
327
  )
328
 
329
- generate = gr.Button("Generate build pack", variant="primary")
330
-
331
- with gr.Tabs():
332
- with gr.Tab("PRD"):
333
- prd = gr.Markdown()
334
- with gr.Tab("UI"):
335
- ui = gr.Markdown()
336
- with gr.Tab("Database"):
337
- db = gr.Markdown()
338
- with gr.Tab("API"):
339
- api = gr.Markdown()
340
- with gr.Tab("Structure"):
341
- tree = gr.Textbox(lines=16, label="Folder structure")
342
- with gr.Tab("Starter code"):
343
- starter = gr.Markdown()
344
- with gr.Tab("Prompt"):
345
- prompt = gr.Code(language="markdown")
346
- with gr.Tab("JSON"):
347
- export_json = gr.Code(language="json")
 
 
 
 
 
 
 
 
 
 
 
 
348
 
349
  generate.click(
350
  fn=build_pack,
351
  inputs=[app_idea, stack, platform, style, auth, database, extras],
352
- outputs=[prd, ui, db, api, tree, starter, prompt, export_json],
353
  )
354
 
355
- demo.launch()
 
 
 
3
 
4
  TITLE = "AppDraft"
5
 
6
+ STACKS = [
7
+ "Next.js + TypeScript",
8
+ "React + Vite",
9
+ "FastAPI + React",
10
+ "Flask + HTMX",
11
+ "Electron + React",
12
+ "React Native + Expo",
13
+ "Vue 3 + TypeScript",
14
+ "SvelteKit",
15
+ ]
16
+
17
+ PLATFORMS = [
18
+ "Web app",
19
+ "Mobile app",
20
+ "Desktop app",
21
+ "Marketplace",
22
+ "SaaS dashboard",
23
+ "Landing page + app",
24
+ "Browser extension",
25
+ "CLI tool",
26
+ ]
27
+
28
+ STYLES = [
29
+ "Minimal modern",
30
+ "Dark SaaS",
31
+ "Bold startup",
32
+ "Playful consumer",
33
+ "Enterprise clean",
34
+ "Mobile-first utility",
35
+ "Glassmorphism",
36
+ "Retro terminal",
37
+ ]
38
+
39
+ AUTHS = ["Email + password", "Magic link", "OAuth (Google/GitHub)", "No auth"]
40
+
41
+ DATABASES = ["PostgreSQL", "Supabase", "SQLite", "MongoDB", "Firebase", "PlanetScale", "Turso"]
42
+
43
+ EXTRAS = ["Payments", "Notifications", "Admin panel", "AI features", "File uploads", "Realtime", "Search", "Analytics"]
44
+
45
+
46
+ def slugify(value: str) -> str:
47
  value = (value or "my-app").strip().lower()
48
  out = []
49
  for ch in value:
 
58
 
59
 
60
  def build_pack(app_idea, stack, platform, style, auth, database, extras):
61
+ if not app_idea or not app_idea.strip():
62
+ return (
63
+ "## No input\n\nPlease describe your app idea in the box above.",
64
+ "", "", "", "", "", "", ""
65
+ )
66
+
67
+ app_name = app_idea.strip().split("\n")[0][:60] or "My App"
68
  slug = slugify(app_name)
69
  extras = extras or []
70
 
71
  feature_pool = [
72
  "Authentication and user onboarding" if auth != "No auth" else "Guest-friendly onboarding and local session flow",
73
  "Dashboard or home view with quick actions",
74
+ "Create, edit, and delete core records",
75
  "Search, filter, and sort data",
76
  "Responsive mobile-friendly UI",
77
+ "Error, loading, and empty states throughout",
78
+ "Activity history and analytics",
79
  ]
 
80
  if "Payments" in extras:
81
  feature_pool.append("Subscriptions, billing, and checkout flow")
82
  if "Notifications" in extras:
83
+ feature_pool.append("Email and in-app notification system")
84
  if "Admin panel" in extras:
85
  feature_pool.append("Role-based admin panel and moderation tools")
86
  if "AI features" in extras:
87
+ feature_pool.append("AI-powered generation, summarization, or recommendations")
88
  if "File uploads" in extras:
89
  feature_pool.append("Secure file upload and storage pipeline")
90
  if "Realtime" in extras:
91
  feature_pool.append("Realtime collaboration or live activity updates")
92
+ if "Search" in extras:
93
+ feature_pool.append("Full-text search with filters and indexing")
94
+ if "Analytics" in extras:
95
+ feature_pool.append("Usage analytics dashboard and event tracking")
96
 
97
  pages = [
98
  "Landing / marketing page",
99
  "Sign in / sign up" if auth != "No auth" else "Welcome / guest entry",
100
  "Main dashboard",
101
+ "List view with filters",
102
+ "Detail / single record view",
103
+ "Create and edit form",
104
+ "User settings and profile",
105
  ]
 
106
  if "Admin panel" in extras:
107
+ pages.append("Admin dashboard and user management")
108
  if "Payments" in extras:
109
+ pages.append("Billing and subscription management")
110
+ if "Analytics" in extras:
111
+ pages.append("Analytics and reporting dashboard")
112
 
113
  components = [
114
+ "Navbar and app shell",
115
  "Sidebar or tab navigation",
116
+ "Hero or empty state block",
117
+ "Data cards and tables",
118
+ "Modal and drawer for quick actions",
119
+ "Toast and alert notification system",
120
+ "Form inputs with validation feedback",
121
+ "Loading skeletons and spinners",
122
+ "Confirmation dialogs",
123
  ]
124
 
125
  tables = [
 
135
  },
136
  {
137
  "table": "items",
138
+ "fields": ["id", "project_id", "title", "content", "type", "order", "created_at", "updated_at"],
139
  },
140
  {
141
  "table": "activity_logs",
142
+ "fields": ["id", "user_id", "action", "entity_type", "entity_id", "metadata", "created_at"],
143
  },
144
  ]
 
145
  if "Payments" in extras:
146
+ tables.append({"table": "subscriptions", "fields": ["id", "user_id", "plan", "status", "provider_customer_id", "renewal_date"]})
 
 
 
 
 
147
  if "Notifications" in extras:
148
+ tables.append({"table": "notifications", "fields": ["id", "user_id", "type", "title", "body", "read_at", "created_at"]})
 
 
 
 
 
149
  if "File uploads" in extras:
150
+ tables.append({"table": "files", "fields": ["id", "owner_id", "entity_id", "filename", "mime_type", "storage_url", "size_bytes", "created_at"]})
151
+ if "Analytics" in extras:
152
+ tables.append({"table": "events", "fields": ["id", "user_id", "event_name", "properties", "session_id", "created_at"]})
 
 
 
153
 
154
  endpoints = [
155
+ "POST /api/auth/register" if auth != "No auth" else "POST /api/session/start",
156
+ "POST /api/auth/login" if auth != "No auth" else "GET /api/session",
157
+ "POST /api/auth/logout" if auth != "No auth" else "",
158
+ "GET /api/projects",
159
+ "POST /api/projects",
160
+ "GET /api/projects/:id",
161
+ "PUT /api/projects/:id",
162
  "DELETE /api/projects/:id",
163
+ "GET /api/items?projectId=:id",
164
+ "POST /api/items",
165
+ "PUT /api/items/:id",
166
+ "DELETE /api/items/:id",
167
  ]
168
+ endpoints = [e for e in endpoints if e]
169
  if "Payments" in extras:
170
+ endpoints += ["POST /api/billing/checkout", "GET /api/billing/subscription", "POST /api/billing/cancel"]
 
 
 
171
  if "Notifications" in extras:
172
+ endpoints += ["GET /api/notifications", "POST /api/notifications/mark-read"]
 
 
 
173
  if "File uploads" in extras:
174
+ endpoints += ["POST /api/files/upload", "GET /api/files", "DELETE /api/files/:id"]
175
+ if "Search" in extras:
176
+ endpoints += ["GET /api/search?q=:query"]
 
177
 
178
  folder_tree = f"""{slug}/
179
  ├── app/
180
  │ ├── components/
181
+ │ │ ├── ui/
182
+ │ │ ├── forms/
183
+ │ │ └── layout/
184
  │ ├── pages/
185
  │ ├── hooks/
186
  │ ├── services/
 
193
  │ └── models/
194
  ├── database/
195
  │ ├── schema.sql
196
+ │ ├── migrations/
197
  │ └── seed.sql
198
  ├── public/
199
+ │ └── assets/
200
  ├── tests/
201
+ │ ├── unit/
202
+ │ └── integration/
203
  ├── .env.example
204
+ ├── .gitignore
205
  ├── README.md
206
  └── package.json"""
207
 
208
+ starter_code = f"""# {app_name} - Starter Code
209
 
210
+ ## Stack
211
  - Frontend: {stack}
212
  - Platform: {platform}
213
+ - UI Style: {style}
214
  - Auth: {auth}
215
  - Database: {database}
216
+ - Extras: {', '.join(extras) if extras else 'None'}
217
+
218
+ ---
219
 
220
+ ## App Shell
221
  ```tsx
222
+ // app/layout.tsx
223
+ export default function RootLayout({{ children }}: {{ children: React.ReactNode }}) {{
224
  return (
225
+ <html lang="en">
226
+ <body>
227
+ <nav className="navbar">
228
+ <h1>{app_name}</h1>
229
+ </nav>
230
+ <main className="main-content">
231
+ {{children}}
232
+ </main>
233
+ </body>
234
+ </html>
235
  );
236
  }}
237
  ```
238
 
239
+ ## API Service
240
  ```ts
241
+ // app/services/api.ts
242
+ const BASE = '/api';
243
+
244
+ export async function fetchProjects() {{
245
+ const res = await fetch(`${{BASE}}/projects`);
246
  if (!res.ok) throw new Error('Failed to load projects');
247
  return res.json();
248
  }}
249
+
250
+ export async function createProject(data: {{ title: string; description: string }}) {{
251
+ const res = await fetch(`${{BASE}}/projects`, {{
252
+ method: 'POST',
253
+ headers: {{ 'Content-Type': 'application/json' }},
254
+ body: JSON.stringify(data),
255
+ }});
256
+ if (!res.ok) throw new Error('Failed to create project');
257
+ return res.json();
258
+ }}
259
  ```
260
 
261
+ ## Database Schema
262
  ```sql
263
+ -- database/schema.sql
264
  CREATE TABLE projects (
265
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
266
+ owner_id UUID NOT NULL,
267
+ title TEXT NOT NULL,
268
  description TEXT,
269
+ status TEXT DEFAULT 'draft',
270
+ created_at TIMESTAMP DEFAULT NOW(),
271
+ updated_at TIMESTAMP DEFAULT NOW()
272
+ );
273
+
274
+ CREATE TABLE items (
275
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
276
+ project_id UUID REFERENCES projects(id) ON DELETE CASCADE,
277
+ title TEXT NOT NULL,
278
+ content TEXT,
279
+ type TEXT DEFAULT 'default',
280
+ "order" INT DEFAULT 0,
281
  created_at TIMESTAMP DEFAULT NOW(),
282
  updated_at TIMESTAMP DEFAULT NOW()
283
  );
284
+ ```
285
 
286
+ ## Environment Variables
287
+ ```env
288
+ # .env.example
289
+ DATABASE_URL=
290
+ NEXT_PUBLIC_API_URL=
291
+ JWT_SECRET=
292
+ NODE_ENV=development
293
+ ```
294
+ """
295
+
296
+ prd = f"""# Product Requirements Document
297
 
298
  ## App Name
299
+ **{app_name}**
300
 
301
+ ## Idea
302
  {app_idea}
303
 
304
+ ---
305
+
306
+ ## Target Platform
307
  {platform}
308
 
309
+ ## Tech Stack
310
  {stack}
311
 
312
+ ## Design Style
313
+ {style}
314
+
315
+ ## Auth Strategy
316
+ {auth}
317
+
318
+ ## Database
319
+ {database}
320
+
321
+ ## Extra Features
322
+ {', '.join(extras) if extras else 'None selected'}
323
+
324
+ ---
325
+
326
+ ## Experience Goal
327
+ Build a {style.lower()} {platform.lower()} that feels fast and intuitive.
328
+ Users should be able to get value within 60 seconds of opening the app.
329
+
330
+ ---
331
+
332
+ ## Core Features
333
+ """ + "\n".join(f"- {item}" for item in feature_pool)
334
+
335
+ ui_plan = f"""# UI Plan
336
+
337
+ ## Pages ({len(pages)} total)
338
+ """ + "\n".join(f"- {p}" for p in pages) + f"""
339
+
340
+ ---
341
 
342
+ ## Components ({len(components)} total)
343
+ """ + "\n".join(f"- {c}" for c in components) + """
344
 
345
+ ---
346
+
347
+ ## Design Tokens
348
+ - Use a consistent spacing scale: 4, 8, 12, 16, 24, 32, 48px
349
+ - Font sizes: 12, 14, 16, 20, 24, 32px
350
+ - Border radius: 4px (inputs), 8px (cards), 16px (modals)
351
+ - Transitions: 150ms ease for hover, 250ms ease for modals
352
+
353
+ ## Accessibility
354
+ - All interactive elements must be keyboard navigable
355
+ - ARIA labels on icon-only buttons
356
+ - Color contrast ratio minimum 4.5:1
357
+ - Focus indicators on all inputs
358
+ """
359
 
360
  db_plan = "# Database Plan\n\n" + "\n\n".join(
361
+ f"## Table: `{t['table']}`\n" + "\n".join(f"- `{field}`" for field in t["fields"])
362
  for t in tables
363
+ ) + """
364
+
365
+ ---
366
+
367
+ ## Indexes to add
368
+ - Index on `owner_id` for all user-owned tables
369
+ - Index on `created_at` for time-sorted queries
370
+ - Index on `status` for filtered list views
371
+
372
+ ## Relationships
373
+ - projects.owner_id -> users.id
374
+ - items.project_id -> projects.id (CASCADE DELETE)
375
+ - activity_logs.user_id -> users.id
376
+ """
377
+
378
+ api_plan = "# API Routes\n\n" + "\n".join(f"- `{route}`" for route in endpoints) + """
379
+
380
+ ---
381
+
382
+ ## Auth headers
383
+ All protected routes require:
384
+ ```
385
+ Authorization: Bearer <token>
386
+ ```
387
+
388
+ ## Error format
389
+ ```json
390
+ {
391
+ "error": true,
392
+ "message": "Human readable message",
393
+ "code": "ERROR_CODE"
394
+ }
395
+ ```
396
+
397
+ ## Success format
398
+ ```json
399
+ {
400
+ "data": {},
401
+ "meta": { "total": 0, "page": 1 }
402
+ }
403
+ ```
404
+ """
405
+
406
+ system_prompt = f"""You are a senior full-stack engineer and product architect.
407
+
408
+ Build a complete, production-ready application based on the following spec:
409
 
410
+ APP IDEA: {app_idea}
411
+
412
+ STACK:
413
+ - Framework: {stack}
414
+ - Platform: {platform}
415
+ - Design style: {style}
416
+ - Auth: {auth}
417
+ - Database: {database}
418
+ - Extra features: {', '.join(extras) if extras else 'None'}
419
+
420
+ DELIVER THE FOLLOWING IN ORDER:
421
+ 1. Folder structure with all files listed
422
+ 2. package.json / requirements.txt with all dependencies
423
+ 3. Database schema (full SQL or ORM models)
424
+ 4. Auth implementation
425
+ 5. Core API routes with full handler code
426
+ 6. Frontend pages: layout, dashboard, list, detail, form
427
+ 7. Reusable UI components
428
+ 8. Environment variable template
429
+ 9. README with setup instructions
430
+
431
+ RULES:
432
+ - Write real, working code. No placeholders.
433
+ - Use TypeScript where applicable.
434
+ - Follow the {style.lower()} design system.
435
+ - All code must be copy-paste ready into an IDE.
436
+ - Keep files under 200 lines each."""
437
 
438
  json_export = json.dumps(
439
  {
 
448
  "features": feature_pool,
449
  "pages": pages,
450
  "components": components,
451
+ "tables": [{"table": t["table"], "fields": t["fields"]} for t in tables],
452
  "endpoints": endpoints,
453
  "folder_tree": folder_tree,
454
  },
 
458
  return prd, ui_plan, db_plan, api_plan, folder_tree, starter_code, system_prompt, json_export
459
 
460
 
461
+ WELCOME = """
 
 
462
  # AppDraft
463
+ Describe your app idea below, pick your stack and options, then hit **Generate**.
464
+ You'll get a full build pack across 8 tabs that you can copy straight into your IDE.
465
+
466
+ | Tab | What you get |
467
+ |---|---|
468
+ | PRD | Product requirements, goals, and feature list |
469
+ | UI | Pages, components, and design tokens |
470
+ | Database | Tables, fields, indexes, and relationships |
471
+ | API | All routes with auth and error format |
472
+ | Structure | Full folder and file tree |
473
+ | Starter code | App shell, services, schema, env template |
474
+ | Prompt | Paste this into any AI to generate the full app |
475
+ | JSON | Machine-readable export of the entire spec |
476
  """
 
477
 
 
 
 
 
 
 
478
 
479
+ with gr.Blocks(title=TITLE) as demo:
480
+ gr.Markdown(WELCOME)
481
+
482
+ with gr.Row(equal_height=False):
483
+ with gr.Column(scale=1):
484
+ gr.Markdown("### Describe your app")
485
+ app_idea = gr.Textbox(
486
+ label="App idea",
487
+ lines=6,
488
+ placeholder="Example: A habit tracker for developers with streaks, GitHub integration, daily standups, and a public profile page.",
489
+ show_label=False,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
490
  )
491
 
492
+ gr.Markdown("### Stack and options")
493
+ stack = gr.Dropdown(STACKS, value="Next.js + TypeScript", label="Target stack")
494
+ platform = gr.Dropdown(PLATFORMS, value="Web app", label="Platform")
495
+ style = gr.Dropdown(STYLES, value="Dark SaaS", label="Design style")
496
+ auth = gr.Dropdown(AUTHS, value="Email + password", label="Auth")
497
+ database = gr.Dropdown(DATABASES, value="PostgreSQL", label="Database")
498
+
499
+ gr.Markdown("### Extra features")
500
+ extras = gr.CheckboxGroup(EXTRAS, label="", value=[])
501
+
502
+ generate = gr.Button("Generate build pack", variant="primary", size="lg")
503
+
504
+ with gr.Column(scale=2):
505
+ gr.Markdown("### Your build pack")
506
+ with gr.Tabs():
507
+ with gr.Tab("PRD"):
508
+ prd_out = gr.Markdown(value="*Fill in the form and click Generate to build your pack.*")
509
+ with gr.Tab("UI"):
510
+ ui_out = gr.Markdown()
511
+ with gr.Tab("Database"):
512
+ db_out = gr.Markdown()
513
+ with gr.Tab("API"):
514
+ api_out = gr.Markdown()
515
+ with gr.Tab("Structure"):
516
+ tree_out = gr.Textbox(lines=20, label="Folder tree", show_copy_button=True)
517
+ with gr.Tab("Starter code"):
518
+ starter_out = gr.Markdown()
519
+ with gr.Tab("Prompt"):
520
+ prompt_out = gr.Code(language="markdown", label="Copy this prompt into any AI")
521
+ with gr.Tab("JSON"):
522
+ json_out = gr.Code(language="json", label="Full spec export")
523
 
524
  generate.click(
525
  fn=build_pack,
526
  inputs=[app_idea, stack, platform, style, auth, database, extras],
527
+ outputs=[prd_out, ui_out, db_out, api_out, tree_out, starter_out, prompt_out, json_out],
528
  )
529
 
530
+
531
+ if __name__ == "__main__":
532
+ demo.launch()