Add Importing // Mapping Overview

2025-12-06 09:31:35 -05:00
commit 015c5d2d9c
+239
@@ -0,0 +1,239 @@
# Battl Builder Import & Mapping Flow Overview
This document explains the entire data ingestion, normalization, and builder-level mapping process used in Battl Builder — from raw AvantLink feed → normalized Battl Builder product → categorized builder slot.
---
## 1. Big Picture Architecture
Battl Builders data flow breaks into three layers:
1. **Import Layer**
_“What did the merchant send us?”_
2. **Domain Layer**
_“What is this part in Battl Builder language?”_
3. **Builder Layer**
_“Where does this part appear in the UI, and what slot does it fill?”_
This doc walks through each step in plain English.
---
## 2. Import Layer (AvantLink → Battl Builder database)
### 2.1 Merchants
Table: `merchants`
Each row stores:
- Merchant name (“Primary Arms”, “Brownells”, etc.)
- AvantLink MID
- Feed URLs
- Active flags
- Timestamps
**Purpose:**
Tell the importer *which* feeds exist and how to read them.
---
### 2.2 AvantLink Product & Offer Feeds
Every merchant provides two key feeds:
#### Product Feed
- brand name
- product name
- description
- merchants category
- MPN, UPC, SKU
- main image
- etc.
#### Offer Feed
- price
- original MSRP
- availability
- buy URL
- merchant id
- AvantLink product id
- timestamps
The importer loops over these feeds continuously.
---
### 2.3 Normalizing Merchant Categories (merchant_category_mappings)
Table: `merchant_category_mappings`
Each row answers this question:
> “When Merchant X says category string Y, what does that mean in our taxonomy?”
Columns include:
- `merchant_id`
- `raw_category` (merchants text)
- `mapped_part_role`
- `mapped_configuration`
- timestamps
This is the **first** normalization hop:
**Merchant category → internal part_role**
---
### 2.4 Brands
Table: `brands`
Import logic:
1. Try to find a case-insensitive match.
2. If found: reuse it.
3. If not found: create a new brand row.
---
### 2.5 Products
Table: `products`
Represents Battl Builders canonical catalog — not merchant-specific.
Columns include:
- `brand_id`
- `name`
- `part_role`
- `platform`
- `slug`
- `mpn`, `upc`
- descriptions
- main image
- `raw_category_key`
- timestamps
**Import behavior:**
1. Sync brand
2. Normalize category → part_role
3. Determine platform
4. Upsert product (insert or update)
---
### 2.6 Product Offers
Table: `product_offers`
Represents merchant-specific availability and pricing.
Columns:
- `product_id`
- `merchant_id`
- `price`, `original_price`
- `currency`
- `in_stock`
- `buy_url`
- timestamps
---
## 3. Domain Layer (Mapping Into Builder Categories)
### 3.1 Part Categories
Table: `part_categories`
Represents categories used in the builder UI such as:
- lower
- upper
- barrel
- optic
- trigger
These map directly to the builders UI slots.
---
### 3.2 Part Role Mappings
Table: `part_role_mappings`
Maps from:
> **platform + part_role → builder category**
Example:
```
AR-15 + LOWER_RECEIVER_STRIPPED → lower
AR-15 + OPTIC_LPVO → optic
```
This is the glue between raw import data and builder UI categories.
---
## 4. Builder Layer (Frontend Consumption)
### How `/builder` loads parts
Frontend calls:
```
GET /api/gunbuilder/products?platform=AR-15&partRoles=optic
```
Backend:
1. Query products
2. Load offers
3. Map to DTOs
4. Return JSON
5. Frontend groups by category via part_role_mappings
---
## 5. Relationship Between Mapping Systems
| Layer | Table | Purpose |
|-------|--------|----------|
| Import | `merchant_category_mappings` | Convert merchant category → part_role |
| Builder | `part_role_mappings` | Convert part_role → builder category slot |
Flow:
```
Merchant raw category
merchant_category_mappings
products.part_role
part_role_mappings
part_categories.slug
Builder slot (frontend)
```
---
## 6. `/builds` Page
Currently placeholder-only. Later it will store real builds composed from imported & mapped products.
---
## 7. Summary
AvantLink feeds → merchant category mapping → products + offers → part_role_mappings → builder UI → user builds.