appdraft / app.py
Matthewmasturbation's picture
Update app.py
6c9e61c verified
import json
import gradio as gr
TITLE = "AppDraft"
STACKS = [
"Next.js + TypeScript",
"React + Vite",
"FastAPI + React",
"Flask + HTMX",
"Electron + React",
"React Native + Expo",
"Vue 3 + TypeScript",
"SvelteKit",
]
PLATFORMS = [
"Web app",
"Mobile app",
"Desktop app",
"Marketplace",
"SaaS dashboard",
"Landing page + app",
"Browser extension",
"CLI tool",
]
STYLES = [
"Minimal modern",
"Dark SaaS",
"Bold startup",
"Playful consumer",
"Enterprise clean",
"Mobile-first utility",
"Glassmorphism",
"Retro terminal",
]
AUTHS = ["Email + password", "Magic link", "OAuth (Google/GitHub)", "No auth"]
DATABASES = ["PostgreSQL", "Supabase", "SQLite", "MongoDB", "Firebase", "PlanetScale", "Turso"]
EXTRAS = ["Payments", "Notifications", "Admin panel", "AI features", "File uploads", "Realtime", "Search", "Analytics"]
def slugify(value: str) -> str:
value = (value or "my-app").strip().lower()
out = []
for ch in value:
if ch.isalnum():
out.append(ch)
elif ch in {" ", "_", ".", "/", "-"}:
out.append("-")
slug = "".join(out)
while "--" in slug:
slug = slug.replace("--", "-")
return slug.strip("-") or "my-app"
def build_pack(app_idea, stack, platform, style, auth, database, extras):
if not app_idea or not app_idea.strip():
return (
"## No input\n\nPlease describe your app idea in the box above.",
"", "", "", "", "", "", ""
)
app_name = app_idea.strip().split("\n")[0][:60] or "My App"
slug = slugify(app_name)
extras = extras or []
feature_pool = [
"Authentication and user onboarding" if auth != "No auth" else "Guest-friendly onboarding and local session flow",
"Dashboard or home view with quick actions",
"Create, edit, and delete core records",
"Search, filter, and sort data",
"Responsive mobile-friendly UI",
"Error, loading, and empty states throughout",
"Activity history and analytics",
]
if "Payments" in extras:
feature_pool.append("Subscriptions, billing, and checkout flow")
if "Notifications" in extras:
feature_pool.append("Email and in-app notification system")
if "Admin panel" in extras:
feature_pool.append("Role-based admin panel and moderation tools")
if "AI features" in extras:
feature_pool.append("AI-powered generation, summarization, or recommendations")
if "File uploads" in extras:
feature_pool.append("Secure file upload and storage pipeline")
if "Realtime" in extras:
feature_pool.append("Realtime collaboration or live activity updates")
if "Search" in extras:
feature_pool.append("Full-text search with filters and indexing")
if "Analytics" in extras:
feature_pool.append("Usage analytics dashboard and event tracking")
pages = [
"Landing / marketing page",
"Sign in / sign up" if auth != "No auth" else "Welcome / guest entry",
"Main dashboard",
"List view with filters",
"Detail / single record view",
"Create and edit form",
"User settings and profile",
]
if "Admin panel" in extras:
pages.append("Admin dashboard and user management")
if "Payments" in extras:
pages.append("Billing and subscription management")
if "Analytics" in extras:
pages.append("Analytics and reporting dashboard")
components = [
"Navbar and app shell",
"Sidebar or tab navigation",
"Hero or empty state block",
"Data cards and tables",
"Modal and drawer for quick actions",
"Toast and alert notification system",
"Form inputs with validation feedback",
"Loading skeletons and spinners",
"Confirmation dialogs",
]
tables = [
{
"table": "users",
"fields": ["id", "email", "password_hash", "role", "created_at"]
if auth != "No auth"
else ["id", "device_id", "display_name", "created_at"],
},
{
"table": "projects",
"fields": ["id", "owner_id", "title", "description", "status", "created_at", "updated_at"],
},
{
"table": "items",
"fields": ["id", "project_id", "title", "content", "type", "order", "created_at", "updated_at"],
},
{
"table": "activity_logs",
"fields": ["id", "user_id", "action", "entity_type", "entity_id", "metadata", "created_at"],
},
]
if "Payments" in extras:
tables.append({"table": "subscriptions", "fields": ["id", "user_id", "plan", "status", "provider_customer_id", "renewal_date"]})
if "Notifications" in extras:
tables.append({"table": "notifications", "fields": ["id", "user_id", "type", "title", "body", "read_at", "created_at"]})
if "File uploads" in extras:
tables.append({"table": "files", "fields": ["id", "owner_id", "entity_id", "filename", "mime_type", "storage_url", "size_bytes", "created_at"]})
if "Analytics" in extras:
tables.append({"table": "events", "fields": ["id", "user_id", "event_name", "properties", "session_id", "created_at"]})
endpoints = [
"POST /api/auth/register" if auth != "No auth" else "POST /api/session/start",
"POST /api/auth/login" if auth != "No auth" else "GET /api/session",
"POST /api/auth/logout" if auth != "No auth" else "",
"GET /api/projects",
"POST /api/projects",
"GET /api/projects/:id",
"PUT /api/projects/:id",
"DELETE /api/projects/:id",
"GET /api/items?projectId=:id",
"POST /api/items",
"PUT /api/items/:id",
"DELETE /api/items/:id",
]
endpoints = [e for e in endpoints if e]
if "Payments" in extras:
endpoints += ["POST /api/billing/checkout", "GET /api/billing/subscription", "POST /api/billing/cancel"]
if "Notifications" in extras:
endpoints += ["GET /api/notifications", "POST /api/notifications/mark-read"]
if "File uploads" in extras:
endpoints += ["POST /api/files/upload", "GET /api/files", "DELETE /api/files/:id"]
if "Search" in extras:
endpoints += ["GET /api/search?q=:query"]
folder_tree = f"""{slug}/
├── app/
│ ├── components/
│ │ ├── ui/
│ │ ├── forms/
│ │ └── layout/
│ ├── pages/
│ ├── hooks/
│ ├── services/
│ ├── lib/
│ └── styles/
├── server/
│ ├── routes/
│ ├── controllers/
│ ├── middleware/
│ └── models/
├── database/
│ ├── schema.sql
│ ├── migrations/
│ └── seed.sql
├── public/
│ └── assets/
├── tests/
│ ├── unit/
│ └── integration/
├── .env.example
├── .gitignore
├── README.md
└── package.json"""
starter_code = f"""# {app_name} - Starter Code
## Stack
- Frontend: {stack}
- Platform: {platform}
- UI Style: {style}
- Auth: {auth}
- Database: {database}
- Extras: {', '.join(extras) if extras else 'None'}
---
## App Shell
```tsx
// app/layout.tsx
export default function RootLayout({{ children }}: {{ children: React.ReactNode }}) {{
return (
<html lang="en">
<body>
<nav className="navbar">
<h1>{app_name}</h1>
</nav>
<main className="main-content">
{{children}}
</main>
</body>
</html>
);
}}
```
## API Service
```ts
// app/services/api.ts
const BASE = '/api';
export async function fetchProjects() {{
const res = await fetch(`${{BASE}}/projects`);
if (!res.ok) throw new Error('Failed to load projects');
return res.json();
}}
export async function createProject(data: {{ title: string; description: string }}) {{
const res = await fetch(`${{BASE}}/projects`, {{
method: 'POST',
headers: {{ 'Content-Type': 'application/json' }},
body: JSON.stringify(data),
}});
if (!res.ok) throw new Error('Failed to create project');
return res.json();
}}
```
## Database Schema
```sql
-- database/schema.sql
CREATE TABLE projects (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
owner_id UUID NOT NULL,
title TEXT NOT NULL,
description TEXT,
status TEXT DEFAULT 'draft',
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE items (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
project_id UUID REFERENCES projects(id) ON DELETE CASCADE,
title TEXT NOT NULL,
content TEXT,
type TEXT DEFAULT 'default',
"order" INT DEFAULT 0,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
```
## Environment Variables
```env
# .env.example
DATABASE_URL=
NEXT_PUBLIC_API_URL=
JWT_SECRET=
NODE_ENV=development
```
"""
prd = f"""# Product Requirements Document
## App Name
**{app_name}**
## Idea
{app_idea}
---
## Target Platform
{platform}
## Tech Stack
{stack}
## Design Style
{style}
## Auth Strategy
{auth}
## Database
{database}
## Extra Features
{', '.join(extras) if extras else 'None selected'}
---
## Experience Goal
Build a {style.lower()} {platform.lower()} that feels fast and intuitive.
Users should be able to get value within 60 seconds of opening the app.
---
## Core Features
""" + "\n".join(f"- {item}" for item in feature_pool)
ui_plan = f"""# UI Plan
## Pages ({len(pages)} total)
""" + "\n".join(f"- {p}" for p in pages) + f"""
---
## Components ({len(components)} total)
""" + "\n".join(f"- {c}" for c in components) + """
---
## Design Tokens
- Use a consistent spacing scale: 4, 8, 12, 16, 24, 32, 48px
- Font sizes: 12, 14, 16, 20, 24, 32px
- Border radius: 4px (inputs), 8px (cards), 16px (modals)
- Transitions: 150ms ease for hover, 250ms ease for modals
## Accessibility
- All interactive elements must be keyboard navigable
- ARIA labels on icon-only buttons
- Color contrast ratio minimum 4.5:1
- Focus indicators on all inputs
"""
db_plan = "# Database Plan\n\n" + "\n\n".join(
f"## Table: `{t['table']}`\n" + "\n".join(f"- `{field}`" for field in t["fields"])
for t in tables
) + """
---
## Indexes to add
- Index on `owner_id` for all user-owned tables
- Index on `created_at` for time-sorted queries
- Index on `status` for filtered list views
## Relationships
- projects.owner_id -> users.id
- items.project_id -> projects.id (CASCADE DELETE)
- activity_logs.user_id -> users.id
"""
api_plan = "# API Routes\n\n" + "\n".join(f"- `{route}`" for route in endpoints) + """
---
## Auth headers
All protected routes require:
```
Authorization: Bearer <token>
```
## Error format
```json
{
"error": true,
"message": "Human readable message",
"code": "ERROR_CODE"
}
```
## Success format
```json
{
"data": {},
"meta": { "total": 0, "page": 1 }
}
```
"""
system_prompt = f"""You are a senior full-stack engineer and product architect.
Build a complete, production-ready application based on the following spec:
APP IDEA: {app_idea}
STACK:
- Framework: {stack}
- Platform: {platform}
- Design style: {style}
- Auth: {auth}
- Database: {database}
- Extra features: {', '.join(extras) if extras else 'None'}
DELIVER THE FOLLOWING IN ORDER:
1. Folder structure with all files listed
2. package.json / requirements.txt with all dependencies
3. Database schema (full SQL or ORM models)
4. Auth implementation
5. Core API routes with full handler code
6. Frontend pages: layout, dashboard, list, detail, form
7. Reusable UI components
8. Environment variable template
9. README with setup instructions
RULES:
- Write real, working code. No placeholders.
- Use TypeScript where applicable.
- Follow the {style.lower()} design system.
- All code must be copy-paste ready into an IDE.
- Keep files under 200 lines each."""
json_export = json.dumps(
{
"name": app_name,
"slug": slug,
"stack": stack,
"platform": platform,
"style": style,
"auth": auth,
"database": database,
"extras": extras,
"features": feature_pool,
"pages": pages,
"components": components,
"tables": [{"table": t["table"], "fields": t["fields"]} for t in tables],
"endpoints": endpoints,
"folder_tree": folder_tree,
},
indent=2,
)
return prd, ui_plan, db_plan, api_plan, folder_tree, starter_code, system_prompt, json_export
WELCOME = """
# AppDraft
Describe your app idea below, pick your stack and options, then hit **Generate**.
You'll get a full build pack across 8 tabs that you can copy straight into your IDE.
| Tab | What you get |
|---|---|
| PRD | Product requirements, goals, and feature list |
| UI | Pages, components, and design tokens |
| Database | Tables, fields, indexes, and relationships |
| API | All routes with auth and error format |
| Structure | Full folder and file tree |
| Starter code | App shell, services, schema, env template |
| Prompt | Paste this into any AI to generate the full app |
| JSON | Machine-readable export of the entire spec |
"""
with gr.Blocks(title=TITLE) as demo:
gr.Markdown(WELCOME)
with gr.Row(equal_height=False):
with gr.Column(scale=1):
gr.Markdown("### Describe your app")
app_idea = gr.Textbox(
label="App idea",
lines=6,
placeholder="Example: A habit tracker for developers with streaks, GitHub integration, daily standups, and a public profile page.",
show_label=False,
)
gr.Markdown("### Stack and options")
stack = gr.Dropdown(STACKS, value="Next.js + TypeScript", label="Target stack")
platform = gr.Dropdown(PLATFORMS, value="Web app", label="Platform")
style = gr.Dropdown(STYLES, value="Dark SaaS", label="Design style")
auth = gr.Dropdown(AUTHS, value="Email + password", label="Auth")
database = gr.Dropdown(DATABASES, value="PostgreSQL", label="Database")
gr.Markdown("### Extra features")
extras = gr.CheckboxGroup(EXTRAS, label="", value=[])
generate = gr.Button("Generate build pack", variant="primary", size="lg")
with gr.Column(scale=2):
gr.Markdown("### Your build pack")
with gr.Tabs():
with gr.Tab("PRD"):
prd_out = gr.Markdown(value="*Fill in the form and click Generate to build your pack.*")
with gr.Tab("UI"):
ui_out = gr.Markdown()
with gr.Tab("Database"):
db_out = gr.Markdown()
with gr.Tab("API"):
api_out = gr.Markdown()
with gr.Tab("Structure"):
tree_out = gr.Textbox(lines=20, label="Folder tree", show_copy_button=True)
with gr.Tab("Starter code"):
starter_out = gr.Markdown()
with gr.Tab("Prompt"):
prompt_out = gr.Code(language="markdown", label="Copy this prompt into any AI")
with gr.Tab("JSON"):
json_out = gr.Code(language="json", label="Full spec export")
generate.click(
fn=build_pack,
inputs=[app_idea, stack, platform, style, auth, database, extras],
outputs=[prd_out, ui_out, db_out, api_out, tree_out, starter_out, prompt_out, json_out],
)
if __name__ == "__main__":
demo.launch()