diff --git a/bench-graph.tmp.mjs b/bench-graph.tmp.mjs new file mode 100644 index 0000000..f056528 --- /dev/null +++ b/bench-graph.tmp.mjs @@ -0,0 +1,132 @@ +import { readFileSync } from 'node:fs'; +import { Graphviz } from '@hpcc-js/wasm-graphviz'; + +const src = readFileSync( + '/home/seb/src/dashdbschema/generate-schema-graph.js', + 'utf8' +); +const parser = src.slice( + src.indexOf('function parseSchema'), + src.indexOf('const EDGE_COLORS') +); +const edgeColorsConst = src.slice( + src.indexOf('const EDGE_COLORS'), + src.indexOf('function edgeKey') +); +const edgeKeyFn = src.slice( + src.indexOf('function edgeKey'), + src.indexOf('/**\n * Only a spanning forest') +); +const ranking = src.slice( + src.indexOf('function selectRankingEdgeKeys'), + src.indexOf('function assignEdgeColors') +); +const edgeColors = src.slice( + src.indexOf('function assignEdgeColors'), + src.indexOf('function escapeHtml') +); +const escape = src.slice( + src.indexOf('function escapeHtml'), + src.indexOf('/**\n * Domain grouping') +); +const clusters = src.slice( + src.indexOf('const CLUSTERS'), + src.indexOf('const COLORS =') +); +const colors = src.slice( + src.indexOf('const COLORS ='), + src.indexOf('const COLORS =') + + src.slice(src.indexOf('const COLORS =')).indexOf('};') + + 2 +); +const orderMembers = src.slice( + src.indexOf('function orderClusterMembers'), + src.indexOf('function buildTableLabel') +); +const plainPositions = src.slice( + src.indexOf('function parsePlainPositions'), + src.indexOf('function flipCompassLR') +); +const reorder = src.slice( + src.indexOf('function reorderColumnsForCrossingReduction'), + src.indexOf('function parsePlainPositions') +); +const builder = src.slice( + src.indexOf('function buildTableLabel'), + src.indexOf('function countSvgCrossings') +); +const crossingsFn = src.slice( + src.indexOf('function countSvgCrossings'), + src.indexOf('/**\n * Graphviz self-edges') +); +const mod = await import( + 'data:text/javascript,' + + encodeURIComponent( + parser + + '\n' + + edgeColorsConst + + '\n' + + clusters + + '\n' + + colors + + '\n' + + orderMembers + + '\n' + + plainPositions + + '\n' + + reorder + + '\n' + + edgeKeyFn + + '\n' + + ranking + + '\n' + + edgeColors + + '\n' + + escape + + '\n' + + builder + + '\n' + + crossingsFn + + '\nexport { parseSchema, buildDot, assignEdgeAnchors, parsePlainPositions, reorderColumnsForCrossingReduction, orderClusterMembers, CLUSTERS, COLORS, countSvgCrossings };' + ) +); + +const schemaSource = readFileSync( + '/home/seb/src/dashdbschema/src/providers/mssql/schema.js', + 'utf8' +); +const { tables, edges } = mod.parseSchema(schemaSource); +const graphviz = await Graphviz.load(); + +let positions = null; +for (let pass = 0; pass < 3; pass++) { + const probeDot = mod.buildDot(tables, edges, positions); + const plain = graphviz.layout(probeDot, 'plain', 'dot'); + positions = mod.parsePlainPositions(plain); + mod.reorderColumnsForCrossingReduction(tables, edges, positions); +} +const anchors = mod.assignEdgeAnchors(edges, positions); +const baseDot = mod.buildDot(tables, edges, positions, anchors); + +const variants = [ + ['mclimit=4.0 splines=spline (current)', 'mclimit=4.0', 'splines=spline'], + ['mclimit=1.0 splines=spline', 'mclimit=1.0', 'splines=spline'], + ['mclimit=0.5 splines=spline', 'mclimit=0.5', 'splines=spline'], + ['mclimit=1.0 splines=true', 'mclimit=1.0', 'splines=true'], + ['mclimit=1.0 splines=polyline', 'mclimit=1.0', 'splines=polyline'], +]; + +for (const [label, mclimit, splines] of variants) { + const dot = baseDot + .replace('mclimit=4.0', mclimit) + .replace('splines=spline', splines); + const t = process.hrtime.bigint(); + const svg = graphviz.layout(dot, 'svg', 'dot'); + const ms = Number(process.hrtime.bigint() - t) / 1e6; + const t2 = process.hrtime.bigint(); + const crossings = mod.countSvgCrossings(svg); + const cms = Number(process.hrtime.bigint() - t2) / 1e6; + console.log( + `${label}: layout=${ms.toFixed(0)}ms crossings=${crossings} (count=${cms.toFixed(0)}ms) total=${(ms + cms).toFixed(0)}ms` + ); +} diff --git a/generate-schema-graph.js b/generate-schema-graph.js index fe29108..c2ea98c 100644 --- a/generate-schema-graph.js +++ b/generate-schema-graph.js @@ -369,13 +369,21 @@ const CLUSTERS = [ }, { id: 'manifests', - label: 'Documents', - tables: ['manifest', 'manifestarticle', 'manifestattachment', 'ledger', 'warehouse'], + label: 'Documents & Shipping', + tables: [ + 'manifest', + 'manifestarticle', + 'manifestattachment', + 'ledger', + 'warehouse', + 'shipping', + 'package', + ], }, { id: 'commerce', - label: 'Pricing', - tables: ['tax', 'price'], + label: 'Pricing & Payments', + tables: ['tax', 'price', 'account', 'payment'], }, { id: 'units', label: 'Units', tables: ['unit'] }, { id: 'pos', label: 'POS', tables: ['posterminal', 'posterminalcategory', 'printer', 'labeltemplate'] }, @@ -500,14 +508,33 @@ function flipCompassNS(compass) { * Greedy exit/port tweaks against real Graphviz splines. Tries L/R flips, * N/S diagonal flips, and adjacent head-port swaps; keeps moves that cut * SVG segment crossings. + * + * Each trial is a full Graphviz layout, so the search is bounded by + * `maxLayouts` and reports progress — otherwise a large schema silently + * runs for many minutes with no output. */ -function optimizeAnchorsWithLayout(graphviz, tables, edges, positions, anchors) { +function optimizeAnchorsWithLayout( + graphviz, + tables, + edges, + positions, + anchors, + maxLayouts = 400 +) { const tailCompass = new Map(anchors.tailCompass); const headPort = new Map(anchors.headPort); const inboundCounts = anchors.inboundCounts; let current = { headPort, tailCompass, inboundCounts }; + let layouts = 0; + const started = Date.now(); const measure = () => { + layouts++; + if (layouts % 25 === 0) { + console.log( + ` optimizing anchors: ${layouts} layouts, ${best} crossings, ${((Date.now() - started) / 1000).toFixed(0)}s` + ); + } const dot = buildDot(tables, edges, positions, current); const svg = fixSelfLoopSvg(graphviz.layout(dot, 'svg', 'dot')); return { svg, crossings: countSvgCrossings(svg), dot }; @@ -525,6 +552,8 @@ function optimizeAnchorsWithLayout(graphviz, tables, edges, positions, anchors) return false; }; + const budgetLeft = () => layouts < maxLayouts; + const trySeed = (seedCompass) => { const saved = new Map(tailCompass); for (const [k, v] of seedCompass) tailCompass.set(k, v); @@ -551,9 +580,11 @@ function optimizeAnchorsWithLayout(graphviz, tables, edges, positions, anchors) let improved = true; for (let sweep = 0; sweep < 4 && improved; sweep++) { improved = false; + if (!budgetLeft()) break; for (const edge of edges) { if (edge.from === edge.to) continue; + if (!budgetLeft()) break; const key = edgeKey(edge); const prev = tailCompass.get(key); if (!prev) continue; @@ -574,6 +605,7 @@ function optimizeAnchorsWithLayout(graphviz, tables, edges, positions, anchors) } for (const group of byTarget.values()) { + if (!budgetLeft()) break; const keys = group .map((e) => edgeKey(e)) .sort( @@ -829,10 +861,12 @@ function buildDot(tables, edges, positions = null, anchors = null) { const lines = [ 'digraph schema {', // TB = landscape for this schema (many tables per rank spread horizontally). - // mclimit bumps Graphviz's own crossing-minimization iterations. + // mclimit is Graphviz's crossing-minimization iteration budget. 4.0 (the + // old value) costs ~12x the layout time for only ~15% fewer crossings, + // which multiplied by the ~157 optimizer trials below. 1.0 is the default. ` graph [rankdir=TB, splines=spline, overlap=false, bgcolor="${COLORS.background}",`, ' nodesep=0.95, ranksep=1.0, pad=0.5, fontname="Helvetica",', - ' compound=true, mclimit=4.0];', + ' compound=true, mclimit=1.0];', ' node [shape=plaintext, fontname="Helvetica"];', ' edge [fontname="Helvetica", fontsize=9, penwidth=1.4, arrowsize=0.7];', '', @@ -941,6 +975,27 @@ function countSvgCrossings(svg) { edgeSegs.push(segs); } + // Two splines can only intersect if their bounding boxes overlap, so the + // sweep below can skip almost every pair. Without this the check is + // O(edges^2 * segments^2) and dominates each optimizer trial. + const boxes = edgeSegs.map((segs) => { + let minX = Infinity; + let minY = Infinity; + let maxX = -Infinity; + let maxY = -Infinity; + for (const [a] of segs) { + if (a[0] < minX) minX = a[0]; + if (a[0] > maxX) maxX = a[0]; + if (a[1] < minY) minY = a[1]; + if (a[1] > maxY) maxY = a[1]; + } + return { minX, minY, maxX, maxY }; + }); + + const order = boxes + .map((_, i) => i) + .sort((a, b) => boxes[a].minX - boxes[b].minX); + const orient = (a, b, c) => (b[1] - a[1]) * (c[0] - b[0]) - (b[0] - a[0]) * (c[1] - b[1]); const crosses = (a, b, c, d) => { @@ -952,8 +1007,17 @@ function countSvgCrossings(svg) { }; let n = 0; - for (let e1 = 0; e1 < edgeSegs.length; e1++) { - for (let e2 = e1 + 1; e2 < edgeSegs.length; e2++) { + for (let ii = 0; ii < order.length; ii++) { + const e1 = order[ii]; + const b1 = boxes[e1]; + for (let jj = ii + 1; jj < order.length; jj++) { + const e2 = order[jj]; + const b2 = boxes[e2]; + // Sorted by minX: once a box starts past b1's right edge, no later + // box can overlap it either. + if (b2.minX > b1.maxX) break; + if (b1.minX > b2.maxX || b1.minY > b2.maxY || b2.minY > b1.maxY) continue; + let pairCrosses = false; outer: for (const [a, b] of edgeSegs[e1]) { for (const [c, d] of edgeSegs[e2]) { @@ -1054,20 +1118,25 @@ const graphviz = await Graphviz.load(); // Layout passes: learn positions, reorder columns/cluster members (barycenter). let positions = null; for (let pass = 0; pass < 3; pass++) { + console.log(`Layout pass ${pass + 1}/3…`); const probeDot = buildDot(tables, edges, positions); const plain = graphviz.layout(probeDot, 'plain', 'dot'); positions = parsePlainPositions(plain); reorderColumnsForCrossingReduction(tables, edges, positions); } -// Hill-climb L/R exits against real spline crossings. +// Hill-climb L/R exits against real spline crossings. Each trial is a full +// layout, so the budget keeps the worst case bounded; raise it via +// SCHEMA_GRAPH_MAX_LAYOUTS if you want a longer search. +const maxLayouts = Number(process.env.SCHEMA_GRAPH_MAX_LAYOUTS ?? 400); const baseAnchors = assignEdgeAnchors(edges, positions); const optimized = optimizeAnchorsWithLayout( graphviz, tables, edges, positions, - baseAnchors + baseAnchors, + maxLayouts ); // Fill the whole canvas (including Graphviz's pad margin) so there is no diff --git a/schema-graph.dot b/schema-graph.dot index 1293518..618d329 100644 --- a/schema-graph.dot +++ b/schema-graph.dot @@ -1,7 +1,7 @@ digraph schema { graph [rankdir=TB, splines=spline, overlap=false, bgcolor="#1e2430", nodesep=0.95, ranksep=1.0, pad=0.5, fontname="Helvetica", - compound=true, mclimit=4.0]; + compound=true, mclimit=1.0]; node [shape=plaintext, fontname="Helvetica"]; edge [fontname="Helvetica", fontsize=9, penwidth=1.4, arrowsize=0.7]; @@ -9,11 +9,11 @@ digraph schema { label="Identity & Company"; labeljust="l"; fontsize=15; style="rounded,filled"; fillcolor="#202a3a"; color="#3f4c5f"; fontcolor="#e2e8f0"; margin=14; - customergroup [label=<
customergroup
idINT PK
company_id?INT FK
nameNVARCHAR(255)
sortINT
updated_atDATETIME2
>]; meta [label=<
meta
keyNVARCHAR(255)
valueNVARCHAR(MAX)
>]; - company [label=<
company
idINT PK
default_language_id?INT FK
root_category_id?INT FK
taxrate?INT FK
reducedtaxrate?INT FK
taxfreerate?INT FK
poscustomergroup_idINT FK
nameNVARCHAR(255)
>]; - companyhistory [label=<
companyhistory
idINT PK
company_idINT FK
companyuser_id?INT FK
dateDATETIME2
textNVARCHAR(MAX)
>]; + customergroup [label=<
customergroup
idINT PK
company_id?INT FK
nameNVARCHAR(255)
sortINT
updated_atDATETIME2
>]; + company [label=<
company
idINT PK
default_language_id?INT FK
taxrate?INT FK
reducedtaxrate?INT FK
taxfreerate?INT FK
root_category_id?INT FK
poscustomergroup_idINT FK
nameNVARCHAR(255)
>]; entityaddress [label=<
entityaddress
idINT PK
entity_idINT FK
first_name?NVARCHAR(255)
name?NVARCHAR(255)
street?NVARCHAR(255)
streetnumber?NVARCHAR(50)
zip?NVARCHAR(50)
city?NVARCHAR(255)
county?NVARCHAR(255)
addresstypeNVARCHAR(50)
sortINT
>]; + companyhistory [label=<
companyhistory
idINT PK
company_idINT FK
companyuser_id?INT FK
dateDATETIME2
textNVARCHAR(MAX)
>]; entity [label=<
entity
idINT PK
customergroup_idINT FK
first_name?NVARCHAR(255)
nameNVARCHAR(255)
number?NVARCHAR(100)
created_atDATETIME2
updated_atDATETIME2
>]; numbers [label=<
numbers
idINT PK
company_idINT FK
typeNVARCHAR(100)
prefixNVARCHAR(50)
paddingINT
nextINT
>]; entitycontact [label=<
entitycontact
idINT PK
entity_idINT FK
contacttypeNVARCHAR(50)
contactNVARCHAR(255)
sortINT
>]; @@ -28,52 +28,56 @@ digraph schema { fontcolor="#e2e8f0"; margin=14; language [label=<
language
idINT PK
iso639NVARCHAR(10)
>]; unittext [label=<
unittext
idINT PK
language_idINT FK
unit_idINT FK
symbolNVARCHAR(50)
nameNVARCHAR(255)
>]; - articletext [label=<
articletext
idINT PK
language_idINT FK
article_idINT FK
nameNVARCHAR(255)
slugNVARCHAR(255)
seo?NVARCHAR(MAX)
desc?NVARCHAR(MAX)
>]; categorytext [label=<
categorytext
idINT PK
language_idINT FK
category_idINT FK
nameNVARCHAR(255)
slugNVARCHAR(255)
seo?NVARCHAR(MAX)
desc?NVARCHAR(MAX)
>]; + articletext [label=<
articletext
idINT PK
language_idINT FK
article_idINT FK
nameNVARCHAR(255)
slugNVARCHAR(255)
seo?NVARCHAR(MAX)
desc?NVARCHAR(MAX)
>]; } subgraph cluster_catalog { label="Catalog"; labeljust="l"; fontsize=15; style="rounded,filled"; fillcolor="#202a3a"; color="#3f4c5f"; fontcolor="#e2e8f0"; margin=14; - articletombstone [label=<
articletombstone
idINT PK
company_idINT FK
article_id?INT
sku?NVARCHAR(100)
name?NVARCHAR(255)
taxrate?DECIMAL(18,4)
net?FLOAT
deleted_atDATETIME2
>]; - brand [label=<
brand
idINT PK
company_idINT FK
nameNVARCHAR(255)
gsprpinfo?NVARCHAR(MAX)
>]; - articlelist [label=<
articlelist
idINT PK
>]; - articlelistarticle [label=<
articlelistarticle
idINT PK
articlelist_idINT FK
article_idINT FK
countINT
sortINT
>]; - optionslist [label=<
optionslist
idINT PK
>]; - optionslistarticle [label=<
optionslistarticle
idINT PK
optionslist_idINT FK
article_idINT FK
countINT
sortINT
mandatedBIT
>]; - articlehistory [label=<
articlehistory
idINT PK
article_idINT FK
companyuser_id?INT FK
dateDATETIME2
textNVARCHAR(MAX)
>]; - articleean [label=<
articleean
idINT PK
article_idINT FK
eanNVARCHAR(50)
>]; - article [label=<
article
idINT PK
unit_idINT FK
brand_id?INT FK
articlelist_id?INT FK
optionslist_id?INT FK
parentarticle_id?INT FK
parentattributename_id?INT FK
company_idINT FK
sku?NVARCHAR(100)
unitamountFLOAT
weightFLOAT
track_stockBIT
is_parentBIT
parentsortINT
created_atDATETIME2
updated_atDATETIME2
>]; - articlesupplier [label=<
articlesupplier
idINT PK
article_idINT FK
tax_id?INT FK
entity_idINT FK
net?FLOAT
sku?NVARCHAR(100)
stock?FLOAT
puFLOAT
sortINT
>]; + categoryarticle [label=<
categoryarticle
idINT PK
category_idINT FK
article_idINT FK
>]; category [label=<
category
idINT PK
parent_id?INT FK
sortINT
updated_atDATETIME2
>]; - categoryarticle [label=<
categoryarticle
idINT PK
article_idINT FK
category_idINT FK
>]; + articlehistory [label=<
articlehistory
idINT PK
article_idINT FK
companyuser_id?INT FK
dateDATETIME2
textNVARCHAR(MAX)
>]; + article [label=<
article
idINT PK
parentattributename_id?INT FK
unit_idINT FK
parentarticle_id?INT FK
articlelist_id?INT FK
optionslist_id?INT FK
brand_id?INT FK
company_idINT FK
sku?NVARCHAR(100)
unitamountFLOAT
weightFLOAT
track_stockBIT
is_parentBIT
parentsortINT
created_atDATETIME2
updated_atDATETIME2
>]; + articleean [label=<
articleean
idINT PK
article_idINT FK
eanNVARCHAR(50)
>]; + articlesupplier [label=<
articlesupplier
idINT PK
tax_id?INT FK
article_idINT FK
entity_idINT FK
net?FLOAT
sku?NVARCHAR(100)
stock?FLOAT
puFLOAT
sortINT
>]; + articlelist [label=<
articlelist
idINT PK
>]; + articlelistarticle [label=<
articlelistarticle
idINT PK
article_idINT FK
articlelist_idINT FK
countINT
sortINT
>]; + optionslist [label=<
optionslist
idINT PK
>]; + optionslistarticle [label=<
optionslistarticle
idINT PK
article_idINT FK
optionslist_idINT FK
countINT
sortINT
mandatedBIT
>]; + brand [label=<
brand
idINT PK
company_idINT FK
nameNVARCHAR(255)
gsprpinfo?NVARCHAR(MAX)
>]; + articletombstone [label=<
articletombstone
idINT PK
company_idINT FK
article_id?INT
sku?NVARCHAR(100)
name?NVARCHAR(255)
taxrate?DECIMAL(18,4)
net?FLOAT
deleted_atDATETIME2
>]; } subgraph cluster_media { label="Media"; labeljust="l"; fontsize=15; style="rounded,filled"; fillcolor="#202a3a"; color="#3f4c5f"; fontcolor="#e2e8f0"; margin=14; pic [label=<
pic
idINT PK
wINT
hINT
sizeBIGINT
hashNVARCHAR(64)
thumbwINT
thumbhINT
thumbhashNVARCHAR(64)
smallthumbwINT
smallthumbhINT
sourceNVARCHAR(MAX)
fullbinaryVARBINARY(MAX)
thumbbinaryVARBINARY(MAX)
smallthumbbinaryVARBINARY(MAX)
>]; - brandpic [label=<
brandpic
idINT PK
brand_idINT FK
pic_idINT FK
sortINT
>]; - articlepic [label=<
articlepic
idINT PK
article_idINT FK
pic_idINT FK
sortINT
>]; + articlepic [label=<
articlepic
idINT PK
pic_idINT FK
article_idINT FK
sortINT
>]; categorypic [label=<
categorypic
idINT PK
pic_idINT FK
category_idINT FK
sortINT
>]; + brandpic [label=<
brandpic
idINT PK
pic_idINT FK
brand_idINT FK
sortINT
>]; file [label=<
file
idINT PK
hashNVARCHAR(64)
mimetypeNVARCHAR(255)
nameNVARCHAR(255)
sizeBIGINT
createdDATETIME2
modifiedDATETIME2
contentVARBINARY(MAX)
thumbavif?VARBINARY(MAX)
thumbx?INT
thumby?INT
meta?NVARCHAR(MAX)
>]; } subgraph cluster_manifests { - label="Documents"; labeljust="l"; fontsize=15; + label="Documents & Shipping"; labeljust="l"; fontsize=15; style="rounded,filled"; fillcolor="#202a3a"; color="#3f4c5f"; fontcolor="#e2e8f0"; margin=14; - warehouse [label=<
warehouse
idINT PK
company_idINT FK
nameNVARCHAR(255)
sortINT
>]; manifestarticle [label=<
manifestarticle
idINT PK
manifest_idINT FK
sku?NVARCHAR(100)
name?NVARCHAR(255)
puFLOAT
amountFLOAT
netFLOAT
comment?NVARCHAR(MAX)
rebateFLOAT
taxrateFLOAT
>]; - manifest [label=<
manifest
idINT PK
company_idINT FK
entity_id?INT FK
numberNVARCHAR(100)
typeNVARCHAR(100)
external_number?NVARCHAR(100)
dateDATETIME2
created_atDATETIME2
>]; - ledger [label=<
ledger
idINT PK
warehouse_id?INT FK
manifestarticle_idINT FK
transaction_typeNVARCHAR(100)
amountFLOAT
transaction_textNVARCHAR(MAX)
hash_versionINT
prev_hash?NVARCHAR(128)
created_atDATETIME2
>]; + ledger [label=<
ledger
idINT PK
manifestarticle_idINT FK
warehouse_id?INT FK
transaction_typeNVARCHAR(100)
amountFLOAT
transaction_textNVARCHAR(MAX)
hash_versionINT
prev_hash?NVARCHAR(128)
created_atDATETIME2
>]; manifestattachment [label=<
manifestattachment
idINT PK
file_idINT FK
manifest_idINT FK
sortINT
>]; + package [label=<
package
idINT PK
shipping_idINT FK
entityaddress_idINT FK
numberNVARCHAR(100)
typeNVARCHAR(100)
stateNVARCHAR(100)
details?NVARCHAR(MAX)
>]; + manifest [label=<
manifest
idINT PK
company_idINT FK
entity_id?INT FK
numberNVARCHAR(100)
typeNVARCHAR(100)
external_number?NVARCHAR(100)
dateDATETIME2
created_atDATETIME2
>]; + shipping [label=<
shipping
idINT PK
manifest_idINT FK
numberNVARCHAR(100)
typeNVARCHAR(100)
stateNVARCHAR(100)
>]; + warehouse [label=<
warehouse
idINT PK
company_idINT FK
nameNVARCHAR(255)
sortINT
>]; } subgraph cluster_commerce { - label="Pricing"; labeljust="l"; fontsize=15; + label="Pricing & Payments"; labeljust="l"; fontsize=15; style="rounded,filled"; fillcolor="#202a3a"; color="#3f4c5f"; fontcolor="#e2e8f0"; margin=14; tax [label=<
tax
idINT PK
rateDECIMAL(18,4)
>]; - price [label=<
price
idINT PK
article_idINT FK
tax_idINT FK
customergroup_idINT FK
minmultiplierDECIMAL(18,4)
netFLOAT
>]; + account [label=<
account
idINT PK
company_idINT FK
typeNVARCHAR(100)
nameNVARCHAR(255)
>]; + price [label=<
price
idINT PK
tax_idINT FK
article_idINT FK
customergroup_idINT FK
minmultiplierDECIMAL(18,4)
netFLOAT
>]; + payment [label=<
payment
idINT PK
account_idINT FK
manifest_idINT FK
typeNVARCHAR(100)
amountFLOAT
>]; } subgraph cluster_units { label="Units"; labeljust="l"; fontsize=15; @@ -85,128 +89,124 @@ digraph schema { label="POS"; labeljust="l"; fontsize=15; style="rounded,filled"; fillcolor="#202a3a"; color="#3f4c5f"; fontcolor="#e2e8f0"; margin=14; - posterminalcategory [label=<
posterminalcategory
idINT PK
category_idINT FK
posterminal_idINT FK
>]; - posterminal [label=<
posterminal
idINT PK
root_category_id?INT FK
company_idINT FK
nameNVARCHAR(255)
token?NVARCHAR(255)
pairingpin?NVARCHAR(50)
paired_at?DATETIME2
clientserial?NVARCHAR(255)
maxknowntombstoneid?INT
sync_root_articlesBIT
lastseen_at?DATETIME2
updated_atDATETIME2
>]; printer [label=<
printer
idINT PK
company_idINT FK
addressNVARCHAR(255)
typeNVARCHAR(50)
model?NVARCHAR(255)
serial?NVARCHAR(255)
sortINT
desc?NVARCHAR(MAX)
>]; + posterminal [label=<
posterminal
idINT PK
root_category_id?INT FK
company_idINT FK
nameNVARCHAR(255)
token?NVARCHAR(255)
pairingpin?NVARCHAR(50)
paired_at?DATETIME2
clientserial?NVARCHAR(255)
maxknowntombstoneid?INT
sync_root_articlesBIT
lastseen_at?DATETIME2
updated_atDATETIME2
>]; + posterminalcategory [label=<
posterminalcategory
idINT PK
category_idINT FK
posterminal_idINT FK
>]; labeltemplate [label=<
labeltemplate
idINT PK
company_idINT FK
nameNVARCHAR(255)
widthINT
heightINT
dpiINT
typeNVARCHAR(50)
contentNVARCHAR(MAX)
thumb?VARBINARY(MAX)
>]; } subgraph cluster_ai { label="AI & Models"; labeljust="l"; fontsize=15; style="rounded,filled"; fillcolor="#202a3a"; color="#3f4c5f"; fontcolor="#e2e8f0"; margin=14; - modelvfs [label=<
modelvfs
idINT PK
company_idINT FK
nameNVARCHAR(255)
mimeNVARCHAR(100)
contentVARBINARY(MAX)
metaNVARCHAR(MAX)
created_atDATETIME2
updated_atDATETIME2
>]; - modelconversation [label=<
modelconversation
idINT PK
companyuser_idINT FK
providerNVARCHAR(100)
modelNVARCHAR(255)
created_atDATETIME2
updated_atDATETIME2
stateNVARCHAR(20)
>]; modelmessage [label=<
modelmessage
idINT PK
conversation_idINT FK
created_atDATETIME2
roleNVARCHAR(20)
messageNVARCHAR(MAX)
>]; + modelconversation [label=<
modelconversation
idINT PK
companyuser_idINT FK
providerNVARCHAR(100)
modelNVARCHAR(255)
created_atDATETIME2
updated_atDATETIME2
stateNVARCHAR(20)
>]; + modelvfs [label=<
modelvfs
idINT PK
company_idINT FK
nameNVARCHAR(255)
mimeNVARCHAR(100)
contentVARBINARY(MAX)
metaNVARCHAR(MAX)
created_atDATETIME2
updated_atDATETIME2
>]; } subgraph cluster_attributes { label="Properties & Attributes"; labeljust="l"; fontsize=15; style="rounded,filled"; fillcolor="#202a3a"; color="#3f4c5f"; fontcolor="#e2e8f0"; margin=14; - articleproperty [label=<
articleproperty
idINT PK
article_idINT FK
property_idINT FK
valueNVARCHAR(MAX)
sortINT
>]; - articleattributevalue [label=<
articleattributevalue
idINT PK
article_idINT FK
attributevalue_idINT FK
sortINT
>]; - categoryproperty [label=<
categoryproperty
idINT PK
category_idINT FK
property_idINT FK
valueNVARCHAR(MAX)
sortINT
>]; - categoryattributevalue [label=<
categoryattributevalue
idINT PK
category_idINT FK
attributevalue_idINT FK
sortINT
>]; propertyname [label=<
propertyname
idINT PK
company_idINT FK
nameNVARCHAR(255)
sortINT
exclusiveBIT
>]; - attributename [label=<
attributename
idINT PK
company_idINT FK
nameNVARCHAR(255)
sortINT
exclusiveBIT
>]; attributevalue [label=<
attributevalue
idINT PK
attribute_idINT FK
valueNVARCHAR(255)
sortINT
>]; + categoryproperty [label=<
categoryproperty
idINT PK
property_idINT FK
category_idINT FK
valueNVARCHAR(MAX)
sortINT
>]; + categoryattributevalue [label=<
categoryattributevalue
idINT PK
attributevalue_idINT FK
category_idINT FK
sortINT
>]; + attributename [label=<
attributename
idINT PK
company_idINT FK
nameNVARCHAR(255)
sortINT
exclusiveBIT
>]; + articleproperty [label=<
articleproperty
idINT PK
property_idINT FK
article_idINT FK
valueNVARCHAR(MAX)
sortINT
>]; + articleattributevalue [label=<
articleattributevalue
idINT PK
attributevalue_idINT FK
article_idINT FK
sortINT
>]; } - account [label=<
account
idINT PK
company_idINT FK
typeNVARCHAR(100)
nameNVARCHAR(255)
>]; - package [label=<
package
idINT PK
entityaddress_idINT FK
shipping_idINT FK
numberNVARCHAR(100)
typeNVARCHAR(100)
stateNVARCHAR(100)
details?NVARCHAR(MAX)
>]; - payment [label=<
payment
idINT PK
account_idINT FK
manifest_idINT FK
typeNVARCHAR(100)
amountFLOAT
>]; - shipping [label=<
shipping
idINT PK
manifest_idINT FK
numberNVARCHAR(100)
typeNVARCHAR(100)
stateNVARCHAR(100)
>]; __legend [label=<
Legend
PKprimary key
FKforeign key
?nullable column
—FOREIGN KEY constraint
- -naming convention only, no constraint
>]; - google_auth:selected_company:w -> company:in16:n [color="#ff6b6b", fontcolor="#ff6b6b", tooltip="FK_google_auth_selected_company", weight=3]; + google_auth:selected_company:w -> company:in14:n [color="#ff6b6b", fontcolor="#ff6b6b", tooltip="FK_google_auth_selected_company", weight=3]; category:parent_id:e -> category:id:e [color="#6bdf9a", fontcolor="#6bdf9a", tooltip="FK_category_parent", constraint=false]; - company:root_category_id:w -> category:in8:n [color="#5aa7ff", fontcolor="#5aa7ff", tooltip="FK_company_root_category", weight=3]; - company:default_language_id:w -> language:in3:n [color="#f5c15c", fontcolor="#f5c15c", tooltip="FK_company_default_language", constraint=false, weight=1]; + company:root_category_id:w -> category:in7:n [color="#5aa7ff", fontcolor="#5aa7ff", tooltip="FK_company_root_category", weight=3]; + company:default_language_id:w -> language:in1:n [color="#f5c15c", fontcolor="#f5c15c", tooltip="FK_company_default_language", constraint=false, weight=1]; company:taxrate:w -> tax:in4:n [color="#c79bff", fontcolor="#c79bff", tooltip="FK_company_taxrate", constraint=false, weight=1]; company:reducedtaxrate:w -> tax:in2:n [color="#ff9f5a", fontcolor="#ff9f5a", tooltip="FK_company_reducedtaxrate", constraint=false, weight=1]; company:taxfreerate:w -> tax:in3:n [color="#5cd6d6", fontcolor="#5cd6d6", tooltip="FK_company_taxfreerate", constraint=false, weight=1]; - customergroup:company_id:se -> company:in11:n [color="#ff7fc2", fontcolor="#ff7fc2", tooltip="FK_customergroup_company", weight=3]; - company:poscustomergroup_id:ne -> customergroup:in2:n [color="#8f95ff", fontcolor="#8f95ff", tooltip="FK_company_poscustomergroup", constraint=false, weight=1]; - entity:customergroup_id:sw -> customergroup:in1:n [color="#58d18a", fontcolor="#58d18a", tooltip="FK_entity_customergroup", weight=3]; - entityaddress:entity_id:ne -> entity:in1:n [color="#ff8f66", fontcolor="#ff8f66", tooltip="FK_entityaddress_entity", weight=3]; - entitycontact:entity_id:sw -> entity:in2:n [color="#4fc4e8", fontcolor="#4fc4e8", tooltip="FK_entitycontact_entity", weight=3]; - entityhistory:entity_id:sw -> entity:in3:n [color="#a98cff", fontcolor="#a98cff", tooltip="FK_entityhistory_entity", weight=3]; + customergroup:company_id:se -> company:in8:n [color="#ff7fc2", fontcolor="#ff7fc2", tooltip="FK_customergroup_company", weight=3]; + company:poscustomergroup_id:ne -> customergroup:in1:n [color="#8f95ff", fontcolor="#8f95ff", tooltip="FK_company_poscustomergroup", constraint=false, weight=1]; + entity:customergroup_id:sw -> customergroup:in2:n [color="#58d18a", fontcolor="#58d18a", tooltip="FK_entity_customergroup", weight=3]; + entityaddress:entity_id:ne -> entity:in2:n [color="#ff8f66", fontcolor="#ff8f66", tooltip="FK_entityaddress_entity", weight=3]; + entitycontact:entity_id:sw -> entity:in3:n [color="#4fc4e8", fontcolor="#4fc4e8", tooltip="FK_entitycontact_entity", weight=3]; + entityhistory:entity_id:sw -> entity:in4:n [color="#a98cff", fontcolor="#a98cff", tooltip="FK_entityhistory_entity", weight=3]; entityhistory:companyuser_id:se -> companyuser:in3:n [color="#ff6f6f", fontcolor="#ff6f6f", tooltip="FK_entityhistory_companyuser", constraint=false, weight=1]; - unit:company_id:e -> company:in0:n [color="#4ecb8f", fontcolor="#4ecb8f", tooltip="FK_unit_company", weight=3]; - unittext:unit_id:se -> unit:in0:n [color="#5aa7e6", fontcolor="#5aa7e6", tooltip="FK_unittext_unit", weight=3]; - unittext:language_id:w -> language:in2:n [color="#ff7aa8", fontcolor="#ff7aa8", tooltip="FK_unittext_language", constraint=false, weight=1]; - brand:company_id:e -> company:in2:n [color="#e0b25a", fontcolor="#e0b25a", tooltip="FK_brand_company", weight=3]; - article:company_id:w -> company:in3:n [color="#56c8c8", fontcolor="#56c8c8", tooltip="FK_article_company", weight=3]; - article:unit_id:w -> unit:in1:n [color="#ff5f9e", fontcolor="#ff5f9e", tooltip="FK_article_unit", constraint=false, weight=1]; - article:brand_id:w -> brand:in0:n [color="#ffb25a", fontcolor="#ffb25a", tooltip="FK_article_brand", constraint=false, weight=1]; - article:articlelist_id:w -> articlelist:in1:n [color="#56d68a", fontcolor="#56d68a", tooltip="FK_article_articlelist", constraint=false, weight=1]; + unit:company_id:e -> company:in3:n [color="#4ecb8f", fontcolor="#4ecb8f", tooltip="FK_unit_company", weight=3]; + unittext:unit_id:w -> unit:in1:n [color="#5aa7e6", fontcolor="#5aa7e6", tooltip="FK_unittext_unit", weight=3]; + unittext:language_id:w -> language:in0:n [color="#ff7aa8", fontcolor="#ff7aa8", tooltip="FK_unittext_language", constraint=false, weight=1]; + brand:company_id:w -> company:in5:n [color="#e0b25a", fontcolor="#e0b25a", tooltip="FK_brand_company", weight=3]; + article:company_id:w -> company:in4:n [color="#56c8c8", fontcolor="#56c8c8", tooltip="FK_article_company", weight=3]; + article:unit_id:e -> unit:in0:n [color="#ff5f9e", fontcolor="#ff5f9e", tooltip="FK_article_unit", constraint=false, weight=1]; + article:brand_id:w -> brand:in1:n [color="#ffb25a", fontcolor="#ffb25a", tooltip="FK_article_brand", constraint=false, weight=1]; + article:articlelist_id:w -> articlelist:in0:n [color="#56d68a", fontcolor="#56d68a", tooltip="FK_article_articlelist", constraint=false, weight=1]; article:optionslist_id:w -> optionslist:in1:n [color="#66b3ff", fontcolor="#66b3ff", tooltip="FK_article_optionslist", constraint=false, weight=1]; article:parentarticle_id:e -> article:id:e [color="#c79bff", fontcolor="#c79bff", tooltip="FK_article_parentarticle", constraint=false]; - article:parentattributename_id:se -> attributename:in1:n [color="#ff6b6b", fontcolor="#ff6b6b", tooltip="FK_article_parentattributename", constraint=false, weight=1]; - article:parentattributename_id:se -> attributename:in1:n [color="#ff6b6b", fontcolor="#ff6b6b", tooltip="FK_article_parentattributename", constraint=false, weight=1]; - articlehistory:article_id:se -> article:in3:n [color="#6bdf9a", fontcolor="#6bdf9a", tooltip="FK_articlehistory_article", weight=3]; - articlehistory:companyuser_id:e -> companyuser:in1:n [color="#5aa7ff", fontcolor="#5aa7ff", tooltip="FK_articlehistory_companyuser", constraint=false, weight=1]; - companyhistory:company_id:nw -> company:in12:n [color="#f5c15c", fontcolor="#f5c15c", tooltip="FK_companyhistory_company", weight=3]; - companyhistory:companyuser_id:e -> companyuser:in0:n [color="#c79bff", fontcolor="#c79bff", tooltip="FK_companyhistory_companyuser", constraint=false, weight=1]; - articletombstone:company_id:w -> company:in1:n [color="#ff9f5a", fontcolor="#ff9f5a", tooltip="FK_articletombstone_company", weight=3]; - articleean:article_id:ne -> article:in4:n [color="#5cd6d6", fontcolor="#5cd6d6", tooltip="FK_articleean_article", weight=3]; - articlepic:article_id:se -> article:in8:n [color="#ff7fc2", fontcolor="#ff7fc2", tooltip="FK_articlepic_article", weight=3]; + article:parentattributename_id:ne -> attributename:in0:n [color="#ff6b6b", fontcolor="#ff6b6b", tooltip="FK_article_parentattributename", constraint=false, weight=1]; + article:parentattributename_id:ne -> attributename:in0:n [color="#ff6b6b", fontcolor="#ff6b6b", tooltip="FK_article_parentattributename", constraint=false, weight=1]; + articlehistory:article_id:sw -> article:in6:n [color="#6bdf9a", fontcolor="#6bdf9a", tooltip="FK_articlehistory_article", weight=3]; + articlehistory:companyuser_id:e -> companyuser:in0:n [color="#5aa7ff", fontcolor="#5aa7ff", tooltip="FK_articlehistory_companyuser", constraint=false, weight=1]; + companyhistory:company_id:nw -> company:in11:n [color="#f5c15c", fontcolor="#f5c15c", tooltip="FK_companyhistory_company", weight=3]; + companyhistory:companyuser_id:e -> companyuser:in1:n [color="#c79bff", fontcolor="#c79bff", tooltip="FK_companyhistory_companyuser", constraint=false, weight=1]; + articletombstone:company_id:w -> company:in6:n [color="#ff9f5a", fontcolor="#ff9f5a", tooltip="FK_articletombstone_company", weight=3]; + articleean:article_id:se -> article:in8:n [color="#5cd6d6", fontcolor="#5cd6d6", tooltip="FK_articleean_article", weight=3]; + articlepic:article_id:se -> article:in3:n [color="#ff7fc2", fontcolor="#ff7fc2", tooltip="FK_articlepic_article", weight=3]; articlepic:pic_id:w -> pic:in0:n [color="#8f95ff", fontcolor="#8f95ff", tooltip="FK_articlepic_pic", constraint=false, weight=1]; - brandpic:brand_id:w -> brand:in1:n [color="#58d18a", fontcolor="#58d18a", tooltip="FK_brandpic_brand", weight=3]; + brandpic:brand_id:e -> brand:in0:n [color="#58d18a", fontcolor="#58d18a", tooltip="FK_brandpic_brand", weight=3]; brandpic:pic_id:w -> pic:in2:n [color="#ff8f66", fontcolor="#ff8f66", tooltip="FK_brandpic_pic", constraint=false, weight=1]; - articlelistarticle:articlelist_id:nw -> articlelist:in0:n [color="#4fc4e8", fontcolor="#4fc4e8", tooltip="FK_articlelistarticle_articlelist", weight=3]; - articlelistarticle:article_id:w -> article:in1:n [color="#a98cff", fontcolor="#a98cff", tooltip="FK_articlelistarticle_article", constraint=false, weight=1]; + articlelistarticle:articlelist_id:se -> articlelist:in1:n [color="#4fc4e8", fontcolor="#4fc4e8", tooltip="FK_articlelistarticle_articlelist", weight=3]; + articlelistarticle:article_id:w -> article:in10:n [color="#a98cff", fontcolor="#a98cff", tooltip="FK_articlelistarticle_article", constraint=false, weight=1]; optionslistarticle:optionslist_id:sw -> optionslist:in0:n [color="#ff6f6f", fontcolor="#ff6f6f", tooltip="FK_optionslistarticle_optionslist", weight=3]; - optionslistarticle:article_id:w -> article:in2:n [color="#4ecb8f", fontcolor="#4ecb8f", tooltip="FK_optionslistarticle_article", constraint=false, weight=1]; - categoryarticle:category_id:nw -> category:in2:n [color="#5aa7e6", fontcolor="#5aa7e6", tooltip="FK_categoryarticle_category", weight=3]; - categoryarticle:article_id:sw -> article:in7:n [color="#ff7aa8", fontcolor="#ff7aa8", tooltip="FK_categoryarticle_article", constraint=false, weight=1]; - categorypic:category_id:sw -> category:in3:n [color="#e0b25a", fontcolor="#e0b25a", tooltip="FK_categorypic_category", weight=3]; + optionslistarticle:article_id:w -> article:in11:n [color="#4ecb8f", fontcolor="#4ecb8f", tooltip="FK_optionslistarticle_article", constraint=false, weight=1]; + categoryarticle:category_id:sw -> category:in2:n [color="#5aa7e6", fontcolor="#5aa7e6", tooltip="FK_categoryarticle_category", weight=3]; + categoryarticle:article_id:sw -> article:in5:n [color="#ff7aa8", fontcolor="#ff7aa8", tooltip="FK_categoryarticle_article", constraint=false, weight=1]; + categorypic:category_id:sw -> category:in5:n [color="#e0b25a", fontcolor="#e0b25a", tooltip="FK_categorypic_category", weight=3]; categorypic:pic_id:w -> pic:in1:n [color="#56c8c8", fontcolor="#56c8c8", tooltip="FK_categorypic_pic", constraint=false, weight=1]; - categorytext:category_id:w -> category:in0:n [color="#ff5f9e", fontcolor="#ff5f9e", tooltip="FK_categorytext_category", weight=3]; - categorytext:language_id:w -> language:in1:n [color="#ffb25a", fontcolor="#ffb25a", tooltip="FK_categorytext_language", constraint=false, weight=1]; - articletext:article_id:e -> article:in0:n [color="#56d68a", fontcolor="#56d68a", tooltip="FK_articletext_article", weight=3]; - articletext:language_id:w -> language:in0:n [color="#66b3ff", fontcolor="#66b3ff", tooltip="FK_articletext_language", constraint=false, weight=1]; - price:tax_id:w -> tax:in1:n [color="#c79bff", fontcolor="#c79bff", tooltip="FK_price_tax", constraint=false, weight=1]; - price:article_id:e -> article:in9:n [color="#ff6b6b", fontcolor="#ff6b6b", tooltip="FK_price_article", weight=3]; + categorytext:category_id:w -> category:in3:n [color="#ff5f9e", fontcolor="#ff5f9e", tooltip="FK_categorytext_category", weight=3]; + categorytext:language_id:w -> language:in2:n [color="#ffb25a", fontcolor="#ffb25a", tooltip="FK_categorytext_language", constraint=false, weight=1]; + articletext:article_id:e -> article:in4:n [color="#56d68a", fontcolor="#56d68a", tooltip="FK_articletext_article", weight=3]; + articletext:language_id:w -> language:in3:n [color="#66b3ff", fontcolor="#66b3ff", tooltip="FK_articletext_language", constraint=false, weight=1]; + price:tax_id:e -> tax:in0:n [color="#c79bff", fontcolor="#c79bff", tooltip="FK_price_tax", constraint=false, weight=1]; + price:article_id:w -> article:in2:n [color="#ff6b6b", fontcolor="#ff6b6b", tooltip="FK_price_article", weight=3]; price:customergroup_id:e -> customergroup:in0:n [color="#6bdf9a", fontcolor="#6bdf9a", tooltip="FK_price_customergroup", constraint=false, weight=1]; - articlesupplier:article_id:sw -> article:in6:n [color="#5aa7ff", fontcolor="#5aa7ff", tooltip="FK_articlesupplier_article", weight=3]; - articlesupplier:entity_id:e -> entity:in0:n [color="#f5c15c", fontcolor="#f5c15c", tooltip="FK_articlesupplier_entity", constraint=false, weight=1]; - articlesupplier:tax_id:e -> tax:in0:n [color="#c79bff", fontcolor="#c79bff", tooltip="FK_articlesupplier_tax", constraint=false, weight=1]; - manifest:company_id:e -> company:in18:n [color="#ff9f5a", fontcolor="#ff9f5a", tooltip="FK_manifest_company", weight=3]; - manifest:entity_id:w -> entity:in4:n [color="#5cd6d6", fontcolor="#5cd6d6", tooltip="FK_manifest_entity", constraint=false, weight=1]; - manifestarticle:manifest_id:nw -> manifest:in2:n [color="#ff7fc2", fontcolor="#ff7fc2", tooltip="FK_manifestarticle_manifest", weight=3]; - warehouse:company_id:w -> company:in17:n [color="#8f95ff", fontcolor="#8f95ff", tooltip="FK_warehouse_company", weight=3]; + articlesupplier:article_id:nw -> article:in9:n [color="#5aa7ff", fontcolor="#5aa7ff", tooltip="FK_articlesupplier_article", weight=3]; + articlesupplier:entity_id:e -> entity:in1:n [color="#f5c15c", fontcolor="#f5c15c", tooltip="FK_articlesupplier_entity", constraint=false, weight=1]; + articlesupplier:tax_id:e -> tax:in1:n [color="#c79bff", fontcolor="#c79bff", tooltip="FK_articlesupplier_tax", constraint=false, weight=1]; + manifest:company_id:sw -> company:in7:n [color="#ff9f5a", fontcolor="#ff9f5a", tooltip="FK_manifest_company", weight=3]; + manifest:entity_id:e -> entity:in0:n [color="#5cd6d6", fontcolor="#5cd6d6", tooltip="FK_manifest_entity", constraint=false, weight=1]; + manifestarticle:manifest_id:sw -> manifest:in2:n [color="#ff7fc2", fontcolor="#ff7fc2", tooltip="FK_manifestarticle_manifest", weight=3]; + warehouse:company_id:se -> company:in9:n [color="#8f95ff", fontcolor="#8f95ff", tooltip="FK_warehouse_company", weight=3]; ledger:manifestarticle_id:sw -> manifestarticle:in0:n [color="#58d18a", fontcolor="#58d18a", tooltip="FK_ledger_manifestarticle", weight=3]; - ledger:warehouse_id:w -> warehouse:in0:n [color="#ff8f66", fontcolor="#ff8f66", tooltip="FK_ledger_warehouse", constraint=false, weight=1]; - numbers:company_id:se -> company:in14:n [color="#4fc4e8", fontcolor="#4fc4e8", tooltip="FK_numbers_company", weight=3]; + ledger:warehouse_id:e -> warehouse:in0:n [color="#ff8f66", fontcolor="#ff8f66", tooltip="FK_ledger_warehouse", constraint=false, weight=1]; + numbers:company_id:se -> company:in10:n [color="#4fc4e8", fontcolor="#4fc4e8", tooltip="FK_numbers_company", weight=3]; companyuser:google_auth_id:e -> google_auth:in0:n [color="#a98cff", fontcolor="#a98cff", tooltip="FK_companyuser_google_auth", constraint=false, weight=1]; - companyuser:company_id:w -> company:in13:n [color="#ff6f6f", fontcolor="#ff6f6f", tooltip="FK_companyuser_company", weight=3]; - modelconversation:companyuser_id:e -> companyuser:in2:n [color="#4ecb8f", fontcolor="#4ecb8f", tooltip="FK_modelconversation_companyuser", weight=3]; - modelvfs:company_id:se -> company:in10:n [color="#5aa7e6", fontcolor="#5aa7e6", tooltip="FK_modelvfs_company", weight=3]; - modelmessage:conversation_id:sw -> modelconversation:in0:n [color="#ff7aa8", fontcolor="#ff7aa8", tooltip="FK_modelmessage_conversation", weight=3]; - companysetting:company_id:e -> company:in15:n [color="#e0b25a", fontcolor="#e0b25a", tooltip="FK_companysetting_company", weight=3]; - posterminal:company_id:e -> company:in4:n [color="#56c8c8", fontcolor="#56c8c8", tooltip="FK_posterminal_company", weight=3]; - posterminal:root_category_id:w -> category:in7:n [color="#ff5f9e", fontcolor="#ff5f9e", tooltip="FK_posterminal_root_category", constraint=false, weight=1]; - posterminalcategory:posterminal_id:se -> posterminal:in0:n [color="#ffb25a", fontcolor="#ffb25a", tooltip="FK_posterminalcategory_posterminal", weight=3]; - posterminalcategory:category_id:w -> category:in4:n [color="#56d68a", fontcolor="#56d68a", tooltip="FK_posterminalcategory_category", constraint=false, weight=1]; - printer:company_id:w -> company:in5:n [color="#66b3ff", fontcolor="#66b3ff", tooltip="FK_printer_company", weight=3]; - labeltemplate:company_id:e -> company:in6:n [color="#c79bff", fontcolor="#c79bff", tooltip="FK_labeltemplate_company", weight=3]; - manifestattachment:manifest_id:se -> manifest:in1:n [color="#ff6b6b", fontcolor="#ff6b6b", tooltip="FK_manifestattachment_manifest", weight=3]; + companyuser:company_id:w -> company:in12:n [color="#ff6f6f", fontcolor="#ff6f6f", tooltip="FK_companyuser_company", weight=3]; + modelconversation:companyuser_id:w -> companyuser:in2:n [color="#4ecb8f", fontcolor="#4ecb8f", tooltip="FK_modelconversation_companyuser", weight=3]; + modelvfs:company_id:w -> company:in15:n [color="#5aa7e6", fontcolor="#5aa7e6", tooltip="FK_modelvfs_company", weight=3]; + modelmessage:conversation_id:se -> modelconversation:in0:n [color="#ff7aa8", fontcolor="#ff7aa8", tooltip="FK_modelmessage_conversation", weight=3]; + companysetting:company_id:e -> company:in13:n [color="#e0b25a", fontcolor="#e0b25a", tooltip="FK_companysetting_company", weight=3]; + posterminal:company_id:w -> company:in17:n [color="#56c8c8", fontcolor="#56c8c8", tooltip="FK_posterminal_company", weight=3]; + posterminal:root_category_id:w -> category:in6:n [color="#ff5f9e", fontcolor="#ff5f9e", tooltip="FK_posterminal_root_category", constraint=false, weight=1]; + posterminalcategory:posterminal_id:nw -> posterminal:in0:n [color="#ffb25a", fontcolor="#ffb25a", tooltip="FK_posterminalcategory_posterminal", weight=3]; + posterminalcategory:category_id:w -> category:in8:n [color="#56d68a", fontcolor="#56d68a", tooltip="FK_posterminalcategory_category", constraint=false, weight=1]; + printer:company_id:w -> company:in16:n [color="#66b3ff", fontcolor="#66b3ff", tooltip="FK_printer_company", weight=3]; + labeltemplate:company_id:w -> company:in18:n [color="#c79bff", fontcolor="#c79bff", tooltip="FK_labeltemplate_company", weight=3]; + manifestattachment:manifest_id:sw -> manifest:in1:n [color="#ff6b6b", fontcolor="#ff6b6b", tooltip="FK_manifestattachment_manifest", weight=3]; manifestattachment:file_id:w -> file:in0:n [color="#6bdf9a", fontcolor="#6bdf9a", tooltip="FK_manifestattachment_file", constraint=false, weight=1]; - propertyname:company_id:se -> company:in8:n [color="#5aa7ff", fontcolor="#5aa7ff", tooltip="FK_propertyname_company", weight=3]; - articleproperty:article_id:w -> article:in10:n [color="#f5c15c", fontcolor="#f5c15c", tooltip="FK_articleproperty_article", weight=3]; - articleproperty:property_id:e -> propertyname:in1:n [color="#c79bff", fontcolor="#c79bff", tooltip="FK_articleproperty_property", constraint=false, weight=1]; - attributename:company_id:e -> company:in9:n [color="#ff9f5a", fontcolor="#ff9f5a", tooltip="FK_attributename_company", weight=3]; - attributevalue:attribute_id:se -> attributename:in2:n [color="#5cd6d6", fontcolor="#5cd6d6", tooltip="FK_attributevalue_attribute", weight=3]; - articleattributevalue:article_id:e -> article:in11:n [color="#ff7fc2", fontcolor="#ff7fc2", tooltip="FK_articleattributevalue_article", weight=3]; - articleattributevalue:attributevalue_id:w -> attributevalue:in0:n [color="#8f95ff", fontcolor="#8f95ff", tooltip="FK_articleattributevalue_attributevalue", constraint=false, weight=1]; - categoryproperty:category_id:w -> category:in6:n [color="#58d18a", fontcolor="#58d18a", tooltip="FK_categoryproperty_category", weight=3]; + propertyname:company_id:e -> company:in0:n [color="#5aa7ff", fontcolor="#5aa7ff", tooltip="FK_propertyname_company", weight=3]; + articleproperty:article_id:e -> article:in1:n [color="#f5c15c", fontcolor="#f5c15c", tooltip="FK_articleproperty_article", weight=3]; + articleproperty:property_id:w -> propertyname:in1:n [color="#c79bff", fontcolor="#c79bff", tooltip="FK_articleproperty_property", constraint=false, weight=1]; + attributename:company_id:e -> company:in1:n [color="#ff9f5a", fontcolor="#ff9f5a", tooltip="FK_attributename_company", weight=3]; + attributevalue:attribute_id:e -> attributename:in2:n [color="#5cd6d6", fontcolor="#5cd6d6", tooltip="FK_attributevalue_attribute", weight=3]; + articleattributevalue:article_id:e -> article:in0:n [color="#ff7fc2", fontcolor="#ff7fc2", tooltip="FK_articleattributevalue_article", weight=3]; + articleattributevalue:attributevalue_id:w -> attributevalue:in1:n [color="#8f95ff", fontcolor="#8f95ff", tooltip="FK_articleattributevalue_attributevalue", constraint=false, weight=1]; + categoryproperty:category_id:e -> category:in0:n [color="#58d18a", fontcolor="#58d18a", tooltip="FK_categoryproperty_category", weight=3]; categoryproperty:property_id:e -> propertyname:in0:n [color="#ff8f66", fontcolor="#ff8f66", tooltip="FK_categoryproperty_property", constraint=false, weight=1]; - categoryattributevalue:category_id:w -> category:in5:n [color="#4fc4e8", fontcolor="#4fc4e8", tooltip="FK_categoryattributevalue_category", weight=3]; - categoryattributevalue:attributevalue_id:e -> attributevalue:in1:n [color="#a98cff", fontcolor="#a98cff", tooltip="FK_categoryattributevalue_attributevalue", constraint=false, weight=1]; - account:company_id:e -> company:in7:n [color="#ff6f6f", fontcolor="#ff6f6f", tooltip="FK_account_company", weight=3]; + categoryattributevalue:category_id:e -> category:in1:n [color="#4fc4e8", fontcolor="#4fc4e8", tooltip="FK_categoryattributevalue_category", weight=3]; + categoryattributevalue:attributevalue_id:e -> attributevalue:in0:n [color="#a98cff", fontcolor="#a98cff", tooltip="FK_categoryattributevalue_attributevalue", constraint=false, weight=1]; + account:company_id:w -> company:in2:n [color="#ff6f6f", fontcolor="#ff6f6f", tooltip="FK_account_company", weight=3]; payment:account_id:w -> account:in0:n [color="#4ecb8f", fontcolor="#4ecb8f", tooltip="FK_payment_account", constraint=false, weight=1]; - payment:manifest_id:se -> manifest:in0:n [color="#5aa7e6", fontcolor="#5aa7e6", tooltip="FK_payment_manifest", weight=3]; + payment:manifest_id:e -> manifest:in0:n [color="#5aa7e6", fontcolor="#5aa7e6", tooltip="FK_payment_manifest", weight=3]; shipping:manifest_id:sw -> manifest:in3:n [color="#ff7aa8", fontcolor="#ff7aa8", tooltip="FK_shipping_manifest", weight=3]; - package:shipping_id:e -> shipping:in0:n [color="#e0b25a", fontcolor="#e0b25a", tooltip="FK_package_shipping", constraint=false, weight=1]; - package:entityaddress_id:sw -> entityaddress:in0:n [color="#56c8c8", fontcolor="#56c8c8", tooltip="FK_package_entityaddress", weight=3]; + package:shipping_id:sw -> shipping:in0:n [color="#e0b25a", fontcolor="#e0b25a", tooltip="FK_package_shipping", constraint=false, weight=1]; + package:entityaddress_id:e -> entityaddress:in0:n [color="#56c8c8", fontcolor="#56c8c8", tooltip="FK_package_entityaddress", weight=3]; } \ No newline at end of file diff --git a/schema-graph.svg b/schema-graph.svg index 9040c17..08de2cb 100644 --- a/schema-graph.svg +++ b/schema-graph.svg @@ -4,297 +4,297 @@ - - + + schema - + cluster_identity - -Identity & Company + +Identity & Company cluster_i18n - -Localization + +Localization cluster_catalog - -Catalog + +Catalog cluster_media - -Media + +Media cluster_manifests - -Documents + +Documents & Shipping cluster_commerce - -Pricing + +Pricing & Payments cluster_units - -Units + +Units cluster_pos - -POS + +POS cluster_ai - -AI & Models + +AI & Models cluster_attributes - -Properties & Attributes + +Properties & Attributes + + + +meta + + +meta + + +key +NVARCHAR(255) + + +value +NVARCHAR(MAX) - + customergroup - - - - - -customergroup - - -id -INT -PK - - -company_id -? -INT -FK - - -name -NVARCHAR(255) - - -sort -INT - - -updated_at -DATETIME2 + + + + + +customergroup + + +id +INT +PK + + +company_id +? +INT +FK + + +name +NVARCHAR(255) + + +sort +INT + + +updated_at +DATETIME2 company - - - - - - - - - - - - - - - - - - - - - -company - - -id -INT -PK - - -default_language_id -? -INT -FK - - -root_category_id -? -INT -FK - - -taxrate -? -INT -FK - - -reducedtaxrate -? -INT -FK - - -taxfreerate -? -INT -FK - - -poscustomergroup_id -INT -FK - - -name -NVARCHAR(255) + + + + + + + + + + + + + + + + + + + + + +company + + +id +INT +PK + + +default_language_id +? +INT +FK + + +taxrate +? +INT +FK + + +reducedtaxrate +? +INT +FK + + +taxfreerate +? +INT +FK + + +root_category_id +? +INT +FK + + +poscustomergroup_id +INT +FK + + +name +NVARCHAR(255) customergroup:se->company:n - - + + - - -meta - - -meta - - -key -NVARCHAR(255) - - -value -NVARCHAR(MAX) - company:ne->customergroup:n - - + + language - - - - - - -language - - -id -INT -PK - - -iso639 -NVARCHAR(10) + + + + + + +language + + +id +INT +PK + + +iso639 +NVARCHAR(10) company:w->language:n - - + + - + category - - - - - - - - - - - -category - - -id -INT -PK - - -parent_id -? -INT -FK - - -sort -INT - - -updated_at -DATETIME2 + + + + + + + + + + + +category + + +id +INT +PK + + +parent_id +? +INT +FK + + +sort +INT + + +updated_at +DATETIME2 company:w->category:n - - + + - + tax - - - - - - - -tax - - -id -INT -PK - - -rate -DECIMAL(18,4) + + + + + + + +tax + + +id +INT +PK + + +rate +DECIMAL(18,4) company:w->tax:n - - + + @@ -302,8 +302,8 @@ company:w->tax:n - - + + @@ -311,188 +311,188 @@ company:w->tax:n - - + + + + + + + +entityaddress + + + +entityaddress + + +id +INT +PK + + +entity_id +INT +FK + + +first_name? +NVARCHAR(255) + + +name? +NVARCHAR(255) + + +street? +NVARCHAR(255) + + +streetnumber? +NVARCHAR(50) + + +zip? +NVARCHAR(50) + + +city? +NVARCHAR(255) + + +county? +NVARCHAR(255) + + +addresstype +NVARCHAR(50) + + +sort +INT + + + +entity + + + + + + + +entity + + +id +INT +PK + + +customergroup_id +INT +FK + + +first_name? +NVARCHAR(255) + + +name +NVARCHAR(255) + + +number? +NVARCHAR(100) + + +created_at +DATETIME2 + + +updated_at +DATETIME2 + + + +entityaddress:ne->entity:n + + + - + companyhistory - - -companyhistory - - -id -INT -PK - - -company_id -INT -FK - - -companyuser_id -? -INT -FK - - -date -DATETIME2 - - -text -NVARCHAR(MAX) + + +companyhistory + + +id +INT +PK + + +company_id +INT +FK + + +companyuser_id +? +INT +FK + + +date +DATETIME2 + + +text +NVARCHAR(MAX) companyhistory:nw->company:n - - + + companyuser - - - - - - -companyuser - - -id -INT -PK - - -company_id -INT -FK - - -google_auth_id -INT -FK + + + + + + +companyuser + + +id +INT +PK + + +company_id +INT +FK + + +google_auth_id +INT +FK companyhistory:e->companyuser:n - - - - - - - -entityaddress - - - -entityaddress - - -id -INT -PK - - -entity_id -INT -FK - - -first_name? -NVARCHAR(255) - - -name? -NVARCHAR(255) - - -street? -NVARCHAR(255) - - -streetnumber? -NVARCHAR(50) - - -zip? -NVARCHAR(50) - - -city? -NVARCHAR(255) - - -county? -NVARCHAR(255) - - -addresstype -NVARCHAR(50) - - -sort -INT - - - -entity - - - - - - - -entity - - -id -INT -PK - - -customergroup_id -INT -FK - - -first_name? -NVARCHAR(255) - - -name -NVARCHAR(255) - - -number? -NVARCHAR(100) - - -created_at -DATETIME2 - - -updated_at -DATETIME2 - - - -entityaddress:ne->entity:n - - - + + @@ -500,88 +500,88 @@ entity:sw->customergroup:n - - + + numbers - - -numbers - - -id -INT -PK - - -company_id -INT -FK - - -type -NVARCHAR(100) - - -prefix -NVARCHAR(50) - - -padding -INT - - -next -INT + + +numbers + + +id +INT +PK + + +company_id +INT +FK + + +type +NVARCHAR(100) + + +prefix +NVARCHAR(50) + + +padding +INT + + +next +INT numbers:se->company:n - - + + entitycontact - - -entitycontact - - -id -INT -PK - - -entity_id -INT -FK - - -contacttype -NVARCHAR(50) - - -contact -NVARCHAR(255) - - -sort -INT + + +entitycontact + + +id +INT +PK + + +entity_id +INT +FK + + +contacttype +NVARCHAR(50) + + +contact +NVARCHAR(255) + + +sort +INT entitycontact:sw->entity:n - - + + @@ -589,96 +589,96 @@ companyuser:w->company:n - - + + google_auth - - - -google_auth - - -id -INT -PK - - -selected_company -? -INT -FK - - -email -NVARCHAR(320) - - -picture? -NVARCHAR(2048) - - -picturebinary? -VARBINARY(MAX) - - -sub? -NVARCHAR(255) - - -created_at -DATETIME2 + + + +google_auth + + +id +INT +PK + + +selected_company +? +INT +FK + + +email +NVARCHAR(320) + + +picture? +NVARCHAR(2048) + + +picturebinary? +VARBINARY(MAX) + + +sub? +NVARCHAR(255) + + +created_at +DATETIME2 companyuser:e->google_auth:n - - + + entityhistory - - -entityhistory - - -id -INT -PK - - -entity_id -INT -FK - - -companyuser_id -? -INT -FK - - -date -DATETIME2 - - -text -NVARCHAR(MAX) + + +entityhistory + + +id +INT +PK + + +entity_id +INT +FK + + +companyuser_id +? +INT +FK + + +date +DATETIME2 + + +text +NVARCHAR(MAX) entityhistory:sw->entity:n - - + + @@ -686,50 +686,50 @@ entityhistory:se->companyuser:n - - + + companysetting - - -companysetting - - -id -INT -PK - - -company_id -INT -FK - - -key -NVARCHAR(255) - - -value -NVARCHAR(MAX) - - -frontend -BIT - - -writeonly -BIT + + +companysetting + + +id +INT +PK + + +company_id +INT +FK + + +key +NVARCHAR(255) + + +value +NVARCHAR(MAX) + + +frontend +BIT + + +writeonly +BIT companysetting:e->company:n - - + + @@ -737,286 +737,134 @@ google_auth:w->company:n - - + + unittext - - -unittext - - -id -INT -PK - - -language_id -INT -FK - - -unit_id -INT -FK - - -symbol -NVARCHAR(50) - - -name -NVARCHAR(255) + + +unittext + + +id +INT +PK + + +language_id +INT +FK + + +unit_id +INT +FK + + +symbol +NVARCHAR(50) + + +name +NVARCHAR(255) unittext:w->language:n - - + + - + unit - - - - -unit - - -id -INT -PK - - -company_id -INT -FK - - -si -NVARCHAR(50) - - -basesi -NVARCHAR(50) - - -basesifactor -FLOAT + + + + +unit + + +id +INT +PK + + +company_id +INT +FK + + +si +NVARCHAR(50) + + +basesi +NVARCHAR(50) + + +basesifactor +FLOAT -unittext:se->unit:n +unittext:w->unit:n - - - - - - - -articletext - - -articletext - - -id -INT -PK - - -language_id -INT -FK - - -article_id -INT -FK - - -name -NVARCHAR(255) - - -slug -NVARCHAR(255) - - -seo? -NVARCHAR(MAX) - - -desc? -NVARCHAR(MAX) - - - -articletext:w->language:n - - - - - - - - -article - - - - - - - - - - - - - - -article - - -id -INT -PK - - -unit_id -INT -FK - - -brand_id -? -INT -FK - - -articlelist_id -? -INT -FK - - -optionslist_id -? -INT -FK - - -parentarticle_id -? -INT -FK - - -parentattributename_id -? -INT -FK - - -company_id -INT -FK - - -sku? -NVARCHAR(100) - - -unitamount -FLOAT - - -weight -FLOAT - - -track_stock -BIT - - -is_parent -BIT - - -parentsort -INT - - -created_at -DATETIME2 - - -updated_at -DATETIME2 - - - -articletext:e->article:n - - - + + - + categorytext - - -categorytext - - -id -INT -PK - - -language_id -INT -FK - - -category_id -INT -FK - - -name -NVARCHAR(255) - - -slug -NVARCHAR(255) - - -seo? -NVARCHAR(MAX) - - -desc? -NVARCHAR(MAX) + + +categorytext + + +id +INT +PK + + +language_id +INT +FK + + +category_id +INT +FK + + +name +NVARCHAR(255) + + +slug +NVARCHAR(255) + + +seo? +NVARCHAR(MAX) + + +desc? +NVARCHAR(MAX) categorytext:w->language:n - - + + @@ -1024,480 +872,200 @@ categorytext:w->category:n - - + + - - -articletombstone - - -articletombstone - - -id -INT -PK - - -company_id -INT -FK - - -article_id? -INT - - -sku? -NVARCHAR(100) - - -name? -NVARCHAR(255) - - -taxrate? -DECIMAL(18,4) - - -net? -FLOAT - - -deleted_at -DATETIME2 + + +articletext + + +articletext + + +id +INT +PK + + +language_id +INT +FK + + +article_id +INT +FK + + +name +NVARCHAR(255) + + +slug +NVARCHAR(255) + + +seo? +NVARCHAR(MAX) + + +desc? +NVARCHAR(MAX) - - -articletombstone:w->company:n - - - + + +articletext:w->language:n + + + - - -brand - - - - -brand - - -id -INT -PK - - -company_id -INT -FK - - -name -NVARCHAR(255) - - -gsprpinfo? -NVARCHAR(MAX) - - - -brand:e->company:n - - - - - - - - -articlelist - - - - -articlelist - - -id -INT -PK - - + -articlelistarticle - - -articlelistarticle - - -id -INT -PK - - -articlelist_id -INT -FK - - -article_id -INT -FK - - -count -INT - - -sort -INT +article + + + + + + + + + + + + + + +article + + +id +INT +PK + + +parentattributename_id +? +INT +FK + + +unit_id +INT +FK + + +parentarticle_id +? +INT +FK + + +articlelist_id +? +INT +FK + + +optionslist_id +? +INT +FK + + +brand_id +? +INT +FK + + +company_id +INT +FK + + +sku? +NVARCHAR(100) + + +unitamount +FLOAT + + +weight +FLOAT + + +track_stock +BIT + + +is_parent +BIT + + +parentsort +INT + + +created_at +DATETIME2 + + +updated_at +DATETIME2 - - -articlelistarticle:nw->articlelist:n - - - + + +articletext:e->article:n + + + - - -articlelistarticle:w->article:n - - - + + +categoryarticle + + +categoryarticle + + +id +INT +PK + + +category_id +INT +FK + + +article_id +INT +FK + + + +categoryarticle:sw->category:n + + + - - -optionslist - - - - -optionslist - - -id -INT -PK - - - -optionslistarticle - - -optionslistarticle - - -id -INT -PK - - -optionslist_id -INT -FK - - -article_id -INT -FK - - -count -INT - - -sort -INT - - -mandated -BIT - - - -optionslistarticle:sw->optionslist:n - - - - - - - - -optionslistarticle:w->article:n - - - - - - - - -articlehistory - - -articlehistory - - -id -INT -PK - - -article_id -INT -FK - - -companyuser_id -? -INT -FK - - -date -DATETIME2 - - -text -NVARCHAR(MAX) - - - -articlehistory:e->companyuser:n - - - - - - - - -articlehistory:se->article:n - - - - - - - - -articleean - - -articleean - - -id -INT -PK - - -article_id -INT -FK - - -ean -NVARCHAR(50) - - - -articleean:ne->article:n - - - - - - - - -article:w->company:n - - - - - - - - -article:w->brand:n - - - - - - - - -article:w->articlelist:n - - - - - - - - -article:w->optionslist:n - - - - - - - - -article:e->article:e - - - - - - - - -article:w->unit:n - - - - - - - - -attributename - - - - - -attributename - - -id -INT -PK - - -company_id -INT -FK - - -name -NVARCHAR(255) - - -sort -INT - - -exclusive -BIT - - - -article:se->attributename:n - - - - - - - - -article:se->attributename:n - - - - - - - - -articlesupplier - - -articlesupplier - - -id -INT -PK - - -article_id -INT -FK - - -tax_id -? -INT -FK - - -entity_id -INT -FK - - -net? -FLOAT - - -sku? -NVARCHAR(100) - - -stock? -FLOAT - - -pu -FLOAT - - -sort -INT - - - -articlesupplier:e->entity:n - - - - - - - - -articlesupplier:sw->article:n - - - - - - - - -articlesupplier:e->tax:n - - - + + +categoryarticle:sw->article:n + + + @@ -1505,194 +1073,582 @@ category:e->category:e - - + + - + + +articlehistory + + +articlehistory + + +id +INT +PK + + +article_id +INT +FK + + +companyuser_id +? +INT +FK + + +date +DATETIME2 + + +text +NVARCHAR(MAX) + + + +articlehistory:e->companyuser:n + + + + + + + + +articlehistory:sw->article:n + + + + + + + + +article:w->company:n + + + + + + + + +article:e->article:e + + + + + + + + +articlelist + + + + +articlelist + + +id +INT +PK + + + +article:w->articlelist:n + + + + + + + + +optionslist + + + + +optionslist + + +id +INT +PK + + + +article:w->optionslist:n + + + + + + + + +brand + + + + +brand + + +id +INT +PK + + +company_id +INT +FK + + +name +NVARCHAR(255) + + +gsprpinfo? +NVARCHAR(MAX) + + + +article:w->brand:n + + + + + + + + +article:e->unit:n + + + + + + + + +attributename + + + + + +attributename + + +id +INT +PK + + +company_id +INT +FK + + +name +NVARCHAR(255) + + +sort +INT + + +exclusive +BIT + + + +article:ne->attributename:n + + + + + + + + +article:ne->attributename:n + + + + + + + + +articleean + + +articleean + + +id +INT +PK + + +article_id +INT +FK + + +ean +NVARCHAR(50) + + + +articleean:se->article:n + + + + + + + + +articlesupplier + + +articlesupplier + + +id +INT +PK + + +tax_id +? +INT +FK + + +article_id +INT +FK + + +entity_id +INT +FK + + +net? +FLOAT + + +sku? +NVARCHAR(100) + + +stock? +FLOAT + + +pu +FLOAT + + +sort +INT + + + +articlesupplier:e->entity:n + + + + + + + + +articlesupplier:nw->article:n + + + + + + + + +articlesupplier:e->tax:n + + + + + + + + +articlelistarticle + + +articlelistarticle + + +id +INT +PK + + +article_id +INT +FK + + +articlelist_id +INT +FK + + +count +INT + + +sort +INT + + + +articlelistarticle:w->article:n + + + + + + + + +articlelistarticle:se->articlelist:n + + + + + + + + +optionslistarticle + + +optionslistarticle + + +id +INT +PK + + +article_id +INT +FK + + +optionslist_id +INT +FK + + +count +INT + + +sort +INT + + +mandated +BIT + + + +optionslistarticle:w->article:n + + + + + + + + +optionslistarticle:sw->optionslist:n + + + + + + + + +brand:w->company:n + + + + + + + -categoryarticle - - -categoryarticle - - -id -INT -PK - - -article_id -INT -FK - - -category_id -INT -FK +articletombstone + + +articletombstone + + +id +INT +PK + + +company_id +INT +FK + + +article_id? +INT + + +sku? +NVARCHAR(100) + + +name? +NVARCHAR(255) + + +taxrate? +DECIMAL(18,4) + + +net? +FLOAT + + +deleted_at +DATETIME2 - - -categoryarticle:sw->article:n - - - - - - - - -categoryarticle:nw->category:n - - - + + +articletombstone:w->company:n + + + pic - - - - - -pic - - -id -INT -PK - - -w -INT - - -h -INT - - -size -BIGINT - - -hash -NVARCHAR(64) - - -thumbw -INT - - -thumbh -INT - - -thumbhash -NVARCHAR(64) - - -smallthumbw -INT - - -smallthumbh -INT - - -source -NVARCHAR(MAX) - - -fullbinary -VARBINARY(MAX) - - -thumbbinary -VARBINARY(MAX) - - -smallthumbbinary -VARBINARY(MAX) - - - -brandpic - - -brandpic - - -id -INT -PK - - -brand_id -INT -FK - - -pic_id -INT -FK - - -sort -INT - - - -brandpic:w->brand:n - - - - - - - - -brandpic:w->pic:n - - - - - + + + + + +pic + + +id +INT +PK + + +w +INT + + +h +INT + + +size +BIGINT + + +hash +NVARCHAR(64) + + +thumbw +INT + + +thumbh +INT + + +thumbhash +NVARCHAR(64) + + +smallthumbw +INT + + +smallthumbh +INT + + +source +NVARCHAR(MAX) + + +fullbinary +VARBINARY(MAX) + + +thumbbinary +VARBINARY(MAX) + + +smallthumbbinary +VARBINARY(MAX) - + articlepic - - -articlepic - - -id -INT -PK - - -article_id -INT -FK - - -pic_id -INT -FK - - -sort -INT + + +articlepic + + +id +INT +PK + + +pic_id +INT +FK + + +article_id +INT +FK + + +sort +INT articlepic:se->article:n - - + + @@ -1700,43 +1656,43 @@ articlepic:w->pic:n - - + + - + categorypic - - -categorypic - - -id -INT -PK - - -pic_id -INT -FK - - -category_id -INT -FK - - -sort -INT + + +categorypic + + +id +INT +PK + + +pic_id +INT +FK + + +category_id +INT +FK + + +sort +INT categorypic:sw->category:n - - + + @@ -1744,1199 +1700,454 @@ categorypic:w->pic:n - - + + + + + + + +brandpic + + +brandpic + + +id +INT +PK + + +pic_id +INT +FK + + +brand_id +INT +FK + + +sort +INT + + + +brandpic:e->brand:n + + + + + + + + +brandpic:w->pic:n + + + file - - - -file - - -id -INT -PK - - -hash -NVARCHAR(64) - - -mimetype -NVARCHAR(255) - - -name -NVARCHAR(255) - - -size -BIGINT - - -created -DATETIME2 - - -modified -DATETIME2 - - -content -VARBINARY(MAX) - - -thumbavif? -VARBINARY(MAX) - - -thumbx? -INT - - -thumby? -INT - - -meta? -NVARCHAR(MAX) - - - -warehouse - - - -warehouse - - -id -INT -PK - - -company_id -INT -FK - - -name -NVARCHAR(255) - - -sort -INT - - - -warehouse:w->company:n - - - - - + + + +file + + +id +INT +PK + + +hash +NVARCHAR(64) + + +mimetype +NVARCHAR(255) + + +name +NVARCHAR(255) + + +size +BIGINT + + +created +DATETIME2 + + +modified +DATETIME2 + + +content +VARBINARY(MAX) + + +thumbavif? +VARBINARY(MAX) + + +thumbx? +INT + + +thumby? +INT + + +meta? +NVARCHAR(MAX) - + manifestarticle - - - -manifestarticle - - -id -INT -PK - - -manifest_id -INT -FK - - -sku? -NVARCHAR(100) - - -name? -NVARCHAR(255) - - -pu -FLOAT - - -amount -FLOAT - - -net -FLOAT - - -comment? -NVARCHAR(MAX) - - -rebate -FLOAT - - -taxrate -FLOAT + + + +manifestarticle + + +id +INT +PK + + +manifest_id +INT +FK + + +sku? +NVARCHAR(100) + + +name? +NVARCHAR(255) + + +pu +FLOAT + + +amount +FLOAT + + +net +FLOAT + + +comment? +NVARCHAR(MAX) + + +rebate +FLOAT + + +taxrate +FLOAT - + manifest - - - - - - -manifest - - -id -INT -PK - - -company_id -INT -FK - - -entity_id -? -INT -FK - - -number -NVARCHAR(100) - - -type -NVARCHAR(100) - - -external_number? -NVARCHAR(100) - - -date -DATETIME2 - - -created_at -DATETIME2 + + + + + + +manifest + + +id +INT +PK + + +company_id +INT +FK + + +entity_id +? +INT +FK + + +number +NVARCHAR(100) + + +type +NVARCHAR(100) + + +external_number? +NVARCHAR(100) + + +date +DATETIME2 + + +created_at +DATETIME2 -manifestarticle:nw->manifest:n +manifestarticle:sw->manifest:n - - - - - - - -manifest:e->company:n - - - - - - - - -manifest:w->entity:n - - - + + - + ledger - - -ledger - - -id -INT -PK - - -warehouse_id -? -INT -FK - - -manifestarticle_id -INT -FK - - -transaction_type -NVARCHAR(100) - - -amount -FLOAT - - -transaction_text -NVARCHAR(MAX) - - -hash_version -INT - - -prev_hash? -NVARCHAR(128) - - -created_at -DATETIME2 - - - -ledger:w->warehouse:n - - - - - + + +ledger + + +id +INT +PK + + +manifestarticle_id +INT +FK + + +warehouse_id +? +INT +FK + + +transaction_type +NVARCHAR(100) + + +amount +FLOAT + + +transaction_text +NVARCHAR(MAX) + + +hash_version +INT + + +prev_hash? +NVARCHAR(128) + + +created_at +DATETIME2 ledger:sw->manifestarticle:n - - + + + + + + + +warehouse + + + +warehouse + + +id +INT +PK + + +company_id +INT +FK + + +name +NVARCHAR(255) + + +sort +INT + + + +ledger:e->warehouse:n + + + - + manifestattachment - - -manifestattachment - - -id -INT -PK - - -file_id -INT -FK - - -manifest_id -INT -FK - - -sort -INT + + +manifestattachment + + +id +INT +PK + + +file_id +INT +FK + + +manifest_id +INT +FK + + +sort +INT manifestattachment:w->file:n - - + + -manifestattachment:se->manifest:n +manifestattachment:sw->manifest:n - - - - - - - -price - - -price - - -id -INT -PK - - -article_id -INT -FK - - -tax_id -INT -FK - - -customergroup_id -INT -FK - - -minmultiplier -DECIMAL(18,4) - - -net -FLOAT - - - -price:e->customergroup:n - - - - - - - - -price:e->article:n - - - - - - - - -price:w->tax:n - - - - - - - - -unit:e->company:n - - - - - - - - -posterminalcategory - - -posterminalcategory - - -id -INT -PK - - -category_id -INT -FK - - -posterminal_id -INT -FK - - - -posterminalcategory:w->category:n - - - - - - - - -posterminal - - - -posterminal - - -id -INT -PK - - -root_category_id -? -INT -FK - - -company_id -INT -FK - - -name -NVARCHAR(255) - - -token? -NVARCHAR(255) - - -pairingpin? -NVARCHAR(50) - - -paired_at? -DATETIME2 - - -clientserial? -NVARCHAR(255) - - -maxknowntombstoneid? -INT - - -sync_root_articles -BIT - - -lastseen_at? -DATETIME2 - - -updated_at -DATETIME2 - - - -posterminalcategory:se->posterminal:n - - - - - - - - -posterminal:e->company:n - - - - - - - - -posterminal:w->category:n - - - - - - - - -printer - - -printer - - -id -INT -PK - - -company_id -INT -FK - - -address -NVARCHAR(255) - - -type -NVARCHAR(50) - - -model? -NVARCHAR(255) - - -serial? -NVARCHAR(255) - - -sort -INT - - -desc? -NVARCHAR(MAX) - - - -printer:w->company:n - - - - - - - - -labeltemplate - - -labeltemplate - - -id -INT -PK - - -company_id -INT -FK - - -name -NVARCHAR(255) - - -width -INT - - -height -INT - - -dpi -INT - - -type -NVARCHAR(50) - - -content -NVARCHAR(MAX) - - -thumb? -VARBINARY(MAX) - - - -labeltemplate:e->company:n - - - - - - - - -modelvfs - - -modelvfs - - -id -INT -PK - - -company_id -INT -FK - - -name -NVARCHAR(255) - - -mime -NVARCHAR(100) - - -content -VARBINARY(MAX) - - -meta -NVARCHAR(MAX) - - -created_at -DATETIME2 - - -updated_at -DATETIME2 - - - -modelvfs:se->company:n - - - - - - - - -modelconversation - - - -modelconversation - - -id -INT -PK - - -companyuser_id -INT -FK - - -provider -NVARCHAR(100) - - -model -NVARCHAR(255) - - -created_at -DATETIME2 - - -updated_at -DATETIME2 - - -state -NVARCHAR(20) - - - -modelconversation:e->companyuser:n - - - - - - - - -modelmessage - - -modelmessage - - -id -INT -PK - - -conversation_id -INT -FK - - -created_at -DATETIME2 - - -role -NVARCHAR(20) - - -message -NVARCHAR(MAX) - - - -modelmessage:sw->modelconversation:n - - - - - - - - -articleproperty - - -articleproperty - - -id -INT -PK - - -article_id -INT -FK - - -property_id -INT -FK - - -value -NVARCHAR(MAX) - - -sort -INT - - - -articleproperty:w->article:n - - - - - - - - -propertyname - - - - -propertyname - - -id -INT -PK - - -company_id -INT -FK - - -name -NVARCHAR(255) - - -sort -INT - - -exclusive -BIT - - - -articleproperty:e->propertyname:n - - - - - - - - -articleattributevalue - - -articleattributevalue - - -id -INT -PK - - -article_id -INT -FK - - -attributevalue_id -INT -FK - - -sort -INT - - - -articleattributevalue:e->article:n - - - - - - - - -attributevalue - - - - -attributevalue - - -id -INT -PK - - -attribute_id -INT -FK - - -value -NVARCHAR(255) - - -sort -INT - - - -articleattributevalue:w->attributevalue:n - - - - - - - - -categoryproperty - - -categoryproperty - - -id -INT -PK - - -category_id -INT -FK - - -property_id -INT -FK - - -value -NVARCHAR(MAX) - - -sort -INT - - - -categoryproperty:w->category:n - - - - - - - - -categoryproperty:e->propertyname:n - - - - - - - - -categoryattributevalue - - -categoryattributevalue - - -id -INT -PK - - -category_id -INT -FK - - -attributevalue_id -INT -FK - - -sort -INT - - - -categoryattributevalue:w->category:n - - - - - - - - -categoryattributevalue:e->attributevalue:n - - - - - - - - -propertyname:se->company:n - - - - - - - - -attributename:e->company:n - - - - - - - - -attributevalue:se->attributename:n - - - - - - - - -account - - - -account - - -id -INT -PK - - -company_id -INT -FK - - -type -NVARCHAR(100) - - -name -NVARCHAR(255) - - - -account:e->company:n - - - + + - + package - - -package - - -id -INT -PK - - -entityaddress_id -INT -FK - - -shipping_id -INT -FK - - -number -NVARCHAR(100) - - -type -NVARCHAR(100) - - -state -NVARCHAR(100) - - -details? -NVARCHAR(MAX) + + +package + + +id +INT +PK + + +shipping_id +INT +FK + + +entityaddress_id +INT +FK + + +number +NVARCHAR(100) + + +type +NVARCHAR(100) + + +state +NVARCHAR(100) + + +details? +NVARCHAR(MAX) -package:sw->entityaddress:n +package:e->entityaddress:n - - + + - + shipping - - - -shipping - - -id -INT -PK - - -manifest_id -INT -FK - - -number -NVARCHAR(100) - - -type -NVARCHAR(100) - - -state -NVARCHAR(100) + + + +shipping + + +id +INT +PK + + +manifest_id +INT +FK + + +number +NVARCHAR(100) + + +type +NVARCHAR(100) + + +state +NVARCHAR(100) -package:e->shipping:n +package:sw->shipping:n - - + + - - -payment - - -payment - - -id -INT -PK - - -account_id -INT -FK - - -manifest_id -INT -FK - - -type -NVARCHAR(100) - - -amount -FLOAT - - - -payment:se->manifest:n - - - + + +manifest:sw->company:n + + + - - -payment:w->account:n - - - + + +manifest:e->entity:n + + + @@ -2944,38 +2155,827 @@ shipping:sw->manifest:n - - + + + + + + + +warehouse:se->company:n + + + + + + + + +account + + + +account + + +id +INT +PK + + +company_id +INT +FK + + +type +NVARCHAR(100) + + +name +NVARCHAR(255) + + + +account:w->company:n + + + + + + + + +price + + +price + + +id +INT +PK + + +tax_id +INT +FK + + +article_id +INT +FK + + +customergroup_id +INT +FK + + +minmultiplier +DECIMAL(18,4) + + +net +FLOAT + + + +price:e->customergroup:n + + + + + + + + +price:w->article:n + + + + + + + + +price:e->tax:n + + + + + + + + +payment + + +payment + + +id +INT +PK + + +account_id +INT +FK + + +manifest_id +INT +FK + + +type +NVARCHAR(100) + + +amount +FLOAT + + + +payment:e->manifest:n + + + + + + + + +payment:w->account:n + + + + + + + + +unit:e->company:n + + + + + + + + +printer + + +printer + + +id +INT +PK + + +company_id +INT +FK + + +address +NVARCHAR(255) + + +type +NVARCHAR(50) + + +model? +NVARCHAR(255) + + +serial? +NVARCHAR(255) + + +sort +INT + + +desc? +NVARCHAR(MAX) + + + +printer:w->company:n + + + + + + + + +posterminal + + + +posterminal + + +id +INT +PK + + +root_category_id +? +INT +FK + + +company_id +INT +FK + + +name +NVARCHAR(255) + + +token? +NVARCHAR(255) + + +pairingpin? +NVARCHAR(50) + + +paired_at? +DATETIME2 + + +clientserial? +NVARCHAR(255) + + +maxknowntombstoneid? +INT + + +sync_root_articles +BIT + + +lastseen_at? +DATETIME2 + + +updated_at +DATETIME2 + + + +posterminal:w->company:n + + + + + + + + +posterminal:w->category:n + + + + + + + + +posterminalcategory + + +posterminalcategory + + +id +INT +PK + + +category_id +INT +FK + + +posterminal_id +INT +FK + + + +posterminalcategory:w->category:n + + + + + + + + +posterminalcategory:nw->posterminal:n + + + + + + + + +labeltemplate + + +labeltemplate + + +id +INT +PK + + +company_id +INT +FK + + +name +NVARCHAR(255) + + +width +INT + + +height +INT + + +dpi +INT + + +type +NVARCHAR(50) + + +content +NVARCHAR(MAX) + + +thumb? +VARBINARY(MAX) + + + +labeltemplate:w->company:n + + + + + + + + +modelmessage + + +modelmessage + + +id +INT +PK + + +conversation_id +INT +FK + + +created_at +DATETIME2 + + +role +NVARCHAR(20) + + +message +NVARCHAR(MAX) + + + +modelconversation + + + +modelconversation + + +id +INT +PK + + +companyuser_id +INT +FK + + +provider +NVARCHAR(100) + + +model +NVARCHAR(255) + + +created_at +DATETIME2 + + +updated_at +DATETIME2 + + +state +NVARCHAR(20) + + + +modelmessage:se->modelconversation:n + + + + + + + + +modelconversation:w->companyuser:n + + + + + + + + +modelvfs + + +modelvfs + + +id +INT +PK + + +company_id +INT +FK + + +name +NVARCHAR(255) + + +mime +NVARCHAR(100) + + +content +VARBINARY(MAX) + + +meta +NVARCHAR(MAX) + + +created_at +DATETIME2 + + +updated_at +DATETIME2 + + + +modelvfs:w->company:n + + + + + + + + +propertyname + + + + +propertyname + + +id +INT +PK + + +company_id +INT +FK + + +name +NVARCHAR(255) + + +sort +INT + + +exclusive +BIT + + + +propertyname:e->company:n + + + + + + + + +attributevalue + + + + +attributevalue + + +id +INT +PK + + +attribute_id +INT +FK + + +value +NVARCHAR(255) + + +sort +INT + + + +attributevalue:e->attributename:n + + + + + + + + +categoryproperty + + +categoryproperty + + +id +INT +PK + + +property_id +INT +FK + + +category_id +INT +FK + + +value +NVARCHAR(MAX) + + +sort +INT + + + +categoryproperty:e->category:n + + + + + + + + +categoryproperty:e->propertyname:n + + + + + + + + +categoryattributevalue + + +categoryattributevalue + + +id +INT +PK + + +attributevalue_id +INT +FK + + +category_id +INT +FK + + +sort +INT + + + +categoryattributevalue:e->category:n + + + + + + + + +categoryattributevalue:e->attributevalue:n + + + + + + + + +attributename:e->company:n + + + + + + + + +articleproperty + + +articleproperty + + +id +INT +PK + + +property_id +INT +FK + + +article_id +INT +FK + + +value +NVARCHAR(MAX) + + +sort +INT + + + +articleproperty:e->article:n + + + + + + + + +articleproperty:w->propertyname:n + + + + + + + + +articleattributevalue + + +articleattributevalue + + +id +INT +PK + + +attributevalue_id +INT +FK + + +article_id +INT +FK + + +sort +INT + + + +articleattributevalue:e->article:n + + + + + + + + +articleattributevalue:w->attributevalue:n + + + __legend - - - -Legend - -PK - -primary key - -FK - -foreign key - -? - -nullable column - -— - -FOREIGN KEY constraint - -- - - -naming convention only, no constraint + + + +Legend + +PK + +primary key + +FK + +foreign key + +? + +nullable column + +— + +FOREIGN KEY constraint + +- - + +naming convention only, no constraint