Skip to content

SiliconX Documentation

SiliconX is a PostgreSQL-first Fair Market Value (FMV) engine for second-hand enterprise compute hardware. The system is a pnpm monorepo with three runtime apps: a Hono REST API deployed as a Lambda ECR container, a Vite+React analyst UI on S3+CloudFront, and a market data ingestion pipeline (ScrapingBee as primary scheduled source, with eBay/CDW/ServerMonkey as manual-only legacy sources). Aurora Serverless v2 is the canonical data store; Kysely provides type-safe access with types generated from the live schema via kysely-codegen. FMV is calculated as baselinePrice × ageMultiplier × configMultiplier × conditionMultiplier × marketabilityFactor, driven by confidence-weighted market comp aggregates (sku_mcmp) and effective-dated rule tables.


Quick Start

bash
git clone git@github.com:SiliconExchange/fmv-data-model.git
cd fmv-data-model
make bootstrap   # install → schema → seed → types-gen
make api-dev     # Hono API on :3001
make web-dev     # Vite UI on :5173

Prerequisite: Docker (for local Postgres), Node 20+, pnpm 9+.

After bootstrap, the local Postgres container (PG 16) holds the full schema and prototype seed data. DEV_ROLE=tester_alice is the default analyst role; set DEV_ROLE=tester_bob or tester_carol for alternate roles.


Architecture

Request Lifecycle


Documentation Map

SectionDescriptionAudienceLink
Getting StartedBootstrap, local dev, env varsAll engineers01-getting-started/
ArchitectureSystem design, ADRs, data flowSenior engineers02-architecture/
API ReferenceAll REST routes, auth, middlewareAPI consumers / FE engineers03-api/
Ingestion PipelineScrapingBee orchestration, staging promoter, LLM normalizerData engineers04-ingestion/
FrontendVite+React UI, TanStack Router, Hono client typesFrontend engineers05-frontend/
DatabaseSchema migrations, views, SQL tests, tbls docsDBA / backend engineers06-database/

Key Files

FilePurposeNotes
apps/api/src/index.tsAPI entrypoint; middleware order + route registration; exports AppTypeloadSecrets() fetches siliconx/lambda-secrets from Secrets Manager on Lambda cold start
apps/api/src/middleware/role.tsJWT validation, role resolution, per-request PG pool checkout, SET LOCAL ROLEJWKS hardcoded (no remote fetch from Lambda VPC); SingleConnectionProvider pattern
apps/api/src/routes/assets.tsAsset CRUD, FMV preview/snapshot, annotations, CSV exportFMV kernel shared between preview (no write) and snapshot (persists)
apps/api/src/routes/skus.tsSKU catalog, pricing stats (IQR-fenced 90-day), images, scrape targets, bundle componentsAuto-generates GEN-* / CB-* verifiedSku codes
apps/api/src/routes/snapshots.tsAudit-lock FMV snapshot detail via v_fmv_snapshot_inputsRead-only; coerces numeric/Date fields
apps/api/src/routes/fleet.tsFleet summary: totals + by-seller + by-class in one round-tripPowers dashboard aggregate cards
apps/api/src/routes/sellers.tsSeller org management; public list + admin CRUDadminOnlyMiddleware gates write routes to ops_admin Cognito group
apps/api/src/routes/transactions.tsMarketplace transaction record; sets asset.lifecycleStateId='sold'Admin-only write; validates allowsListing=true before insert
apps/ingestion/src/pipeline/promoter.tsValidates staging rows → writes to canonical market_comp / skuGatekeeper between raw scrape data and canonical tables
apps/ingestion/src/pipeline/mcmp.tsRecomputes sku_mcmp confidence-weighted aggregate after new market_comp rowsFeeds FMV baseline
apps/ingestion/src/llm/normalizer.tsLLM-based listing normalization (ScrapingBee raw → structured)Used in ScrapingBee path only
packages/shared/src/db.d.tsAuto-generated Kysely DB types; never hand-editRegenerated via make types-gen after every schema change
db/schema/SQL migrations 010–452; append-onlyNever edit applied files; always add a new numbered file
MakefileAll dev targets: bootstrap, deploy, test, docsPrimary dev entry point
CONTEXT.mdBounded domain vocabularyRead before naming anything

Tech Stack

TechnologyRoleVersion / Config
PostgreSQLPrimary data storePG 16 (Aurora Serverless v2 in prod; Docker in dev)
HonoREST API frameworkLambda ECR container; exports AppType for client type inference
KyselyType-safe SQL query builderTypes from kysely-codegen against live schema
Aurora Serverless v2Managed PostgreSQLus-east-1; VPC-isolated (no outbound HTTP from Lambda)
AWS LambdaAPI computeContainer image (ECR); siliconx/lambda-secrets via Secrets Manager
AWS S3 + CloudFrontWeb app hosting + SKU image CDNVite build → S3 sync → invalidation
AWS CognitoProduction authenticationPool us-east-1_cEADa8wlF; groups ops_admin / ops_analyst
Vite + ReactAnalyst UITanStack Router (file-based); hc<AppType>() for type-safe API calls
ScrapingBeePrimary market data sourceEventBridge-scheduled; writes to market_comp_staging
pnpm workspacesMonorepo package managementapps/api, apps/web, apps/ingestion, packages/shared
tblsSchema documentation generatormake schema-docsdocs/schema/
VitestSQL behavior teststests/sql/*.sql via make test-sql
batsSchema harness testsmake schema-test

FMV Calculation

The FMV kernel resolves five factors per asset:

fmv = baselinePrice
    × ageMultiplier         -- from age_curve table (asset class + model version)
    × configMultiplier      -- class_attributes JSONB vs. base config
    × conditionMultiplier   -- condition_band (new / refurbished / used)
    × marketabilityFactor   -- marketability_tier (A / B / C)

baselinePrice comes from sku_mcmp (confidence-weighted aggregate of market_comp rows, IQR-fenced per sku_price_bound). Friction costs are applied via friction_cost_rule (effective-dated, no-overlap enforced by EXCLUDE constraint — see ADR 0001).


DB Schema Overview

54 tables across 10 domains. Auto-generated ER diagrams and per-table docs live in docs/schema/.

DomainKey Tables
Hardware catalogasset, sku, asset_class, asset_class_schemas
Market pricingmarket_comp, sku_mcmp, sku_price_bound, market_comp_staging
FMV enginefmv_pricing_snapshot, age_curve, condition_multiplier, friction_cost_rule, marketability_assignment
Orgsseller_org, buyer_org
Exchangemarketplace_transaction
OEM specssku_oem_spec, sku_list_price_history
Ingestionasset_import_staging, scrape_target
Imagessku_image
Lifecycleasset_lifecycle_state
Geographydata_center, region

class_attributes JSONB on sku and asset is validated against versioned JSON Schemas in asset_class_schemas (see ADR 0002).


Role Model

RoleSourceDB RoleCapabilities
tester_alice / tester_bob / tester_carolDev env (DEV_ROLE)directFull dev access
ops_readonlyCognito group ops_analystops_readonlyRead-only analyst queries
ops_adminCognito group ops_adminops_readonly + adminOnlyMiddlewareAll routes including org management, transactions

Per-request: BEGIN → SET LOCAL ROLE → SET LOCAL statement_timeout='5s' → query → COMMIT/ROLLBACK.


Ingestion Pipeline

Legacy sources (eBay, CDW, ServerMonkey) follow the same *_staging → promoter path but are triggered manually via pnpm scrape:legacy.

SiliconX FMV Engine — Internal Documentation