Building a Custom Web App
Create a custom web application that leverages Fiberwise agents for intelligent functionality. This tutorial takes about 60 minutes and covers full-stack app development.
📋 What You'll Build
A comprehensive task management application that:
- ✅ Manages tasks with AI-powered prioritization
- ✅ Uses real-time collaboration features
- ✅ Integrates custom data models and storage
- ✅ Provides intelligent task insights and recommendations
- ✅ Features a professional, responsive user interface
Final Result: A production-ready web application with AI agent integration.
📚 What You'll Learn
Full-Stack Development Skills
- Custom Data Models - Designing and implementing app-specific data structures
- Real-time Features - Building collaborative, live-updating interfaces
- Agent Integration - Seamlessly connecting AI agents to web interfaces
- Advanced UI/UX - Creating professional, responsive web applications
Platform Integration
- Advanced Fiberwise JavaScript SDK usage
- Complex agent workflows and data processing
- Production deployment and scaling considerations
- Performance optimization and error handling
📋 Prerequisites: Your Setup Checklist
Before you begin, you need a fully configured Fiberwise environment. This is the foundation for building any app on the platform.
🔧 Required Setup
✅ All Set?
Once all boxes are checked, you are ready to proceed. If not, please complete the linked guides first.
📋 Step 1: Create App Manifest
Create my_app/app_manifest.yaml
:
app:
name: Task Manager AI
app_slug: task-manager-ai
version: 1.0.0
description: AI-powered task management with smart prioritization
entryPoint: index.js
icon: fas fa-tasks
category: productivity
minPlatformVersion: 1.6.0
models:
- name: Task
model_slug: tasks
description: Task management with AI insights
fields:
- name: ID
field_column: id
type: uuid
required: true
is_system_field: true
- name: User ID
field_column: user_id
type: uuid
required: true
is_system_field: true
description: Task owner (automatically set by platform)
- name: Title
field_column: title
type: string
required: true
max_length: 200
description: Task title
- name: Description
field_column: description
type: text
required: false
description: Detailed task description
- name: Priority
field_column: priority
type: string
required: true
default: medium
choices: [low, medium, high, urgent]
description: Task priority level
- name: Status
field_column: status
type: string
required: true
default: todo
choices: [todo, in_progress, completed, archived]
description: Current task status
- name: Due Date
field_column: due_date
type: datetime
required: false
description: Task deadline
- name: AI Insights
field_column: ai_insights
type: jsonb
required: false
description: AI-generated task analysis
- name: Created At
field_column: created_at
type: datetime
required: true
auto_now_add: true
is_system_field: true
description: Creation timestamp
- name: Updated At
field_column: updated_at
type: datetime
required: true
auto_now: true
is_system_field: true
description: Last update timestamp
routes:
- path: /
component: task-dashboard
title: Dashboard
icon: fas fa-chart-line
- path: /tasks
component: task-list
title: All Tasks
icon: fas fa-list
- path: /analytics
component: task-analytics
title: Analytics
icon: fas fa-chart-bar
agents:
- name: Task Prioritizer
description: AI agent that analyzes and prioritizes tasks
file_path: agents/task_prioritizer.py
capabilities: [task_analysis, priority_scoring]
functions: []
workflows: []
pipelines: []
🤖 Step 2: Create the AI Agent
Create agents/task_prioritizer.py
:
from fiberwise_sdk import FiberAgent
import json
from datetime import datetime
class TaskPrioritizer(FiberAgent):
"""AI agent that prioritizes tasks intelligently"""
def run_agent(self, input_data: dict, llm_provider: LLMProviderService, fiber_app: FiberApp):
tasks = input_data.get('tasks', [])
context = input_data.get('context', {})
if not tasks:
return {'error': 'No tasks provided', 'status': 'failed'}
# Analyze tasks with AI
prioritized_tasks = []
for task in tasks:
analysis = self._analyze_task(task, context, llm_provider)
# Update task with AI insights
task['ai_insights'] = analysis
task['priority'] = analysis.get('recommended_priority', task.get('priority', 'medium'))
prioritized_tasks.append(task)
# Save to database if available
if fiber_app:
fiber_app.data.update('tasks', task['id'], task)
# Sort by priority score
prioritized_tasks.sort(key=lambda x: x['ai_insights'].get('priority_score', 0), reverse=True)
return {
'status': 'success',
'prioritized_tasks': prioritized_tasks,
'total_analyzed': len(tasks),
'summary': f'Analyzed and prioritized {len(tasks)} tasks'
}
def _analyze_task(self, task, context, llm_provider):
"""Analyze individual task with AI"""
title = task.get('title', '')
description = task.get('description', '')
due_date = task.get('due_date', '')
current_priority = task.get('priority', 'medium')
prompt = f"""
Analyze this task and provide intelligent prioritization:
Title: {title}
Description: {description}
Due Date: {due_date}
Current Priority: {current_priority}
Context: {context}
Provide analysis in JSON format:
{
"priority_score": 0-100,
"recommended_priority": "low/medium/high/urgent",
"urgency_factors": ["factor1", "factor2"],
"estimated_effort": "low/medium/high",
"dependencies": ["task_id1", "task_id2"],
"recommendations": "specific advice for this task"
}
"""
try:
analysis_text = llm_provider.complete(prompt)
import json
return json.loads(analysis_text)
except Exception as e:
return {
'priority_score': 50,
'recommended_priority': current_priority,
'error': f'Analysis failed: {str(e)}'
}
🎨 Step 3: Build the Web Interface
Create index.js
with advanced functionality:
import { Apps, DynamicData, Agents, Realtime } from 'fiberwise';
class TaskManagerApp {
constructor() {
this.apps = new Apps();
this.data = new DynamicData();
this.agents = new Agents();
this.realtime = new Realtime();
this.currentApp = null;
this.tasks = [];
this.init();
}
async init() {
try {
// Get current app context
this.currentApp = await this.apps.getCurrentApp();
// Set up real-time updates
this.realtime.subscribe('task_updates', this.handleTaskUpdate.bind(this));
// Load initial data
await this.loadTasks();
// Render interface
this.render();
console.log('✅ Task Manager initialized successfully');
} catch (error) {
console.error('App initialization failed:', error);
this.showError('Failed to initialize app');
}
}
async loadTasks() {
try {
this.tasks = await this.data.query('tasks', {
orderBy: ['-created_at'],
limit: 100
});
} catch (error) {
console.error('Failed to load tasks:', error);
this.tasks = [];
}
}
async createTask(taskData) {
try {
const newTask = await this.data.create('tasks', {
...taskData,
status: 'todo',
created_at: new Date().toISOString()
});
this.tasks.unshift(newTask);
this.renderTasks();
this.showMessage('Task created successfully');
return newTask;
} catch (error) {
console.error('Failed to create task:', error);
this.showError('Failed to create task');
}
}
async prioritizeTasks() {
try {
const incompleteTasks = this.tasks.filter(t => t.status !== 'completed');
if (incompleteTasks.length === 0) {
this.showMessage('No tasks to prioritize');
return;
}
this.showLoading('Analyzing tasks with AI...');
const result = await this.agents.activate(
'task_prioritizer',
{
tasks: incompleteTasks,
context: {
user_preferences: 'focus on urgent deadlines',
current_date: new Date().toISOString()
}
}
);
if (result.status === 'success') {
this.tasks = result.prioritized_tasks.concat(
this.tasks.filter(t => t.status === 'completed')
);
this.renderTasks();
this.showMessage(`Successfully prioritized ${result.total_analyzed} tasks`);
} else {
this.showError('Task prioritization failed');
}
} catch (error) {
console.error('Task prioritization failed:', error);
this.showError('Failed to prioritize tasks');
} finally {
this.hideLoading();
}
}
handleTaskUpdate(update) {
// Handle real-time task updates
const { action, task } = update;
switch (action) {
case 'created':
this.tasks.unshift(task);
break;
case 'updated':
const index = this.tasks.findIndex(t => t.id === task.id);
if (index !== -1) {
this.tasks[index] = task;
}
break;
case 'deleted':
this.tasks = this.tasks.filter(t => t.id !== task.id);
break;
}
this.renderTasks();
}
render() {
const appContainer = document.getElementById('app');
appContainer.innerHTML = `
📋 Task Manager AI
${this.tasks.filter(t => t.status === 'todo').length}
To Do
${this.tasks.filter(t => t.status === 'in_progress').length}
In Progress
${this.tasks.filter(t => t.status === 'completed').length}
Completed
`;
this.renderTasks();
this.attachEventListeners();
}
renderTasks() {
const container = document.getElementById('tasks-container');
if (this.tasks.length === 0) {
container.innerHTML = `
No tasks yet
Create your first task to get started!
`;
return;
}
container.innerHTML = this.tasks.map(task => `
${task.title}
${task.priority}
${task.description ? `${task.description}
` : ''}
${task.ai_insights ? `
AI Score: ${task.ai_insights.priority_score}/100
${task.ai_insights.recommendations ? `
Recommendation: ${task.ai_insights.recommendations}
` : ''}
` : ''}
`).join('');
}
attachEventListeners() {
// AI Prioritization
document.getElementById('prioritize-btn').addEventListener('click', () => {
this.prioritizeTasks();
});
// New Task Button
document.getElementById('new-task-btn').addEventListener('click', () => {
this.showNewTaskDialog();
});
// Task status changes
document.addEventListener('change', (e) => {
if (e.target.classList.contains('status-select')) {
const taskId = e.target.dataset.taskId;
const newStatus = e.target.value;
this.updateTaskStatus(taskId, newStatus);
}
});
// Task deletion
document.addEventListener('click', (e) => {
if (e.target.classList.contains('delete-btn')) {
const taskId = e.target.dataset.taskId;
this.deleteTask(taskId);
}
});
}
async updateTaskStatus(taskId, status) {
try {
const task = this.tasks.find(t => t.id === taskId);
if (task) {
task.status = status;
await this.data.update('tasks', taskId, { status });
this.renderTasks();
}
} catch (error) {
console.error('Failed to update task:', error);
this.showError('Failed to update task');
}
}
async deleteTask(taskId) {
if (!confirm('Are you sure you want to delete this task?')) return;
try {
await this.data.delete('tasks', taskId);
this.tasks = this.tasks.filter(t => t.id !== taskId);
this.renderTasks();
this.showMessage('Task deleted successfully');
} catch (error) {
console.error('Failed to delete task:', error);
this.showError('Failed to delete task');
}
}
showNewTaskDialog() {
const dialog = document.createElement('div');
dialog.className = 'modal-overlay';
dialog.innerHTML = `
Create New Task
`;
document.body.appendChild(dialog);
// Handle form submission
document.getElementById('new-task-form').addEventListener('submit', async (e) => {
e.preventDefault();
const taskData = {
title: document.getElementById('task-title').value,
description: document.getElementById('task-description').value,
due_date: document.getElementById('task-due-date').value || null
};
await this.createTask(taskData);
dialog.remove();
});
// Handle cancel
dialog.querySelector('.btn-cancel').addEventListener('click', () => {
dialog.remove();
});
// Focus first input
document.getElementById('task-title').focus();
}
showLoading(message = 'Loading...') {
const loading = document.getElementById('loading');
loading.querySelector('p').textContent = message;
loading.classList.remove('hidden');
}
hideLoading() {
document.getElementById('loading').classList.add('hidden');
}
showMessage(message, type = 'success') {
const messages = document.getElementById('messages');
const messageEl = document.createElement('div');
messageEl.className = `message message-${type}`;
messageEl.textContent = message;
messages.appendChild(messageEl);
setTimeout(() => {
messageEl.remove();
}, 5000);
}
showError(message) {
this.showMessage(message, 'error');
}
}
// Initialize app when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
window.app = new TaskManagerApp();
});
📄 Complete Code Available
The full JavaScript implementation with UI components, styling, and all functionality is extensive. You can find the complete code in our examples repository.
🎨 Step 4: Add Styling
Create style.css
with responsive design and modern UI components. Key styling features include:
- Task Cards: Clean, professional task display with priority indicators
- AI Insights: Special styling for AI-generated recommendations
- Real-time Updates: Smooth animations for live updates
- Responsive Design: Mobile-friendly layouts
- Loading States: User-friendly loading indicators
🎨 Full Styling
Complete CSS with animations, responsive grid layouts, and professional styling is available in the example repository.
🚀 Step 5: Deploy and Test
# Deploy the app
fiber app deploy my_app/
# Access via web interface
# Navigate to http://localhost:8000/task-manager-ai
🎉 Congratulations!
You've built a complete web application with:
- AI-powered task prioritization
- Real-time collaboration features
- Professional UI with responsive design
- Full CRUD operations with data persistence
🚀 Next Steps
Amazing work! You've completed all major tutorials and built progressively more complex applications. Here's what to explore next:
🏆 Congratulations!
You've successfully:
- ✅ Built a comprehensive full-stack web application
- ✅ Integrated complex AI agent workflows
- ✅ Implemented real-time collaboration features
- ✅ Created professional, responsive user interfaces
- ✅ Mastered advanced Fiberwise platform capabilities
You're now ready to build sophisticated, production-ready applications with Fiberwise!