80 KiB
Project Mycelium - Master Architecture Guide v2.0
Complete Single Source of Truth for AI-Assisted Development
Document Purpose: Comprehensive architectural reference consolidating ALL design decisions, implementation patterns, roadmaps, and development standards for the Project Mycelium. This serves as the definitive guide for AI coders, developers, and system architects.
Last Updated: 2025-08-15 12:41 Architecture Version: 3.2 Status: Production Implementation Active
🎯 Executive Summary
The Project Mycelium has evolved into a production-ready, industry-standard platform built on comprehensive builder pattern architecture, log-free codebase principles, and persistent data-only operations. The system eliminates all mock data, centralizes all construction patterns, and maintains zero compilation errors through systematic architectural decisions.
Key Achievements (2025)
- ✅ 881+ Log Statements Removed: Complete log-free codebase
- ✅ 245+ ResponseBuilder Patterns Migrated: 10 controllers complete, 1 in progress
- ✅ 1,120+ Lines of Code Reduced: Through builder pattern consolidation
- ✅ 100% Mock Data Elimination: Persistent data-only architecture
- ✅ Zero Compilation Errors: Clean builds maintained throughout
- ✅ Single Source of Truth: All construction patterns centralized
- ✅ TFC Credits System: Industry-standard credit model (1 TFC = 1 USD)
- ✅ Major Controllers Completed: Marketplace, Rental, Pool, Order, Simple Controllers
- ✅ Critical Milestone: Dashboard compilation errors fixed (18 errors → 0 errors)
- ✅ Public Pages Added: Changelog and Roadmap pages with comprehensive project status
- ✅ Public Controller: New PublicController for legal, changelog, and roadmap pages
- ✅ Authentication & Buy-Now Flow Fixed: Critical wallet balance issue resolved
- ✅ Middleware Authentication: Fixed route exclusion and session validation
- ✅ Frontend-Backend Integration: ResponseBuilder pattern compatibility established
- ✅ Order Management System: Complete user-centric order persistence and display
- ✅ Payment Method Persistence: Enhanced UX with last payment method remembering
- ✅ Authentication Flow Enhancement: Improved buy-now messaging and redirect to dashboard
- ✅ Preferred Currency Displayed Throughout: Navbar, Wallet, Orders, and Dashboard use server-formatted values; dashboard overview wallet label made dynamic via navbar dropdown API
🏗️ Core Architectural Principles
1. Log-Free Codebase Policy 🚫📝
Policy: Zero log::
statements in main/development branches
Implementation:
- Developers may use
log::
for troubleshooting in feature branches - All logs must be removed before merging to main/development
- Automated cleanup:
find src -name "*.rs" -exec perl -i -pe 'BEGIN{undef $/;} s/\s*log::[^;]*;//g' {} \;
Benefits:
- Clean, production-ready code
- Simplified AI-assisted development
- Reduced file complexity and size
- Eliminated performance overhead
2. Builder Pattern Architecture 🏗️
Philosophy: Single-source-of-truth construction for all complex objects
Core Builders:
SessionDataBuilder
: UserPersistentData constructionConfigurationBuilder
: Environment variable accessResponseBuilder
: HTTP response handlingServiceFactory
: Service instantiation
ResponseBuilder Pattern - Critical Frontend Integration ⚠️
IMPORTANT: All API responses are automatically wrapped by ResponseBuilder
Response Structure:
// Backend Controller Code:
ResponseBuilder::ok().json(serde_json::json!({
"success": true,
"last_payment_method": "credit_card"
})).build()
// Actual API Response (wrapped by ResponseBuilder):
{
"data": {
"success": true,
"last_payment_method": "credit_card"
},
"success": true
}
Frontend Compatibility Pattern:
// ✅ CORRECT - Handle ResponseBuilder wrapping
const response = await fetch('/api/endpoint');
const result = await response.json();
const data = result.data || result; // Handle both wrapped and unwrapped
if (data.success && data.field) {
// Use data.field
}
// ❌ INCORRECT - Direct access fails with ResponseBuilder
if (result.success && result.field) {
// This fails because actual data is in result.data.field
}
Implementation Examples:
- Orders:
data.data.orders
(nested due to ResponseBuilder + order response structure) - Payment Methods:
data.last_payment_method
(single ResponseBuilder wrapping) - Wallet Balance (Navbar dropdown):
data.wallet_balance_formatted
anddata.display_currency
from/api/navbar/dropdown-data
- Wallet Balance (direct API, if used):
data.balance
or similar numeric field; always unwrap viaconst data = result.data || result;
Key Rules for AI Coders:
- Always use:
const data = result.data || result;
for API responses - Test both: Wrapped and unwrapped response structures
- Debug with:
console.log('API response:', result);
to see actual structure - Remember: ResponseBuilder adds automatic
{"data": {...}, "success": true}
wrapper
CSP-Compliant Frontend: External JS + JSON Hydration (2025-08-11)
Policy: Zero inline scripts and zero inline event handlers. All page behavior lives in external JS with JSON hydration blocks.
Implementation:
- Externalized base and page scripts to
src/static/js/
(e.g.,base.js
,wallet.js
,statistics.js
). - Added
{% block scripts %}{% endblock %}
insrc/views/base.html
for page-specific includes. - Pages provide a
<script type="application/json" id="...">
hydration block. All injected values are server-rendered and must usejson_encode
to produce valid JSON under CSP.
Hydration example (wallet):
<script type="application/json" id="wallet-hydration">
{"currency_symbol": {{ currency_symbol | default(value='$') | json_encode() }}}
</script>
Recent Fix (root cause of server exit):
- Tera failed to parse
src/views/wallet/index.html
due to invalid filter usage inside JSON and quoting issues. - Fixed by using the named-arg form
default(value='$')
and emitting JSON viajson_encode()
. - Added explicit Tera init logging in
src/main.rs
so startup errors print to stderr:- File:
src/main.rs
→ logTera initialization error: {e}
before exiting.
- File:
- Outcome:
cargo run --bin projectmycelium
now keeps the Actix server running; template errors are clearly reported.
Benefits:
- Security: Strict CSP compliance (no inline code) reduces XSS risk.
- Maintainability: Clear separation of structure (HTML), data (hydration JSON), and behavior (external JS).
- Performance: External JS is cacheable across pages; smaller HTML payloads.
- Testability: Hydration data is deterministic JSON; easier unit/integration tests.
- Consistency: One binding pattern via
DOMContentLoaded
and data attributes, not scattered inline handlers.
Rules of use:
- Never use
onclick
/onchange
in templates; bind events in JS onDOMContentLoaded
. - Always emit hydration via
<script type="application/json" id="...">
and parse it in JS. - Always
json_encode
any value rendered into hydration JSON; prefer named-arg filters (e.g.,default(value='...')
).
Files updated:
src/static/js/base.js
(navbar/cart globals),src/static/js/wallet.js
,src/static/js/statistics.js
,src/static/js/checkout.js
,src/static/js/services.js
.src/views/base.html
(external scripts block),src/views/wallet/index.html
(hydration block fix),src/views/marketplace/checkout.html
,src/views/marketplace/services.html
.src/main.rs
(Tera initialization error logging for startup diagnostics).
Next steps to complete CSP externalization:
- Externalize remaining inline handlers across marketplace and dashboard templates (cart/checkout/orders/services, pools, user, farmer, service_provider, invoice/report print buttons) using per-page JS and hydration.
- Replace inline
window.print()
with a shared print utility and bind viadata-action="print"
. - Audit all hydration blocks to use
json_encode
and provide{}
when no data is needed.
- Replace inline
Services Page Externalization — Completed 2025-08-11
- Removed all inline scripts and
onclick
/onchange
handlers fromsrc/views/marketplace/services.html
. - Added CSP-safe hydration block:
<script type="application/json" id="services-data">{}</script>
and stable container idid="services-grid"
. - Implemented
src/static/js/services.js
to bind.add-to-cart-btn
clicks, show auth modal on 401, listen forserviceCreated
events, and render service cards without inline handlers. - Integrates with
base.js
globals when present (updateCartCount
,emitCartUpdated
).
Dashboard Orders Page Externalization — Completed 2025-08-11
- Removed all inline scripts and event handlers from
src/views/dashboard/orders.html
. - Added CSP-safe hydration block
#orders-hydration
with per-field JSON encoding:
<script type="application/json" id="orders-hydration">
{
"currency_symbol": {{ currency_symbol | default(value='$') | json_encode() }},
"display_currency": {{ display_currency | default(value='USD') | json_encode() }}
}
</script>
- Included external script:
src/static/js/dashboard_orders.js
. - Event delegation via
data-action
attributes:toggle-details
,view-invoice
,contact-support
,view-invoice-from-modal
.
- ResponseBuilder compatibility handled in JS:
const payload = result.data || result;
. - Tera parse fix: replaced quoted defaults inside JSON with named-arg defaults and
json_encode()
per field to emit valid JSON; resolved the startup error “expected a value that can be negated or an array of values”.
✅ CSP Externalization COMPLETE — 2025-08-12
ACHIEVEMENT: The entire Project Mycelium is now 100% CSP-compliant with zero inline handlers across all templates.
Dashboard Service Provider Externalization — COMPLETED:
- Removed inline handlers for availability and service creation in
src/views/dashboard/service_provider.html
by usingdata-action
attributes and external JS. - Implemented delegated handlers in
src/static/js/dashboard-service-provider.js
:availability.toggle
→toggleAvailability()
for checkbox changes (no API write).availability.update
→updateAvailability()
PUT/api/dashboard/availability
with validation and notifications.services.create
→createNewService()
opens modal, validates, submits to API, and refreshes lists.
- Fixed and initialized
loadAvailabilitySettings()
onDOMContentLoaded
to hydrate UI safely under CSP. - Added delegated handler:
data-action="services.saveChanges"
→ calls existingsaveServiceChanges()
for the Save Changes button (no inline JS). - Hydration: confirmed CSP-safe JSON block
#sp-dashboard-hydration
present and parsed in initialization. - Tera parse fix applied to
src/views/dashboard/service_provider.html
: moved page-specific styles to{% block head %}
and hydration/external scripts to{% block scripts %}
at the top level;dashboard_content
now contains only markup/modals.
Final CSP Cleanup — COMPLETED 2025-08-12:
- ✅
src/views/cart.html
— ConvertededitCartItem()
&removeCartItem()
todata-action="cart.edit"
&data-action="cart.remove"
- ✅
src/views/dashboard/user.html
— ConvertedviewBookingDetails()
&contactProvider()
todata-action="booking.view"
&data-action="provider.contact"
- ✅
src/views/dashboard/farmer.html
— Converted 6 inline handlers to data-action patterns:refreshSliceCalculations()
→data-action="slice.refresh"
syncWithGrid()
→data-action="grid.sync"
viewNodeSlices()
→data-action="node.view"
setMaintenanceMode()
→data-action="node.maintenance"
restartNode()
→data-action="node.restart"
Create Service Modal Flicker — Root Cause Fix (2025-08-12)
- Root cause: Background elements (cards, rows, service items) had broad
transition: all
and hover effects. During.modal.fade
, these hover transitions triggered expensive repaints, causing visible flicker on modal buttons. - Fix: Preserve Bootstrap fade while eliminating repaint conflicts.
- Tighten transitions to specific properties (e.g.,
box-shadow
,transform
,background-color
). - Suppress hover-driven transitions while any modal is open via
body.modal-open
rules (reset transforms/box-shadows/bg-color to static values). - Restore
.modal.fade
on#createServiceModal
to keep smooth animation. - Add light GPU compositing hints on modal buttons (
will-change
,transform: translateZ(0)
,backface-visibility: hidden
). - Verified single-initialization for delegated handlers and Enter-key submit prevention on modal forms.
- Tighten transitions to specific properties (e.g.,
- Files changed:
src/static/css/styles.css
,src/views/dashboard/service_provider.html
.
CSP Verification Results — 2025-08-12:
- ✅ Zero inline handlers found across all templates (confirmed via comprehensive audit)
- ✅ All external JS files exist and properly structured
- ✅ JSON hydration blocks in place for CSP-safe data passing
- ✅ Print utilities confirmed available
✅ COMPLETE: Global CSP Compliance Achieved (100%):
- Dashboard templates
- ✅
src/views/dashboard/wallet.html
(done) - ✅
src/views/dashboard/pools.html
(done) - ✅
src/views/dashboard/service_provider.html
(COMPLETED) - ✅
src/views/dashboard/user.html
(COMPLETED 2025-08-12) - ✅
src/views/dashboard/farmer.html
(COMPLETED 2025-08-12) - ✅
src/views/dashboard/orders.html
(done) - ✅
src/views/dashboard/cart.html
(done) - ✅
src/views/dashboard/welcome.html
(no inline handlers found)
- ✅
- Dashboard JS
- ✅
src/static/js/dashboard_pools.js
- ✅
src/static/js/dashboard-service-provider.js
(COMPLETED) - ✅
src/static/js/dashboard_user.js
(verified existing) - ✅
src/static/js/dashboard_farmer.js
(verified existing) - ✅
src/static/js/dashboard_orders.js
(done) - ✅
src/static/js/dashboard_cart.js
(done) - ✅
src/static/js/print-utils.js
(verified existing)
- ✅
- Marketplace templates
- ✅
src/views/marketplace/services.html
(done) - ✅
src/views/marketplace/checkout.html
(done) - ✅
src/views/cart.html
(COMPLETED 2025-08-12) - ✅ All other marketplace templates (no inline handlers found)
- ✅
- Marketplace JS
- ✅
src/static/js/services.js
(done) - ✅
src/static/js/checkout.js
(done) - ✅
src/static/js/cart.js
(verified existing) - ✅ All other required JS files (verified existing)
- ✅
Security & Compliance Benefits Achieved:
- ✅ Strict CSP compliance — No inline code execution vectors
- ✅ XSS risk reduction — All user interactions via external event delegation
- ✅ Maintainability — Clean separation of HTML structure, JSON data, and JS behavior
- ✅ Performance — External JS cacheable across pages, smaller HTML payloads
- ✅ Testability — Deterministic hydration JSON, easier unit/integration tests
Tera JSON Hydration & Template Safety Guidelines (Must Read)
To avoid Tera parse errors and ensure CSP-safe, valid JSON in hydration blocks, follow these rules:
-
Always encode each field individually
- Use:
{{ value | default(value=...) | json_encode() }}
per field. - Strings: use named-arg defaults, e.g.,
default(value='USD')
. - Optionals: use
default(value=null)
to producenull
. - Note: Avoid
default(value=none)
as some template contexts can treatnone
as an unresolved variable. If in doubt, prefer explicitnull
or guard with{% if var is defined %}{{ var | json_encode() }}{% else %}null{% endif %}
.
- Use:
-
Do NOT create an object literal inside a single interpolation
- Don’t:
{{ { "user_currency": user_currency, "cart_details": cart_details } | json_encode }}
- This can trigger: “expected a value that can be negated or an array of values”.
- Don’t:
-
Recommended pattern for hydration blocks
- Build the JSON shape literally and encode each field:
<script type="application/json" id="checkout-hydration"> { "user_currency": {{ user_currency | default(value='USD') | json_encode() }}, "cart_details": {{ cart_details | default(value=none) | json_encode() }} } </script>
-
When to use
safe
type="application/json"
blocks are not executed; JSON encoding avoids HTML escaping.safe
is typically unnecessary if you encode each field. If you emit one fully-encoded JSON string, you may append| safe
.
-
General Tera tips
- Prefer named arguments in filters:
default(value='...')
. - Never mix template control structures inside JSON literals.
- Log startup errors: we print Tera init errors in
src/main.rs
to surface issues early. - Validate JSON quickly by copying the block into a linter when in doubt.
- Prefer named arguments in filters:
Checkout fix (2025-08-11): src/views/marketplace/checkout.html
switched from a single interpolated object to the per-field encoding pattern above, resolving the runtime Tera parse error.
Tera Block Structure – Common Pitfall (Fixed 2025-08-12)
Tera blocks cannot be nested inside other blocks. Child templates must keep structural blocks (head
, scripts
) at the top level and place page markup inside the content block only.
-
Do:
- Put page styles inside
{% block head %}...{% endblock %}
. - Put hydration JSON and external JS includes inside
{% block scripts %}...{% endblock %}
. - Keep
dashboard_content
(orcontent
) limited to HTML and modal markup only.
- Put page styles inside
-
Don't:
- Nest
{% block scripts %}
or style blocks insidedashboard_content
.
- Nest
-
Recent fix:
src/views/dashboard/service_provider.html
raised an "unexpected{% endblock %}
" parse error due to nested blocks. We refactored by moving:- Styles → top-level
{% block head %}
- Hydration JSON (
#sp-dashboard-hydration
) and external JS includes → top-level{% block scripts %}
- Result: Tera parses cleanly; CSP structure is preserved.
- Styles → top-level
DevX: Rust Error-Only Compilation Logs — Added 2025-08-12
To streamline debugging and keep output readable, we added a small toolchain to capture only Rust compiler errors (no warnings) from cargo check
:
- Script:
scripts/dev/cargo-errors.sh
- Make targets:
make check-errors
make fixtures-errors
(runs with fixtures env)
- Output:
/tmp/cargo_errors_only.log
(override withOUT=/path/to/file.log
) - Dependencies: Prefers
jq
for precise filtering; falls back to a sed/awk parser ifjq
is not installed.
Usage examples:
# Standard
make check-errors
# Fixtures mode
make fixtures-errors
# Custom output path
OUT=/tmp/my_errors.log make check-errors
# Quick count/peek
grep -c '^error' /tmp/cargo_errors_only.log
sed -n '1,80p' /tmp/cargo_errors_only.log
Behavior:
- Suppresses warnings entirely; logs only error diagnostics.
- Returns
cargo check
exit code (non‑zero when errors present), so it fits CI or hooks. - Color is disabled via
CARGO_TERM_COLOR=never
to keep the log clean.
3. Persistent Data Only 💾
Policy: No mock data in production code
- All data operations use
user_data/
directory - Real user data drives marketplace content
- MockDataService completely eliminated
User-Centric Data Storage Pattern 🎯
Architectural Decision: Orders stored as part of user's persistent data (UserPersistence
)
- Localized Source of Truth: Each user owns their complete data set
- Industry Standard: Follows GDPR compliance and data portability requirements
- Implementation: Orders stored in
UserPersistentData.orders
vector - Data Flow: Purchase → UserPersistence → API → ResponseBuilder → Frontend
- Benefits: Simplified data management, easier account operations, better user privacy
Order Management Implementation:
instant_purchase.rs
: Orders pushed topersistent_data.orders
vectororder.rs
:get_user_orders()
reads from UserPersistence, sorts bycreated_at
DESCorders.html
: Frontend handles nested ResponseBuilder JSON structure (data.data.orders
)- ResponseBuilder Compatibility: All API responses wrapped in
{"data": {...}, "success": true}
Marketplace Order Invoices (2025-08-09)
- Endpoint:
GET /orders/{id}/invoice
renders an HTML invoice view for printing. - Controller:
OrderController::get_order_invoice
insrc/controllers/order.rs
.- Ownership check prefers
session["user_email"]
for user identity. - Dual-source order retrieval: first check in-memory
OrderStorage
; if not found, fallback to persistentUserPersistence
(email-based). This fixes buy-now invoice access.
- Ownership check prefers
- Template:
src/views/marketplace/order_invoice.html
renders order id, date, items, qty, unit price, line totals, subtotal/total, payment method, billing email, and includes a Print button. - Frontend UI:
src/views/dashboard/orders.html
opens the HTML view in a new tab.- CTA text changed to "View Invoice" with eye icon.
- JS handlers renamed:
downloadInvoice
→viewInvoice
,downloadInvoiceFromModal
→viewInvoiceFromModal
.
- Not implemented (by design): direct download API (
/api/orders/{id}/invoice
).- Rationale: Current UX uses "View Invoice" + browser Print → Save as PDF; avoids extra dependencies/complexity; no immediate need for programmatic downloads. Can be added later if integrations require it.
Service Requests and Bookings Flow — Current Status and Fix Plan (2025-08-14)
• Current state
- Providers can create services; buyers can purchase them.
- Buyer sees entries under “My Service Requests” (
/dashboard/user
). - Provider sees entries under “Service Requests” (
/dashboard/service-provider
). - Provider lookup/persistence fixed: requests saved under correct provider file.
• Issues observed
- Status mismatch: when provider accepts (In Progress), buyer still sees Pending.
- View CTA error: “Cannot read properties of undefined (reading 'id')” (likely envelope/shape mismatch).
- Update CTA causes the request to disappear (tab filtering not refreshed or destructive overwrite/mock fallback).
- Buyer booking details view shows only a success button (insufficient detail rendering).
• Backend actions
- Synchronize status updates across users:
- In
DashboardController::update_service_request_progress
(andupdate_service_request
), update both:- Provider
service_requests
inuser_data/{provider}.json
. - Buyer
service_bookings
inuser_data/{buyer}.json
.
- Provider
- Use stable identifiers:
request.id
,customer_email
, and optionallylinked_booking_id
. - Ensure non-destructive in-place updates via
UserPersistence
(find by id; mutate fields; keep others). - Add structured logs: before/after counts, updated ids, file paths; bubble errors.
- In
- Normalize details endpoints to a consistent DTO and ResponseBuilder envelope:
GET /api/dashboard/service-requests/{id}/details
,.../completed-details
,.../report
→ return{ success, data: { id, status, product, customer_email, ... } }
.
• Frontend actions
- Always unwrap API with
const data = result.data || result;
and referencedata.id
. - After updates, re-render tables and migrate rows between tabs (Pending → In Progress → Completed) instead of removing.
- Improve buyer “My Service Bookings” details to render provider/product/status timeline.
- Guard null/undefined records and missing properties.
• Testing
- E2E: provider creates → buyer purchases → provider accepts.
- Assert provider request status and buyer booking status both advance to In Progress.
- API contract tests: details endpoints include
id
and consistent field names.
• Observability
- Add structured logging to update endpoints and persistence helpers to trace ids, counts, and file paths during updates.
Progress Update — Service Requests & Bookings (2025-08-14 13:35)
- Removed inline mock
client_requests
arrays insrc/models/user.rs
(replaced withVec::new()
), aligning with the persistent‑data‑only policy and fixing compile errors from new fields. - Confirmed
ServiceRequest
includeshours_worked: Option<f64>
andnotes: Option<String>
with#[serde(default)]
; all construction sites initialize them (e.g.,src/services/order.rs
setsNone
). - Controllers
dashboard::update_service_request
anddashboard::update_service_request_progress
now normalize responses viaResponseBuilder
, reload the updated request, and synchronize the buyer’sservice_bookings
with the provider’sservice_requests
. - Persistence (
UserPersistence
): added/used helpers to update buyer booking fields; persisthours_worked
andnotes
; setcompleted_date
when status is Completed or progress ≥ 100. - Build status:
cargo check
passes; only warnings remain (unrelated to this flow).
Next:
- Remove remaining inline mocks (e.g.,
revenue_history
) and source exclusively from persistent storage. - Audit update paths to ensure
APP_ENABLE_MOCKS=0
has zero mock fallbacks.
Progress Update — Service Provider Dashboard Persistent Data (2025-08-15 08:46)
- Template refactor:
src/views/dashboard/service_provider.html
now binds exclusively to injected persistent contextservice_provider_data
(e.g.,active_services
,total_clients
,monthly_revenue_usd
). Removed alluser.mock_data.service_provider_data.*
references. - Hydration: The
#sp-dashboard-hydration
JSON block outputs the persistentservice_provider_data
usingjson_encode()
for CSP-safe parsing. - Frontend JS:
src/static/js/dashboard-service-provider.js
aligned to persistent USD fields (monthly_revenue_usd
,total_revenue_usd
,price_per_hour_usd
). Fallback init payload keys updated to*_usd
. ResponseBuilder unwrap pattern enforced (const data = result.data || result;
). Removed legacy/mock field usage. - Backend controller:
DashboardController::service_provider_section
constructs and injects persistentServiceProviderData
viaUserPersistence
(summary metrics, services, client requests). No mock fallbacks remain. Placeholder series likerevenue_history
are empty-by-design, not mock-driven. - Verification:
cargo check
passes; manual dashboard UI test underAPP_ENABLE_MOCKS=0
confirms cards, tables, and charts render from persistent data/hydration.
Next:
- Apply the same persistent-only mapping to
/dashboard/app-provider
and/dashboard/user
(templates + JS + controller sections). Ensure*_usd
naming in UI logic and remove anyuser.mock_data
access. - Replace/remove any remaining placeholder arrays (e.g.,
revenue_history
) with persisted metrics or clearly mark as not-yet-implemented (no mock values).
Progress Update — App Provider Dashboard Persistent Data (2025-08-15 10:30)
- Frontend JS (
src/static/js/dashboard-app-provider.js
):- Removed legacy
monthly_revenue
fallbacks and anysessionStorage
merges; all revenue logic uses persistent*_usd
fields only (e.g.,monthly_revenue_usd
). - Treated deployment status "Running" as "Active" for UI consistency.
- Exposed
window.__appProviderDashboard
for modal helpers to estimate revenue. - Updated deployment details modal to use estimated deployment revenue derived from app-level revenue.
- Removed legacy
- Backend (
src/controllers/dashboard.rs
):- Fixed
GET /api/dashboard/deployment/{id}
to return proper JSON success/failure envelopes viaResponseBuilder
. json_to_app
helper readsmonthly_revenue_usd
with a soft fallback to legacymonthly_revenue
for backward compatibility.
- Fixed
- Verification: UI tested under
APP_ENABLE_MOCKS=0
; charts, tables, and modals source only persistent data. ResponseBuilder unwrap pattern enforced on the frontend.
Progress Update — Dashboard Overview Activities Mapping — COMPLETED (2025-08-15 10:30)
- Root cause:
src/views/dashboard/index.html
referencedactivity.date
, but backend providedUserActivity
without adate
field, causing a Tera render error. - Fix: In
src/controllers/dashboard.rs
, mapUserActivity
into a template-friendlyrecent_activities
table with fields:date
: formatted fromtimestamp
as%Y-%m-%d %H:%M
action
: derived fromActivityType
(e.g., Login, Purchase, Deployment, ...)status
: frommetadata.status
when present; defaults toActive
for deployments, otherwiseCompleted
details
: fromdescription
- Outcome:
/dashboard
renders successfully with persistent activities. No template changes required; context now matches template expectations.
Progress Update — Mock Gating & Status Normalization (2025-08-15 12:41)
- Backend: Gated legacy mock initialization in OAuth flow.
src/controllers/gitea_auth.rs
now attachesMockUserData::new_user()
only whenAPP_ENABLE_MOCKS
is enabled viaget_app_config().enable_mock_data()
. - Model/Docs: Normalized deployment status nomenclature to “Active”. Updated
src/services/slice_calculator.rs
comment from "Running" → "Active" for deployment status examples. - Build:
cargo check
passing after changes (warnings only).
Recent related changes:
- Mock data normalization: In
src/models/user.rs
mockDeploymentStat
for "Enterprise AI Suite", status was changed from "Running" → "Active". - Frontend demo:
src/static/js/demo-workflow.js
emits "Active" in simulateddeploymentStatusChange
events.
Next:
- Audit all controllers for unconditional mock usage (e.g.,
src/controllers/dashboard.rs
) and gate behindAPP_ENABLE_MOCKS
. - Normalize remaining "Running" → "Active" across:
- Rust builders:
src/models/builders.rs
(DeploymentStatBuilder
default status) - Frontend:
src/static/js/marketplace-integration.js
,src/static/js/dashboard-user.js
- Templates: any status badge strings
- Rust builders:
- Run
cargo test
and perform manual UI verification withAPP_ENABLE_MOCKS=0
.
User Data Loading & Scan Hardening — COMPLETED 2025-08-14 15:29
• Problem
- Multiple modules scanned
user_data/
broadly and attempted to parse non-user fixture files (e.g.,session_data.json
, carts, aggregated fixtures), causing serde parse errors and runtime failures.
• Design Decision
- Enforce a strict, uniform filter for per-user JSON files across the entire codebase.
- Criteria for a valid user file:
- Filename ends with
.json
- Filename contains
_at_
(email encoding) - Filename does NOT contain
_cart
- Filename is not
session_data.json
- Filename ends with
• Implementation (Rust)
- Updated directory scans to apply the filter in:
src/services/node_marketplace.rs
→get_all_marketplace_nodes()
,get_all_slice_combinations()
src/services/node_rental.rs
→find_node_owner()
src/services/order.rs
→find_app_provider()
,find_service_provider()
src/controllers/dashboard.rs
→ deployment counting logicsrc/utils/data_cleanup.rs
→DataCleanup::cleanup_all_users()
src/utils/data_validator.rs
→DataValidator::validate_all_user_files()
- Confirmed existing aggregators in
src/services/user_persistence.rs
already applied equivalent filtering for services/apps/products.
• Behavior & Guarantees
- Only real per-user files are parsed; non-user fixtures are ignored.
- Eliminates deserialization errors and runtime crashes from non-user files.
- Provider dashboard data accesses go through
UserPersistence
; no production mock fallbacks (APP_ENABLE_MOCKS=0
).
• Build & Verification
cargo check
passed after changes.- Integration tests that parse user JSON remain valid; further E2E will confirm dashboard stability.
Insufficient Balance – Unified Error Contract (2025-08-09)
- Decision: Standardize the API error response for insufficient funds across checkout, buy-now, and cart-related validations.
- Status Code: Recommend 402 Payment Required as the single status for insufficient funds. If current implementations differ, document and migrate to 402.
- Canonical Response (via ResponseBuilder):
{
"success": false,
"error": {
"code": "INSUFFICIENT_FUNDS",
"message": "Insufficient balance",
"details": {
"currency": "USD",
"wallet_balance_usd": 0,
"required_usd": 0,
"deficit_usd": 0
}
}
}
- Apply in:
- Controllers/Services that perform funds checks:
src/controllers/order.rs
,src/services/order.rs
,src/services/instant_purchase.rs
- Wallet-dependent controllers:
src/controllers/wallet.rs
,src/controllers/pool.rs
,src/controllers/rental.rs
- Controllers/Services that perform funds checks:
- Frontend Guidance:
- Consume
error.details
to render a consistent message: "Insufficient balance. Need $ more." (currency-aware) - Do not hardcode numbers; read from
details
. Maintainconst data = result.data || result;
wrapper tolerance.
- Consume
- Testing:
- API tests: assert status code and JSON shape for checkout and buy-now flows (and cart validations if applicable).
- UI tests/steps: verify consistent rendering and clear CTAs (e.g., "Add Funds").
- Compatibility:
- If legacy shapes exist, document temporary adapter logic and a removal timeline.
Product Data Architecture: User-Owned Products & Derived Catalog (2025-08-10)
Decision: Products are owned by the creating user (single source of truth). The marketplace catalog is a derived read model. Avoid dual writes.
- Single Source of Truth (now): user-persistent storage via
UserPersistence
(per-user JSON) holds canonical product records owned by that user (provider_id
/user_email
). - Catalog (read model):
ProductService
aggregates user-owned products (and fixture seeds in fixtures mode), dedupes byid
, and derives categories at runtime. Do not write to the catalog directly. - Fixtures Mode:
user_data/products.json
is seed/demo-only and not a write target. Optionally, a dev-only generated cacheuser_data/catalog.products.json
may be produced by an indexing task and must be marked as generated. - Implemented: id-based deduplication in
ProductService::get_all_products()
prevents overlap between seeds and user-owned items. Later sources override earlier ones to honor the SOT. - Consistency:
ProductService::get_product_by_id()
now queries the aggregated, de-duplicated catalog to ensure the same precedence rules apply to detail views.
Category ID Normalization (Fixtures) — 2025-08-10
- Rationale: Historical fixture data used plural/alias category IDs that did not match frontend filters/routes.
- Implementation: During fixture load,
ProductService
normalizes category IDs to canonical singular forms (e.g., "applications" → "application", "gateways" → "gateway"). - Data Hygiene:
user_data/products.json
is updated to store singularcategory_id
values. - Outcome: All marketplace category views (
/marketplace/applications
,/marketplace/gateways
, etc.) display the correct products.
Provider → Marketplace → Consumer Flow — Implemented 2025-08-12
- Creation (Provider)
- Service/App creation via dashboard APIs:
- Services:
GET/POST /api/dashboard/services
,PUT /api/dashboard/services/{id}
,DELETE /api/dashboard/services/{id}
- Apps:
GET/POST /api/dashboard/apps
,PUT /api/dashboard/apps/{id}
,DELETE /api/dashboard/apps/{id}
- Generic products:
GET/POST /api/dashboard/products
- Services:
- Persistence:
UserPersistence
writes touser_data/{email}.json
underproducts
(single source of truth).
- Service/App creation via dashboard APIs:
- Aggregation (Marketplace)
src/services/product.rs::ProductService::get_all_products()
aggregates fixtures + user products (+ optional slice products) and de-duplicates byid
.- Category normalization applied uniformly via
canonical_category_id
(see below). - Optional dev TTL cache controlled by
APP_CATALOG_CACHE
andAPP_CATALOG_CACHE_TTL_SECS
.
- Visibility (Consumer)
src/controllers/marketplace.rs::MarketplaceController::services()
filters by canonical categoriesservice
andapplication
, converts prices to user currency, and injectsservice_products
intosrc/views/marketplace/services.html
.- Template contract: Each entry is
{ product, price, formatted_price }
. Page is CSP-compliant with JSON hydration and external JS (src/static/js/services.js
).
- Purchase Flows
- Add to Cart:
POST /api/cart/add
→OrderController::add_to_cart
. - Buy Now:
- Affordability:
GET /api/wallet/check-affordability?amount=<Decimal>
- Instant Purchase:
POST /api/wallet/instant-purchase
- Affordability:
- ResponseBuilder envelope: Frontend unwraps with
const data = result.data || result;
.
- Add to Cart:
- Generalization
- App providers follow the same flow; canonical
application
category is normalized and displayed on/marketplace/applications
with equivalent pricing and purchase behaviors.
- App providers follow the same flow; canonical
Category Normalization (User Products) — 2025-08-12
- Problem: Providers historically saved subcategory IDs (e.g.,
Consulting
,Deployment
) causing products to be filtered out of/marketplace/services
. - Solution:
src/services/product.rs::canonical_category_id
maps professional service subcategories (Consulting, Deployment, Support, Training, Development, Maintenance) to canonicalservice
. - Result: User-created services stored in
user_data/{email}.json
are visible post-aggregation; controller still tolerates bothservice
andapplication
during transition.
Catalog Dev Cache (Development) — 2025-08-10
- Purpose: Speed up local development by caching the aggregated catalog derived from fixtures, user-owned products, and optional slice combinations.
- Implementation: In-memory TTL cache inside
ProductService
keyed byinclude_slice_products
.- Structure:
static CATALOG_CACHE: OnceLock<Mutex<CatalogCache>>
holding two buckets (with/without slices). - Entry:
CacheEntry { products: Vec<Product>, fetched_at: Instant }
. - Behavior:
get_all_products()
checks TTL and returns cached vector; on miss/expiry, recomputes viaaggregate_all_products_uncached()
and stores new entry. De-duplication semantics are preserved.
- Structure:
- Configuration:
- Flags:
APP_CATALOG_CACHE
(true/false),APP_CATALOG_CACHE_TTL_SECS
(u64 seconds). - Defaults: Development/Test enabled with TTL=5s; Production disabled unless explicitly enabled.
- Accessors:
AppConfiguration::is_catalog_cache_enabled()
andcatalog_cache_ttl_secs()
.
- Flags:
- Scope & Consistency:
- Caches only the aggregated catalog vector; downstream helpers (e.g., categories) continue to derive from that consistent list.
- Slice toggle maintains distinct caches; category normalization and id-based dedupe remain intact.
- Invalidation & Non-goals (Phase 0):
- No write-through invalidation yet; rely on small TTL for freshness during dev.
- Manual bust options: restart the server or wait for TTL to lapse. Changing env TTL requires restart to take effect.
- Code pointers:
src/services/product.rs::ProductService::get_all_products()
,aggregate_all_products_uncached()
; configuration insrc/config/builder.rs
. - Generated artifacts: If you generate
user_data/catalog.products.json
, keep it out of VCS (e.g., add to.gitignore
). - Acceptance:
- Manual test: results update after TTL; no duplicate products; category pages reflect normalized IDs.
- Build:
cargo check
passes.
- Phase Roadmap:
- Phase 0 (now): In-memory TTL cache for dev.
- Phase 1: Optional dev-only cache-bust endpoint or keyboard shortcut in debug UI.
- Phase 2: Optional fine-grained caches (by category/provider) or Redis toggle for production scalability.
Marketplace Overview Composition & De-duplication — 2025-08-10
- Overview Sections: The dashboard composes multiple product sections, notably "Featured Items" (curated) and "Popular Applications" (category-filtered).
- De-duplication Rule: Items already rendered in "Featured Items" are excluded from "Popular Applications" to prevent duplicate cards.
- Implementation:
src/controllers/marketplace.rs
collects featured product IDs into a set and filters the popular list prior to price conversion and render. - Scope: De-duplication is local to the overview page; category/detail pages show full results without cross-section filtering.
Migration Blueprint: PostgreSQL + PostgREST
- Tables:
users(id uuid pk, email text unique, ...)
products(id uuid pk, owner_user_id uuid fk, name text, description text, category_id text, base_price numeric(18,8), base_currency text, availability text, attributes jsonb, metadata jsonb, status text check in (draft,published,archived), created_at timestamptz, updated_at timestamptz)
categories(id text pk, name text, ... )
- Views/Indexes:
public_products
view exposing onlystatus = 'published'
rows for catalog queries- GIN/trigram indexes on searchable text/jsonb fields for efficient search
- RLS Policies:
- Owners:
INSERT/UPDATE/DELETE
whereowner_user_id = auth.uid()
- Public:
SELECT
frompublic_products
only - Auth via JWT (GoTrue) used by PostgREST
- Owners:
- Lifecycle:
- Publishing controlled by
status
(draft→published→archived), separate fromavailability
(e.g., InStock/OutOfStock) - Prefer soft-delete with audit columns over hard delete
- Publishing controlled by
Env/Mode Notes:
- Fixtures:
APP_DATA_SOURCE=fixtures
,APP_FIXTURES_PATH=./user_data
,APP_ENABLE_MOCKS=0
- Mock (dev-only):
APP_DATA_SOURCE=mock APP_ENABLE_MOCKS=1
to visualize legacy mock data during development. - Personas for demos:
user1..user10@example.com
with passwordpassword
(seedocs/dev/design/current/ux/current_personas.md
) - Manual test checklist:
docs/dev/design/current/ux/manual_fixture_test_checklist.md
Quick .env for Phase 0 (fixtures/dev):
APP_DATA_SOURCE=fixtures
APP_FIXTURES_PATH=./user_data
APP_ENABLE_MOCKS=0
APP_CATALOG_CACHE=true
APP_CATALOG_CACHE_TTL_SECS=5
Roadmap to Final Marketplace (2025-08-10)
Phases are incremental and shippable; each has crisp acceptance criteria.
Phase 0: Polish fixtures/dev mode (now–short)
- Catalog dev cache: Optional generated
user_data/catalog.products.json
from aggregator; documented as generated-only. - Acceptance: cold-start marketplace loads ≥300 ms faster locally; cache invalidation documented.
- Mock cleanup: Ensure prod path never touches mock data/services; annotate remaining dev-only templates (e.g., mock timeline) and gate behind config.
- Acceptance: production run with
APP_ENABLE_MOCKS=0
has zero mock reads/writes. - Tests:
- Invoices: ownership checks, 403/404, print view loads.
- Cart badge/events: add/remove/clear flows consistent after reload.
- Marketplace dashboard loads with mocks disabled (HTTP 200).
- Rental endpoints return 404 when mocks are disabled and resource is missing.
- Acceptance: tests green in CI; fixtures-run smoke passes.
Phase 1: Unified insufficient balance contract
- Backend: Standardize on 402 Payment Required and canonical ResponseBuilder error payload across
src/controllers/order.rs
,src/services/order.rs
,src/services/instant_purchase.rs
, and wallet-related controllers. - Reference: See prompt doc
docs/dev/design/current/prompts/prompt-1.md
— section "🔥 Critical: Insufficient Balance – Unified Error Contract" for the JSON envelope and acceptance details. - Frontend: One renderer consumes
error.details
(e.g., “Insufficient balance. Need $X more.”). - Acceptance: Each major purchase flow has one insufficient-funds behavior; e2e verified.
Phase 2: Orders API enrichment — COMPLETED 2025-08-13
- Added
invoice_available
andinvoice_url
in/api/orders
and/api/orders/{id}
. - UI enables/disables invoice CTAs from payload.
- Acceptance: No dead CTAs; invoices open consistently from both list and detail.
Phase 3: Provider and catalog readiness
- Minimal “publishing status” on products (draft/published) respected by aggregator (fixtures treat all as published).
- Featured curation source-of-truth file (config JSON) for Featured Items, decoupled from categories.
- Acceptance: Only published items appear; Featured fully driven by config.
Phase 4: Search, filters, and category UX
- Add keyword search and common filters (category, price range, availability).
- Acceptance: Search/filters consistent across overview and category pages; no duplicates with Featured on overview.
Phase 5: Database migration (PostgreSQL + PostgREST)
- Implement schema and
public_products
view with RLS as per blueprint in this guide. - Wire
ProductService
reads to PostgREST in “db mode”; keep fixtures mode intact for demos. - Migration scripts + seed path for demo data.
- Acceptance: App runs in db mode with same UX; fixtures mode remains supported for demos.
Phase 6: Payments and wallet top-up
- Stripe integration to purchase TFC credits; lock rates at checkout; record payment method.
- Commission logic applied to marketplace orders.
- Acceptance: Successful top-up flows; orders complete with correct balances and auditable records.
Phase 7: Security and reliability
- CSRF, rate limiting, session hardening; structured logging where appropriate; metrics & health endpoints.
- Acceptance: Security checklist green; basic SLOs monitored.
Phase 8: Launch readiness
- CI/CD, load testing, PWA/performance polish, accessibility, documentation/runbooks.
- Acceptance: Go-live checklist complete; rollback plan defined.
4. TFC Credits System 💰
Decision: Pure ThreeFold Credits (1 TFC = 1 USD configurable)
- Eliminates complex TFP/USD conversion logic
- Industry-standard credit model (AWS/Google/Azure pattern)
- Simplified user experience and developer maintenance
5. Cart Count Consistency (Navbar Badge)
Backend (src/services/order.rs
):
OrderService::get_cart_with_details()
cleans orphaned cart items (missing products), recomputesitem_count
from valid items, and persists cleaned carts to session and user storage.remove_from_cart()
,update_cart_item_quantity()
, andclear_cart()
save to session and, for logged-in users, to persistent JSON underuser_data/*_cart.json
.transfer_guest_cart_to_user()
merges guest items into the user cart on login and saves.
Frontend:
- Global
updateCartCount()
insrc/views/base.html
fetches/api/cart
withcache: 'no-store'
and updates the navbar badge. window.updateCartCount
is called onDOMContentLoaded
and on a globalcartUpdated
event.- Pages that modify the cart call
window.updateCartCount()
and dispatchcartUpdated
after changes. src/views/marketplace/dashboard.html
uses a locally namedupdateCartCountLocal()
to avoid overriding the global function.
Result: After restarts or rebuilds, the navbar badge accurately reflects the backend cart state.
6. Cart Clear UX (Post-Reload Success Toast)
Rationale: After clearing the cart, we force a short-delayed full page reload to guarantee a consistent empty-state UI. To preserve positive UX, a success toast is shown after the reload.
Pattern:
- Before reload (after successful DELETE /api/cart):
- Call
window.emitCartUpdated(0)
andwindow.updateCartCount()
to update the navbar badge immediately. - Set a session flag:
sessionStorage.setItem('cartCleared', '1')
. setTimeout(() => window.location.reload(), 50);
- Call
- On page load:
- In
DOMContentLoaded
, check the flag; if present, remove it and show a success toast.
- In
Implementation:
- Guest Cart:
src/views/cart.html
- Sets
cartCleared
flag before reload. - On load, shows
showToast('Cart cleared', 'success')
and removes the flag.
- Sets
- Dashboard Cart (logged-in):
src/views/dashboard/cart.html
- Sets
cartCleared
flag before reload; setswindow._suppressCartLoadToast = true
to avoid false error toasts during reload. - On load, shows
showToast('Cart cleared', 'success')
and removes the flag.
- Sets
- Marketplace Cart View:
src/views/marketplace/cart.html
- Sets
cartCleared
flag before reload. - On load, shows local
showSuccess('Cart cleared')
and removes the flag.
- Sets
Notes:
- All flows include credentials where required and handle ResponseBuilder responses safely (204/non-JSON tolerant where applicable).
- This pattern ensures both guest and logged-in users receive immediate feedback post-reload without UI flicker or mixed toasts.
7. Cart Fetch & Event Standardization (2025-08-09)
To ensure consistent cart state, session handling, and UI updates across all views, cart-related reads and mutations have been standardized.
- Global Event Helper:
- Use
window.emitCartUpdated(cartCount?)
instead of manually dispatchingCustomEvent('cartUpdated', ...)
. - Global badge updater lives in
src/views/base.html
aswindow.updateCartCount()
and listens tocartUpdated
.
- Use
- Reads (
GET /api/cart
):- Always include
{ cache: 'no-store', credentials: 'same-origin' }
to avoid stale data and ensure cookies/sessions.
- Always include
- Mutations (POST/PUT/DELETE to
/api/cart
and/api/cart/item/{id}
):- Always include
{ credentials: 'same-origin' }
.
- Always include
- Robustness:
- Tolerant JSON parsing where 204/No Content or non-JSON responses can occur.
- Affected Templates:
src/views/dashboard/cart.html
src/views/marketplace/cart.html
src/views/marketplace/cart_full.html
src/views/marketplace/cart_standalone.html
src/views/cart.html
(guest)
- Outcome:
- Navbar badge updates instantly and reliably across guest and logged-in flows.
- No stale reads; session credentials are sent for all cart operations.
🗂️ System Architecture
Application Layer Structure
src/
├── controllers/ # HTTP request handlers
│ ├── auth.rs ✅ ResponseBuilder complete (10 patterns)
│ ├── wallet.rs ✅ ResponseBuilder complete (49 patterns)
│ ├── product.rs ✅ ResponseBuilder complete (7 patterns)
│ ├── currency.rs ✅ ResponseBuilder complete (12 patterns)
│ ├── marketplace.rs ✅ ResponseBuilder complete (44 patterns)
│ ├── rental.rs ✅ ResponseBuilder complete (24 patterns)
│ ├── pool.rs ✅ ResponseBuilder complete (13 patterns)
│ ├── order.rs ✅ ResponseBuilder complete (26 patterns)
│ ├── debug.rs ✅ ResponseBuilder complete (1 pattern)
│ ├── gitea_auth.rs ✅ ResponseBuilder complete (2 patterns)
│ ├── public.rs ✅ Uses render_template utility (no direct patterns)
│ └── dashboard.rs ✅ ResponseBuilder complete (331 patterns)
├── services/ # Business logic layer
│ ├── farmer.rs ✅ ServiceFactory migrated
│ ├── currency.rs ✅ ServiceFactory migrated
│ ├── user_persistence.rs ✅ ServiceFactory migrated
│ ├── session_manager.rs ✅ ServiceFactory migrated
│ ├── node_rental.rs ✅ ServiceFactory migrated
│ ├── slice_rental.rs ✅ ServiceFactory migrated
│ └── order.rs ✅ ServiceFactory migrated
├── models/ # Data structures and builders
│ └── builders.rs ✅ SessionDataBuilder complete
├── utils/ # Utility functions and builders
│ ├── response_builder.rs ✅ Centralized HTTP responses
│ ├── configuration.rs ✅ ConfigurationBuilder complete
│ ├── mod.rs ✅ render_template utility integrated with ResponseBuilder (HTML support)
│ └── data_cleanup.rs ✅ Log-free utilities
└── user_data/ # Persistent data storage
├── *.json # User persistent data files
└── *_cart.json # User cart persistence
📊 Implementation Status
Completed Migrations ✅
1. Log-Free Codebase (100% Complete)
- Scope: Entire codebase (24 files)
- Impact: 881+ log statements removed
- Result: Clean, production-ready code
2. SessionDataBuilder (100% Complete)
- Scope: All UserPersistentData construction
- Impact: ~800 lines of code reduced
- Usage:
SessionDataBuilder::load_or_create(email)
3. ConfigurationBuilder (100% Complete)
- Scope: All environment variable access
- Impact: ~150 lines of code reduced
- Usage:
ConfigurationBuilder::new().jwt_secret().build()
4. ServiceFactory (100% Complete)
- Scope: All service instantiation
- Impact: ~100+ lines of code reduced
- Usage:
ServiceFactory::currency_service()
5. ResponseBuilder (521 patterns complete)
- Auth Controller: 10/10 patterns ✅
- Wallet Controller: 49/49 patterns ✅
- Product Controller: 7/7 patterns ✅
- Currency Controller: 12/12 patterns ✅
- Marketplace Controller: 44/44 patterns ✅
- Rental Controller: 24/24 patterns ✅
- Pool Controller: 13/13 patterns ✅
- Order Controller: 26/26 patterns ✅
- Debug Controller: 1/1 patterns ✅
- Gitea Auth Controller: 2/2 patterns ✅
- Public Controller: ✅ Uses render_template utility (no direct patterns)
- Dashboard Controller: 331/331 patterns ✅ (COMPLETE - 100% migrated)
- Utils Module: 1/1 patterns ✅ (render_template function complete with HTML support)
Completed ✅
1. Dashboard Controller ResponseBuilder Migration Complete
- Status: ✅ COMPLETE - All 331/331 patterns successfully migrated
- Achievement: 100% ResponseBuilder pattern coverage across entire codebase
- Patterns Migrated: 17 HttpResponse patterns including redirects, JSON responses, and error handling
- Quality: Zero compilation errors maintained throughout entire migration
- Testing: Full functional verification completed - dashboard application runs successfully
🛠️ Technical Specifications
ResponseBuilder API
// Success responses
ResponseBuilder::ok().json(data).build()
// Error responses
ResponseBuilder::bad_request().json(error_data).build()
ResponseBuilder::unauthorized().json(auth_error).build()
ResponseBuilder::internal_error().json(server_error).build()
// Specialized responses
ResponseBuilder::not_found().json(not_found_error).build()
ResponseBuilder::payment_required().json(payment_error).build()
// Plain text responses
ResponseBuilder::internal_error().body("Template rendering failed").build()
SessionDataBuilder Pattern
// Create new user
let user_data = SessionDataBuilder::new_user(email);
// Load existing or create new
let user_data = SessionDataBuilder::load_or_create(email);
// Automatic field inclusion via Default
UserPersistentData {
user_email: email.to_string(),
wallet_balance_usd: dec!(0),
..Default::default() // Includes all new fields automatically
}
🚀 Strategic Roadmap
Database Evolution: Supabase Architecture
Current State
- Storage: JSON file-based (
user_data/
directory) - Scalability: Limited to single-node deployment
- Features: Basic CRUD operations
Target Architecture: Self-Hosted Supabase
- Database: PostgreSQL with ACID compliance
- API: PostgREST auto-generated REST endpoints
- Auth: GoTrue JWT-based authentication
- Real-time: WebSocket subscriptions
- Management: Supabase Studio web interface
Three-Phase Deployment Strategy
Phase 1: Development/Testing
- Local Ubuntu 24.04 with Docker Compose
- Complete TFP→TFC refactor
- Migrate from JSON to PostgreSQL
- Access: http://localhost:8000
Phase 2: Production (Single Node)
- ThreeFold Grid Ubuntu 24.04 VM
- Same Docker Compose as development
- Production deployment with acceptable SPOF
- Cost-effective, decentralized
Phase 3: High Availability
- k3s cluster with multiple masters + workers
- Tools: tfgrid-k3s or k3scluster
- Zero downtime, automatic failover
- Horizontal scaling capabilities
Complete Marketplace Ecosystem
Payment Integration Strategy
graph TD
A[User Browses Marketplace] --> B[Selects App/VM/Service]
B --> C[Add to Cart]
C --> D[Review Cart]
D --> E{Payment Method}
E -->|Has TFC Credits| F[Pay with TFC]
E -->|Needs Credits| G[Buy TFC with Stripe]
G --> H[Stripe Payment]
H --> I[TFC Credits Added]
I --> F
F --> J[Service Deployment Queue]
J --> K[TFC → TFT Conversion]
K --> L[ThreeFold Grid Deployment]
L --> M[Service Active]
Revenue Model & Commission Structure
- Marketplace Commission: 5-15% on all transactions
- Payment Processing: Stripe fees (2.9% + $0.30)
- Grid Deployment: TFT conversion at market rates
- Provider Revenue: 85-95% after commissions
Deployment Automation Pipeline
// Core deployment service structure
pub struct DeploymentJob {
pub id: String,
pub user_id: String,
pub service_spec: ServiceSpec,
pub tfc_amount: Decimal,
pub status: DeploymentStatus,
}
impl DeploymentQueue {
pub async fn process_deployment(&self, job: DeploymentJob) -> Result<(), DeploymentError> {
// 1. Calculate commission
let commission = job.tfc_amount * self.commission_rate;
let deployment_amount = job.tfc_amount - commission;
// 2. Convert TFC to TFT
let tft_amount = self.convert_tfc_to_tft(deployment_amount).await?;
// 3. Deploy to ThreeFold Grid using GridDriver
let deployment = self.grid_driver.deploy_service(&job.service_spec, tft_amount).await?;
// 4. Update user with deployment details
self.update_user_deployment(job.user_id, deployment).await?;
Ok(())
}
}
ThreeFold Grid Integration
GridDriver: Official ThreeFold Grid deployment interface
- Repository: https://github.com/threefoldtech/griddriver
- Purpose: Standardized API for ThreeFold Grid deployments
- Features: VM deployment, Kubernetes clusters, storage allocation
- Integration: Direct Rust bindings for marketplace automation
- Benefits: Official support, maintained by ThreeFold team, production-ready
📋 Development Standards
Code Quality Requirements
- Zero Compilation Errors: All migrations maintain clean builds
- Minimal Warnings: Only unused variable warnings acceptable
- Builder Pattern Usage: Mandatory for complex object construction
- Persistent Data Only: No mock data in production code
- Log-Free Code: No
log::
statements in main/development branches
Migration Methodology
- Manual Systematic Migration: Preferred over automated scripts
- Bulk All-at-Once Edits: Efficient for simple controllers
- Section-by-Section: For complex controllers (dashboard, order)
- Compilation Verification:
cargo check
after each batch - Exact Target Content: Precise pattern matching to avoid errors
🔧 Decision Trail & Historical Context
Decision #001: TFP → TFC Credits System Refactor
Date: 2025-08-04
Status: ✅ APPROVED - Implementation Complete
Problem Statement
The marketplace used a hybrid TFP (ThreeFold Points) to USD conversion system that created:
- Complex conversion logic throughout the codebase
- Confusing user experience with dual currency displays
- Maintenance overhead with exchange rate calculations
Solution: TFC (ThreeFold Credits)
- Model: 1 TFC = 1 USD (configurable)
- Benefits: Industry standard (AWS/Google/Azure pattern)
- Implementation: Global rename TFP → TFC, remove conversion logic
- User Experience: Simple mental model, familiar credit system
Decision #002: Log-Free Codebase Policy
Date: 2025-08-05
Status: ✅ IMPLEMENTED - 881+ logs removed
Rationale
- Production-ready code should not contain debug logging
- Simplified AI-assisted development and code analysis
- Reduced file complexity and compilation overhead
- Industry best practice for clean codebases
Decision #003: Builder Pattern Architecture
Date: 2025-08-03
Status: ✅ IMPLEMENTED - Single source of truth
Benefits Achieved
- 95.8% compilation error reduction (24 → 0 errors)
- ~1,120+ lines of code reduction
- Future-proof field additions via
..Default::default()
- Consistent patterns across entire codebase
Decision #004: Multi-Currency Display with USD Settlement
Date: 2025-08-07
Status: ✅ IMPLEMENTED
Summary
- Design: Users can select a display currency (USD, TFC, CAD, EUR, …). All settlements occur in USD (via Stripe at a later stage).
- Backend Support: Added currencies in
src/services/currency.rs::CurrencyService::get_supported_currencies()
- TFC:
Custom("credits")
,exchange_rate_to_base = 1.0
,decimal_places = 2
,is_active = true
- CAD:
Fiat
,exchange_rate_to_base = 1.35
(placeholder),decimal_places = 2
,is_active = true
- EUR: already supported
- TFC:
- Controller: Preference and listing endpoints already validate/accept these currencies.
- File:
src/controllers/currency.rs
- File:
- UI Fix: Removed duplicate USD and added TFC to the currency selector.
- File:
src/views/dashboard/settings.html
- File:
Rationale
- Standard e-commerce pattern: multi-currency display with single-currency settlement simplifies accounting and Stripe integration.
- Keeps USD as canonical base for pricing, accounting, and refunds.
Implementation Notes
- Store canonical
base_usd_amount
on orders, plusdisplay_currency
,display_amount
,rate_used
, andtimestamp
for transparency. - Server-side conversions via
CurrencyService.convert_amount()
; do not trust client-side for totals. - Navbar dropdown API (
/api/navbar/dropdown-data
) provides fully formatted wallet balance (wallet_balance_formatted
) anddisplay_currency
for consistent UI display. - Dashboard overview wallet section (
src/views/dashboard/index.html
) updates#dashboardWalletBalance
and#dashboardCurrencyCode
on load using:- Safe unwrap pattern:
const data = result.data || result;
- Values:
data.wallet_balance_formatted
anddata.display_currency
- Safe unwrap pattern:
UX Guidance
- Show both: e.g.,
Total: $123.45 USD (≈ 167.89 CAD)
and note: “final charge in USD; conversions approximate.” - On rate refresh/expiry, prompt user to accept updated totals before checkout.
Future Enhancements (Optional)
- Populate currency selector dynamically from
/api/currency/supported
to avoid UI/backend drift. - Add rate locking at checkout and audit trails for exchange rates used per order.
Decision #005: Externalized Dashboard Scripts & JSON Hydration
Date: 2025-08-11
Status: ✅ IMPLEMENTED
Summary
- Removed inline JavaScript containing template syntax from
src/views/dashboard/index.html
to eliminate template/JS lint conflicts and improve maintainability. - Introduced a safe data hydration pattern via
<script type="application/json" id="dashboard-chart-data">
that embeds server-provided values as pure JSON. - Moved dashboard logic (chart initialization and wallet balance updater) to
static/js/dashboard.js
.
Rationale
- CSP compliance and security (no inline scripts required for charts logic).
- Better caching and performance for static JS assets.
- Cleaner separation of concerns and reduced IDE false-positive lints from mixed template/JS syntax.
Implementation Notes
- Chart data (resource utilization, usage trends, user activity, deployment distribution) is emitted as JSON; the external JS reads and initializes charts accordingly.
- Wallet balance and display currency continue to come from
/api/navbar/dropdown-data
and are applied to#dashboardWalletBalance
and#dashboardCurrencyCode
at page load. - Static asset path convention:
/static/js/...
as used elsewhere in the app.
🎯 Next Steps & Priorities
Immediate (Current Sprint) ✅ COMPLETE
-
✅ Dashboard Controller Migration Complete
- ✅ MILESTONE ACHIEVED: All 331/331 patterns successfully migrated to ResponseBuilder
- ✅ 17 Pattern Types: Redirect (3), JSON Success (6), JSON Error (5), Unauthorized (1), Internal Error (1), Plain Text (1)
- ✅ Zero Compilation Errors: Clean build maintained throughout entire migration
- ✅ Full Functional Testing: Dashboard application runs successfully with all features working
-
✅ Public Pages Implementation Complete
- ✅ Added comprehensive changelog page with version history
- ✅ Added detailed roadmap page with current progress tracking
- ✅ Implemented PublicController with 7 new endpoints
- ✅ Added routes for
/changelog
and/roadmap
pages
-
✅ Authentication & Buy-Now Flow Critical Fix
- ✅ RESOLVED: Wallet balance issue where users with sufficient funds saw "insufficient balance"
- ✅ ROOT CAUSE: Frontend JavaScript expecting
{can_afford: true}
but receiving{data: {can_afford: true}, success: true}
- ✅ SOLUTION: Updated frontend to handle ResponseBuilder's nested response format
- ✅ IMPACT: Buy-now functionality now works correctly for authenticated users
- ✅ TECHNICAL: Fixed middleware route exclusion and session validation
- ✅ DEBUGGING: Added comprehensive logging to identify ResponseBuilder pattern mismatches
-
✅ Utils Module ResponseBuilder Migration Complete
- ✅ COMPLETED: Migrated 1 HttpResponse pattern in
render_template
- ✅ Applied ResponseBuilder pattern to template rendering utility
- ✅ All controllers that use template rendering now benefit from centralized pattern
- ✅ HTML response support added to ResponseBuilder architecture
- ✅ COMPLETED: Migrated 1 HttpResponse pattern in
-
✅ Builder Pattern Architecture Complete
- ✅ 100% Coverage: All 521/521 patterns across entire codebase migrated
- ✅ All Controllers: Complete ResponseBuilder implementation
- ✅ Single Source of Truth: Centralized HTTP response construction
- ✅ Architecture Goal Achieved: Complete builder pattern implementation
Short Term (Next 2-4 weeks)
-
✅ Builder Pattern Architecture Complete
- ✅ All ResponseBuilder migrations completed across entire codebase
- ✅ Zero compilation errors maintained across entire codebase
- ✅ Unused HttpResponse imports can be cleaned up
- ✅ All ResponseBuilder patterns verified and tested
-
Code Cleanup and Optimization
- Remove unused HttpResponse imports from all controllers
- Clean up any remaining unused variables or imports
- Optimize ResponseBuilder usage patterns
- Final code quality improvements
Medium Term (1-2 months)
-
Payment Integration Implementation
- Stripe integration for TFC purchases
- TFC → TFT conversion service
- Commission calculation system
-
Database Migration Planning
- Design PostgreSQL schema
- Plan JSON to SQL migration
- Supabase deployment preparation
Long Term (3-6 months)
-
Complete Marketplace Ecosystem
- Deployment automation pipeline
- ThreeFold Grid integration
- Real-time deployment status
-
High Availability Implementation
- k3s cluster deployment
- Multi-node redundancy
- Horizontal scaling capabilities
📚 Related Documentation Structure
Current Architecture Documents (./parts/
)
- Builder Pattern Architecture - Detailed builder implementation
- Builder Pattern Progress Tracker - Migration status
- Log-Free Codebase Policy - Log removal policy
- Service Factory Architecture - Service instantiation patterns
- Supabase Architecture Roadmap - Database evolution plan
- Road Taken - Historical architectural decisions
Strategic Roadmap Documents (./parts/roadmap/
)
- Complete Marketplace Roadmap - Full ecosystem vision
- Deployment Automation Spec - Technical deployment pipeline
- Payment Integration Spec - Stripe and TFC system
- Dual UX Specification - Web2/Web3 bridge design
📈 Performance Metrics
Before Architecture Implementation
- Log Statements: 881+ across 24 files
- Compilation Errors: 67+ scattered errors
- Code Duplication: ~1,120+ lines of duplicate code
- Mock Data: Scattered throughout codebase
- Response Patterns: Direct HttpResponse usage
After Architecture Implementation
- Log Statements: 0 (100% reduction)
- Compilation Errors: 0 (100% reduction)
- Code Duplication: ~1,120+ lines eliminated
- Mock Data: 100% eliminated
- Response Patterns: 521 patterns centralized (ALL controllers complete, 1 new controller added, 1 utils module complete)
Quantitative Benefits
- File Size Reduction: Significant across all migrated files
- Compilation Time: Improved due to reduced complexity
- Maintainability: Single source of truth for all patterns
- Developer Experience: Consistent patterns across codebase
- AI Assistance: Simplified code analysis and generation
- Migration Progress: 521/521 patterns complete (100% overall) 🎉
- Architecture Complete: All controllers fully migrated to ResponseBuilder
- Critical Milestone: Complete builder pattern architecture implementation achieved
- New Features: Comprehensive changelog and roadmap pages provide project transparency
- Utils Module Complete: render_template function successfully migrated with HTML support
- HTML Template Support: ResponseBuilder now supports both JSON and HTML responses
- Dashboard Controller: Largest migration component (331 patterns) successfully completed
🎉 MAJOR MILESTONE ACHIEVED (2025-08-08)
Complete Builder Pattern Architecture Implementation ✅
ACHIEVEMENT: 100% ResponseBuilder pattern coverage across entire Project Mycelium codebase
Dashboard Controller Migration Complete
- Scope: Largest remaining migration component (331 HttpResponse patterns)
- Patterns Migrated: 17 distinct HttpResponse usage types
- Redirect Patterns: 3 (
HttpResponse::Found
→ResponseBuilder::redirect
) - JSON Success Patterns: 6 (
HttpResponse::Ok
→ResponseBuilder::ok
) - JSON Error Patterns: 5 (
HttpResponse::BadRequest
→ResponseBuilder::bad_request
) - Unauthorized Pattern: 1 (
HttpResponse::Unauthorized
→ResponseBuilder::unauthorized
) - Internal Error Pattern: 1 (
HttpResponse::InternalServerError
→ResponseBuilder::internal_error
) - Plain Text Pattern: 1 (
HttpResponse::Ok
with text/plain →ResponseBuilder::ok
with content_type)
- Redirect Patterns: 3 (
Technical Excellence Maintained
- Zero Compilation Errors: Clean build maintained throughout entire migration process
- Functional Verification: Complete dashboard application testing performed
- API Compatibility: All endpoints verified to return proper HTTP responses
- Authentication Flow: Login, wallet, cart, and dashboard functionality confirmed working
Architecture Impact
- Total Patterns: 521/521 complete (100% coverage)
- All Controllers: Complete ResponseBuilder implementation
- Single Source of Truth: Centralized HTTP response construction achieved
- Future-Proof: Easy addition of new response types through ResponseBuilder
- Maintainability: Consistent response patterns across entire application
Project Status
The Project Mycelium now has complete builder pattern architecture with:
- ✅ SessionDataBuilder: 100% complete
- ✅ ConfigurationBuilder: 100% complete
- ✅ ServiceFactory: 100% complete
- ✅ ResponseBuilder: 100% complete (521/521 patterns)
- ✅ Log-Free Codebase: 100% complete
- ✅ Persistent Data Only: 100% complete
This represents the completion of the comprehensive architectural modernization initiative.
---
🔧 Previous Session Accomplishments (2025-08-07)
Critical Authentication & Buy-Now Flow Fix ✅
Problem: Users with sufficient wallet balance (e.g., $5989) were incorrectly shown "You need $X.XX more in your wallet" when attempting purchases.
Root Cause Analysis:
- Middleware Issue: Buy-now routes were excluded from authentication checks
- Session Validation: Multi-factor session validation needed enhancement
- ResponseBuilder Pattern Mismatch: Frontend expected
{can_afford: true}
but backend returned{data: {can_afford: true}, success: true}
Technical Solutions Implemented:
-
Middleware Fix (
src/middleware/mod.rs:197
):- Removed buy-now route exclusion from authentication middleware
- Ensured all purchase routes require proper authentication
-
Enhanced Session Validation (
src/controllers/auth.rs:387
):- Improved auth_status endpoint with multi-factor session validation
- Added comprehensive session state checking
-
Frontend ResponseBuilder Compatibility (
src/static/js/buy-now.js:186
):- Updated JavaScript to handle ResponseBuilder's nested response format
- Added fallback logic:
affordabilityData = affordabilityResult.data || affordabilityResult
- Maintained backward compatibility with direct response format
-
Debug Infrastructure (
src/services/instant_purchase.rs:110-130
):- Added comprehensive debugging to wallet balance loading
- Enhanced error tracking for user data persistence
- Improved logging for affordability calculations
Impact & Results:
- ✅ Authentication Flow: Now properly validates users before purchase attempts
- ✅ Wallet Balance: Correctly reads $5989 balance for user1@example.com
- ✅ Buy-Now Functionality: Successfully proceeds with purchases when funds are sufficient
- ✅ ResponseBuilder Integration: Frontend now compatible with backend response patterns
- ✅ User Experience: Eliminated false "insufficient funds" messages
Technical Debt Addressed:
- Fixed inconsistency between ResponseBuilder pattern usage and frontend expectations
- Resolved middleware authentication gaps in purchase flow
- Established proper debugging infrastructure for future troubleshooting
🧩 New Findings & Required Actions (2025-08-09)
The following updates align the implementation with existing architecture and codify next steps.
1) Marketplace Order Invoices – Endpoints, Views, Wiring
- Backend endpoints:
- GET
/orders/{id}/invoice
→ Render HTML invoice (Tera) for print/view. Implemented 2025-08-09. - Not planned:
GET /api/orders/{id}/invoice
direct download. See rationale in "Marketplace Order Invoices (2025-08-09)"; may be added later if integrations require it.
- GET
- Controller:
get_order_invoice()
implemented insrc/controllers/order.rs
with ownership checks and invoice data assembly. - Template:
src/views/marketplace/order_invoice.html
exists and renders order id, date, items, quantities, unit price, line totals, subtotal/total, payment method, billing email, and a Print button. - Frontend wiring:
src/views/dashboard/orders.html
opens/orders/{id}/invoice
in a new tab; CTA text "View Invoice"; handlers renamed:downloadInvoice
→viewInvoice
,downloadInvoiceFromModal
→viewInvoiceFromModal
. - API contract enrichment — Implemented 2025-08-13: include
invoice_available: bool
andinvoice_url: String
(empty when unavailable) in/api/orders
and/api/orders/{id}
responses to drive UI state.
2) Insufficient Balance – Unified Error Contract
- Standard error envelope when funds are insufficient (JSON):
{ "success": false, "code": "insufficient_balance", "message": "Insufficient balance", "insufficient_balance": { "required": 0.00, "available": 0.00, "shortfall": 0.00, "currency": "USD" } }
- Apply consistently via ResponseBuilder in:
src/controllers/order.rs
(checkout/place order),src/services/order.rs
(payment paths)src/services/instant_purchase.rs
(buy-now), and any wallet-dependent controllers (wallet.rs
,pool.rs
,rental.rs
) that currently emit varied structures/messages.
- Frontend handling: branch on
payload.insufficient_balance
when present and render a unified copy: "Insufficient balance. Need $X more." (shortfall with currency-aware formatting). Keepconst data = result.data || result;
pattern.
3) Cart Events, Cache, and Credentials – Standardization
- Event emission: use
window.emitCartUpdated(cartCount?)
everywhere instead of ad-hocnew CustomEvent('cartUpdated', ...)
. - Fresh reads: all
fetch('/api/cart')
calls must include{ cache: 'no-store' }
. - Mutations: all cart-changing requests must include
{ credentials: 'same-origin' }
. - Rationale: avoids stale navbar badge and ensures session coherence across logged-in and guest flows. Aligns with global updater defined in
src/views/base.html
.
4) Mock/Fixture/Stub Data – Production Gating
- Compliance audit found residual dev-only modules/usages (e.g.,
MockDataService
, selective fields insession_manager.rs
) still present in tree. Architecture requires persistent data only for production runtime. - Action:
- Introduce
AppConfig.enable_mock_data
flag (default: false in production). Gate any legacy mock readers/writers behind this flag; remove from production routes/services. - Ensure product and session flows source exclusively from persistent stores in production (
user_data/
viaUserPersistence
). - Document dev-only paths and make them opt-in for local demos/tests.
- Introduce
5) Tests & Observability
-
Add integration tests covering:
- Invoice endpoints (ownership checks, HTML view, file headers, success path)
- Insufficient balance contract across checkout and buy-now endpoints
- Cart badge update: mutation →
emitCartUpdated
→ globalupdateCartCount()
effect
-
Extend API docs to include the insufficient balance envelope and invoice routes.
-
Template Engine Parity (Tera):
- In tests, initialize Tera with the same template glob as production (e.g.,
src/views/**/*.html
). - Register all custom Tera functions before configuring routes, so templates render identically in tests and production.
- Tera syntax rule: avoid parentheses around filter expressions in conditions. Use
collection | length > 0
instead of(collection | length) > 0
.
- In tests, initialize Tera with the same template glob as production (e.g.,
Buyer and Provider Dashboard Flows — Offer → Buy → Track (2025-08-13)
- Scope: buyers see purchased services in
/dashboard/user
("My Services"); providers see incoming service requests in/dashboard/service-provider
("Service Requests"). Extend this pattern to all product types. - Data model: derive from persisted orders joined with products; ownership via
buyer_id
andseller_id
. Currency viaCurrencyService
; persistent data only (no mocks in production). - Endpoints (ResponseBuilder JSON):
- GET
/api/dashboard/user/services/purchased?product_type=service|app|bundle|any
- Items purchased by current user (buyer). Default
product_type=service
;any
returns all types.
- Items purchased by current user (buyer). Default
- GET
/api/dashboard/service-provider/requests?product_type=service|app|bundle|any
- Orders where current user is seller/provider. Include order status and buyer alias/contact where available.
- Errors: mutations related to these flows must emit the unified insufficient balance envelope (see “Insufficient Balance – Unified Error Contract”).
- GET
- Payload shape (example):
{ "success": true, "data": { "items": [ { "order_id": "ord_123", "product_id": "prod_abc", "product_type": "service", "title": "Consulting Hours", "status": "completed", "unit_price": { "amount": 99.0, "currency": "USD", "display": "$99.00" }, "quantity": 1, "buyer_id": "user_b", "seller_id": "user_a", "purchased_at": "2025-08-13T00:00:00Z" } ], "currency": "USD" } }
- Frontend bindings:
src/views/dashboard/user.html
+src/static/js/dashboard-user.js
render purchased services. Useconst data = result.data || result;
, tolerate emptyitems
.src/views/dashboard/service_provider.html
+src/static/js/dashboard-service-provider.js
render “Service Requests”.- Use
data-action
handlers only; reads use{ cache: 'no-store' }
; mutations use{ credentials: 'same-origin' }
.
- Extension to all product types:
- Drive by
product_type
filter; reuseProductService::get_all_products()
aggregation and category normalization to surface types in the correct marketplace views.
- Drive by
- Acceptance:
- Buyer sees purchased services tracked in dashboard; provider sees incoming requests; consistent currency formatting and ResponseBuilder usage.
Document Maintainer: AI Architecture Team Review Cycle: Updated with each major architectural change Approval: Required for any deviations from established patterns Distribution: All developers, AI systems, and stakeholders