# 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 construction - `ConfigurationBuilder`: Environment variable access - `ResponseBuilder`: HTTP response handling - `ServiceFactory`: Service instantiation #### **ResponseBuilder Pattern - Critical Frontend Integration** ⚠️ **IMPORTANT**: All API responses are automatically wrapped by ResponseBuilder **Response Structure**: ```json // 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**: ```javascript // βœ… 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` and `data.display_currency` from `/api/navbar/dropdown-data` - **Wallet Balance (direct API, if used)**: `data.balance` or similar numeric field; always unwrap via `const data = result.data || result;` **Key Rules for AI Coders**: 1. **Always use**: `const data = result.data || result;` for API responses 2. **Test both**: Wrapped and unwrapped response structures 3. **Debug with**: `console.log('API response:', result);` to see actual structure 4. **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 %}` in `src/views/base.html` for page-specific includes. - Pages provide a ` ``` **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 via `json_encode()`. - Added explicit Tera init logging in `src/main.rs` so startup errors print to stderr: - File: `src/main.rs` β†’ log `Tera initialization error: {e}` before exiting. - 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 on `DOMContentLoaded`. - Always emit hydration via `` and stable container id `id="services-grid"`. - Implemented `src/static/js/services.js` to bind `.add-to-cart-btn` clicks, show auth modal on 401, listen for `serviceCreated` 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: ```html ``` - 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 using `data-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()` on `DOMContentLoaded` to hydrate UI safely under CSP. - Added delegated handler: `data-action="services.saveChanges"` β†’ calls existing `saveServiceChanges()` 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` β€” Converted `editCartItem()` & `removeCartItem()` to `data-action="cart.edit"` & `data-action="cart.remove"` - βœ… `src/views/dashboard/user.html` β€” Converted `viewBookingDetails()` & `contactProvider()` to `data-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. - __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 produce `null`. - Note: Avoid `default(value=none)` as some template contexts can treat `none` as an unresolved variable. If in doubt, prefer explicit `null` or guard with `{% if var is defined %}{{ var | json_encode() }}{% else %}null{% endif %}`. - __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”. - __Recommended pattern for hydration blocks__ - Build the JSON shape literally and encode each field: ```html ``` - __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. __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` (or `content`) limited to HTML and modal markup only. - __Don't__: - Nest `{% block scripts %}` or style blocks inside `dashboard_content`. - __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. ### 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 with `OUT=/path/to/file.log`) - **Dependencies**: Prefers `jq` for precise filtering; falls back to a sed/awk parser if `jq` is not installed. Usage examples: ```bash # 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 to `persistent_data.orders` vector - `order.rs`: `get_user_orders()` reads from UserPersistence, sorts by `created_at` DESC - `orders.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` in `src/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 persistent `UserPersistence` (email-based). This fixes buy-now invoice access. - 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` (and `update_service_request`), update both: 1) Provider `service_requests` in `user_data/{provider}.json`. 2) Buyer `service_bookings` in `user_data/{buyer}.json`. - Use stable identifiers: `request.id`, `customer_email`, and optionally `linked_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. - 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 reference `data.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 in `src/models/user.rs` (replaced with `Vec::new()`), aligning with the persistent‑data‑only policy and fixing compile errors from new fields. - Confirmed `ServiceRequest` includes `hours_worked: Option` and `notes: Option` with `#[serde(default)]`; all construction sites initialize them (e.g., `src/services/order.rs` sets `None`). - Controllers `dashboard::update_service_request` and `dashboard::update_service_request_progress` now normalize responses via `ResponseBuilder`, reload the updated request, and synchronize the buyer’s `service_bookings` with the provider’s `service_requests`. - Persistence (`UserPersistence`): added/used helpers to update buyer booking fields; persist `hours_worked` and `notes`; set `completed_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 context `service_provider_data` (e.g., `active_services`, `total_clients`, `monthly_revenue_usd`). Removed all `user.mock_data.service_provider_data.*` references. - Hydration: The `#sp-dashboard-hydration` JSON block outputs the persistent `service_provider_data` using `json_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 persistent `ServiceProviderData` via `UserPersistence` (summary metrics, services, client requests). No mock fallbacks remain. Placeholder series like `revenue_history` are empty-by-design, not mock-driven. - Verification: `cargo check` passes; manual dashboard UI test under `APP_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 any `user.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 any `sessionStorage` 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. - Backend (`src/controllers/dashboard.rs`): - Fixed `GET /api/dashboard/deployment/{id}` to return proper JSON success/failure envelopes via `ResponseBuilder`. - `json_to_app` helper reads `monthly_revenue_usd` with a soft fallback to legacy `monthly_revenue` for backward compatibility. - 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` referenced `activity.date`, but backend provided `UserActivity` without a `date` field, causing a Tera render error. - Fix: In `src/controllers/dashboard.rs`, map `UserActivity` into a template-friendly `recent_activities` table with fields: - `date`: formatted from `timestamp` as `%Y-%m-%d %H:%M` - `action`: derived from `ActivityType` (e.g., Login, Purchase, Deployment, ...) - `status`: from `metadata.status` when present; defaults to `Active` for deployments, otherwise `Completed` - `details`: from `description` - 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 attaches `MockUserData::new_user()` only when `APP_ENABLE_MOCKS` is enabled via `get_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` mock `DeploymentStat` for "Enterprise AI Suite", status was changed from "Running" β†’ "Active". - Frontend demo: `src/static/js/demo-workflow.js` emits "Active" in simulated `deploymentStatusChange` events. Next: - Audit all controllers for unconditional mock usage (e.g., `src/controllers/dashboard.rs`) and gate behind `APP_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 - Run `cargo test` and perform manual UI verification with `APP_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` β€’ 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 logic - `src/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): ```json { "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` - Frontend Guidance: - Consume `error.details` to render a consistent message: "Insufficient balance. Need $ more." (currency-aware) - Do not hardcode numbers; read from `details`. Maintain `const data = result.data || result;` wrapper tolerance. - 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 by `id`, 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 cache `user_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 singular `category_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` - Persistence: `UserPersistence` writes to `user_data/{email}.json` under `products` (single source of truth). - Aggregation (Marketplace) - `src/services/product.rs::ProductService::get_all_products()` aggregates fixtures + user products (+ optional slice products) and de-duplicates by `id`. - Category normalization applied uniformly via `canonical_category_id` (see below). - Optional dev TTL cache controlled by `APP_CATALOG_CACHE` and `APP_CATALOG_CACHE_TTL_SECS`. - Visibility (Consumer) - `src/controllers/marketplace.rs::MarketplaceController::services()` filters by canonical categories `service` and `application`, converts prices to user currency, and injects `service_products` into `src/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=` - Instant Purchase: `POST /api/wallet/instant-purchase` - ResponseBuilder envelope: Frontend unwraps with `const data = result.data || result;`. - Generalization - App providers follow the same flow; canonical `application` category is normalized and displayed on `/marketplace/applications` with equivalent pricing and purchase behaviors. #### 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 canonical `service`. - Result: User-created services stored in `user_data/{email}.json` are visible post-aggregation; controller still tolerates both `service` and `application` 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 by `include_slice_products`. - Structure: `static CATALOG_CACHE: OnceLock>` holding two buckets (with/without slices). - Entry: `CacheEntry { products: Vec, fetched_at: Instant }`. - Behavior: `get_all_products()` checks TTL and returns cached vector; on miss/expiry, recomputes via `aggregate_all_products_uncached()` and stores new entry. De-duplication semantics are preserved. - 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()` and `catalog_cache_ttl_secs()`. - 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 in `src/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 only `status = 'published'` rows for catalog queries - GIN/trigram indexes on searchable text/jsonb fields for efficient search - RLS Policies: - Owners: `INSERT/UPDATE/DELETE` where `owner_user_id = auth.uid()` - Public: `SELECT` from `public_products` only - Auth via JWT (GoTrue) used by PostgREST - Lifecycle: - Publishing controlled by `status` (draftβ†’publishedβ†’archived), separate from `availability` (e.g., InStock/OutOfStock) - Prefer soft-delete with audit columns over hard delete 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 password `password` (see `docs/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): ```dotenv 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` and `invoice_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), recomputes `item_count` from valid items, and persists cleaned carts to session and user storage. - `remove_from_cart()`, `update_cart_item_quantity()`, and `clear_cart()` save to session and, for logged-in users, to persistent JSON under `user_data/*_cart.json`. - `transfer_guest_cart_to_user()` merges guest items into the user cart on login and saves. Frontend: - Global `updateCartCount()` in `src/views/base.html` fetches `/api/cart` with `cache: 'no-store'` and updates the navbar badge. - `window.updateCartCount` is called on `DOMContentLoaded` and on a global `cartUpdated` event. - Pages that modify the cart call `window.updateCartCount()` and dispatch `cartUpdated` after changes. - `src/views/marketplace/dashboard.html` uses a locally named `updateCartCountLocal()` 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)` and `window.updateCartCount()` to update the navbar badge immediately. - Set a session flag: `sessionStorage.setItem('cartCleared', '1')`. - `setTimeout(() => window.location.reload(), 50);` - On page load: - In `DOMContentLoaded`, check the flag; if present, remove it and show a success toast. Implementation: - Guest Cart: `src/views/cart.html` - Sets `cartCleared` flag before reload. - On load, shows `showToast('Cart cleared', 'success')` and removes the flag. - Dashboard Cart (logged-in): `src/views/dashboard/cart.html` - Sets `cartCleared` flag before reload; sets `window._suppressCartLoadToast = true` to avoid false error toasts during reload. - On load, shows `showToast('Cart cleared', 'success')` and removes the flag. - Marketplace Cart View: `src/views/marketplace/cart.html` - Sets `cartCleared` flag before reload. - On load, shows local `showSuccess('Cart cleared')` and removes the flag. 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 dispatching `CustomEvent('cartUpdated', ...)`. - Global badge updater lives in `src/views/base.html` as `window.updateCartCount()` and listens to `cartUpdated`. - Reads (`GET /api/cart`): - Always include `{ cache: 'no-store', credentials: 'same-origin' }` to avoid stale data and ensure cookies/sessions. - Mutations (POST/PUT/DELETE to `/api/cart` and `/api/cart/item/{id}`): - Always include `{ credentials: 'same-origin' }`. - 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 ```rust // 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 ```rust // 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 ```mermaid 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 ```rust // 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 - **Controller**: Preference and listing endpoints already validate/accept these currencies. - File: `src/controllers/currency.rs` - **UI Fix**: Removed duplicate USD and added TFC to the currency selector. - File: `src/views/dashboard/settings.html` #### 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, plus `display_currency`, `display_amount`, `rate_used`, and `timestamp` 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`) and `display_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` and `data.display_currency` #### 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 `