Developer Docs

Tech & Electronics

The Tech vertical powers electronics retailers, SaaS vendors, gadget makers, and IT service providers with four integrated systems: product specification engine, software licensing, warranty management, and trade-in programs. Malet Owners configure these features via the Storefront Window layout system.

NOTE

These features live in the experiences subgraph โ€” the same cross-vertical Feature Plane that houses Entertainment & Experiences, Professional Services, Wellness & Beauty, and Culture & Arts. The architecture is documented in docs/architecture/18-progressive-vertical-extraction.md.


Architecture: Two-Plane Design

The Tech vertical uses the same Control + Feature plane separation as its sibling verticals:

  • Control Plane (malets subgraph): VerticalConfig feature flags decide which Tech modules are enabled per Malet โ€” specEngine, softwareLicensing, warrantyManagement, tradeInProgram.
  • Feature Plane (experiences subgraph): Self-contained SpecSheetModule and WarrantyModule. Each can be extracted to its own subgraph when a dedicated Tech vertical Team forms.
  • Extensions (services subgraph): License type and activation fields on existing Service entities.

Three new Storefront Window layout slot types are available: SPEC_COMPARISON, WARRANTY_CENTER, and TRADE_IN_PORTAL.

What Tech Reuses

Reused System From Vertical Tech Use Case
Digital Credit Wallets Entertainment Trade-in value deposited as Malet-scoped wallet balance
Gamified Loyalty Entertainment Reward repeat buyers, warranty registrations, and reviews

Product Specification Engine

Create structured, machine-readable spec sheets for products with comparison capabilities and "Works with" compatibility linking.

Spec Entries

Each SpecEntry is a key-value pair with optional unit and grouping:

Field Type Example
key String! "Processor", "RAM", "Battery"
value String! "Apple M3 Pro", "16", "22-hour"
unit String "GB", "GHz", "mAh"
group String "Performance", "Display", "Battery"

Mutations

# Add a spec entry to a product (upserts on maletId + productId)
mutation {
	upsertProductSpec(
		maletId: "m_techshop"
		productId: "prod_macbook"
		key: "Processor"
		value: "Apple M3 Pro"
		group: "Performance"
	) {
		id
		productId
		entries {
			key
			value
			unit
			group
		}
	}
}

# Add another spec entry
mutation {
	upsertProductSpec(
		maletId: "m_techshop"
		productId: "prod_macbook"
		key: "RAM"
		value: "16"
		unit: "GB"
		group: "Performance"
	) {
		id
		entries {
			key
			value
			unit
			group
		}
	}
}

# Remove a spec entry by key
mutation {
	removeProductSpecEntry(productId: "prod_macbook", key: "RAM") {
		id
		entries {
			key
			value
		}
	}
}

# Set compatible products ("Works with")
mutation {
	setCompatibleProducts(
		productId: "prod_macbook"
		compatibleProductIds: ["prod_usbc_hub", "prod_magic_mouse", "prod_sleeve_14"]
	) {
		id
		compatibleProductIds
	}
}

Queries

# Get specs for a single product (public โ€” product detail page)
query {
	productSpec(productId: "prod_macbook") {
		id
		productId
		entries {
			key
			value
			unit
			group
		}
		compatibleProductIds
	}
}

# Compare 2-4 products side-by-side
query {
	compareProductSpecs(productIds: ["prod_macbook", "prod_thinkpad", "prod_xps15"]) {
		productId
		entries {
			key
			value
			unit
			group
		}
	}
}

# All spec sheets for a Malet (Malet Owner)
query {
	maletProductSpecs(maletId: "m_techshop") {
		id
		productId
		entries {
			key
			value
			unit
			group
		}
		compatibleProductIds
	}
}

Comparison Tool

The compareProductSpecs query accepts 2-4 product IDs and returns their full spec sheets. The frontend renders a side-by-side table aligned by key:

Spec MacBook Pro 14" ThinkPad X1 Dell XPS 15
Processor Apple M3 Pro Intel i7-1365U Intel i7-13700H
RAM 16 GB 16 GB 32 GB
Storage 512 GB SSD 512 GB SSD 1 TB SSD
Battery 22 hours 15 hours 13 hours

TIP

Group specs by their group field for organized display. Common groups: "Performance", "Display", "Storage", "Battery", "Connectivity", "Physical".


Software Licensing

Extended service fields for digital license products on the existing services subgraph:

Service Fields

Field Type Description
licenseType LicenseType PERPETUAL, SUBSCRIPTION, TRIAL
maxActivations Int Maximum license activations allowed

License Types

Type Description Example
PERPETUAL One-time purchase, permanent access Desktop software, firmware updates
SUBSCRIPTION Recurring billing, time-limited access SaaS tools, cloud services
TRIAL Free time-limited evaluation 30-day trial, freemium tier

Example: Create a Licensed Software Product

mutation {
	createOneService(
		input: {
			service: {
				name: "PhotoEdit Pro โ€” Perpetual License"
				description: "Professional photo editing software with lifetime updates"
				price: 9900 # $99.00 (cents)
				maletId: "m_techshop"
				licenseType: PERPETUAL
				maxActivations: 3
			}
		}
	) {
		id
		name
		licenseType
		maxActivations
	}
}

Warranty Management

Register warranties on purchase and manage claims through a full lifecycle. Warranty is tracked via two entities: WarrantyRegistration (the coverage) and WarrantyClaim (a claim against the coverage).

Warranty Status

ACTIVE โ†’ EXPIRED (automatic on date)
       โ†’ VOIDED (manual by Malet Owner)

Claim Lifecycle

SUBMITTED โ†’ REVIEWING โ†’ APPROVED โ†’ RESOLVED
                      โ†’ DENIED

Registration Mutations

# Register warranty on purchase (Malet Owner or auto on Murchase)
mutation {
	registerWarranty(
		maletId: "m_techshop"
		productId: "prod_macbook"
		buyerId: "user_kagiso"
		murchaseId: "murch_1"
		warrantyMonths: 12
		serialNumber: "SN-2025-MACBOOK-001"
	) {
		id
		serialNumber
		registeredAt
		expiresAt
		warrantyMonths
		status
	}
}

# Void a warranty (Malet Owner)
mutation {
	voidWarranty(warrantyId: "war_1") {
		id
		status
	}
}

Claim Mutations

# Submit a warranty claim (Buyer)
mutation {
	submitWarrantyClaim(
		registrationId: "war_1"
		maletId: "m_techshop"
		claimantId: "user_kagiso"
		description: "Screen flickering after 3 months of normal use"
	) {
		id
		status
		submittedAt
	}
}

# Begin reviewing a claim (Malet Owner)
mutation {
	reviewWarrantyClaim(claimId: "claim_1") {
		id
		status
	}
}

# Approve the claim
mutation {
	approveWarrantyClaim(claimId: "claim_1") {
		id
		status
	}
}

# Resolve with a specific resolution type
mutation {
	resolveWarrantyClaim(
		claimId: "claim_1"
		resolution: REPAIR
		resolutionNotes: "Screen panel replaced under warranty. Device tested and returned."
	) {
		id
		status
		resolution
		resolutionNotes
		resolvedAt
	}
}

# Deny a claim
mutation {
	denyWarrantyClaim(
		claimId: "claim_1"
		resolutionNotes: "Physical damage โ€” not covered under warranty terms."
	) {
		id
		status
		resolutionNotes
	}
}

Resolution Types

Resolution Description Follow-up
REPAIR Device repaired and returned Repair booking via Workroom
REPLACE Device replaced with equivalent New Murchase created
REFUND Refund issued to Buyer Refund via payments

Queries

# Buyer checks their warranties
query {
	myWarranties(buyerId: "user_kagiso") {
		id
		productId
		serialNumber
		registeredAt
		expiresAt
		status
	}
}

# Malet Owner views all warranties
query {
	maletWarranties(maletId: "m_techshop", status: ACTIVE) {
		id
		productId
		buyerId
		serialNumber
		expiresAt
	}
}

# Get a single warranty by ID
query {
	warranty(id: "war_1") {
		id
		serialNumber
		status
		expiresAt
	}
}

# Get claims for a warranty
query {
	warrantyClaims(registrationId: "war_1") {
		id
		description
		photoUrls
		status
		resolution
		resolutionNotes
		submittedAt
		resolvedAt
	}
}

# Malet Owner views all claims by status
query {
	maletWarrantyClaims(maletId: "m_techshop", status: SUBMITTED) {
		id
		registrationId
		claimantId
		description
		status
	}
}

Warranty Enforcement

Claims are validated against the warranty registration:

  • Active check: Only ACTIVE warranties accept claims
  • Expiry check: If expiresAt < now(), the claim is rejected with BadRequestException
  • Evidence: Claims support photoUrls[] for visual evidence of the issue

Trade-In Program

Trade-in value is deposited into the Buyer's Credit Wallet as Malet-scoped credit. The existing CreditWallet from the Entertainment vertical provides:

  • Atomic $inc balance updates
  • Full transaction ledger
  • Balance guard (prevents negative balance)
  • PURCHASE / SPEND / REFUND / BONUS / ADJUSTMENT transaction types

Trade-In Flow

  1. Buyer selects a product for trade-in
  2. Malet Owner assesses device condition (Phase 1: manual, Phase 2: guided questionnaire)
  3. Trade-in value is determined and deposited as BONUS credit:
mutation {
	addCredits(
		maletId: "m_techshop"
		userId: "user_kagiso"
		amount: 35000 # R350.00 trade-in credit
		description: "Trade-in: iPhone 13 Pro (Good condition)"
		referenceId: "tradein_001"
	) {
		id
		balance
		transactions {
			type
			amount
			description
			createdAt
		}
	}
}
  1. Buyer applies credit toward new Murchase via SPEND transaction

Workroom Steps

The Tech vertical ships with 4 default Workroom steps for warranty and repair lifecycle management:

Step Type Assignee Description
Warranty Registration APPROVAL Malet Owner Verify purchase and register warranty with serial number
Diagnostic Assessment FORM Malet Owner Run diagnostics, assess device condition for repair or trade-in
Repair / Resolution APPROVAL Malet Owner Complete repair, replacement, or refund based on claim outcome
Device Return APPROVAL Buyer Confirm device received in working condition after repair

These steps are automatically configured on new Tech Malets via the vertical seed (slate/cyan branding).


Deferred Features

The following capabilities are planned for future phases using in-house, open-source/standard solutions โ€” no third-party SaaS dependencies:

Feature Phase Approach
License Key Pool Phase 2 licensePool: LicenseKey[] on Product with claim-on-purchase via $pop
Trade-In Assessment Phase 2 Guided condition questionnaire + algorithmic quote engine
Download Portal Phase 2 Time-limited pre-signed R2/S3 URLs via media subgraph
Subscription Seats Phase 2 Extend MembershipSubscription with seatCount + assignedSeats[]

TIP

All Phase 2 deferred features are tracked in the consolidated docs/PHASE2_BACKLOG.md. The softwareLicensing and tradeInProgram feature flags are already present in the Control Plane.


Frontend Implementation

Three Svelte 5 storefront widgets render the Tech vertical in the Visitor-facing storefront:

Components

Widget File Description
SpecComparison src/lib/components/tech/SpecComparison.svelte Grouped specification table with optional compare mode for side-by-side product specs. Shows compatibility badge for "Works with" products.
WarrantyTracker src/lib/components/tech/WarrantyTracker.svelte Warranty registration cards with status badges (Active/Expired/Voided), serial numbers, expiry countdown progress bars, and 30-day expiry warnings. Auth-gated.
TradeInPortal src/lib/components/tech/TradeInPortal.svelte 4-step trade-in flow cards (Select Product, Describe Condition, Get Estimate, Ship & Earn) with CTA linking to the Malet's trade-in page.

File Map

File Purpose
src/lib/queries/tech.ts GraphQL queries (GET_PRODUCT_SPEC, GET_MY_WARRANTIES, GET_WARRANTY_CLAIMS) + TypeScript interfaces
src/lib/utils/techUtils.ts 10 utility functions โ€” spec grouping by category, warranty status/duration, claim lifecycle status, resolution labels
src/lib/components/storefront/WidgetRegistry.svelte Widget registration: SPEC_COMPARISON, WARRANTY_TRACKER, TRADE_IN_PORTAL
tests/techUtils.test.ts 15 unit tests covering all utility functions

Layout Slot Types

Slot Type Widget Auth Required
SPEC_COMPARISON SpecComparison No
WARRANTY_TRACKER WarrantyTracker โœ… Yes
TRADE_IN_PORTAL TradeInPortal No

NOTE

For Visitor-facing documentation on specifications, warranties, and trade-in, see the Support Manual: Specs, Warranties & Trade-In.