init projectmycelium
This commit is contained in:
@@ -0,0 +1,550 @@
|
||||
# Dual UX Specification: Modern App + E-commerce Flows
|
||||
|
||||
**Document Purpose**: Comprehensive UX specification supporting both modern app-style instant purchase and traditional e-commerce cart workflows.
|
||||
|
||||
**Last Updated**: 2025-08-04
|
||||
**Status**: Implementation Ready
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The Project Mycelium supports **two distinct user experience patterns** to accommodate different user preferences and use cases:
|
||||
|
||||
1. **Modern App Flow** (OpenRouter-style): Instant purchase with wallet top-up
|
||||
2. **Traditional E-commerce Flow**: Cart-based shopping with checkout
|
||||
|
||||
---
|
||||
|
||||
## UX Flow Comparison
|
||||
|
||||
### **Flow 1: Modern App Style (OpenRouter-inspired)**
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Browse Marketplace] --> B[Register/Login]
|
||||
B --> C[View Service]
|
||||
C --> D[Buy Now Button]
|
||||
D --> E{TFC Balance Check}
|
||||
E -->|Sufficient| F[Instant Deploy]
|
||||
E -->|Insufficient| G[Auto Top-up Modal]
|
||||
G --> H[Stripe Payment]
|
||||
H --> I[TFC Added]
|
||||
I --> F
|
||||
F --> J[Deployment Status]
|
||||
J --> K[Service Active]
|
||||
```
|
||||
|
||||
**Key Features:**
|
||||
- **Instant Purchase**: Single-click buying
|
||||
- **Auto Top-up**: Seamless balance management
|
||||
- **Wallet-centric**: Balance always visible
|
||||
- **Minimal Friction**: No cart, no checkout process
|
||||
|
||||
### **Flow 2: Traditional E-commerce Style**
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Browse Marketplace] --> B[View Service]
|
||||
B --> C[Add to Cart]
|
||||
C --> D[Continue Shopping]
|
||||
D --> E[Review Cart]
|
||||
E --> F[Checkout]
|
||||
F --> G{Payment Method}
|
||||
G -->|TFC Balance| H[Pay with TFC]
|
||||
G -->|Credit Card| I[Stripe Checkout]
|
||||
I --> J[TFC Purchase]
|
||||
J --> H
|
||||
H --> K[Batch Deployment]
|
||||
K --> L[Order Confirmation]
|
||||
```
|
||||
|
||||
**Key Features:**
|
||||
- **Bulk Shopping**: Multiple items in cart
|
||||
- **Price Comparison**: Review before purchase
|
||||
- **Batch Deployment**: Deploy multiple services together
|
||||
- **Familiar UX**: Traditional e-commerce experience
|
||||
|
||||
---
|
||||
|
||||
## Detailed UX Specifications
|
||||
|
||||
### **Modern App Flow Implementation**
|
||||
|
||||
#### **1. Wallet-First Interface**
|
||||
|
||||
```html
|
||||
<!-- Wallet Status Component (Always Visible) -->
|
||||
<div class="wallet-status-bar">
|
||||
<div class="balance-display">
|
||||
<span class="balance-amount">{{user.tfc_balance}} TFC</span>
|
||||
<span class="usd-equivalent">${{user.tfc_balance}} USD</span>
|
||||
</div>
|
||||
<div class="wallet-actions">
|
||||
<button class="btn btn-sm btn-outline-primary" onclick="showTopUpModal()">
|
||||
<i class="bi bi-plus-circle"></i> Top Up
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-secondary" onclick="toggleAutoTopUp()">
|
||||
<i class="bi bi-arrow-repeat"></i> Auto Top-up: {{#if user.auto_topup}}ON{{else}}OFF{{/if}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
#### **2. Buy Now Button (Primary Action)**
|
||||
|
||||
```html
|
||||
<!-- Service Card with Buy Now -->
|
||||
<div class="service-card modern-style">
|
||||
<div class="service-header">
|
||||
<h4>{{service.name}}</h4>
|
||||
<div class="price-tag">
|
||||
<span class="tfc-price">{{service.price_tfc}} TFC</span>
|
||||
<span class="deployment-time">~2 min deploy</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="service-actions">
|
||||
<button class="btn btn-primary btn-lg buy-now-btn"
|
||||
onclick="buyNowInstant('{{service.id}}')">
|
||||
<i class="bi bi-lightning-fill"></i>
|
||||
Buy Now & Deploy
|
||||
</button>
|
||||
|
||||
<button class="btn btn-outline-secondary add-to-cart-btn"
|
||||
onclick="addToCart('{{service.id}}')">
|
||||
<i class="bi bi-cart-plus"></i>
|
||||
Add to Cart
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Balance Check Indicator -->
|
||||
<div class="balance-check">
|
||||
{{#if (gte user.tfc_balance service.price_tfc)}}
|
||||
<span class="text-success">
|
||||
<i class="bi bi-check-circle"></i> Ready to deploy
|
||||
</span>
|
||||
{{else}}
|
||||
<span class="text-warning">
|
||||
<i class="bi bi-exclamation-triangle"></i>
|
||||
Need {{subtract service.price_tfc user.tfc_balance}} more TFC
|
||||
</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
#### **3. Auto Top-up Configuration**
|
||||
|
||||
```html
|
||||
<!-- Auto Top-up Settings Modal -->
|
||||
<div class="modal fade" id="autoTopUpModal">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5>Auto Top-up Settings</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label>Enable Auto Top-up</label>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" id="enableAutoTopUp">
|
||||
<label class="form-check-label">Automatically add TFC when balance is low</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Trigger Threshold</label>
|
||||
<select class="form-select" id="topUpThreshold">
|
||||
<option value="10">When balance < 10 TFC</option>
|
||||
<option value="25">When balance < 25 TFC</option>
|
||||
<option value="50" selected>When balance < 50 TFC</option>
|
||||
<option value="100">When balance < 100 TFC</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Top-up Amount</label>
|
||||
<select class="form-select" id="topUpAmount">
|
||||
<option value="50">Add 50 TFC ($50)</option>
|
||||
<option value="100" selected>Add 100 TFC ($100)</option>
|
||||
<option value="200">Add 200 TFC ($200)</option>
|
||||
<option value="500">Add 500 TFC ($500)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle"></i>
|
||||
Auto top-up uses your saved payment method. You'll receive an email confirmation for each transaction.
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" onclick="saveAutoTopUpSettings()">Save Settings</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### **Traditional E-commerce Flow Implementation**
|
||||
|
||||
#### **1. Shopping Cart Component**
|
||||
|
||||
```html
|
||||
<!-- Shopping Cart (Sidebar or Page) -->
|
||||
<div class="shopping-cart">
|
||||
<div class="cart-header">
|
||||
<h4>Shopping Cart</h4>
|
||||
<span class="item-count">{{cart.items.length}} items</span>
|
||||
</div>
|
||||
|
||||
<div class="cart-items">
|
||||
{{#each cart.items}}
|
||||
<div class="cart-item">
|
||||
<div class="item-info">
|
||||
<h6>{{this.service_name}}</h6>
|
||||
<p class="item-specs">{{this.cpu}}CPU • {{this.memory}}GB RAM • {{this.storage}}GB</p>
|
||||
</div>
|
||||
<div class="item-price">
|
||||
<span class="tfc-price">{{this.price_tfc}} TFC</span>
|
||||
<button class="btn btn-sm btn-outline-danger" onclick="removeFromCart('{{this.id}}')">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
|
||||
<div class="cart-summary">
|
||||
<div class="summary-line">
|
||||
<span>Subtotal:</span>
|
||||
<span>{{cart.subtotal}} TFC</span>
|
||||
</div>
|
||||
<div class="summary-line">
|
||||
<span>Estimated Deploy Time:</span>
|
||||
<span>~{{cart.estimated_deploy_time}} minutes</span>
|
||||
</div>
|
||||
<div class="summary-line total">
|
||||
<span><strong>Total:</strong></span>
|
||||
<span><strong>{{cart.total}} TFC</strong></span>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-primary btn-lg w-100" onclick="proceedToCheckout()">
|
||||
<i class="bi bi-credit-card"></i>
|
||||
Proceed to Checkout
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
#### **2. Checkout Process**
|
||||
|
||||
```html
|
||||
<!-- Checkout Page -->
|
||||
<div class="checkout-container">
|
||||
<div class="checkout-steps">
|
||||
<div class="step active">1. Review Order</div>
|
||||
<div class="step">2. Payment</div>
|
||||
<div class="step">3. Deployment</div>
|
||||
</div>
|
||||
|
||||
<div class="checkout-content">
|
||||
<div class="order-review">
|
||||
<h5>Order Summary</h5>
|
||||
<!-- Cart items review -->
|
||||
|
||||
<div class="deployment-options">
|
||||
<h6>Deployment Options</h6>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="deploymentTiming" value="immediate" checked>
|
||||
<label class="form-check-label">Deploy immediately after payment</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="deploymentTiming" value="scheduled">
|
||||
<label class="form-check-label">Schedule deployment for later</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="payment-section">
|
||||
<h5>Payment Method</h5>
|
||||
<div class="payment-options">
|
||||
<div class="payment-option" onclick="selectPaymentMethod('tfc')">
|
||||
<div class="option-header">
|
||||
<i class="bi bi-wallet2"></i>
|
||||
<span>Pay with TFC Balance</span>
|
||||
<span class="balance-info">{{user.tfc_balance}} TFC available</span>
|
||||
</div>
|
||||
{{#if (lt user.tfc_balance cart.total)}}
|
||||
<div class="insufficient-notice">
|
||||
<span class="text-warning">Insufficient balance. Need {{subtract cart.total user.tfc_balance}} more TFC.</span>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="payment-option" onclick="selectPaymentMethod('stripe')">
|
||||
<div class="option-header">
|
||||
<i class="bi bi-credit-card"></i>
|
||||
<span>Credit/Debit Card</span>
|
||||
<span class="amount-info">${{cart.total}} USD</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="payment-option" onclick="selectPaymentMethod('mixed')">
|
||||
<div class="option-header">
|
||||
<i class="bi bi-shuffle"></i>
|
||||
<span>Use TFC + Credit Card</span>
|
||||
<span class="mixed-info">{{user.tfc_balance}} TFC + ${{subtract cart.total user.tfc_balance}} USD</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## JavaScript Implementation
|
||||
|
||||
### **Modern App Flow Functions**
|
||||
|
||||
```javascript
|
||||
// Modern App Style - Instant Purchase
|
||||
async function buyNowInstant(serviceId) {
|
||||
try {
|
||||
// Check balance first
|
||||
const balance = await getUserTFCBalance();
|
||||
const service = await getServiceDetails(serviceId);
|
||||
|
||||
if (balance >= service.price_tfc) {
|
||||
// Sufficient balance - instant deploy
|
||||
showLoadingToast('Starting deployment...');
|
||||
const result = await initiateDeployment(serviceId, 'tfc');
|
||||
|
||||
if (result.success) {
|
||||
showSuccessToast('Deployment started! Redirecting...');
|
||||
window.location.href = `/dashboard/deployments/${result.deployment_id}`;
|
||||
}
|
||||
} else {
|
||||
// Insufficient balance - auto top-up flow
|
||||
const needed = service.price_tfc - balance;
|
||||
|
||||
if (await isAutoTopUpEnabled()) {
|
||||
showAutoTopUpModal(needed, serviceId);
|
||||
} else {
|
||||
showManualTopUpModal(needed, serviceId);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
showErrorToast('Failed to process purchase');
|
||||
}
|
||||
}
|
||||
|
||||
// Auto Top-up Flow
|
||||
async function handleAutoTopUp(amount, serviceId) {
|
||||
try {
|
||||
showLoadingToast('Processing auto top-up...');
|
||||
|
||||
const topUpResult = await processAutoTopUp(amount);
|
||||
if (topUpResult.success) {
|
||||
showSuccessToast('Balance updated! Starting deployment...');
|
||||
|
||||
// Proceed with deployment
|
||||
const deployResult = await initiateDeployment(serviceId, 'tfc');
|
||||
if (deployResult.success) {
|
||||
window.location.href = `/dashboard/deployments/${deployResult.deployment_id}`;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
showErrorToast('Auto top-up failed');
|
||||
}
|
||||
}
|
||||
|
||||
// Real-time Balance Updates
|
||||
function startBalancePolling() {
|
||||
setInterval(async () => {
|
||||
const balance = await getUserTFCBalance();
|
||||
updateBalanceDisplay(balance);
|
||||
}, 10000); // Update every 10 seconds
|
||||
}
|
||||
|
||||
function updateBalanceDisplay(balance) {
|
||||
document.querySelector('.balance-amount').textContent = `${balance} TFC`;
|
||||
document.querySelector('.usd-equivalent').textContent = `$${balance} USD`;
|
||||
|
||||
// Update buy buttons state
|
||||
document.querySelectorAll('.buy-now-btn').forEach(btn => {
|
||||
const servicePrice = parseFloat(btn.dataset.price);
|
||||
if (balance >= servicePrice) {
|
||||
btn.classList.remove('insufficient-balance');
|
||||
btn.disabled = false;
|
||||
} else {
|
||||
btn.classList.add('insufficient-balance');
|
||||
btn.disabled = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### **Traditional E-commerce Functions**
|
||||
|
||||
```javascript
|
||||
// Traditional E-commerce - Cart Management
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = JSON.parse(localStorage.getItem('cart_items') || '[]');
|
||||
this.updateCartDisplay();
|
||||
}
|
||||
|
||||
addItem(serviceId, serviceName, price, specs) {
|
||||
const existingItem = this.items.find(item => item.service_id === serviceId);
|
||||
|
||||
if (existingItem) {
|
||||
showInfoToast('Item already in cart');
|
||||
return;
|
||||
}
|
||||
|
||||
this.items.push({
|
||||
id: generateId(),
|
||||
service_id: serviceId,
|
||||
service_name: serviceName,
|
||||
price_tfc: price,
|
||||
specs: specs,
|
||||
added_at: new Date().toISOString()
|
||||
});
|
||||
|
||||
this.saveCart();
|
||||
this.updateCartDisplay();
|
||||
showSuccessToast('Added to cart');
|
||||
}
|
||||
|
||||
removeItem(itemId) {
|
||||
this.items = this.items.filter(item => item.id !== itemId);
|
||||
this.saveCart();
|
||||
this.updateCartDisplay();
|
||||
showSuccessToast('Removed from cart');
|
||||
}
|
||||
|
||||
getTotal() {
|
||||
return this.items.reduce((total, item) => total + item.price_tfc, 0);
|
||||
}
|
||||
|
||||
async proceedToCheckout() {
|
||||
if (this.items.length === 0) {
|
||||
showErrorToast('Cart is empty');
|
||||
return;
|
||||
}
|
||||
|
||||
// Navigate to checkout page with cart data
|
||||
const cartData = encodeURIComponent(JSON.stringify(this.items));
|
||||
window.location.href = `/checkout?cart=${cartData}`;
|
||||
}
|
||||
|
||||
saveCart() {
|
||||
localStorage.setItem('cart_items', JSON.stringify(this.items));
|
||||
}
|
||||
|
||||
updateCartDisplay() {
|
||||
const cartCount = document.querySelector('.cart-count');
|
||||
const cartTotal = document.querySelector('.cart-total');
|
||||
|
||||
if (cartCount) cartCount.textContent = this.items.length;
|
||||
if (cartTotal) cartTotal.textContent = `${this.getTotal()} TFC`;
|
||||
}
|
||||
}
|
||||
|
||||
// Checkout Process
|
||||
async function processCheckout(paymentMethod, cartItems) {
|
||||
try {
|
||||
showLoadingToast('Processing order...');
|
||||
|
||||
const orderData = {
|
||||
items: cartItems,
|
||||
payment_method: paymentMethod,
|
||||
total_tfc: cartItems.reduce((sum, item) => sum + item.price_tfc, 0)
|
||||
};
|
||||
|
||||
const result = await fetch('/api/checkout/process', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(orderData)
|
||||
});
|
||||
|
||||
const response = await result.json();
|
||||
|
||||
if (response.success) {
|
||||
// Clear cart
|
||||
localStorage.removeItem('cart_items');
|
||||
|
||||
// Redirect to order confirmation
|
||||
window.location.href = `/orders/${response.order_id}`;
|
||||
} else {
|
||||
showErrorToast(response.message);
|
||||
}
|
||||
} catch (error) {
|
||||
showErrorToast('Checkout failed');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## User Preference System
|
||||
|
||||
### **UX Mode Selection**
|
||||
|
||||
```html
|
||||
<!-- User Preferences - UX Mode -->
|
||||
<div class="ux-preference-setting">
|
||||
<h6>Shopping Experience</h6>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="uxMode" value="modern" id="modernUX">
|
||||
<label class="form-check-label" for="modernUX">
|
||||
<strong>Modern App Style</strong>
|
||||
<br><small>Instant purchases with wallet top-up (like OpenRouter)</small>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="uxMode" value="ecommerce" id="ecommerceUX">
|
||||
<label class="form-check-label" for="ecommerceUX">
|
||||
<strong>Traditional E-commerce</strong>
|
||||
<br><small>Shopping cart with checkout process</small>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="uxMode" value="both" id="bothUX" checked>
|
||||
<label class="form-check-label" for="bothUX">
|
||||
<strong>Both Options</strong>
|
||||
<br><small>Show both "Buy Now" and "Add to Cart" buttons</small>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Benefits of Dual UX Approach
|
||||
|
||||
### **Modern App Flow Benefits:**
|
||||
- ✅ **Speed**: Instant purchases
|
||||
- ✅ **Simplicity**: Minimal clicks
|
||||
- ✅ **Mobile-friendly**: Touch-optimized
|
||||
- ✅ **Auto-management**: Set-and-forget top-ups
|
||||
|
||||
### **Traditional E-commerce Benefits:**
|
||||
- ✅ **Bulk Shopping**: Multiple services at once
|
||||
- ✅ **Price Comparison**: Review before buying
|
||||
- ✅ **Familiar**: Standard shopping experience
|
||||
- ✅ **Planning**: Schedule deployments
|
||||
|
||||
### **Combined Advantages:**
|
||||
- 🎯 **User Choice**: Accommodate different preferences
|
||||
- 🎯 **Use Case Flexibility**: Quick single purchases OR planned bulk orders
|
||||
- 🎯 **Market Coverage**: Appeal to both app users and traditional shoppers
|
||||
- 🎯 **Conversion Optimization**: Multiple paths to purchase
|
||||
|
||||
---
|
||||
|
||||
This dual UX specification ensures the Project Mycelium appeals to both modern app users (who want instant, frictionless purchases) and traditional e-commerce users (who prefer to review and plan their purchases).
|
Reference in New Issue
Block a user