From 3396f16f4124f520f844fdbed76242a1eb338d6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Knuchel?= Date: Wed, 7 Aug 2024 16:28:47 +0200 Subject: [PATCH 01/16] Initial commit with design --- demos/ecommerce-usrv/README.md | 35 + demos/ecommerce-usrv/design.md | 815 ++++++++++++++++++ .../script_1_referential_sqlserver.sql | 100 +++ .../script_2_identity_mariadb.sql | 144 ++++ frontend/src/Models/Project/ColumnType.elm | 4 +- .../src/Models/Project/ProjectSettings.elm | 2 +- .../tests/Models/Project/ColumnTypeTest.elm | 2 + frontend/tests/Storage/ProjectV2Test.elm | 4 +- libs/connector-mariadb/src/index.ts | 3 +- 9 files changed, 1102 insertions(+), 7 deletions(-) create mode 100644 demos/ecommerce-usrv/README.md create mode 100644 demos/ecommerce-usrv/design.md create mode 100644 demos/ecommerce-usrv/script_1_referential_sqlserver.sql create mode 100644 demos/ecommerce-usrv/script_2_identity_mariadb.sql diff --git a/demos/ecommerce-usrv/README.md b/demos/ecommerce-usrv/README.md new file mode 100644 index 000000000..4c02dfee0 --- /dev/null +++ b/demos/ecommerce-usrv/README.md @@ -0,0 +1,35 @@ +# Azimutt full demo + +Here are some technical explanations to setup the [e-commerce micro-services demo](https://azimutt.app/fe9aef15-febe-490b-a631-225367749278/91395eb9-bd5d-4205-a8d6-d03bd1968ec4) of Azimutt. + +Have a look to the [associated blog](https://azimutt.app/blob/ecommerce-database-with-microservices-demo) post for more explanations of how to use it and what to look ;) + +Each domain has its own database, here is how to set them up: + +# Domains + +## Referential + +This domain is for general data. + +Import it in a [SQL Server database](../../libs/connector-sqlserver/README.md#local-setup) with the [script_1_referential_sqlserver.sql](script_1_referential_sqlserver.sql). +You will have it at this url: `sqlserver://sa:azimutt_42@localhost:1433/Referential` + +You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) + +## Identity + +This domain is user identity: who they are, what they can do. + +Import it in a [MariaDB database](../../libs/connector-mariadb/README.md#local-setup) with the [script_2_identity_mariadb.sql](script_2_identity_mariadb.sql). +You will have it at this url: `mariadb://root:mariadb@localhost:3307/identity` + +You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) + +## Inventory +## Catalog +## Shopping +## Billing +## Shipping +## CRM +## Analytics diff --git a/demos/ecommerce-usrv/design.md b/demos/ecommerce-usrv/design.md new file mode 100644 index 000000000..12b567c78 --- /dev/null +++ b/demos/ecommerce-usrv/design.md @@ -0,0 +1,815 @@ +# Referential + +referential.Countries | needs to be referenced for legal reasons + CountryId bigint pk + Code varchar + Name varchar + CreatedAt timestamp + DeletedAt timestamp nullable + +referential.States | used for auto-competes + StateId bigint pk + CountryId bigint fk referential.Countries.CountryId + Code varchar + Name varchar + CreatedAt timestamp + DeletedAt timestamp nullable + +referential.Cities | used for auto-competes + CityId bigint pk + StateId bigint fk referential.States.StateId + Name varchar + CreatedAt timestamp + DeletedAt timestamp nullable + +# Identity + +identity.Users + id bigint pk + first_name varchar index=name + last_name varchar index=name + username varchar unique + email varchar unique + settings json + created_at timestamp + updated_at timestamp + deleted_at timestamp nullable index + +identity.Credentials + user_id bigint pk fk identity.Users.id + provider auth_provider(password, google, linkedin, facebook, twitter) pk | the used provider + provider_id varchar pk | the user id from the provider, in case of password, stores the hashed password with the salt + provider_data json nullable + used_last timestamp + used_count int + created_at timestamp + updated_at timestamp | for password change mostly + +identity.PasswordResets + id bigint pk + email varchar index + token varchar index | the key sent by email to allow to change the password without being logged + requested_at timestamp + expire_at timestamp + used_at timestamp nullable + +identity.Devices | a device is a browser tagged by a random id in its session + id bigint pk + sid uuid unique | a unique id stored in the browser to track it when not logged + user_agent varchar + created_at timestamp | first time this device is seen + +identity.UserDevices | created on user login to know which users are using which devices + user_id bigint pk fk identity.Users.id + device_id bigint pk fk identity.Devices.id + linked_at timestamp | on login + unlinked_at timestamp nullable | on logout + +identity.AuthLogs + id bigint pk + user_id bigint nullable fk identity.Users.id + email varchar nullable + event auth_event(signup, login_success, login_failure, password_reset_asked, password_reset_used) + ip varchar + ip_location geography nullable + user_agent varchar + device_id bigint fk identity.Devices.id + created_at timestamp + +identity.TrustedDevices | users can add a device to their trusted ones, so they will have longer session and less security validations + user_id bigint pk fk identity.Users.id + device_id bigint fk identity.Devices.id + name varchar nullable + kind device_kind(desktop, tablet, phone) nullable + usage device_usage(perso, pro) nullable + used_last timestamp + created_at timestamp + deleted_at timestamp nullable index + +# Inventory + +inventory.Brands + id bigint pk + slug varchar unique | ex: "google" + name varchar unique | ex: "Google" + created_at timestamp + updated_at timestamp + deleted_at timestamp nullable index + +inventory.Products + id bigint pk + slug varchar unique | ex: "pixel-8-pro" + name varchar unique | ex: "Pixel 8 Pro" + brand bigint nullable fk inventory.Brands.id + category varchar nullable | ex: "Phones" + subcategory varchar nullable | ex: "Smartphones" + width float | typical width of the product, see Products for the real one + length float | typical length of the product, see Products for the real one + height float | typical height of the product, see Products for the real one + weight float | typical weight of the product, see Products for the real one + remarks text nullable | ex: fragile + created_at timestamp + updated_at timestamp + deleted_at timestamp nullable index + +inventory.ProductVersions + id bigint pk + product_id bigint fk inventory.Products.id + sku varchar(12) unique | internal id + ean varchar(13) unique | european id + name varchar unique | ex: "Pixel 8 Pro Menthe 128 Go" + specs json | specificities of this version, ex: `{color: "Menthe", storage: 128}` + width float + length float + height float + weight float + remarks text nullable + created_at timestamp + updated_at timestamp + deleted_at timestamp nullable index + +inventory.PhysicalProducts + id bigint pk + product_version_id bigint fk inventory.ProductVersions.id + snid varchar(12) unique | serial number of this product + expiration timestamp nullable | when Product has an expiration date, null otherwise + remarks text nullable + stored bigint nullable fk inventory.ShelfPositions.id + created_at timestamp + updated_at timestamp + deleted_at timestamp nullable index + +inventory.Employees + id bigint pk + first_name varchar index=name + last_name varchar index=name + email varchar nullable index + phone varchar nullable + created_at timestamp + created_by bigint fk identity.Users.id + updated_at timestamp + updated_by bigint fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +inventory.Suppliers + id bigint pk + name varchar index + level int | the lower, the more priority is given to this supplier + currency global_currency(EUR, USD) + created_at timestamp + updated_at timestamp + deleted_at timestamp nullable index + +inventory.SupplierPrices + supplier_id bigint pk fk inventory.Suppliers.id + product_version_id bigint pk fk inventory.ProductVersions.id + price double + created_at timestamp + updated_at timestamp + deleted_at timestamp nullable index + +inventory.SupplierEmployees + supplier_id bigint pk fk inventory.Suppliers.id + employee_id bigint pk fk inventory.Employees.id + role supplier_role(delivery, sale) + start timestamp nullable + end timestamp nullable + created_at timestamp + created_by bigint fk identity.Users.id + updated_at timestamp + updated_by bigint fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +inventory.PurchaseOrders + id bigint pk + supplier_id bigint fk inventory.Suppliers.id + price double | total price, computed from items price x quantity + currency global_currency(EUR, USD) + details text nullable | additional text for the supplier + notes text nullable | internal text for employees + created_at timestamp + created_by bigint fk identity.Users.id + updated_at timestamp + updated_by bigint fk identity.Users.id + sent_at timestamp nullable | can't be updated once sent + sent_by bigint nullable fk identity.Users.id + paid_at timestamp nullable + delivered_at timestamp nullable + validated_at timestamp nullable + validated_by bigint nullable fk identity.Users.id + +inventory.PurchaseOrderItems + purchase_order_id bigint pk fk inventory.PurchaseOrders.id + product_version_id bigint pk fk inventory.ProductVersions.id + quantity int + price double + created_at timestamp + created_by bigint fk identity.Users.id + updated_at timestamp + updated_by bigint fk identity.Users.id + +inventory.Warehouses + id bigint pk + name varchar unique + address global_address + manager bigint fk inventory.Employees.id + created_at timestamp + created_by bigint fk identity.Users.id + updated_at timestamp + updated_by bigint fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +inventory.Halls + id bigint pk + warehouse_id bigint fk inventory.Warehouses.id + name varchar index + manager bigint fk inventory.Employees.id + created_at timestamp + created_by bigint fk identity.Users.id + updated_at timestamp + updated_by bigint fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +inventory.Aisles + id bigint pk + hall_id bigint fk inventory.Halls.id + name varchar index + manager bigint fk inventory.Employees.id + created_at timestamp + created_by bigint fk identity.Users.id + updated_at timestamp + updated_by bigint fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +inventory.Racks + id bigint pk + aisle_id bigint fk inventory.Aisles.id + name varchar index + created_at timestamp + created_by bigint fk identity.Users.id + updated_at timestamp + updated_by bigint fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +inventory.Shelves + id bigint pk + rack_id bigint fk inventory.Racks.id + name varchar index + created_at timestamp + created_by bigint fk identity.Users.id + updated_at timestamp + updated_by bigint fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +inventory.ShelfPositions + id bigint pk + shelf_id bigint fk inventory.Shelves.id + name varchar index + created_at timestamp + created_by bigint fk identity.Users.id + updated_at timestamp + updated_by bigint fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +inventory.WarehouseEmployees + warehouse_id bigint pk fk inventory.Warehouses.id + employee_id bigint pk fk inventory.Employees.id + role warehouse_role(manager, stocker, loader, receiver) + start timestamp nullable + end timestamp nullable + created_at timestamp + created_by bigint fk identity.Users.id + updated_at timestamp + updated_by bigint fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +inventory.WarehouseIdentityProofs | how to check the employee is identified, can be several + warehouse_id bigint pk fk inventory.Warehouses.id + employees_id bigint pk fk inventory.Employees.id + kind identity_proof_kind(name, cni, badge) pk + value varchar + expire timestamp nullable + created_at timestamp + created_by bigint fk identity.Users.id + +inventory.Deliveries + id bigint pk + reason delivery_reason(supplier_delivery, customer_return, other) + accepted boolean + purchase_order_id bigint nullable fk inventory.PurchaseOrders.id + warehouse_id bigint fk inventory.WarehouseEmployees.warehouse_id + warehouse_employee_id bigint fk inventory.WarehouseEmployees.employee_id + supplier_id bigint fk inventory.SupplierEmployees.supplier_id + supplier_employee_id bigint fk inventory.SupplierEmployees.employee_id + delivered_at timestamp + +inventory.DeliveryItems + delivery_id bigint pk fk inventory.Deliveries.id + physical_product_id bigint pk fk inventory.PhysicalProducts.id + +inventory.Pickups + id bigint pk + reason pickup_reason(customer_delivery, supplier_return, other) + accepted boolean + warehouse_id bigint fk inventory.WarehouseEmployees.warehouse_id + warehouse_employee_id bigint fk inventory.WarehouseEmployees.employee_id + supplier_id bigint fk inventory.SupplierEmployees.supplier_id + supplier_employee_id bigint fk inventory.SupplierEmployees.employee_id + delivered_at timestamp + +inventory.PickupItems + pickup_id bigint pk fk inventory.Pickups.id + physical_product_id bigint pk fk inventory.PhysicalProducts.id + +inventory.Inventories + id bigint pk + name varchar + warehouse_id bigint fk inventory.Warehouses.id + hall_id bigint nullable fk inventory.Halls.id + aisle_id bigint nullable fk inventory.Aisles.id + planned timestamp nullable + finished timestamp nullable + created_at timestamp + created_by bigint fk identity.Users.id + updated_at timestamp + updated_by bigint fk identity.Users.id + +inventory.InventoryMembers + inventory_id bigint pk fk inventory.Inventories.id + warehouse_id bigint pk fk inventory.WarehouseEmployees.warehouse_id + employee_id bigint pk fk inventory.WarehouseEmployees.employee_id + +inventory.InventoryObservations + id bigint pk + inventory_id bigint nullable fk inventory.Inventories.id + physical_product_id bigint fk inventory.PhysicalProducts.id + status inventory_status(missing, broken, degraded) + message text nullable + created_at timestamp + created_by bigint fk identity.Users.id + updated_at timestamp + updated_by bigint fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +# Catalog + +catalog.Categories + id bigint pk + parent bigint nullable fk catalog.Categories.id + depth int | easily accessible information of number of parents + slug varchar unique + name varchar + description text nullable + description_html text nullable + created_at timestamp + updated_at timestamp + deleted_at timestamp nullable index + +catalog.Products + id bigint pk fk inventory.Products.id + slug varchar unique + name varchar + category_id bigint fk catalog.Categories.id + description text nullable | TODO: handle i18n + description_html text nullable + versions json | ex: `[{key: "color", label: "Couleur", values: [{name: "Bleu Azur", value: "#95bbe2"}]}, {key: "storage", name: "Taille", values: [{name: "128GB", value: 128}]}]` + attributes json | ex: `[{key: "Marque", value: "Google"}]` + stock int | informative stock, may not be accurate + created_at timestamp + updated_at timestamp + deleted_at timestamp nullable index + +catalog.ProductVersions + id bigint pk fk inventory.ProductVersions.id + product_id bigint fk catalog.Products.id + name varchar + specs json | ex: `{color: "Bleu Azur", storage: 128}` + price double + stock int | informative stock, may not be accurate + created_at timestamp + updated_at timestamp + deleted_at timestamp nullable index + +catalog.ProductCrossSellOptions + product_id bigint pk fk catalog.Products.id + product_version_id bigint pk fk catalog.ProductVersions.id + label varchar + created_at timestamp + updated_at timestamp + deleted_at timestamp nullable index + +catalog.ProductAlternatives + product_id bigint pk fk catalog.Products.id + alternative_product_id bigint pk fk catalog.Products.id + created_at timestamp + updated_at timestamp + deleted_at timestamp nullable index + +catalog.Assets + id bigint pk + kind asset_kind(picture, video, embed) + format asset_format(1:1, 16:9) + size asset_size(low, medium, high, retina) + path varchar + alt varchar + width int + height int + weight int + created_at timestamp + updated_at timestamp + deleted_at timestamp nullable index + +catalog.CategoryAssets + category_id bigint pk fk catalog.Categories.id + asset_id bigint pk fk catalog.Assets.id + placement category_asset_placement(banner, icon) + created_at timestamp + updated_at timestamp + deleted_at timestamp nullable index + +catalog.ProductAssets + product_id bigint pk fk catalog.Products.id + asset_id bigint pk fk catalog.Assets.id + placement category_asset_placement(banner, icon) + created_at timestamp + updated_at timestamp + deleted_at timestamp nullable index + +catalog.ProductVersionAssets + product_version_id bigint pk fk catalog.ProductVersions.id + asset_id bigint pk fk catalog.Assets.id + placement category_asset_placement(banner, icon) + created_at timestamp + updated_at timestamp + deleted_at timestamp nullable index + +catalog.ProductReviews + id bigint pk + product_id bigint fk catalog.Products.id + product_version_id bigint nullable fk catalog.ProductVersions.id + invoice_id bigint nullable fk billing.Invoices.id + physical_product_id bigint nullable fk inventory.PhysicalProducts.id + rating int + review text nullable + created_at timestamp + created_by bigint fk identity.Users.id + updated_at timestamp + updated_by bigint fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +catalog.ProductReviewAssets + product_review_id bigint pk fk catalog.ProductReviews.id + asset_id bigint pk fk catalog.Assets.id + created_at timestamp + created_by bigint fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +catalog.ProductReviewFeedbacks + product_review_id bigint pk fk catalog.ProductReviews.id + kind feedback_kind(like, report) + created_at timestamp + created_by bigint pk fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +# Shopping + +shopping.Carts + id bigint pk + owner_kind cart_owner(identity.Devices, identity.Users) | Devices are used for anonymous carts, otherwise it's Users + owner_id bigint + expire_at timestamp + created_at timestamp + updated_at timestamp + deleted_at timestamp nullable index +fk shopping.Carts.owner_id -> identity.Devices.id +fk shopping.Carts.owner_id -> identity.Users.id + +shopping.CartItems + cart_id bigint pk fk shopping.Carts.id + product_version_id bigint pk fk catalog.ProductVersions.id + quantity int + price double | at the time the product was added to the card, prevent price changes after a product has been added to a cart + created_at timestamp + created_by bigint nullable fk identity.Users.id + updated_at timestamp + updated_by bigint nullable fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +shopping.Wishlists + id bigint pk + name varchar + description text nullable + public boolean + created_at timestamp + created_by bigint fk identity.Users.id + updated_at timestamp + updated_by bigint fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +shopping.WishlistItems + wishlist_id bigint pk fk shopping.Wishlists.id + product_id bigint pk fk catalog.Products.id + specs json nullable | if the user saved specific configuration + created_at timestamp + created_by bigint fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +shopping.WishlistMembers + wishlist_id bigint pk fk shopping.Wishlists.id + user_id bigint pk fk identity.Users.id + rights wishlist_rights(edit, comment, view) + created_at timestamp + created_by bigint fk identity.Users.id + updated_at timestamp + updated_by bigint fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +# Billing + +billing.Customers + id bigint pk + name varchar + billing_address bigint nullable fk billing.CustomerAddresses.id + siret varchar nullable + tva varchar nullable + created_at timestamp + created_by bigint fk identity.Users.id + updated_at timestamp + updated_by bigint fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +billing.CustomerMembers + customer_id bigint pk fk billing.Customers.id + user_id bigint pk fk identity.Users.id + can_edit boolean + can_invite boolean + can_buy boolean + budget_allowance int nullable + created_at timestamp + created_by bigint fk identity.Users.id + updated_at timestamp + updated_by bigint fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +billing.CustomerPaymentMethods + id bigint pk + customer_id bigint fk billing.Customers.id + name varchar + kind payment_kind(card, paypal) + details json + created_at timestamp + created_by bigint fk identity.Users.id + updated_at timestamp + updated_by bigint fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +billing.CustomerAddresses + id bigint pk + name varchar + street varchar + city varchar + state varchar + zipcode varchar + country bigint fk referential.Countries.CountryId + complements text nullable + created_at timestamp + created_by bigint fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +billing.Invoices + id bigint pk + reference varchar unique + cart_id bigint nullable fk shopping.Carts.id + customer_id bigint fk billing.Customers.id + billing_address bigint fk billing.CustomerAddresses.id + total_price double + currency global_currency(EUR, USD) + paid_at timestamp nullable + created_at timestamp + created_by bigint nullable fk identity.Users.id + +billing.InvoiceLines + invoice_id bigint pk fk billing.Invoices.id + index int pk + product_version_id bigint nullable fk catalog.ProductVersions.id + description text nullable + price double + quantity int + +billing.Payments + id bigint pk + invoice_id bigint fk billing.Invoices.id + payment_method_id bigint nullable fk billing.CustomerPaymentMethods.id + amount double + currency global_currency(EUR, USD) + created_at timestamp + +# Shipping + +shipping.Carriers + id bigint pk + registration varchar + cargo_width float + cargo_length float + cargo_height float + cargo_weight float + created_at timestamp + created_by bigint nullable fk identity.Users.id + updated_at timestamp + updated_by bigint nullable fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +shipping.Shipments + id bigint pk + carrier_id bigint nullable fk shipping.Carriers.id + created_at timestamp + collected_at timestamp nullable + collected_by bigint nullable fk identity.Users.id + packaged_at timestamp nullable + packaged_by bigint nullable fk identity.Users.id + loaded_at timestamp nullable + loaded_by bigint nullable fk identity.Users.id + delivered_at timestamp nullable + delivered_by bigint nullable fk identity.Users.id + +shipping.ShipmentItems + shipment_id bigint pk fk shipping.Shipments.id + physical_product_id bigint pk fk inventory.PhysicalProducts.id + invoice_id bigint fk billing.InvoiceLines.invoice_id + invoice_line int fk billing.InvoiceLines.index + delivered_at timestamp nullable + delivered_to bigint nullable fk identity.Users.id + +# CRM + +crm.People + id bigint pk + name varchar + email varchar nullable + phone varchar nullable + created_at timestamp + created_by bigint nullable fk identity.Users.id + updated_at timestamp + updated_by bigint nullable fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +crm.Organizations + id bigint pk + name varchar + created_at timestamp + created_by bigint nullable fk identity.Users.id + updated_at timestamp + updated_by bigint nullable fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +crm.OrganizationMembers + person_id bigint pk fk crm.People.id + organization_id bigint pk fk crm.Organizations.id + role varchar + created_at timestamp + created_by bigint nullable fk identity.Users.id + updated_at timestamp + updated_by bigint nullable fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +crm.SocialAccounts + id bigint pk + network social_network(twitter, linkedin, facebook, instagram, tiktok, snapchat) + username varchar + owner_kind social_account_owner_kind(crm.People, crm.Organizations) nullable + owner_id bigint nullable + created_at timestamp + created_by bigint nullable fk identity.Users.id + updated_at timestamp + updated_by bigint nullable fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id +fk crm.SocialAccounts.owner_id -> crm.People.id +fk crm.SocialAccounts.owner_id -> crm.Organizations.id + +crm.Campaigns + id bigint pk + name varchar + status campaign_status(draft, live, paused) + starts timestamp nullable + ends timestamp nullable + kind campaign_kind(email, sms, push, twitter, linkedin, instagram, facebook) + audience text | DSL for selecting the audience, from crm.People for email & sms or from crm.SocialAccounts for others + subject varchar nullable + message text nullable | HTML with templating using recipient info + created_at timestamp + created_by bigint nullable fk identity.Users.id + updated_at timestamp + updated_by bigint nullable fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +crm.CampaignMessages + id bigint pk + campaign_id bigint fk crm.Campaigns.id + contact_id bigint fk crm.People.id + social_id bigint nullable fk crm.SocialAccounts.id + sent_to varchar | can be email, phone number, social account... depending on campaign kind + created_at timestamp + sent_at timestamp nullable + opened_at timestamp nullable + clicked_at timestamp nullable + +crm.Issues + id bigint pk + subject varchar + created_at timestamp + created_by bigint fk identity.Users.id + closed_at timestamp nullable index + closed_by bigint nullable fk identity.Users.id + +crm.IssueMessages + id bigint pk + issue_id bigint fk crm.Issues.id + content text + created_at timestamp + created_by bigint fk identity.Users.id + updated_at timestamp + updated_by bigint fk identity.Users.id + +crm.IssueMessageReactions + id bigint pk + message_id bigint fk crm.IssueMessages.id + kind reaction_kind(like, dislike) + created_at timestamp + created_by bigint fk identity.Users.id + deleted_at timestamp nullable index + deleted_by bigint nullable fk identity.Users.id + +crm.Discounts + id bigint pk + name varchar + description varchar + kind discount_kind(percentage, amount) + value double + enable_at timestamp nullable + expire_at timestamp nullable + created_at timestamp + created_by bigint fk identity.Users.id + updated_at timestamp + updated_by bigint fk identity.Users.id + deleted_at timestamp + deleted_by bigint fk identity.Users.id + +crm.Coupons + id bigint pk + discount_id bigint fk crm.Discounts.id + code varchar unique | public code to use the discount + expire_at timestamp nullable + created_at timestamp + created_by bigint fk identity.Users.id + updated_at timestamp + updated_by bigint fk identity.Users.id + deleted_at timestamp + deleted_by bigint fk identity.Users.id + +crm.ProductPicks +crm.LoyaltyCards + +# Analytics + +analytics.Events + id uuid pk | UUIDv7 to be time ordered + name string index | in form of `$context__$object__$action` + source event_source(website, app, admin, job) | the name of the system which emitted this event + details json | any additional info for the event + entities json | {[kind: string]: {id: string, name: string}[]} + created_at timestamp + +analytics.Entities + id string pk + kind string + name string + properties json + created_at timestamp + updated_at timestamp diff --git a/demos/ecommerce-usrv/script_1_referential_sqlserver.sql b/demos/ecommerce-usrv/script_1_referential_sqlserver.sql new file mode 100644 index 000000000..e6b7fb060 --- /dev/null +++ b/demos/ecommerce-usrv/script_1_referential_sqlserver.sql @@ -0,0 +1,100 @@ +-- drop everything +USE master; -- in order to stop using Referential ^^ +DROP DATABASE IF EXISTS Referential; + +-- create the database +CREATE DATABASE Referential; +USE Referential; +CREATE SCHEMA [referential]; + +CREATE TABLE [referential].[Countries] +( + [CountryId] [bigint] IDENTITY (1,1) PRIMARY KEY, + [Code] [nvarchar](5) NOT NULL, + [Name] [nvarchar](255) NOT NULL, + [CreatedAt] [datetime] NOT NULL DEFAULT GETDATE(), + [DeletedAt] [datetime] +); +CREATE INDEX [IDX_Countries_Code] ON [referential].[Countries] ([Code]); +CREATE INDEX [IDX_Countries_Name] ON [referential].[Countries] ([Name]); + +CREATE TABLE [referential].[States] +( + [StateId] [bigint] IDENTITY (1,1) PRIMARY KEY, + [CountryId] [bigint] NOT NULL, + [Code] [nvarchar](5) NOT NULL, + [Name] [nvarchar](255) NOT NULL, + [CreatedAt] [datetime] NOT NULL DEFAULT GETDATE(), + [DeletedAt] [datetime], + CONSTRAINT [FK_States_Country] FOREIGN KEY ([CountryId]) REFERENCES [referential].[Countries] ([CountryId]) +); +CREATE INDEX [IDX_States_CountryId] ON [referential].[States] ([CountryId]); +CREATE INDEX [IDX_States_Code] ON [referential].[States] ([Code]); +CREATE INDEX [IDX_States_Name] ON [referential].[States] ([Name]); + +CREATE TABLE [referential].[Cities] +( + [CityId] [bigint] IDENTITY (1,1) PRIMARY KEY, + [StateId] [bigint] NOT NULL, + [Name] [nvarchar](255) NOT NULL, + [CreatedAt] [datetime] NOT NULL DEFAULT GETDATE(), + [DeletedAt] [datetime], + CONSTRAINT [FK_Cities_State] FOREIGN KEY ([StateId]) REFERENCES [referential].[States] ([StateId]) +); +CREATE INDEX [IDX_Cities_StateId] ON [referential].[Cities] ([StateId]); +CREATE INDEX [IDX_Cities_Name] ON [referential].[Cities] ([Name]); + +-- insert some data +INSERT INTO [referential].[Countries] ([Code], [Name]) +VALUES ('FRA', 'France'), + ('DEU', 'Germany'), + ('ESP', 'Spain'), + ('ITA', 'Italy'), + ('USA', 'United States'), + ('CAN', 'Canada'), + ('MEX', 'Mexico'); + +INSERT INTO [referential].[States] ([CountryId], [Code], [Name]) +VALUES (1, 'IDF', N'Île-de-France'), + (1, 'PAC', N'Provence-Alpes-Côte d''Azur'), + (2, 'BE', 'Berlin'), + (2, 'BW', N'Baden-Württemberg'), + (3, 'MD', 'Madrid'), + (3, 'CAT', 'Catalonia'), + (4, 'LAZ', 'Lazio'), + (4, 'LOM', 'Lombardy'), + (5, 'CA', 'California'), + (5, 'TX', 'Texas'), + (5, 'NY', 'New York'), + (6, 'ON', 'Ontario'), + (6, 'QC', 'Quebec'), + (7, 'CDMX', N'Ciudad de México'), + (7, 'JAL', 'Jalisco'); + +INSERT INTO [referential].[Cities] ([StateId], [Name]) +VALUES (1, 'Paris'), + (1, 'Boulogne-Billancourt'), + (2, 'Marseille'), + (2, 'Nice'), + (3, 'Berlin'), + (4, 'Stuttgart'), + (4, 'Karlsruhe'), + (5, 'Madrid'), + (6, 'Barcelona'), + (6, 'Girona'), + (7, 'Rome'), + (7, 'Latina'), + (8, 'Milan'), + (8, 'Bergamo'), + (9, 'Los Angeles'), + (9, 'San Francisco'), + (10, 'Houston'), + (10, 'Dallas'), + (11, 'New York City'), + (11, 'Buffalo'), + (12, 'Toronto'), + (12, 'Ottawa'), + (13, 'Montreal'), + (13, 'Quebec City'), + (14, 'Mexico City'), + (15, 'Guadalajara'); diff --git a/demos/ecommerce-usrv/script_2_identity_mariadb.sql b/demos/ecommerce-usrv/script_2_identity_mariadb.sql new file mode 100644 index 000000000..613641cea --- /dev/null +++ b/demos/ecommerce-usrv/script_2_identity_mariadb.sql @@ -0,0 +1,144 @@ +-- drop everything +DROP DATABASE IF EXISTS identity; + +-- create the database (needs admin rights) +CREATE DATABASE identity; +USE identity; + +CREATE TABLE identity.Users +( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + first_name VARCHAR(255) NOT NULL, + last_name VARCHAR(255) NOT NULL, + username VARCHAR(255) NOT NULL UNIQUE, + email VARCHAR(255) NOT NULL UNIQUE, + settings JSON CHECK (JSON_VALID(settings)), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted_at TIMESTAMP, + INDEX idx_name (first_name, last_name), + INDEX idx_deleted_at (deleted_at) +); + +CREATE TABLE identity.Credentials +( + user_id BIGINT NOT NULL, + provider ENUM ('password', 'google', 'linkedin', 'facebook', 'twitter') NOT NULL, + provider_id VARCHAR(255) NOT NULL, + provider_data JSON CHECK (JSON_VALID(provider_data)), + used_last TIMESTAMP, + used_count INT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (user_id, provider, provider_id), + FOREIGN KEY (user_id) REFERENCES identity.Users (id) +); + +CREATE TABLE identity.PasswordResets +( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + email VARCHAR(255) NOT NULL, + token VARCHAR(255) NOT NULL, + requested_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + expire_at TIMESTAMP, + used_at TIMESTAMP, + INDEX idx_email (email), + INDEX idx_token (token) +); + +CREATE TABLE identity.Devices +( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + sid CHAR(36) NOT NULL UNIQUE, + user_agent VARCHAR(255) NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE identity.UserDevices +( + user_id BIGINT NOT NULL, + device_id BIGINT NOT NULL, + linked_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + unlinked_at TIMESTAMP, + PRIMARY KEY (user_id, device_id), + FOREIGN KEY (user_id) REFERENCES identity.Users (id), + FOREIGN KEY (device_id) REFERENCES identity.Devices (id) +); + +CREATE TABLE identity.AuthLogs +( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + user_id BIGINT, + email VARCHAR(255), + event ENUM ('signup', 'login_success', 'login_failure', 'password_reset_asked', 'password_reset_used') NOT NULL, + ip VARCHAR(45) NOT NULL, + ip_location POINT, + user_agent VARCHAR(255) NOT NULL, + device_id BIGINT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (user_id) REFERENCES identity.Users (id), + FOREIGN KEY (device_id) REFERENCES identity.Devices (id) +); + +CREATE TABLE identity.TrustedDevices +( + user_id BIGINT NOT NULL, + device_id BIGINT NOT NULL, + name VARCHAR(255), + kind ENUM ('desktop', 'tablet', 'phone'), + `usage` ENUM ('perso', 'pro'), + used_last TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP, + PRIMARY KEY (user_id, device_id), + FOREIGN KEY (user_id) REFERENCES identity.Users (id), + FOREIGN KEY (device_id) REFERENCES identity.Devices (id), + INDEX idx_deleted_at (deleted_at) +); + +-- insert some data +INSERT INTO identity.Users (first_name, last_name, username, email, settings) +VALUES ('Loïc', 'Knuchel', 'loicknuchel', 'loic@azimutt.app', '{"theme": "dark", "language": "fr"}'), + ('John', 'Doe', 'johndoe', 'john.doe@example.com', '{"theme": "dark", "language": "en"}'), + ('Jane', 'Smith', 'janesmith', 'jane.smith@example.com', '{"theme": "light", "language": "fr"}'), + ('Alice', 'Brown', 'alicebrown', 'alice.brown@example.com', '{"theme": "dark", "language": "es"}'), + ('Bob', 'Davis', 'bobdavis', 'bob.davis@example.com', '{"theme": "light", "language": "de"}'); + +INSERT INTO identity.Credentials (user_id, provider, provider_id, provider_data, used_last, used_count) +VALUES (1, 'twitter', 'loicknuchel', '{"refresh_token": "xxx"}', CURRENT_TIMESTAMP, 42), + (2, 'password', 'hashed_password_1', NULL, CURRENT_TIMESTAMP, 10), + (3, 'password', 'hashed_password_2', NULL, CURRENT_TIMESTAMP, 5), + (4, 'google', 'superalice', '{"refresh_token": "refresh_token_3"}', CURRENT_TIMESTAMP, 15), + (5, 'facebook', 'bobisking', '{"access_token": "access_token_4"}', CURRENT_TIMESTAMP, 20); + +INSERT INTO identity.PasswordResets (email, token, requested_at, expire_at) +VALUES ('loic@azimutt.app', 'token_1', CURRENT_TIMESTAMP, DATE_ADD(CURRENT_TIMESTAMP, INTERVAL 1 HOUR)), + ('jane.smith@example.com', 'token_2', CURRENT_TIMESTAMP, DATE_ADD(CURRENT_TIMESTAMP, INTERVAL 1 HOUR)); + +INSERT INTO identity.Devices (sid, user_agent) +VALUES (UUID(), 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'), + (UUID(), 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15'), + (UUID(), 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Mobile/15E148 Safari/604.1'), + (UUID(), 'Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36'), + (UUID(), 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15'); + +INSERT INTO identity.UserDevices (user_id, device_id, linked_at) +VALUES (1, 1, CURRENT_TIMESTAMP), + (2, 2, CURRENT_TIMESTAMP), + (3, 3, CURRENT_TIMESTAMP), + (4, 4, CURRENT_TIMESTAMP), + (5, 5, CURRENT_TIMESTAMP); + +INSERT INTO identity.AuthLogs (user_id, email, event, ip, ip_location, user_agent, device_id) +VALUES (1, 'loic@azimutt.app', 'login_success', '192.168.1.1', ST_GeomFromText('POINT(48.8588443 2.2943506)'), 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', 1), + (2, 'john.doe@example.com', 'login_success', '192.168.1.1', ST_GeomFromText('POINT(48.8588443 2.2943506)'), 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', 1), + (3, 'jane.smith@example.com', 'login_failure', '192.168.1.2', ST_GeomFromText('POINT(51.507351 -0.127758)'), 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15', 2), + (4, 'alice.brown@example.com', 'password_reset_asked', '192.168.1.3', ST_GeomFromText('POINT(40.712776 -74.005974)'), 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Mobile/15E148 Safari/604.1', 3), + (5, 'bob.davis@example.com', 'signup', '192.168.1.4', ST_GeomFromText('POINT(34.052235 -118.243683)'), 'Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36', 4); + +INSERT INTO identity.TrustedDevices (user_id, device_id, name, kind, `usage`, used_last, created_at) +VALUES (1, 1, 'Dell perso', 'desktop', 'perso', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + (2, 2, 'John\'s Laptop', 'desktop', 'perso', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + (3, 3, 'Jane\'s MacBook', 'desktop', 'pro', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + (4, 4, 'Alice\'s iPhone', 'phone', 'perso', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + (5, 5, 'Bob\'s Pixel', 'phone', 'pro', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); diff --git a/frontend/src/Models/Project/ColumnType.elm b/frontend/src/Models/Project/ColumnType.elm index 05a052fb8..15af3d68a 100644 --- a/frontend/src/Models/Project/ColumnType.elm +++ b/frontend/src/Models/Project/ColumnType.elm @@ -56,10 +56,10 @@ parse kind = else if kind |> Regex.matchI "^ARRAY<.*>$" then Array (parse (kind |> String.dropLeft 6 |> String.dropRight 1)) - else if (kind |> Regex.matchI "^(tiny|medium|long|ci)?text$") || (kind |> Regex.matchI "^character(\\s+varying)?\\s*(\\(\\d+\\))?$") || (kind |> Regex.matchI "^n?(var)?char\\d?\\s*(\\([^)]+\\))?(\\s+CHARACTER\\s+SET\\s+[^ ]+)?$") || (kind |> Regex.matchI "^string(\\(\\d+\\))?$") || (kind |> Regex.matchI "^clob$") then + else if (kind |> Regex.matchI "^(tiny|medium|long|ci)?text$") || (kind |> Regex.matchI "^character(\\s+varying)?\\s*(\\(\\d+\\))?$") || (kind |> Regex.matchI "^n?(var)?char\\d?\\s*(\\([^)]+\\))?(\\s+CHARACTER\\s+SET\\s+[^ ]+)?$") || (kind |> Regex.matchI "^string(\\(\\d+\\))?$") || (kind |> Regex.matchI "^clob$") || (kind |> Regex.matchI "^enum\\('.+'\\)$") then Text - else if (kind |> Regex.matchI "integer|bit") || (kind |> Regex.matchI "number\\(\\d+(\\s*,\\s*0)?\\)") || (kind |> Regex.matchI "^(small)?serial$") || (kind |> Regex.matchI "^(tiny|small|big)?int\\s*(\\d+)?(\\(\\d+\\))?(\\s+unsigned)?$") then + else if (kind |> Regex.matchI "integer|bit") || (kind |> Regex.matchI "number\\(\\d+(\\s*,\\s*0)?\\)") || (kind |> Regex.matchI "^(small)?serial$") || (kind |> Regex.matchI "^(tiny|small|big)?int\\s*(\\d+)?(\\(\\d+\\))?(\\s+unsigned)?$") || (kind |> Regex.matchI "^enum\\(\\d+.*\\)$") then Int else if (kind |> Regex.matchI "double(\\s+precision)?") || (kind |> Regex.matchI "number") || (kind |> Regex.matchI "^numeric\\s*(\\(\\d+,\\d+\\))?$") || (kind |> Regex.matchI "^decimal\\s*(\\(\\d+,\\d+\\))?$") then diff --git a/frontend/src/Models/Project/ProjectSettings.elm b/frontend/src/Models/Project/ProjectSettings.elm index 485435602..c36256d6b 100644 --- a/frontend/src/Models/Project/ProjectSettings.elm +++ b/frontend/src/Models/Project/ProjectSettings.elm @@ -53,7 +53,7 @@ init defaultSchema = , removedSchemas = [] , removeViews = False , removedTables = "" - , hiddenColumns = { list = "created_.+, updated_.+, deleted_.+", max = 15, props = False, relations = False } + , hiddenColumns = { list = "created.+, updated.+, deleted.+", max = 15, props = False, relations = False } , columnOrder = ColumnOrder.OrderByProperty , relationStyle = RelationStyle.Bezier , columnBasicTypes = True diff --git a/frontend/tests/Models/Project/ColumnTypeTest.elm b/frontend/tests/Models/Project/ColumnTypeTest.elm index dde6b4780..611c6f0c7 100644 --- a/frontend/tests/Models/Project/ColumnTypeTest.elm +++ b/frontend/tests/Models/Project/ColumnTypeTest.elm @@ -56,6 +56,8 @@ suite = , testParse "interval(6)" "Interval" , testParse "bytea" "Binary" , testParse "uuid" "Uuid" + , testParse "enum(1, 2)" "Int" + , testParse "enum('a', 'b')" "Text" , testParse "bigint[]" "Int[]" , testParse "character varying(255)[]" "Text[]" , describe "BigQuery" diff --git a/frontend/tests/Storage/ProjectV2Test.elm b/frontend/tests/Storage/ProjectV2Test.elm index 8ba3dae20..12238ab8c 100644 --- a/frontend/tests/Storage/ProjectV2Test.elm +++ b/frontend/tests/Storage/ProjectV2Test.elm @@ -134,7 +134,7 @@ project1 = , ( "empty", Layout [] [] [] [] (time 1202) (time 1203) ) ] , tableRowsSeq = 1 - , settings = ProjectSettings (FindPathSettings 4 "" "") defaultSchema [] False "" (HiddenColumns "created_.+, updated_.+, deleted_.+" 15 False False) OrderByProperty Bezier True False Nothing + , settings = ProjectSettings (FindPathSettings 4 "" "") defaultSchema [] False "" (HiddenColumns "created.+, updated.+, deleted.+" 15 False False) OrderByProperty Bezier True False Nothing , storage = ProjectStorage.Local , visibility = ProjectVisibility.None , version = ProjectEncodingVersion.current @@ -238,7 +238,7 @@ project2 = , ( "users", Layout [ TableProps ( "public", "users" ) (gridPos 90 100) Size.zeroCanvas Tw.red [ ColumnPath.fromString "id", ColumnPath.fromString "name" ] True False False ] [] [] [] (time 1202) (time 1203) ) ] , tableRowsSeq = 1 - , settings = ProjectSettings (FindPathSettings 4 "users" "created_by") defaultSchema [] False "" (HiddenColumns "created_.+, updated_.+, deleted_.+" 15 False False) OrderByProperty Bezier True False Nothing + , settings = ProjectSettings (FindPathSettings 4 "users" "created_by") defaultSchema [] False "" (HiddenColumns "created.+, updated.+, deleted.+" 15 False False) OrderByProperty Bezier True False Nothing , storage = ProjectStorage.Local , visibility = ProjectVisibility.None , version = ProjectEncodingVersion.current diff --git a/libs/connector-mariadb/src/index.ts b/libs/connector-mariadb/src/index.ts index a7514941f..eef0204e7 100644 --- a/libs/connector-mariadb/src/index.ts +++ b/libs/connector-mariadb/src/index.ts @@ -10,7 +10,6 @@ import { DatabaseQuery, DatabaseUrlParsed, EntityRef, - parseDatabaseOptions, QueryAnalyze, QueryResults, zodParseAsync @@ -26,7 +25,7 @@ export const mariadb: Connector = { const urlOptions = url.options || {} const options: ConnectorSchemaOpts = { ...opts, - schema: opts.schema || urlOptions['schema'], + schema: opts.schema || urlOptions['schema'] || url.db, entity: opts.entity || urlOptions['table'] } return connect(application, url, getSchema(options), options).then(zodParseAsync(Database)) From a5d23a03118fe7bcc661e7addc053f5e893de27d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Knuchel?= Date: Fri, 9 Aug 2024 18:05:58 +0200 Subject: [PATCH 02/16] Add Inventory source --- demos/ecommerce-usrv/README.md | 4 + demos/ecommerce-usrv/design.md | 552 +++++++++--------- .../script_1_referential_sqlserver.sql | 2 + .../script_2_identity_mariadb.sql | 2 + .../script_3_inventory_oracle.sql | 474 +++++++++++++++ libs/connector-oracle/src/index.ts | 2 +- libs/connector-oracle/src/oracle.ts | 2 +- libs/connector-oracle/src/query.test.ts | 3 +- libs/connector-oracle/src/query.ts | 14 +- libs/models/src/databaseUrl.test.ts | 10 + libs/models/src/databaseUrl.ts | 2 +- 11 files changed, 785 insertions(+), 282 deletions(-) create mode 100644 demos/ecommerce-usrv/script_3_inventory_oracle.sql diff --git a/demos/ecommerce-usrv/README.md b/demos/ecommerce-usrv/README.md index 4c02dfee0..315304eda 100644 --- a/demos/ecommerce-usrv/README.md +++ b/demos/ecommerce-usrv/README.md @@ -27,6 +27,10 @@ You will have it at this url: `mariadb://root:mariadb@localhost:3307/identity` You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) ## Inventory + +Import it in a [Oracle database](../../libs/connector-oracle/README.md#local-setup) with the [script_3_inventory_oracle.sql](script_3_inventory_oracle.sql). +You will have it at this url: `oracle:thin:C##INVENTORY/inventory@localhost:1521/FREE` + ## Catalog ## Shopping ## Billing diff --git a/demos/ecommerce-usrv/design.md b/demos/ecommerce-usrv/design.md index 12b567c78..f43f407ae 100644 --- a/demos/ecommerce-usrv/design.md +++ b/demos/ecommerce-usrv/design.md @@ -88,278 +88,278 @@ identity.TrustedDevices | users can add a device to their trusted ones, so they # Inventory -inventory.Brands - id bigint pk - slug varchar unique | ex: "google" - name varchar unique | ex: "Google" - created_at timestamp - updated_at timestamp - deleted_at timestamp nullable index - -inventory.Products - id bigint pk - slug varchar unique | ex: "pixel-8-pro" - name varchar unique | ex: "Pixel 8 Pro" - brand bigint nullable fk inventory.Brands.id - category varchar nullable | ex: "Phones" - subcategory varchar nullable | ex: "Smartphones" - width float | typical width of the product, see Products for the real one - length float | typical length of the product, see Products for the real one - height float | typical height of the product, see Products for the real one - weight float | typical weight of the product, see Products for the real one - remarks text nullable | ex: fragile - created_at timestamp - updated_at timestamp - deleted_at timestamp nullable index - -inventory.ProductVersions - id bigint pk - product_id bigint fk inventory.Products.id - sku varchar(12) unique | internal id - ean varchar(13) unique | european id - name varchar unique | ex: "Pixel 8 Pro Menthe 128 Go" - specs json | specificities of this version, ex: `{color: "Menthe", storage: 128}` - width float - length float - height float - weight float - remarks text nullable - created_at timestamp - updated_at timestamp - deleted_at timestamp nullable index - -inventory.PhysicalProducts - id bigint pk - product_version_id bigint fk inventory.ProductVersions.id - snid varchar(12) unique | serial number of this product - expiration timestamp nullable | when Product has an expiration date, null otherwise - remarks text nullable - stored bigint nullable fk inventory.ShelfPositions.id - created_at timestamp - updated_at timestamp - deleted_at timestamp nullable index - -inventory.Employees - id bigint pk - first_name varchar index=name - last_name varchar index=name - email varchar nullable index - phone varchar nullable - created_at timestamp - created_by bigint fk identity.Users.id - updated_at timestamp - updated_by bigint fk identity.Users.id - deleted_at timestamp nullable index - deleted_by bigint nullable fk identity.Users.id - -inventory.Suppliers - id bigint pk - name varchar index - level int | the lower, the more priority is given to this supplier - currency global_currency(EUR, USD) - created_at timestamp - updated_at timestamp - deleted_at timestamp nullable index - -inventory.SupplierPrices - supplier_id bigint pk fk inventory.Suppliers.id - product_version_id bigint pk fk inventory.ProductVersions.id - price double - created_at timestamp - updated_at timestamp - deleted_at timestamp nullable index - -inventory.SupplierEmployees - supplier_id bigint pk fk inventory.Suppliers.id - employee_id bigint pk fk inventory.Employees.id - role supplier_role(delivery, sale) - start timestamp nullable - end timestamp nullable - created_at timestamp - created_by bigint fk identity.Users.id - updated_at timestamp - updated_by bigint fk identity.Users.id - deleted_at timestamp nullable index - deleted_by bigint nullable fk identity.Users.id - -inventory.PurchaseOrders - id bigint pk - supplier_id bigint fk inventory.Suppliers.id - price double | total price, computed from items price x quantity - currency global_currency(EUR, USD) - details text nullable | additional text for the supplier - notes text nullable | internal text for employees - created_at timestamp - created_by bigint fk identity.Users.id - updated_at timestamp - updated_by bigint fk identity.Users.id - sent_at timestamp nullable | can't be updated once sent - sent_by bigint nullable fk identity.Users.id - paid_at timestamp nullable - delivered_at timestamp nullable - validated_at timestamp nullable - validated_by bigint nullable fk identity.Users.id - -inventory.PurchaseOrderItems - purchase_order_id bigint pk fk inventory.PurchaseOrders.id - product_version_id bigint pk fk inventory.ProductVersions.id - quantity int - price double - created_at timestamp - created_by bigint fk identity.Users.id - updated_at timestamp - updated_by bigint fk identity.Users.id - -inventory.Warehouses - id bigint pk - name varchar unique - address global_address - manager bigint fk inventory.Employees.id - created_at timestamp - created_by bigint fk identity.Users.id - updated_at timestamp - updated_by bigint fk identity.Users.id - deleted_at timestamp nullable index - deleted_by bigint nullable fk identity.Users.id - -inventory.Halls - id bigint pk - warehouse_id bigint fk inventory.Warehouses.id - name varchar index - manager bigint fk inventory.Employees.id - created_at timestamp - created_by bigint fk identity.Users.id - updated_at timestamp - updated_by bigint fk identity.Users.id - deleted_at timestamp nullable index - deleted_by bigint nullable fk identity.Users.id - -inventory.Aisles - id bigint pk - hall_id bigint fk inventory.Halls.id - name varchar index - manager bigint fk inventory.Employees.id - created_at timestamp - created_by bigint fk identity.Users.id - updated_at timestamp - updated_by bigint fk identity.Users.id - deleted_at timestamp nullable index - deleted_by bigint nullable fk identity.Users.id - -inventory.Racks - id bigint pk - aisle_id bigint fk inventory.Aisles.id - name varchar index - created_at timestamp - created_by bigint fk identity.Users.id - updated_at timestamp - updated_by bigint fk identity.Users.id - deleted_at timestamp nullable index - deleted_by bigint nullable fk identity.Users.id - -inventory.Shelves - id bigint pk - rack_id bigint fk inventory.Racks.id - name varchar index - created_at timestamp - created_by bigint fk identity.Users.id - updated_at timestamp - updated_by bigint fk identity.Users.id - deleted_at timestamp nullable index - deleted_by bigint nullable fk identity.Users.id - -inventory.ShelfPositions - id bigint pk - shelf_id bigint fk inventory.Shelves.id - name varchar index - created_at timestamp - created_by bigint fk identity.Users.id - updated_at timestamp - updated_by bigint fk identity.Users.id - deleted_at timestamp nullable index - deleted_by bigint nullable fk identity.Users.id - -inventory.WarehouseEmployees - warehouse_id bigint pk fk inventory.Warehouses.id - employee_id bigint pk fk inventory.Employees.id - role warehouse_role(manager, stocker, loader, receiver) - start timestamp nullable - end timestamp nullable - created_at timestamp - created_by bigint fk identity.Users.id - updated_at timestamp - updated_by bigint fk identity.Users.id - deleted_at timestamp nullable index - deleted_by bigint nullable fk identity.Users.id - -inventory.WarehouseIdentityProofs | how to check the employee is identified, can be several - warehouse_id bigint pk fk inventory.Warehouses.id - employees_id bigint pk fk inventory.Employees.id - kind identity_proof_kind(name, cni, badge) pk - value varchar - expire timestamp nullable - created_at timestamp - created_by bigint fk identity.Users.id - -inventory.Deliveries - id bigint pk - reason delivery_reason(supplier_delivery, customer_return, other) - accepted boolean - purchase_order_id bigint nullable fk inventory.PurchaseOrders.id - warehouse_id bigint fk inventory.WarehouseEmployees.warehouse_id - warehouse_employee_id bigint fk inventory.WarehouseEmployees.employee_id - supplier_id bigint fk inventory.SupplierEmployees.supplier_id - supplier_employee_id bigint fk inventory.SupplierEmployees.employee_id - delivered_at timestamp - -inventory.DeliveryItems - delivery_id bigint pk fk inventory.Deliveries.id - physical_product_id bigint pk fk inventory.PhysicalProducts.id - -inventory.Pickups - id bigint pk - reason pickup_reason(customer_delivery, supplier_return, other) - accepted boolean - warehouse_id bigint fk inventory.WarehouseEmployees.warehouse_id - warehouse_employee_id bigint fk inventory.WarehouseEmployees.employee_id - supplier_id bigint fk inventory.SupplierEmployees.supplier_id - supplier_employee_id bigint fk inventory.SupplierEmployees.employee_id - delivered_at timestamp - -inventory.PickupItems - pickup_id bigint pk fk inventory.Pickups.id - physical_product_id bigint pk fk inventory.PhysicalProducts.id - -inventory.Inventories - id bigint pk - name varchar - warehouse_id bigint fk inventory.Warehouses.id - hall_id bigint nullable fk inventory.Halls.id - aisle_id bigint nullable fk inventory.Aisles.id - planned timestamp nullable - finished timestamp nullable - created_at timestamp - created_by bigint fk identity.Users.id - updated_at timestamp - updated_by bigint fk identity.Users.id - -inventory.InventoryMembers - inventory_id bigint pk fk inventory.Inventories.id - warehouse_id bigint pk fk inventory.WarehouseEmployees.warehouse_id - employee_id bigint pk fk inventory.WarehouseEmployees.employee_id - -inventory.InventoryObservations - id bigint pk - inventory_id bigint nullable fk inventory.Inventories.id - physical_product_id bigint fk inventory.PhysicalProducts.id - status inventory_status(missing, broken, degraded) - message text nullable - created_at timestamp - created_by bigint fk identity.Users.id - updated_at timestamp - updated_by bigint fk identity.Users.id - deleted_at timestamp nullable index - deleted_by bigint nullable fk identity.Users.id +C##INVENTORY.EMPLOYEES + ID BIGINT pk + FIRST_NAME VARCHAR index=name + LAST_NAME VARCHAR index=name + EMAIL VARCHAR nullable index + PHONE VARCHAR nullable + CREATED_AT TIMESTAMP + CREATED_BY BIGINT fk identity.Users.id + UPDATED_AT TIMESTAMP + UPDATED_BY BIGINT fk identity.Users.id + DELETED_AT TIMESTAMP nullable index + DELETED_BY BIGINT nullable fk identity.Users.id + +C##INVENTORY.WAREHOUSES + ID BIGINT pk + NAME VARCHAR unique + ADDRESS GLOBAL_ADDRESS + MANAGER BIGINT fk C##INVENTORY.EMPLOYEES.ID + CREATED_AT TIMESTAMP + CREATED_BY BIGINT fk identity.Users.id + UPDATED_AT TIMESTAMP + UPDATED_BY BIGINT fk identity.Users.id + DELETED_AT TIMESTAMP nullable index + DELETED_BY BIGINT nullable fk identity.Users.id + +C##INVENTORY.HALLS + ID BIGINT pk + WAREHOUSE_ID BIGINT fk C##INVENTORY.WAREHOUSES.ID + NAME VARCHAR index + MANAGER BIGINT fk C##INVENTORY.EMPLOYEES.ID + CREATED_AT TIMESTAMP + CREATED_BY BIGINT fk identity.Users.id + UPDATED_AT TIMESTAMP + UPDATED_BY BIGINT fk identity.Users.id + DELETED_AT TIMESTAMP nullable index + DELETED_BY BIGINT nullable fk identity.Users.id + +C##INVENTORY.AISLES + ID BIGINT pk + HALL_ID BIGINT fk C##INVENTORY.HALLS.ID + NAME VARCHAR index + MANAGER BIGINT fk C##INVENTORY.EMPLOYEES.ID + CREATED_AT TIMESTAMP + CREATED_BY BIGINT fk identity.Users.id + UPDATED_AT TIMESTAMP + UPDATED_BY BIGINT fk identity.Users.id + DELETED_AT TIMESTAMP nullable index + DELETED_BY BIGINT nullable fk identity.Users.id + +C##INVENTORY.RACKS + ID BIGINT pk + AISLE_ID BIGINT fk C##INVENTORY.AISLES.ID + NAME VARCHAR index + CREATED_AT TIMESTAMP + CREATED_BY BIGINT fk identity.Users.id + UPDATED_AT TIMESTAMP + UPDATED_BY BIGINT fk identity.Users.id + DELETED_AT TIMESTAMP nullable index + DELETED_BY BIGINT nullable fk identity.Users.id + +C##INVENTORY.SHELVES + ID BIGINT pk + RACK_ID BIGINT fk C##INVENTORY.RACKS.ID + NAME VARCHAR index + CREATED_AT TIMESTAMP + CREATED_BY BIGINT fk identity.Users.id + UPDATED_AT TIMESTAMP + UPDATED_BY BIGINT fk identity.Users.id + DELETED_AT TIMESTAMP nullable index + DELETED_BY BIGINT nullable fk identity.Users.id + +C##INVENTORY.SHELF_POSITIONS + ID BIGINT pk + SHELF_ID BIGINT fk C##INVENTORY.SHELVES.ID + NAME VARCHAR index + CREATED_AT TIMESTAMP + CREATED_BY BIGINT fk identity.Users.id + UPDATED_AT TIMESTAMP + UPDATED_BY BIGINT fk identity.Users.id + DELETED_AT TIMESTAMP nullable index + DELETED_BY BIGINT nullable fk identity.Users.id + +C##INVENTORY.WAREHOUSE_EMPLOYEES + WAREHOUSE_ID BIGINT pk fk C##INVENTORY.WAREHOUSES.ID + EMPLOYEE_ID BIGINT pk fk C##INVENTORY.EMPLOYEES.ID + ROLE warehouse_role(manager, stocker, loader, receiver) + START TIMESTAMP nullable + END TIMESTAMP nullable + CREATED_AT TIMESTAMP + CREATED_BY BIGINT fk identity.Users.id + UPDATED_AT TIMESTAMP + UPDATED_BY BIGINT fk identity.Users.id + DELETED_AT TIMESTAMP nullable index + DELETED_BY BIGINT nullable fk identity.Users.id + +C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS | how to check the employee is identified, can be several + WAREHOUSE_ID BIGINT pk fk C##INVENTORY.WAREHOUSES.ID + EMPLOYEES_ID BIGINT pk fk C##INVENTORY.EMPLOYEES.ID + KIND identity_proof_kind(name, cni, badge) pk + VALUE VARCHAR + EXPIRE TIMESTAMP nullable + CREATED_AT TIMESTAMP + CREATED_BY BIGINT fk identity.Users.id + +C##INVENTORY.BRANDS + ID BIGINT pk + SLUG VARCHAR unique | ex: "google" + NAME VARCHAR unique | ex: "Google" + CREATED_AT TIMESTAMP + UPDATED_AT TIMESTAMP + DELETED_AT TIMESTAMP nullable index + +C##INVENTORY.PRODUCTS + ID BIGINT pk + SLUG VARCHAR unique | ex: "pixel-8-pro" + NAME VARCHAR unique | ex: "Pixel 8 Pro" + BRAND BIGINT nullable fk C##INVENTORY.BRANDS.ID + CATEGORY VARCHAR nullable | ex: "Phones" + SUBCATEGORY VARCHAR nullable | ex: "Smartphones" + WIDTH FLOAT | typical width of the product, see PRODUCTS for the real one + LENGTH FLOAT | typical length of the product, see PRODUCTS for the real one + HEIGHT FLOAT | typical height of the product, see PRODUCTS for the real one + WEIGHT FLOAT | typical weight of the product, see PRODUCTS for the real one + REMARKS TEXT nullable | ex: fragile + CREATED_AT TIMESTAMP + UPDATED_AT TIMESTAMP + DELETED_AT TIMESTAMP nullable index + +C##INVENTORY.PRODUCT_VERSIONS + ID BIGINT pk + PRODUCT_ID BIGINT fk C##INVENTORY.PRODUCTS.ID + SKU VARCHAR(12) unique | internal id + EAN VARCHAR(13) unique | european id + NAME VARCHAR unique | ex: "Pixel 8 Pro Menthe 128 Go" + SPECS JSON | specificities of this version, ex: `{color: "Menthe", storage: 128}` + WIDTH FLOAT + LENGTH FLOAT + HEIGHT FLOAT + WEIGHT FLOAT + REMARKS TEXT nullable + CREATED_AT TIMESTAMP + UPDATED_AT TIMESTAMP + DELETED_AT TIMESTAMP nullable index + +C##INVENTORY.PHYSICAL_PRODUCTS + ID BIGINT pk + PRODUCT_VERSION_ID BIGINT fk C##INVENTORY.PRODUCT_VERSIONS.ID + SNID VARCHAR(12) unique | serial number of this product + EXPIRATION TIMESTAMP nullable | when Product has an expiration date, null otherwise + REMARKS TEXT nullable + STORED BIGINT nullable fk C##INVENTORY.SHELF_POSITIONS.ID + CREATED_AT TIMESTAMP + UPDATED_AT TIMESTAMP + DELETED_AT TIMESTAMP nullable index + +C##INVENTORY.SUPPLIERS + ID BIGINT pk + NAME VARCHAR index + LEVEL INT | the lower, the more priority is given to this supplier + CURRENCY global_currency(EUR, USD) + CREATED_AT TIMESTAMP + UPDATED_AT TIMESTAMP + DELETED_AT TIMESTAMP nullable index + +C##INVENTORY.SUPPLIER_PRICES + SUPPLIER_ID BIGINT pk fk C##INVENTORY.SUPPLIERS.ID + PRODUCT_VERSION_ID BIGINT pk fk C##INVENTORY.PRODUCT_VERSIONS.ID + PRICE DOUBLE + CREATED_AT TIMESTAMP + UPDATED_AT TIMESTAMP + DELETED_AT TIMESTAMP nullable index + +C##INVENTORY.SUPPLIER_EMPLOYEES + SUPPLIER_ID BIGINT pk fk C##INVENTORY.SUPPLIERS.ID + EMPLOYEE_ID BIGINT pk fk C##INVENTORY.Employees.ID + ROLE supplier_role(delivery, sale) + START TIMESTAMP nullable + END TIMESTAMP nullable + CREATED_AT TIMESTAMP + CREATED_BY BIGINT fk identity.Users.id + UPDATED_AT TIMESTAMP + UPDATED_BY BIGINT fk identity.Users.id + DELETED_AT TIMESTAMP nullable index + DELETED_BY BIGINT nullable fk identity.Users.id + +C##INVENTORY.PURCHASE_ORDERS + ID BIGINT pk + SUPPLIER_ID BIGINT fk C##INVENTORY.SUPPLIERS.ID + PRICE DOUBLE | total price, computed from items price x quantity + CURRENCY global_currency(EUR, USD) + DETAILS TEXT nullable | additional text for the supplier + NOTES TEXT nullable | internal text for employees + CREATED_AT TIMESTAMP + CREATED_BY BIGINT fk identity.Users.id + UPDATED_AT TIMESTAMP + UPDATED_BY BIGINT fk identity.Users.id + SENT_AT TIMESTAMP nullable | can't be updated once sent + SENT_BY BIGINT nullable fk identity.Users.id + PAID_AT TIMESTAMP nullable + DELIVERED_AT TIMESTAMP nullable + VALIDATED_AT TIMESTAMP nullable + VALIDATED_BY BIGINT nullable fk identity.Users.id + +C##INVENTORY.PURCHASE_ORDER_ITEMS + PURCHASE_ORDER_ID BIGINT pk fk C##INVENTORY.PURCHASE_ORDERS.ID + PRODUCT_VERSION_ID BIGINT pk fk C##INVENTORY.PRODUCT_VERSIONS.ID + QUANTITY INT + PRICE DOUBLE + CREATED_AT TIMESTAMP + CREATED_BY BIGINT fk identity.Users.id + UPDATED_AT TIMESTAMP + UPDATED_BY BIGINT fk identity.Users.id + +C##INVENTORY.DELIVERIES + ID BIGINT pk + REASON delivery_reason(supplier_delivery, customer_return, other) + ACCEPTED BOOLEAN + PURCHASE_ORDER_ID BIGINT nullable fk C##INVENTORY.PURCHASE_ORDERS.ID + WAREHOUSE_ID BIGINT fk C##INVENTORY.WAREHOUSE_EMPLOYEES.WAREHOUSE_ID + WAREHOUSE_EMPLOYEE_ID BIGINT fk C##INVENTORY.WAREHOUSE_EMPLOYEES.EMPLOYEE_ID + SUPPLIER_ID BIGINT fk C##INVENTORY.SUPPLIER_EMPLOYEES.SUPPLIER_ID + SUPPLIER_EMPLOYEE_ID BIGINT fk C##INVENTORY.SUPPLIER_EMPLOYEES.EMPLOYEE_ID + DELIVERED_AT TIMESTAMP + +C##INVENTORY.DELIVERY_ITEMS + DELIVERY_ID BIGINT pk fk C##INVENTORY.DELIVERIES.ID + PHYSICAL_PRODUCT_ID BIGINT pk fk C##INVENTORY.PHYSICAL_PRODUCTS.ID + +C##INVENTORY.PICKUPS + ID BIGINT pk + REASON pickup_reason(customer_delivery, supplier_return, other) + ACCEPTED BOOLEAN + WAREHOUSE_ID BIGINT fk C##INVENTORY.WAREHOUSE_EMPLOYEES.WAREHOUSE_ID + WAREHOUSE_EMPLOYEE_ID BIGINT fk C##INVENTORY.WAREHOUSE_EMPLOYEES.EMPLOYEE_ID + SUPPLIER_ID BIGINT fk C##INVENTORY.SUPPLIER_EMPLOYEES.SUPPLIER_ID + SUPPLIER_EMPLOYEE_ID BIGINT fk C##INVENTORY.SUPPLIER_EMPLOYEES.EMPLOYEE_ID + DELIVERED_AT TIMESTAMP + +C##INVENTORY.PICKUP_ITEMS + PICKUP_ID BIGINT pk fk C##INVENTORY.PICKUPS.ID + PHYSICAL_PRODUCT_ID BIGINT pk fk C##INVENTORY.PHYSICAL_PRODUCTS.ID + +C##INVENTORY.INVENTORIES + ID BIGINT pk + NAME VARCHAR + WAREHOUSE_ID BIGINT fk C##INVENTORY.WAREHOUSES.ID + HALL_ID BIGINT nullable fk C##INVENTORY.HALLS.ID + AISLE_ID BIGINT nullable fk C##INVENTORY.AISLES.ID + PLANNED TIMESTAMP nullable + FINISHED TIMESTAMP nullable + CREATED_AT TIMESTAMP + CREATED_BY BIGINT fk identity.Users.id + UPDATED_AT TIMESTAMP + UPDATED_BY BIGINT fk identity.Users.id + +C##INVENTORY.INVENTORY_MEMBERS + INVENTORY_ID BIGINT pk fk C##INVENTORY.INVENTORIES.ID + WAREHOUSE_ID BIGINT pk fk C##INVENTORY.WAREHOUSE_EMPLOYEES.WAREHOUSE_ID + EMPLOYEE_ID BIGINT pk fk C##INVENTORY.WAREHOUSE_EMPLOYEES.EMPLOYEE_ID + +C##INVENTORY.INVENTORY_OBSERVATIONS + ID BIGINT pk + INVENTORY_ID BIGINT nullable fk C##INVENTORY.INVENTORIES.ID + PHYSICAL_PRODUCT_ID BIGINT fk C##INVENTORY.PHYSICAL_PRODUCTS.ID + STATUS INVENTORY_STATUS(missing, broken, degraded) + MESSAGE TEXT nullable + CREATED_AT TIMESTAMP + CREATED_BY BIGINT fk identity.Users.id + UPDATED_AT TIMESTAMP + UPDATED_BY BIGINT fk identity.Users.id + DELETED_AT TIMESTAMP nullable index + DELETED_BY BIGINT nullable fk identity.Users.id # Catalog @@ -376,7 +376,7 @@ catalog.Categories deleted_at timestamp nullable index catalog.Products - id bigint pk fk inventory.Products.id + id bigint pk fk C##INVENTORY.PRODUCTS.ID slug varchar unique name varchar category_id bigint fk catalog.Categories.id @@ -390,7 +390,7 @@ catalog.Products deleted_at timestamp nullable index catalog.ProductVersions - id bigint pk fk inventory.ProductVersions.id + id bigint pk fk C##INVENTORY.PRODUCT_VERSIONS.ID product_id bigint fk catalog.Products.id name varchar specs json | ex: `{color: "Bleu Azur", storage: 128}` @@ -458,7 +458,7 @@ catalog.ProductReviews product_id bigint fk catalog.Products.id product_version_id bigint nullable fk catalog.ProductVersions.id invoice_id bigint nullable fk billing.Invoices.id - physical_product_id bigint nullable fk inventory.PhysicalProducts.id + physical_product_id bigint nullable fk C##INVENTORY.PHYSICAL_PRODUCTS.ID rating int review text nullable created_at timestamp @@ -656,7 +656,7 @@ shipping.Shipments shipping.ShipmentItems shipment_id bigint pk fk shipping.Shipments.id - physical_product_id bigint pk fk inventory.PhysicalProducts.id + physical_product_id bigint pk fk C##INVENTORY.PHYSICAL_PRODUCTS.ID invoice_id bigint fk billing.InvoiceLines.invoice_id invoice_line int fk billing.InvoiceLines.index delivered_at timestamp nullable diff --git a/demos/ecommerce-usrv/script_1_referential_sqlserver.sql b/demos/ecommerce-usrv/script_1_referential_sqlserver.sql index e6b7fb060..12c7d6d49 100644 --- a/demos/ecommerce-usrv/script_1_referential_sqlserver.sql +++ b/demos/ecommerce-usrv/script_1_referential_sqlserver.sql @@ -7,6 +7,7 @@ CREATE DATABASE Referential; USE Referential; CREATE SCHEMA [referential]; + CREATE TABLE [referential].[Countries] ( [CountryId] [bigint] IDENTITY (1,1) PRIMARY KEY, @@ -44,6 +45,7 @@ CREATE TABLE [referential].[Cities] CREATE INDEX [IDX_Cities_StateId] ON [referential].[Cities] ([StateId]); CREATE INDEX [IDX_Cities_Name] ON [referential].[Cities] ([Name]); + -- insert some data INSERT INTO [referential].[Countries] ([Code], [Name]) VALUES ('FRA', 'France'), diff --git a/demos/ecommerce-usrv/script_2_identity_mariadb.sql b/demos/ecommerce-usrv/script_2_identity_mariadb.sql index 613641cea..5c4053b9f 100644 --- a/demos/ecommerce-usrv/script_2_identity_mariadb.sql +++ b/demos/ecommerce-usrv/script_2_identity_mariadb.sql @@ -5,6 +5,7 @@ DROP DATABASE IF EXISTS identity; CREATE DATABASE identity; USE identity; + CREATE TABLE identity.Users ( id BIGINT PRIMARY KEY AUTO_INCREMENT, @@ -96,6 +97,7 @@ CREATE TABLE identity.TrustedDevices INDEX idx_deleted_at (deleted_at) ); + -- insert some data INSERT INTO identity.Users (first_name, last_name, username, email, settings) VALUES ('Loïc', 'Knuchel', 'loicknuchel', 'loic@azimutt.app', '{"theme": "dark", "language": "fr"}'), diff --git a/demos/ecommerce-usrv/script_3_inventory_oracle.sql b/demos/ecommerce-usrv/script_3_inventory_oracle.sql new file mode 100644 index 000000000..4a27c8b7c --- /dev/null +++ b/demos/ecommerce-usrv/script_3_inventory_oracle.sql @@ -0,0 +1,474 @@ +-- drop everything +DROP ROLE C##INVENTORY_ROLE; +DROP USER C##INVENTORY CASCADE; + +-- create the database (needs admin rights) +CREATE USER C##INVENTORY IDENTIFIED BY inventory; +GRANT UNLIMITED TABLESPACE TO C##INVENTORY; +CREATE ROLE C##INVENTORY_ROLE; +GRANT CREATE SESSION, CREATE TABLE, CREATE SEQUENCE, CREATE VIEW, CREATE MATERIALIZED VIEW, CREATE TYPE, CREATE TRIGGER to C##inventory_role; +GRANT C##INVENTORY_ROLE TO C##INVENTORY; + + +CREATE TABLE C##INVENTORY.EMPLOYEES +( + ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + FIRST_NAME VARCHAR2(255), + LAST_NAME VARCHAR2(255), + EMAIL VARCHAR2(255), + PHONE VARCHAR2(20), + CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CREATED_BY NUMBER, + UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UPDATED_BY NUMBER, + DELETED_AT TIMESTAMP, + DELETED_BY NUMBER +); + +CREATE INDEX IDX_EMPLOYEES_NAME ON C##INVENTORY.EMPLOYEES (FIRST_NAME, LAST_NAME); +CREATE INDEX IDX_EMPLOYEES_EMAIL ON C##INVENTORY.EMPLOYEES (EMAIL); +CREATE INDEX IDX_EMPLOYEES_DELETED_AT ON C##INVENTORY.EMPLOYEES (DELETED_AT); + +CREATE TABLE C##INVENTORY.WAREHOUSES +( + ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + NAME VARCHAR2(255) UNIQUE, + ADDRESS CLOB, + MANAGER NUMBER REFERENCES C##INVENTORY.EMPLOYEES (ID), + CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CREATED_BY NUMBER, + UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UPDATED_BY NUMBER, + DELETED_AT TIMESTAMP, + DELETED_BY NUMBER +); + +CREATE INDEX IDX_WAREHOUSES_DELETED_AT ON C##INVENTORY.WAREHOUSES (DELETED_AT); + +CREATE TABLE C##INVENTORY.HALLS +( + ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + WAREHOUSE_ID NUMBER REFERENCES C##INVENTORY.WAREHOUSES (ID), + NAME VARCHAR2(255), + MANAGER NUMBER REFERENCES C##INVENTORY.EMPLOYEES (ID), + CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CREATED_BY NUMBER, + UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UPDATED_BY NUMBER, + DELETED_AT TIMESTAMP, + DELETED_BY NUMBER +); + +CREATE INDEX IDX_HALLS_DELETED_AT ON C##INVENTORY.HALLS (DELETED_AT); + +CREATE TABLE C##INVENTORY.AISLES +( + ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + HALL_ID NUMBER REFERENCES C##INVENTORY.HALLS (ID), + NAME VARCHAR2(255), + MANAGER NUMBER REFERENCES C##INVENTORY.EMPLOYEES (ID), + CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CREATED_BY NUMBER, + UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UPDATED_BY NUMBER, + DELETED_AT TIMESTAMP, + DELETED_BY NUMBER +); + +CREATE INDEX IDX_AISLES_DELETED_AT ON C##INVENTORY.AISLES (DELETED_AT); + +CREATE TABLE C##INVENTORY.RACKS +( + ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + AISLE_ID NUMBER REFERENCES C##INVENTORY.AISLES (ID), + NAME VARCHAR2(255), + CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CREATED_BY NUMBER, + UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UPDATED_BY NUMBER, + DELETED_AT TIMESTAMP, + DELETED_BY NUMBER +); + +CREATE INDEX IDX_RACKS_DELETED_AT ON C##INVENTORY.RACKS (DELETED_AT); + +CREATE TABLE C##INVENTORY.SHELVES +( + ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + RACK_ID NUMBER REFERENCES C##INVENTORY.RACKS (ID), + NAME VARCHAR2(255), + CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CREATED_BY NUMBER, + UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UPDATED_BY NUMBER, + DELETED_AT TIMESTAMP, + DELETED_BY NUMBER +); + +CREATE INDEX IDX_SHELVES_DELETED_AT ON C##INVENTORY.SHELVES (DELETED_AT); + +CREATE TABLE C##INVENTORY.SHELF_POSITIONS +( + ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + SHELF_ID NUMBER REFERENCES C##INVENTORY.SHELVES (ID), + NAME VARCHAR2(255), + CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CREATED_BY NUMBER, + UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UPDATED_BY NUMBER, + DELETED_AT TIMESTAMP, + DELETED_BY NUMBER +); + +CREATE INDEX IDX_SHELF_POSITIONS_DELETED_AT ON C##INVENTORY.SHELF_POSITIONS (DELETED_AT); + +CREATE TABLE C##INVENTORY.WAREHOUSE_EMPLOYEES +( + WAREHOUSE_ID NUMBER, + EMPLOYEE_ID NUMBER, + ROLE VARCHAR2(255), + "START" TIMESTAMP, + END TIMESTAMP, + CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CREATED_BY NUMBER, + UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UPDATED_BY NUMBER, + DELETED_AT TIMESTAMP, + DELETED_BY NUMBER, + PRIMARY KEY (WAREHOUSE_ID, EMPLOYEE_ID), + FOREIGN KEY (WAREHOUSE_ID) REFERENCES C##INVENTORY.WAREHOUSES (ID), + FOREIGN KEY (EMPLOYEE_ID) REFERENCES C##INVENTORY.EMPLOYEES (ID) +); + +CREATE INDEX IDX_WAREHOUSE_EMPLOYEES_DELETED_AT ON C##INVENTORY.WAREHOUSE_EMPLOYEES (DELETED_AT); + +CREATE TABLE C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS +( + WAREHOUSE_ID NUMBER, + EMPLOYEES_ID NUMBER, + KIND VARCHAR2(255), + VALUE VARCHAR2(255), + EXPIRE TIMESTAMP, + CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CREATED_BY NUMBER, + PRIMARY KEY (WAREHOUSE_ID, EMPLOYEES_ID, KIND), + FOREIGN KEY (WAREHOUSE_ID) REFERENCES C##INVENTORY.WAREHOUSES (ID), + FOREIGN KEY (EMPLOYEES_ID) REFERENCES C##INVENTORY.EMPLOYEES (ID) +); + +CREATE TABLE C##INVENTORY.BRANDS +( + ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + SLUG VARCHAR2(255) UNIQUE, + NAME VARCHAR2(255) UNIQUE, + CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + DELETED_AT TIMESTAMP +); + +CREATE INDEX IDX_BRANDS_DELETED_AT ON C##INVENTORY.BRANDS (DELETED_AT); + +CREATE TABLE C##INVENTORY.PRODUCTS +( + ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + SLUG VARCHAR2(255) UNIQUE, + NAME VARCHAR2(255) UNIQUE, + BRAND NUMBER REFERENCES C##INVENTORY.BRANDS (ID), + CATEGORY VARCHAR2(255), + SUBCATEGORY VARCHAR2(255), + WIDTH FLOAT, + LENGTH FLOAT, + HEIGHT FLOAT, + WEIGHT FLOAT, + REMARKS CLOB, + CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + DELETED_AT TIMESTAMP +); + +CREATE INDEX IDX_PRODUCTS_DELETED_AT ON C##INVENTORY.PRODUCTS (DELETED_AT); + +CREATE TABLE C##INVENTORY.PRODUCT_VERSIONS +( + ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + PRODUCT_ID NUMBER REFERENCES C##INVENTORY.PRODUCTS (ID), + SKU VARCHAR2(12) UNIQUE, + EAN VARCHAR2(13) UNIQUE, + NAME VARCHAR2(255) UNIQUE, + SPECS JSON, + WIDTH FLOAT, + LENGTH FLOAT, + HEIGHT FLOAT, + WEIGHT FLOAT, + REMARKS CLOB, + CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + DELETED_AT TIMESTAMP +); + +CREATE INDEX IDX_PRODUCT_VERSIONS_DELETED_AT ON C##INVENTORY.PRODUCT_VERSIONS (DELETED_AT); + +CREATE TABLE C##INVENTORY.PHYSICAL_PRODUCTS +( + ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + PRODUCT_VERSION_ID NUMBER REFERENCES C##INVENTORY.PRODUCT_VERSIONS (ID), + SNID VARCHAR2(12) UNIQUE, + EXPIRATION TIMESTAMP, + REMARKS CLOB, + STORED NUMBER REFERENCES C##INVENTORY.SHELF_POSITIONS (ID), + CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + DELETED_AT TIMESTAMP +); + +CREATE INDEX IDX_PHYSICAL_PRODUCTS_DELETED_AT ON C##INVENTORY.PHYSICAL_PRODUCTS (DELETED_AT); + +CREATE TABLE C##INVENTORY.SUPPLIERS +( + ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + NAME VARCHAR2(255), + "LEVEL" NUMBER, + CURRENCY VARCHAR2(3), + CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + DELETED_AT TIMESTAMP +); + +CREATE INDEX IDX_SUPPLIERS_NAME ON C##INVENTORY.SUPPLIERS (NAME); +CREATE INDEX IDX_SUPPLIERS_DELETED_AT ON C##INVENTORY.SUPPLIERS (DELETED_AT); + +CREATE TABLE C##INVENTORY.SUPPLIER_PRICES +( + SUPPLIER_ID NUMBER, + PRODUCT_VERSION_ID NUMBER, + PRICE FLOAT, + CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + DELETED_AT TIMESTAMP, + PRIMARY KEY (SUPPLIER_ID, PRODUCT_VERSION_ID), + FOREIGN KEY (SUPPLIER_ID) REFERENCES C##INVENTORY.SUPPLIERS (ID), + FOREIGN KEY (PRODUCT_VERSION_ID) REFERENCES C##INVENTORY.PRODUCT_VERSIONS (ID) +); + +CREATE INDEX IDX_SUPPLIER_PRICES_DELETED_AT ON C##INVENTORY.SUPPLIER_PRICES (DELETED_AT); + +CREATE TABLE C##INVENTORY.SUPPLIER_EMPLOYEES +( + SUPPLIER_ID NUMBER, + EMPLOYEE_ID NUMBER, + ROLE VARCHAR2(255), + "START" TIMESTAMP, + END TIMESTAMP, + CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CREATED_BY NUMBER, + UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UPDATED_BY NUMBER, + DELETED_AT TIMESTAMP, + DELETED_BY NUMBER, + PRIMARY KEY (SUPPLIER_ID, EMPLOYEE_ID), + FOREIGN KEY (SUPPLIER_ID) REFERENCES C##INVENTORY.SUPPLIERS (ID), + FOREIGN KEY (EMPLOYEE_ID) REFERENCES C##INVENTORY.EMPLOYEES (ID) +); + +CREATE INDEX IDX_SUPPLIER_EMPLOYEES_DELETED_AT ON C##INVENTORY.SUPPLIER_EMPLOYEES (DELETED_AT); + +CREATE TABLE C##INVENTORY.PURCHASE_ORDERS +( + ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + SUPPLIER_ID NUMBER REFERENCES C##INVENTORY.SUPPLIERS (ID), + PRICE FLOAT, + CURRENCY VARCHAR2(3), + DETAILS CLOB, + NOTES CLOB, + CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CREATED_BY NUMBER, + UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UPDATED_BY NUMBER, + SENT_AT TIMESTAMP, + SENT_BY NUMBER, + PAID_AT TIMESTAMP, + DELIVERED_AT TIMESTAMP, + VALIDATED_AT TIMESTAMP, + VALIDATED_BY NUMBER +); + +CREATE TABLE C##INVENTORY.PURCHASE_ORDER_ITEMS +( + PURCHASE_ORDER_ID NUMBER, + PRODUCT_VERSION_ID NUMBER, + QUANTITY NUMBER, + PRICE FLOAT, + CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CREATED_BY NUMBER, + UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UPDATED_BY NUMBER, + PRIMARY KEY (PURCHASE_ORDER_ID, PRODUCT_VERSION_ID), + FOREIGN KEY (PURCHASE_ORDER_ID) REFERENCES C##INVENTORY.PURCHASE_ORDERS (ID), + FOREIGN KEY (PRODUCT_VERSION_ID) REFERENCES C##INVENTORY.PRODUCT_VERSIONS (ID) +); + +CREATE TABLE C##INVENTORY.DELIVERIES +( + ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + REASON VARCHAR2(255), + ACCEPTED CHAR(1) CHECK (ACCEPTED IN ('Y', 'N')), + PURCHASE_ORDER_ID NUMBER REFERENCES C##INVENTORY.PURCHASE_ORDERS (ID), + WAREHOUSE_ID NUMBER, + WAREHOUSE_EMPLOYEE_ID NUMBER, + SUPPLIER_ID NUMBER, + SUPPLIER_EMPLOYEE_ID NUMBER, + DELIVERED_AT TIMESTAMP, + FOREIGN KEY (WAREHOUSE_ID, WAREHOUSE_EMPLOYEE_ID) REFERENCES C##INVENTORY.WAREHOUSE_EMPLOYEES (WAREHOUSE_ID, EMPLOYEE_ID), + FOREIGN KEY (SUPPLIER_ID, SUPPLIER_EMPLOYEE_ID) REFERENCES C##INVENTORY.SUPPLIER_EMPLOYEES (SUPPLIER_ID, EMPLOYEE_ID) +); + +CREATE TABLE C##INVENTORY.DELIVERY_ITEMS +( + DELIVERY_ID NUMBER, + PHYSICAL_PRODUCT_ID NUMBER, + PRIMARY KEY (DELIVERY_ID, PHYSICAL_PRODUCT_ID), + FOREIGN KEY (DELIVERY_ID) REFERENCES C##INVENTORY.DELIVERIES (ID), + FOREIGN KEY (PHYSICAL_PRODUCT_ID) REFERENCES C##INVENTORY.PHYSICAL_PRODUCTS (ID) +); + +CREATE TABLE C##INVENTORY.PICKUPS +( + ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + REASON VARCHAR2(255), + ACCEPTED CHAR(1) CHECK (ACCEPTED IN ('Y', 'N')), + WAREHOUSE_ID NUMBER, + WAREHOUSE_EMPLOYEE_ID NUMBER, + SUPPLIER_ID NUMBER, + SUPPLIER_EMPLOYEE_ID NUMBER, + DELIVERED_AT TIMESTAMP, + FOREIGN KEY (WAREHOUSE_ID, WAREHOUSE_EMPLOYEE_ID) REFERENCES C##INVENTORY.WAREHOUSE_EMPLOYEES (WAREHOUSE_ID, EMPLOYEE_ID), + FOREIGN KEY (SUPPLIER_ID, SUPPLIER_EMPLOYEE_ID) REFERENCES C##INVENTORY.SUPPLIER_EMPLOYEES (SUPPLIER_ID, EMPLOYEE_ID) +); + +CREATE TABLE C##INVENTORY.PICKUP_ITEMS +( + PICKUP_ID NUMBER, + PHYSICAL_PRODUCT_ID NUMBER, + PRIMARY KEY (PICKUP_ID, PHYSICAL_PRODUCT_ID), + FOREIGN KEY (PICKUP_ID) REFERENCES C##INVENTORY.PICKUPS (ID), + FOREIGN KEY (PHYSICAL_PRODUCT_ID) REFERENCES C##INVENTORY.PHYSICAL_PRODUCTS (ID) +); + +CREATE TABLE C##INVENTORY.INVENTORIES +( + ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + NAME VARCHAR2(255), + WAREHOUSE_ID NUMBER REFERENCES C##INVENTORY.WAREHOUSES (ID), + HALL_ID NUMBER REFERENCES C##INVENTORY.HALLS (ID), + AISLE_ID NUMBER REFERENCES C##INVENTORY.AISLES (ID), + PLANNED TIMESTAMP, + FINISHED TIMESTAMP, + CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CREATED_BY NUMBER, + UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UPDATED_BY NUMBER +); + +CREATE TABLE C##INVENTORY.INVENTORY_MEMBERS +( + INVENTORY_ID NUMBER, + WAREHOUSE_ID NUMBER, + EMPLOYEE_ID NUMBER, + PRIMARY KEY (INVENTORY_ID, WAREHOUSE_ID, EMPLOYEE_ID), + FOREIGN KEY (INVENTORY_ID) REFERENCES C##INVENTORY.INVENTORIES (ID), + FOREIGN KEY (WAREHOUSE_ID, EMPLOYEE_ID) REFERENCES C##INVENTORY.WAREHOUSE_EMPLOYEES (WAREHOUSE_ID, EMPLOYEE_ID) +); + +CREATE TABLE C##INVENTORY.INVENTORY_OBSERVATIONS +( + ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + INVENTORY_ID NUMBER REFERENCES C##INVENTORY.INVENTORIES (ID), + PHYSICAL_PRODUCT_ID NUMBER REFERENCES C##INVENTORY.PHYSICAL_PRODUCTS (ID), + STATUS VARCHAR2(255), + MESSAGE CLOB, + CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CREATED_BY NUMBER, + UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UPDATED_BY NUMBER, + DELETED_AT TIMESTAMP, + DELETED_BY NUMBER +); + +CREATE INDEX IDX_INVENTORY_OBSERVATIONS_DELETED_AT ON C##INVENTORY.INVENTORY_OBSERVATIONS (DELETED_AT); + + +-- insert some data +INSERT INTO C##INVENTORY.EMPLOYEES (FIRST_NAME, LAST_NAME, EMAIL, PHONE, CREATED_BY, UPDATED_BY) VALUES ('John', 'Doe', 'john.doe@example.com', '1234567890', 1, 1); +INSERT INTO C##INVENTORY.EMPLOYEES (FIRST_NAME, LAST_NAME, EMAIL, PHONE, CREATED_BY, UPDATED_BY) VALUES ('Jane', 'Smith', 'jane.smith@example.com', '0987654321', 1, 1); + +INSERT INTO C##INVENTORY.WAREHOUSES (NAME, ADDRESS, MANAGER, CREATED_BY, UPDATED_BY) VALUES ('Main Warehouse', '1234 Warehouse St.', 1, 1, 1); +INSERT INTO C##INVENTORY.WAREHOUSES (NAME, ADDRESS, MANAGER, CREATED_BY, UPDATED_BY) VALUES ('Secondary Warehouse', '5678 Warehouse Ave.', 2, 1, 1); + +INSERT INTO C##INVENTORY.HALLS (WAREHOUSE_ID, NAME, MANAGER, CREATED_BY, UPDATED_BY) VALUES (1, 'Hall A', 1, 1, 1); +INSERT INTO C##INVENTORY.HALLS (WAREHOUSE_ID, NAME, MANAGER, CREATED_BY, UPDATED_BY) VALUES (2, 'Hall B', 2, 1, 1); + +INSERT INTO C##INVENTORY.AISLES (HALL_ID, NAME, MANAGER, CREATED_BY, UPDATED_BY) VALUES (1, 'Aisle 1', 1, 1, 1); +INSERT INTO C##INVENTORY.AISLES (HALL_ID, NAME, MANAGER, CREATED_BY, UPDATED_BY) VALUES (2, 'Aisle 2', 2, 1, 1); + +INSERT INTO C##INVENTORY.RACKS (AISLE_ID, NAME, CREATED_BY, UPDATED_BY) VALUES (1, 'Rack 1', 1, 1); +INSERT INTO C##INVENTORY.RACKS (AISLE_ID, NAME, CREATED_BY, UPDATED_BY) VALUES (2, 'Rack 2', 1, 1); + +INSERT INTO C##INVENTORY.SHELVES (RACK_ID, NAME, CREATED_BY, UPDATED_BY) VALUES (1, 'Shelf 1', 1, 1); +INSERT INTO C##INVENTORY.SHELVES (RACK_ID, NAME, CREATED_BY, UPDATED_BY) VALUES (2, 'Shelf 2', 1, 1); + +INSERT INTO C##INVENTORY.SHELF_POSITIONS (SHELF_ID, NAME, CREATED_BY, UPDATED_BY) VALUES (1, 'Position 1', 1, 1); +INSERT INTO C##INVENTORY.SHELF_POSITIONS (SHELF_ID, NAME, CREATED_BY, UPDATED_BY) VALUES (2, 'Position 2', 1, 1); + +INSERT INTO C##INVENTORY.WAREHOUSE_EMPLOYEES (WAREHOUSE_ID, EMPLOYEE_ID, ROLE, CREATED_BY, UPDATED_BY) VALUES (1, 1, 'manager', 1, 1); +INSERT INTO C##INVENTORY.WAREHOUSE_EMPLOYEES (WAREHOUSE_ID, EMPLOYEE_ID, ROLE, CREATED_BY, UPDATED_BY) VALUES (2, 2, 'stocker', 1, 1); + +INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, CREATED_BY) VALUES (1, 1, 'badge', '123456', 1); +INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, CREATED_BY) VALUES (2, 2, 'cni', '987654', 1); + +INSERT INTO C##INVENTORY.BRANDS (SLUG, NAME) VALUES ('google', 'Google'); +INSERT INTO C##INVENTORY.BRANDS (SLUG, NAME) VALUES ('apple', 'Apple'); + +INSERT INTO C##INVENTORY.PRODUCTS (SLUG, NAME, BRAND, CATEGORY, SUBCATEGORY, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES ('pixel-8-pro', 'Pixel 8 Pro', 1, 'Phones', 'Smartphones', 2.8, 5.8, 0.3, 0.5); +INSERT INTO C##INVENTORY.PRODUCTS (SLUG, NAME, BRAND, CATEGORY, SUBCATEGORY, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES ('iphone-14', 'iPhone 14', 2, 'Phones', 'Smartphones', 2.7, 5.7, 0.3, 0.4); + +INSERT INTO C##INVENTORY.PRODUCT_VERSIONS (PRODUCT_ID, SKU, EAN, NAME, SPECS, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (1, 'P8P128', '1234567890123', 'Pixel 8 Pro Menthe 128 Go', '{"color": "Menthe", "storage": 128}', 2.8, 5.8, 0.3, 0.5); +INSERT INTO C##INVENTORY.PRODUCT_VERSIONS (PRODUCT_ID, SKU, EAN, NAME, SPECS, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (2, 'I14128', '1234567890124', 'iPhone 14 Bleu 128 Go', '{"color": "Bleu", "storage": 128}', 2.7, 5.7, 0.3, 0.4); + +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (PRODUCT_VERSION_ID, SNID, EXPIRATION) VALUES (1, 'SN1234567890', TO_TIMESTAMP('2025-12-31 23:59:59', 'YYYY-MM-DD HH24:MI:SS')); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (PRODUCT_VERSION_ID, SNID) VALUES (1, 'SN1234567891'); + +INSERT INTO C##INVENTORY.SUPPLIERS (NAME, "LEVEL", CURRENCY) VALUES ('Supplier A', 1, 'USD'); +INSERT INTO C##INVENTORY.SUPPLIERS (NAME, "LEVEL", CURRENCY) VALUES ('Supplier B', 2, 'EUR'); + +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (1, 1, 70.00); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (2, 2, 80.00); + +INSERT INTO C##INVENTORY.SUPPLIER_EMPLOYEES (SUPPLIER_ID, EMPLOYEE_ID, ROLE, CREATED_BY, UPDATED_BY) VALUES (1, 1, 'delivery', 1, 1); +INSERT INTO C##INVENTORY.SUPPLIER_EMPLOYEES (SUPPLIER_ID, EMPLOYEE_ID, ROLE, CREATED_BY, UPDATED_BY) VALUES (2, 2, 'sale', 1, 1); + +INSERT INTO C##INVENTORY.PURCHASE_ORDERS (SUPPLIER_ID, PRICE, CURRENCY, DETAILS, NOTES, CREATED_BY, UPDATED_BY) VALUES (1, 700.00, 'USD', 'Order details for Supplier A', 'Internal notes', 1, 1); +INSERT INTO C##INVENTORY.PURCHASE_ORDERS (SUPPLIER_ID, PRICE, CURRENCY, DETAILS, NOTES, CREATED_BY, UPDATED_BY) VALUES (2, 800.00, 'EUR', 'Order details for Supplier B', 'Internal notes', 1, 1); + +INSERT INTO C##INVENTORY.PURCHASE_ORDER_ITEMS (PURCHASE_ORDER_ID, PRODUCT_VERSION_ID, QUANTITY, PRICE, CREATED_BY, UPDATED_BY) VALUES (1, 1, 10, 70.00, 1, 1); +INSERT INTO C##INVENTORY.PURCHASE_ORDER_ITEMS (PURCHASE_ORDER_ID, PRODUCT_VERSION_ID, QUANTITY, PRICE, CREATED_BY, UPDATED_BY) VALUES (2, 2, 5, 160.00, 1, 1); + +INSERT INTO C##INVENTORY.DELIVERIES (REASON, ACCEPTED, PURCHASE_ORDER_ID, WAREHOUSE_ID, WAREHOUSE_EMPLOYEE_ID, SUPPLIER_ID, SUPPLIER_EMPLOYEE_ID, DELIVERED_AT) VALUES ('supplier_delivery', 'Y', 1, 1, 1, 1, 1, CURRENT_TIMESTAMP); +INSERT INTO C##INVENTORY.DELIVERIES (REASON, ACCEPTED, PURCHASE_ORDER_ID, WAREHOUSE_ID, WAREHOUSE_EMPLOYEE_ID, SUPPLIER_ID, SUPPLIER_EMPLOYEE_ID, DELIVERED_AT) VALUES ('customer_return', 'N', 2, 2, 2, 2, 2, CURRENT_TIMESTAMP); + +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 1); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (2, 2); + +INSERT INTO C##INVENTORY.PICKUPS (REASON, ACCEPTED, WAREHOUSE_ID, WAREHOUSE_EMPLOYEE_ID, SUPPLIER_ID, SUPPLIER_EMPLOYEE_ID, DELIVERED_AT) VALUES ('customer_delivery', 'Y', 1, 1, 1, 1, CURRENT_TIMESTAMP); +INSERT INTO C##INVENTORY.PICKUPS (REASON, ACCEPTED, WAREHOUSE_ID, WAREHOUSE_EMPLOYEE_ID, SUPPLIER_ID, SUPPLIER_EMPLOYEE_ID, DELIVERED_AT) VALUES ('supplier_return', 'N', 2, 2, 2, 2, CURRENT_TIMESTAMP); + +INSERT INTO C##INVENTORY.PICKUP_ITEMS (PICKUP_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 1); +INSERT INTO C##INVENTORY.PICKUP_ITEMS (PICKUP_ID, PHYSICAL_PRODUCT_ID) VALUES (2, 2); + +INSERT INTO C##INVENTORY.INVENTORIES (NAME, WAREHOUSE_ID, PLANNED, CREATED_BY, UPDATED_BY) VALUES ('Inventory 1', 1, TO_TIMESTAMP('2022-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 1, 1); +INSERT INTO C##INVENTORY.INVENTORIES (NAME, WAREHOUSE_ID, PLANNED, CREATED_BY, UPDATED_BY) VALUES ('Inventory 2', 2, TO_TIMESTAMP('2022-01-02 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 1, 1); + +INSERT INTO C##INVENTORY.INVENTORY_MEMBERS (INVENTORY_ID, WAREHOUSE_ID, EMPLOYEE_ID) VALUES (1, 1, 1); +INSERT INTO C##INVENTORY.INVENTORY_MEMBERS (INVENTORY_ID, WAREHOUSE_ID, EMPLOYEE_ID) VALUES (2, 2, 2); + +INSERT INTO C##INVENTORY.INVENTORY_OBSERVATIONS (INVENTORY_ID, PHYSICAL_PRODUCT_ID, STATUS, MESSAGE, CREATED_BY, UPDATED_BY) VALUES (1, 1, 'missing', 'Item not found', 1, 1); +INSERT INTO C##INVENTORY.INVENTORY_OBSERVATIONS (INVENTORY_ID, PHYSICAL_PRODUCT_ID, STATUS, MESSAGE, CREATED_BY, UPDATED_BY) VALUES (2, 2, 'broken', 'Item damaged', 1, 1); diff --git a/libs/connector-oracle/src/index.ts b/libs/connector-oracle/src/index.ts index f496b7e06..fed5c2bce 100644 --- a/libs/connector-oracle/src/index.ts +++ b/libs/connector-oracle/src/index.ts @@ -26,7 +26,7 @@ export const oracle: Connector = { const urlOptions = url.options || {} const options: ConnectorSchemaOpts = { ...opts, - schema: opts.schema || urlOptions['schema'] || urlOptions['owner'], + schema: opts.schema || urlOptions['schema'] || urlOptions['owner'] || urlOptions['user'], entity: opts.entity || urlOptions['table'], } return connect(application, url, getSchema(options), options).then(zodParseAsync(Database)) diff --git a/libs/connector-oracle/src/oracle.ts b/libs/connector-oracle/src/oracle.ts index 8d151fe7c..eebbc279a 100644 --- a/libs/connector-oracle/src/oracle.ts +++ b/libs/connector-oracle/src/oracle.ts @@ -448,7 +448,7 @@ export const getIndexes = (opts: ScopeOpts) => async (conn: Conn): Promise { test.skip('execQuery2', async () => { const query = 'SELECT *\nFROM "C##AZIMUTT"."USERS"\nFETCH FIRST 100 ROWS ONLY;' const results = await connect(application, url, execQuery(query, []), opts) + console.log('results', results) expect(results.attributes).toEqual([ {name: 'ID', ref: {schema: 'C##AZIMUTT', entity: 'USERS', attribute: ['ID']}}, {name: 'NAME', ref: {schema: 'C##AZIMUTT', entity: 'USERS', attribute: ['NAME']}}, diff --git a/libs/connector-oracle/src/query.ts b/libs/connector-oracle/src/query.ts index 996efe110..af7d104c7 100644 --- a/libs/connector-oracle/src/query.ts +++ b/libs/connector-oracle/src/query.ts @@ -1,4 +1,5 @@ -import {buildQueryAttributes, QueryResults} from "@azimutt/models"; +import * as oracledb from "oracledb"; +import {AttributeValue, buildQueryAttributes, QueryResults} from "@azimutt/models"; import {Conn, QueryResultArrayMode} from "./connect"; export const execQuery = (query: string, parameters: any[]) => (conn: Conn): Promise => { @@ -7,6 +8,15 @@ export const execQuery = (query: string, parameters: any[]) => (conn: Conn): Pro async function buildResults(conn: Conn, query: string, result: QueryResultArrayMode): Promise { const attributes = buildQueryAttributes(result.fields, query) - const rows = result.rows.map(row => attributes.reduce((acc, col, i) => ({...acc, [col.name]: row[i]}), {})) + const rows = await Promise.all(result.rows.map(async row => Object.fromEntries(await Promise.all(attributes.map((attr, i) => buildValue(row[i]).then(v => [attr.name, v])))))) return {query, attributes, rows} } + +async function buildValue(v: AttributeValue): Promise { + if (typeof v === 'object' && v !== null && v.constructor.name === 'Lob') return getLobData(v as oracledb.Lob) + return v +} + +function getLobData(lob: oracledb.Lob): AttributeValue { + return lob.getData().then(data => typeof data === 'string' ? data : data.toString()) +} diff --git a/libs/models/src/databaseUrl.test.ts b/libs/models/src/databaseUrl.test.ts index f61f4b7b0..59860cf80 100644 --- a/libs/models/src/databaseUrl.test.ts +++ b/libs/models/src/databaseUrl.test.ts @@ -117,6 +117,16 @@ describe('databaseUrl', () => { host: 'localhost', port: 5221, }) + expect(parseDatabaseUrl('oracle:thin:system/oracle@localhost:1521/FREE?schema=C##AZIMUTT')).toEqual({ + full: 'oracle:thin:system/oracle@localhost:1521/FREE?schema=C##AZIMUTT', + kind: 'oracle', + user: 'system', + pass: 'oracle', + host: 'localhost', + port: 1521, + db: 'FREE', + options: {schema: 'C##AZIMUTT'} + }) }) test('parse postgres url', () => { expect(parseDatabaseUrl('postgres://postgres0.example.com')).toEqual({ diff --git a/libs/models/src/databaseUrl.ts b/libs/models/src/databaseUrl.ts index dcc9cb888..68fb83786 100644 --- a/libs/models/src/databaseUrl.ts +++ b/libs/models/src/databaseUrl.ts @@ -22,7 +22,7 @@ const couchbaseRegexxxxxxxxxxx = /^couchbases?:\/\/(?:([^:]+):([^@]*)@)?([^:/?&] const mariadbRegexxxxxxx = /^(?:jdbc:)?mariadb:\/\/(?:([^:]+):([^@]*)@)?([^:/?&]+)(?::(\d+))?(?:\/([^?]+))?(?:\?(.+))?$/ const mongoRegexxxxxxxxxx = /^mongodb(?:\+srv)?:\/\/(?:([^:]+):([^@]*)@)?([^:/?&]+)(?::(\d+))?(?:\/([^?]+))?(?:\?(.+))?$/ const mysqlRegexxxxxxxxxxx = /^(?:jdbc:)?mysql:\/\/(?:([^:]+):([^@]*)@)?([^:/?&]+)(?::(\d+))?(?:\/([^?]+))?(?:\?(.+))?$/ -const oracleRegexxxxxx = /^(?:jdbc:)?oracle:thin:(?:([^\/]+)\/([^@]+)@)?(?:\/\/)?([^:\/]+)(?::(\d+))?(?:[\/:]([^?]+))?$/ +const oracleRegexxxxxx = /^(?:jdbc:)?oracle:thin:(?:([^\/]+)\/([^@]+)@)?(?:\/\/)?([^:\/]+)(?::(\d+))?(?:[\/:]([^?]+))?(?:\?(.+))?$/ const postgresRe = /^(?:jdbc:)?postgres(?:ql)?:\/\/(?:([^:]+):([^@]*)@)?([^:/?&]+)(?::(\d+))?(?:\/([^?]+))?(?:\?(.+))?$/ const sqlserver = /^(?:jdbc:)?sqlserver(?:ql)?:\/\/(?:([^:]+):([^@]*)@)?([^:/?&]+)(?::(\d+))?(?:\/([^?]+))?(?:\?(.+))?$/ const snowflakeRegexxx = /^(?:jdbc:)?snowflake:\/\/(?:([^:]+):([^@]*)@)?([^:/?&]+)(?::(\d+))?(?:\/([^?]+))?(?:\?(.+))?$/ From 0eee93babb8be2e26625116c92cc0fcb21c50a21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Knuchel?= Date: Wed, 14 Aug 2024 17:04:53 +0200 Subject: [PATCH 03/16] Add catalog & shopping domains --- demos/{ecommerce-usrv => ecommerce}/README.md | 0 demos/{ecommerce-usrv => ecommerce}/design.md | 88 +++---- .../script_1_referential_sqlserver.sql | 0 .../script_2_identity_mariadb.sql | 0 .../script_3_inventory_oracle.sql | 0 demos/ecommerce/script_4_catalog_postgres.sql | 231 ++++++++++++++++++ .../ecommerce/script_5_shopping_postgres.sql | 103 ++++++++ 7 files changed, 378 insertions(+), 44 deletions(-) rename demos/{ecommerce-usrv => ecommerce}/README.md (100%) rename demos/{ecommerce-usrv => ecommerce}/design.md (93%) rename demos/{ecommerce-usrv => ecommerce}/script_1_referential_sqlserver.sql (100%) rename demos/{ecommerce-usrv => ecommerce}/script_2_identity_mariadb.sql (100%) rename demos/{ecommerce-usrv => ecommerce}/script_3_inventory_oracle.sql (100%) create mode 100644 demos/ecommerce/script_4_catalog_postgres.sql create mode 100644 demos/ecommerce/script_5_shopping_postgres.sql diff --git a/demos/ecommerce-usrv/README.md b/demos/ecommerce/README.md similarity index 100% rename from demos/ecommerce-usrv/README.md rename to demos/ecommerce/README.md diff --git a/demos/ecommerce-usrv/design.md b/demos/ecommerce/design.md similarity index 93% rename from demos/ecommerce-usrv/design.md rename to demos/ecommerce/design.md index f43f407ae..930653ffd 100644 --- a/demos/ecommerce-usrv/design.md +++ b/demos/ecommerce/design.md @@ -363,9 +363,9 @@ C##INVENTORY.INVENTORY_OBSERVATIONS # Catalog -catalog.Categories +catalog.categories id bigint pk - parent bigint nullable fk catalog.Categories.id + parent bigint nullable fk catalog.categories.id depth int | easily accessible information of number of parents slug varchar unique name varchar @@ -375,11 +375,11 @@ catalog.Categories updated_at timestamp deleted_at timestamp nullable index -catalog.Products +catalog.products id bigint pk fk C##INVENTORY.PRODUCTS.ID slug varchar unique name varchar - category_id bigint fk catalog.Categories.id + category_id bigint fk catalog.categories.id description text nullable | TODO: handle i18n description_html text nullable versions json | ex: `[{key: "color", label: "Couleur", values: [{name: "Bleu Azur", value: "#95bbe2"}]}, {key: "storage", name: "Taille", values: [{name: "128GB", value: 128}]}]` @@ -389,9 +389,9 @@ catalog.Products updated_at timestamp deleted_at timestamp nullable index -catalog.ProductVersions +catalog.product_versions id bigint pk fk C##INVENTORY.PRODUCT_VERSIONS.ID - product_id bigint fk catalog.Products.id + product_id bigint fk catalog.products.id name varchar specs json | ex: `{color: "Bleu Azur", storage: 128}` price double @@ -400,22 +400,22 @@ catalog.ProductVersions updated_at timestamp deleted_at timestamp nullable index -catalog.ProductCrossSellOptions - product_id bigint pk fk catalog.Products.id - product_version_id bigint pk fk catalog.ProductVersions.id +catalog.product_cross_sell_options + product_id bigint pk fk catalog.products.id + product_version_id bigint pk fk catalog.product_versions.id label varchar created_at timestamp updated_at timestamp deleted_at timestamp nullable index -catalog.ProductAlternatives - product_id bigint pk fk catalog.Products.id - alternative_product_id bigint pk fk catalog.Products.id +catalog.product_alternatives + product_id bigint pk fk catalog.products.id + alternative_product_id bigint pk fk catalog.products.id created_at timestamp updated_at timestamp deleted_at timestamp nullable index -catalog.Assets +catalog.assets id bigint pk kind asset_kind(picture, video, embed) format asset_format(1:1, 16:9) @@ -429,34 +429,34 @@ catalog.Assets updated_at timestamp deleted_at timestamp nullable index -catalog.CategoryAssets - category_id bigint pk fk catalog.Categories.id - asset_id bigint pk fk catalog.Assets.id +catalog.category_assets + category_id bigint pk fk catalog.categories.id + asset_id bigint pk fk catalog.assets.id placement category_asset_placement(banner, icon) created_at timestamp updated_at timestamp deleted_at timestamp nullable index -catalog.ProductAssets - product_id bigint pk fk catalog.Products.id - asset_id bigint pk fk catalog.Assets.id +catalog.product_assets + product_id bigint pk fk catalog.products.id + asset_id bigint pk fk catalog.assets.id placement category_asset_placement(banner, icon) created_at timestamp updated_at timestamp deleted_at timestamp nullable index -catalog.ProductVersionAssets - product_version_id bigint pk fk catalog.ProductVersions.id - asset_id bigint pk fk catalog.Assets.id +catalog.product_version_assets + product_version_id bigint pk fk catalog.product_versions.id + asset_id bigint pk fk catalog.assets.id placement category_asset_placement(banner, icon) created_at timestamp updated_at timestamp deleted_at timestamp nullable index -catalog.ProductReviews +catalog.product_reviews id bigint pk - product_id bigint fk catalog.Products.id - product_version_id bigint nullable fk catalog.ProductVersions.id + product_id bigint fk catalog.products.id + product_version_id bigint nullable fk catalog.product_versions.id invoice_id bigint nullable fk billing.Invoices.id physical_product_id bigint nullable fk C##INVENTORY.PHYSICAL_PRODUCTS.ID rating int @@ -468,16 +468,16 @@ catalog.ProductReviews deleted_at timestamp nullable index deleted_by bigint nullable fk identity.Users.id -catalog.ProductReviewAssets - product_review_id bigint pk fk catalog.ProductReviews.id - asset_id bigint pk fk catalog.Assets.id +catalog.product_review_assets + product_review_id bigint pk fk catalog.product_reviews.id + asset_id bigint pk fk catalog.assets.id created_at timestamp created_by bigint fk identity.Users.id deleted_at timestamp nullable index deleted_by bigint nullable fk identity.Users.id -catalog.ProductReviewFeedbacks - product_review_id bigint pk fk catalog.ProductReviews.id +catalog.product_review_feedbacks + product_review_id bigint pk fk catalog.product_reviews.id kind feedback_kind(like, report) created_at timestamp created_by bigint pk fk identity.Users.id @@ -486,7 +486,7 @@ catalog.ProductReviewFeedbacks # Shopping -shopping.Carts +shopping.carts id bigint pk owner_kind cart_owner(identity.Devices, identity.Users) | Devices are used for anonymous carts, otherwise it's Users owner_id bigint @@ -494,12 +494,12 @@ shopping.Carts created_at timestamp updated_at timestamp deleted_at timestamp nullable index -fk shopping.Carts.owner_id -> identity.Devices.id -fk shopping.Carts.owner_id -> identity.Users.id +fk shopping.carts.owner_id -> identity.Devices.id +fk shopping.carts.owner_id -> identity.Users.id -shopping.CartItems - cart_id bigint pk fk shopping.Carts.id - product_version_id bigint pk fk catalog.ProductVersions.id +shopping.cart_items + cart_id bigint pk fk shopping.carts.id + product_version_id bigint pk fk catalog.product_versions.id quantity int price double | at the time the product was added to the card, prevent price changes after a product has been added to a cart created_at timestamp @@ -509,7 +509,7 @@ shopping.CartItems deleted_at timestamp nullable index deleted_by bigint nullable fk identity.Users.id -shopping.Wishlists +shopping.wishlists id bigint pk name varchar description text nullable @@ -521,17 +521,17 @@ shopping.Wishlists deleted_at timestamp nullable index deleted_by bigint nullable fk identity.Users.id -shopping.WishlistItems - wishlist_id bigint pk fk shopping.Wishlists.id - product_id bigint pk fk catalog.Products.id +shopping.wishlist_items + wishlist_id bigint pk fk shopping.wishlists.id + product_id bigint pk fk catalog.products.id specs json nullable | if the user saved specific configuration created_at timestamp created_by bigint fk identity.Users.id deleted_at timestamp nullable index deleted_by bigint nullable fk identity.Users.id -shopping.WishlistMembers - wishlist_id bigint pk fk shopping.Wishlists.id +shopping.wishlist_members + wishlist_id bigint pk fk shopping.wishlists.id user_id bigint pk fk identity.Users.id rights wishlist_rights(edit, comment, view) created_at timestamp @@ -600,7 +600,7 @@ billing.CustomerAddresses billing.Invoices id bigint pk reference varchar unique - cart_id bigint nullable fk shopping.Carts.id + cart_id bigint nullable fk shopping.carts.id customer_id bigint fk billing.Customers.id billing_address bigint fk billing.CustomerAddresses.id total_price double @@ -612,7 +612,7 @@ billing.Invoices billing.InvoiceLines invoice_id bigint pk fk billing.Invoices.id index int pk - product_version_id bigint nullable fk catalog.ProductVersions.id + product_version_id bigint nullable fk catalog.product_versions.id description text nullable price double quantity int diff --git a/demos/ecommerce-usrv/script_1_referential_sqlserver.sql b/demos/ecommerce/script_1_referential_sqlserver.sql similarity index 100% rename from demos/ecommerce-usrv/script_1_referential_sqlserver.sql rename to demos/ecommerce/script_1_referential_sqlserver.sql diff --git a/demos/ecommerce-usrv/script_2_identity_mariadb.sql b/demos/ecommerce/script_2_identity_mariadb.sql similarity index 100% rename from demos/ecommerce-usrv/script_2_identity_mariadb.sql rename to demos/ecommerce/script_2_identity_mariadb.sql diff --git a/demos/ecommerce-usrv/script_3_inventory_oracle.sql b/demos/ecommerce/script_3_inventory_oracle.sql similarity index 100% rename from demos/ecommerce-usrv/script_3_inventory_oracle.sql rename to demos/ecommerce/script_3_inventory_oracle.sql diff --git a/demos/ecommerce/script_4_catalog_postgres.sql b/demos/ecommerce/script_4_catalog_postgres.sql new file mode 100644 index 000000000..e11ba452d --- /dev/null +++ b/demos/ecommerce/script_4_catalog_postgres.sql @@ -0,0 +1,231 @@ +-- drop everything +DROP SCHEMA IF EXISTS catalog CASCADE; +CREATE SCHEMA catalog; + + +-- create the database +CREATE TABLE catalog.categories +( + id BIGINT PRIMARY KEY, + parent BIGINT REFERENCES catalog.categories (id), + depth INT, + slug VARCHAR(255) UNIQUE, + name VARCHAR(255), + description TEXT, + description_html TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP +); + +CREATE INDEX idx_categories_deleted_at ON catalog.categories (deleted_at); + +CREATE TABLE catalog.products +( + id BIGINT PRIMARY KEY, + slug VARCHAR(255) UNIQUE, + name VARCHAR(255), + category_id BIGINT REFERENCES catalog.categories (id), + description TEXT, + description_html TEXT, + versions JSON, + attributes JSON, + stock INT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP +); + +CREATE INDEX idx_products_deleted_at ON catalog.products (deleted_at); + +CREATE TABLE catalog.product_versions +( + id BIGINT PRIMARY KEY, + product_id BIGINT REFERENCES catalog.products (id), + name VARCHAR(255), + specs JSON, + price DOUBLE PRECISION, + stock INT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP +); + +CREATE INDEX idx_product_versions_deleted_at ON catalog.product_versions (deleted_at); + +CREATE TABLE catalog.product_cross_sell_options +( + product_id BIGINT REFERENCES catalog.products (id), + product_version_id BIGINT REFERENCES catalog.product_versions (id), + label VARCHAR(255), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP, + PRIMARY KEY (product_id, product_version_id) +); + +CREATE INDEX idx_product_cross_sell_options_deleted_at ON catalog.product_cross_sell_options (deleted_at); + +CREATE TABLE catalog.product_alternatives +( + product_id BIGINT REFERENCES catalog.products (id), + alternative_product_id BIGINT REFERENCES catalog.products (id), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP, + PRIMARY KEY (product_id, alternative_product_id) +); + +CREATE INDEX idx_product_alternatives_deleted_at ON catalog.product_alternatives (deleted_at); + +CREATE TABLE catalog.assets +( + id BIGINT PRIMARY KEY, + kind VARCHAR(50), + format VARCHAR(10), + size VARCHAR(10), + path VARCHAR(255), + alt VARCHAR(255), + width INT, + height INT, + weight INT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP +); + +CREATE INDEX idx_assets_deleted_at ON catalog.assets (deleted_at); + +CREATE TABLE catalog.category_assets +( + category_id BIGINT REFERENCES catalog.categories (id), + asset_id BIGINT REFERENCES catalog.assets (id), + placement VARCHAR(50), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP, + PRIMARY KEY (category_id, asset_id) +); + +CREATE INDEX idx_category_assets_deleted_at ON catalog.category_assets (deleted_at); + +CREATE TABLE catalog.product_assets +( + product_id BIGINT REFERENCES catalog.products (id), + asset_id BIGINT REFERENCES catalog.assets (id), + placement VARCHAR(50), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP, + PRIMARY KEY (product_id, asset_id) +); + +CREATE INDEX idx_product_assets_deleted_at ON catalog.product_assets (deleted_at); + +CREATE TABLE catalog.product_version_assets +( + product_version_id BIGINT REFERENCES catalog.product_versions (id), + asset_id BIGINT REFERENCES catalog.assets (id), + placement VARCHAR(50), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP, + PRIMARY KEY (product_version_id, asset_id) +); + +CREATE INDEX idx_product_version_assets_deleted_at ON catalog.product_version_assets (deleted_at); + +CREATE TABLE catalog.product_reviews +( + id BIGINT PRIMARY KEY, + product_id BIGINT REFERENCES catalog.products (id), + product_version_id BIGINT REFERENCES catalog.product_versions (id), + invoice_id BIGINT, + physical_product_id BIGINT, + rating INT, + review TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + created_by BIGINT, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, + deleted_at TIMESTAMP, + deleted_by BIGINT +); + +CREATE INDEX idx_product_reviews_deleted_at ON catalog.product_reviews (deleted_at); + +CREATE TABLE catalog.product_review_assets +( + product_review_id BIGINT REFERENCES catalog.product_reviews (id), + asset_id BIGINT REFERENCES catalog.assets (id), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + created_by BIGINT, + deleted_at TIMESTAMP, + deleted_by BIGINT, + PRIMARY KEY (product_review_id, asset_id) +); + +CREATE INDEX idx_product_review_assets_deleted_at ON catalog.product_review_assets (deleted_at); + +CREATE TABLE catalog.product_review_feedbacks +( + product_review_id BIGINT REFERENCES catalog.product_reviews (id), + kind VARCHAR(50), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + created_by BIGINT, + deleted_at TIMESTAMP, + deleted_by BIGINT, + PRIMARY KEY (product_review_id, created_by, kind) +); + +CREATE INDEX idx_product_review_feedbacks_deleted_at ON catalog.product_review_feedbacks (deleted_at); + + +-- insert some data +INSERT INTO catalog.categories (id, parent, depth, slug, name, description, description_html) +VALUES (1, NULL, 0, 'electronics', 'Electronics', 'All electronic items', '

All electronic items

'), + (2, 1, 1, 'phones', 'Phones', 'All kinds of phones', '

All kinds of phones

'); + +INSERT INTO catalog.products (id, slug, name, category_id, description, description_html, versions, attributes, stock) +VALUES (1, 'pixel-8-pro', 'Pixel 8 Pro', 2, 'A high-end smartphone by Google', '

A high-end smartphone by Google

','[{"key": "color", "label": "Couleur", "values": [{"name": "Bleu Azur", "value": "#95bbe2"}]}, {"key": "storage", "label": "Taille", "values": [{"name": "128GB", "value": 128}]}]', '[{"key": "Marque", "value": "Google"}]', 100), + (2, 'iphone-14', 'iPhone 14', 2, 'The latest iPhone by Apple', '

The latest iPhone by Apple

', '[{"key": "color", "label": "Couleur", "values": [{"name": "Noir", "value": "#000000"}]}, {"key": "storage", "label": "Taille", "values": [{"name": "256GB", "value": 256}]}]', '[{"key": "Marque", "value": "Apple"}]', 50); + +INSERT INTO catalog.product_versions (id, product_id, name, specs, price, stock) +VALUES (1, 1, 'Pixel 8 Pro Menthe 128 Go', '{"color": "Menthe", "storage": 128}', 899.99, 50), + (2, 2, 'iPhone 14 Noir 256 Go', '{"color": "Noir", "storage": 256}', 1099.99, 25); + +INSERT INTO catalog.product_cross_sell_options (product_id, product_version_id, label) +VALUES (1, 2, 'Buy with iPhone 14 case'), + (2, 1, 'Buy with Pixel 8 Pro case'); + +INSERT INTO catalog.product_alternatives (product_id, alternative_product_id) +VALUES (1, 2), + (2, 1); + +INSERT INTO catalog.assets (id, kind, format, size, path, alt, width, height, weight) +VALUES (1, 'picture', '1:1', 'high', '/images/pixel-8-pro.png', 'Pixel 8 Pro Image', 1024, 1024, 500), + (2, 'picture', '1:1', 'high', '/images/iphone-14.png', 'iPhone 14 Image', 1024, 1024, 500); + +INSERT INTO catalog.category_assets (category_id, asset_id, placement) +VALUES (1, 1, 'banner'), + (2, 2, 'icon'); + +INSERT INTO catalog.product_assets (product_id, asset_id, placement) +VALUES (1, 1, 'banner'), + (2, 2, 'icon'); + +INSERT INTO catalog.product_version_assets (product_version_id, asset_id, placement) +VALUES (1, 1, 'banner'), + (2, 2, 'icon'); + +INSERT INTO catalog.product_reviews (id, product_id, product_version_id, rating, review, created_by, updated_by) +VALUES (1, 1, 1, 5, 'Amazing phone!', 1, 1), + (2, 2, 2, 4, 'Great, but too expensive.', 2, 2); + +INSERT INTO catalog.product_review_assets (product_review_id, asset_id, created_by) +VALUES (1, 1, 1), + (2, 2, 2); + +INSERT INTO catalog.product_review_feedbacks (product_review_id, kind, created_by) +VALUES (1, 'like', 1), + (2, 'report', 2); diff --git a/demos/ecommerce/script_5_shopping_postgres.sql b/demos/ecommerce/script_5_shopping_postgres.sql new file mode 100644 index 000000000..3a801dfc7 --- /dev/null +++ b/demos/ecommerce/script_5_shopping_postgres.sql @@ -0,0 +1,103 @@ +-- drop everything +DROP SCHEMA IF EXISTS shopping CASCADE; +CREATE SCHEMA shopping; + + +-- create the database +CREATE TABLE shopping.carts +( + id BIGINT PRIMARY KEY, + owner_kind VARCHAR(255), + owner_id BIGINT, + expire_at TIMESTAMP, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP +); + +CREATE INDEX idx_carts_deleted_at ON shopping.carts (deleted_at); + +CREATE TABLE shopping.cart_items +( + cart_id BIGINT REFERENCES shopping.carts (id), + product_version_id BIGINT, + quantity INT, + price DOUBLE PRECISION, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + created_by BIGINT, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, + deleted_at TIMESTAMP, + deleted_by BIGINT, + PRIMARY KEY (cart_id, product_version_id) +); + +CREATE INDEX idx_cart_items_deleted_at ON shopping.cart_items (deleted_at); + +CREATE TABLE shopping.wishlists +( + id BIGINT PRIMARY KEY, + name VARCHAR(255), + description TEXT, + public BOOLEAN, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + created_by BIGINT, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, + deleted_at TIMESTAMP, + deleted_by BIGINT +); + +CREATE INDEX idx_wishlists_deleted_at ON shopping.wishlists (deleted_at); + +CREATE TABLE shopping.wishlist_items +( + wishlist_id BIGINT REFERENCES shopping.wishlists (id), + product_id BIGINT, + specs JSON, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + created_by BIGINT, + deleted_at TIMESTAMP, + deleted_by BIGINT, + PRIMARY KEY (wishlist_id, product_id) +); + +CREATE INDEX idx_wishlist_items_deleted_at ON shopping.wishlist_items (deleted_at); + +CREATE TABLE shopping.wishlist_members +( + wishlist_id BIGINT REFERENCES shopping.wishlists (id), + user_id BIGINT, + rights VARCHAR(50), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + created_by BIGINT, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_by BIGINT, + deleted_at TIMESTAMP, + deleted_by BIGINT, + PRIMARY KEY (wishlist_id, user_id) +); + +CREATE INDEX idx_wishlist_members_deleted_at ON shopping.wishlist_members (deleted_at); + + +-- insert some data +INSERT INTO shopping.carts (id, owner_kind, owner_id, expire_at) +VALUES (1, 'identity.Users', 1, CURRENT_TIMESTAMP + INTERVAL '1 day'), + (2, 'identity.Devices', 1, CURRENT_TIMESTAMP + INTERVAL '1 day'); + +INSERT INTO shopping.cart_items (cart_id, product_version_id, quantity, price, created_by, updated_by) +VALUES (1, 1, 2, 899.99, 1, 1), + (2, 2, 1, 1099.99, 2, 2); + +INSERT INTO shopping.wishlists (id, name, description, public, created_by, updated_by) +VALUES (1, 'John''s Wishlist', 'John''s favorite products', TRUE, 1, 1), + (2, 'Jane''s Wishlist', 'Jane''s favorite products', FALSE, 2, 2); + +INSERT INTO shopping.wishlist_items (wishlist_id, product_id, specs, created_by) +VALUES (1, 1, '{"color": "Menthe", "storage": 128}', 1), + (2, 2, '{"color": "Noir", "storage": 256}', 2); + +INSERT INTO shopping.wishlist_members (wishlist_id, user_id, rights, created_by, updated_by) +VALUES (1, 1, 'edit', 1, 1), + (2, 2, 'view', 2, 2); From 061cd56042c87aeb0b775bb2558b028eb442d308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Knuchel?= Date: Sat, 17 Aug 2024 22:35:09 +0200 Subject: [PATCH 04/16] Add Billing --- demos/ecommerce/README.md | 26 +++- demos/ecommerce/design.md | 146 +++++++++--------- .../ecommerce/script_6_billing_sqlserver.sql | 143 +++++++++++++++++ 3 files changed, 239 insertions(+), 76 deletions(-) create mode 100644 demos/ecommerce/script_6_billing_sqlserver.sql diff --git a/demos/ecommerce/README.md b/demos/ecommerce/README.md index 315304eda..c9201c21b 100644 --- a/demos/ecommerce/README.md +++ b/demos/ecommerce/README.md @@ -12,7 +12,7 @@ Each domain has its own database, here is how to set them up: This domain is for general data. -Import it in a [SQL Server database](../../libs/connector-sqlserver/README.md#local-setup) with the [script_1_referential_sqlserver.sql](script_1_referential_sqlserver.sql). +Import it in a [SQL Server database](../../libs/connector-sqlserver/README.md#local-setup) with the [script_1_referential_sqlserver.sql](./script_1_referential_sqlserver.sql). You will have it at this url: `sqlserver://sa:azimutt_42@localhost:1433/Referential` You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) @@ -21,19 +21,39 @@ You can then import it in your Azimutt project or explore it with the e-commerce This domain is user identity: who they are, what they can do. -Import it in a [MariaDB database](../../libs/connector-mariadb/README.md#local-setup) with the [script_2_identity_mariadb.sql](script_2_identity_mariadb.sql). +Import it in a [MariaDB database](../../libs/connector-mariadb/README.md#local-setup) with the [script_2_identity_mariadb.sql](./script_2_identity_mariadb.sql). You will have it at this url: `mariadb://root:mariadb@localhost:3307/identity` You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) ## Inventory -Import it in a [Oracle database](../../libs/connector-oracle/README.md#local-setup) with the [script_3_inventory_oracle.sql](script_3_inventory_oracle.sql). +Import it in a [Oracle database](../../libs/connector-oracle/README.md#local-setup) with the [script_3_inventory_oracle.sql](./script_3_inventory_oracle.sql). You will have it at this url: `oracle:thin:C##INVENTORY/inventory@localhost:1521/FREE` +You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) + ## Catalog + +Import it in a [PostgreSQL database](../../libs/connector-postgres/README.md#local-setup) with the [script_4_catalog_postgres.sql](./script_4_catalog_postgres.sql). +You will have it at this url: `postgresql://postgres:postgres@localhost:5433/postgres?schema=catalog` + +You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) + ## Shopping + +Import it in a [PostgreSQL database](../../libs/connector-postgres/README.md#local-setup) with the [script_5_shopping_postgres.sql](./script_5_shopping_postgres.sql). +You will have it at this url: `postgresql://postgres:postgres@localhost:5433/postgres?schema=shopping` + +You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) + ## Billing + +Import it in a [SQL Server database](../../libs/connector-sqlserver/README.md#local-setup) with the [script_6_billing_sqlserver.sql](./script_6_billing_sqlserver.sql). +You will have it at this url: `sqlserver://sa:azimutt_42@localhost:1433/Billing` + +You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) + ## Shipping ## CRM ## Analytics diff --git a/demos/ecommerce/design.md b/demos/ecommerce/design.md index 930653ffd..cb5b69afe 100644 --- a/demos/ecommerce/design.md +++ b/demos/ecommerce/design.md @@ -457,7 +457,7 @@ catalog.product_reviews id bigint pk product_id bigint fk catalog.products.id product_version_id bigint nullable fk catalog.product_versions.id - invoice_id bigint nullable fk billing.Invoices.id + invoice_id bigint nullable fk billing.Invoices.InvoiceId physical_product_id bigint nullable fk C##INVENTORY.PHYSICAL_PRODUCTS.ID rating int review text nullable @@ -543,87 +543,87 @@ shopping.wishlist_members # Billing +billing.CustomerAddresses + CustomerAddressesId bigint pk + Name varchar + Street varchar + City varchar + State varchar + ZipCode varchar + Country bigint fk referential.Countries.CountryId + Complements text nullable + CreatedAt timestamp + CreatedBy bigint fk identity.Users.id + DeletedAt timestamp nullable index + DeletedBy bigint nullable fk identity.Users.id + billing.Customers - id bigint pk - name varchar - billing_address bigint nullable fk billing.CustomerAddresses.id - siret varchar nullable - tva varchar nullable - created_at timestamp - created_by bigint fk identity.Users.id - updated_at timestamp - updated_by bigint fk identity.Users.id - deleted_at timestamp nullable index - deleted_by bigint nullable fk identity.Users.id + CustomerId bigint pk + Name varchar + BillingAddress bigint nullable fk billing.CustomerAddresses.CustomerAddressesId + Siret varchar nullable + TVA varchar nullable + CreatedAt timestamp + CreatedBy bigint fk identity.Users.id + UpdatedAt timestamp + UpdatedBy bigint fk identity.Users.id + DeletedAt timestamp nullable index + DeletedBy bigint nullable fk identity.Users.id billing.CustomerMembers - customer_id bigint pk fk billing.Customers.id - user_id bigint pk fk identity.Users.id - can_edit boolean - can_invite boolean - can_buy boolean - budget_allowance int nullable - created_at timestamp - created_by bigint fk identity.Users.id - updated_at timestamp - updated_by bigint fk identity.Users.id - deleted_at timestamp nullable index - deleted_by bigint nullable fk identity.Users.id + CustomerId bigint pk fk billing.Customers.CustomerId + UserId bigint pk fk identity.Users.id + CanEdit boolean + CanInvite boolean + CanBuy boolean + BudgetAllowance int nullable + CreatedAt timestamp + CreatedBy bigint fk identity.Users.id + UpdatedAt timestamp + UpdatedBy bigint fk identity.Users.id + DeletedAt timestamp nullable index + DeletedBy bigint nullable fk identity.Users.id billing.CustomerPaymentMethods - id bigint pk - customer_id bigint fk billing.Customers.id - name varchar - kind payment_kind(card, paypal) - details json - created_at timestamp - created_by bigint fk identity.Users.id - updated_at timestamp - updated_by bigint fk identity.Users.id - deleted_at timestamp nullable index - deleted_by bigint nullable fk identity.Users.id - -billing.CustomerAddresses - id bigint pk - name varchar - street varchar - city varchar - state varchar - zipcode varchar - country bigint fk referential.Countries.CountryId - complements text nullable - created_at timestamp - created_by bigint fk identity.Users.id - deleted_at timestamp nullable index - deleted_by bigint nullable fk identity.Users.id + CustomerPaymentMethodId bigint pk + CustomerId bigint fk billing.Customers.CustomerId + Name varchar + Kind payment_kind(card, paypal) + Details json + CreatedAt timestamp + CreatedBy bigint fk identity.Users.id + UpdatedAt timestamp + UpdatedBy bigint fk identity.Users.id + DeletedAt timestamp nullable index + DeletedBy bigint nullable fk identity.Users.id billing.Invoices - id bigint pk - reference varchar unique - cart_id bigint nullable fk shopping.carts.id - customer_id bigint fk billing.Customers.id - billing_address bigint fk billing.CustomerAddresses.id - total_price double - currency global_currency(EUR, USD) - paid_at timestamp nullable - created_at timestamp - created_by bigint nullable fk identity.Users.id + InvoiceId bigint pk + Reference varchar unique + CartId bigint nullable fk shopping.carts.id + CustomerId bigint fk billing.Customers.CustomerId + BillingAddress bigint fk billing.CustomerAddresses.CustomerAddressesId + TotalPrice double + Currency global_currency(EUR, USD) + PaidAt timestamp nullable + CreatedAt timestamp + CreatedBy bigint nullable fk identity.Users.id billing.InvoiceLines - invoice_id bigint pk fk billing.Invoices.id - index int pk - product_version_id bigint nullable fk catalog.product_versions.id - description text nullable - price double - quantity int + InvoiceId bigint pk fk billing.Invoices.InvoiceId + Index int pk + ProductVersionId bigint nullable fk catalog.product_versions.id + Description text nullable + Price double + Quantity int billing.Payments - id bigint pk - invoice_id bigint fk billing.Invoices.id - payment_method_id bigint nullable fk billing.CustomerPaymentMethods.id - amount double - currency global_currency(EUR, USD) - created_at timestamp + PaymentId bigint pk + InvoiceId bigint fk billing.Invoices.InvoiceId + PaymentMethodId bigint nullable fk billing.CustomerPaymentMethods.CustomerPaymentMethodId + Amount double + Currency global_currency(EUR, USD) + CreatedAt timestamp # Shipping @@ -657,8 +657,8 @@ shipping.Shipments shipping.ShipmentItems shipment_id bigint pk fk shipping.Shipments.id physical_product_id bigint pk fk C##INVENTORY.PHYSICAL_PRODUCTS.ID - invoice_id bigint fk billing.InvoiceLines.invoice_id - invoice_line int fk billing.InvoiceLines.index + invoice_id bigint fk billing.InvoiceLines.InvoiceId + invoice_line int fk billing.InvoiceLines.Index delivered_at timestamp nullable delivered_to bigint nullable fk identity.Users.id diff --git a/demos/ecommerce/script_6_billing_sqlserver.sql b/demos/ecommerce/script_6_billing_sqlserver.sql new file mode 100644 index 000000000..be17edc61 --- /dev/null +++ b/demos/ecommerce/script_6_billing_sqlserver.sql @@ -0,0 +1,143 @@ +-- drop everything +USE master; -- in order to stop using Billing ^^ +DROP DATABASE IF EXISTS Billing; + +-- create the database +CREATE DATABASE Billing; +USE Billing; +CREATE SCHEMA [billing]; + + +CREATE TABLE [billing].[CustomerAddresses] +( + [CustomerAddressesId] [bigint] IDENTITY (1,1) PRIMARY KEY, + [Name] [nvarchar](255) NOT NULL, + [Street] [nvarchar](255) NOT NULL, + [City] [nvarchar](255) NOT NULL, + [State] [nvarchar](255) NOT NULL, + [ZipCode] [nvarchar](20) NOT NULL, + [Country] [bigint], + [Complements] [text], + [CreatedAt] [datetime] DEFAULT CURRENT_TIMESTAMP, + [CreatedBy] [bigint], + [DeletedAt] [datetime], + [DeletedBy] [bigint] +); +CREATE INDEX [IdxCustomerAddressesDeletedAt] ON [billing].[CustomerAddresses] ([DeletedAt]); + +CREATE TABLE [billing].[Customers] +( + [CustomerId] [bigint] IDENTITY (1,1) PRIMARY KEY, + [Name] [nvarchar](255) NOT NULL, + [BillingAddress] [bigint] REFERENCES [billing].[CustomerAddresses] ([CustomerAddressesId]), + [Siret] [nvarchar](14), + [TVA] [nvarchar](13), + [CreatedAt] [datetime] DEFAULT CURRENT_TIMESTAMP, + [CreatedBy] [bigint], + [UpdatedAt] [datetime] DEFAULT CURRENT_TIMESTAMP, + [UpdatedBy] [bigint], + [DeletedAt] [datetime], + [DeletedBy] [bigint] +); +CREATE INDEX [IdxCustomersDeletedAt] ON [billing].[Customers] ([DeletedAt]); + +CREATE TABLE [billing].[CustomerMembers] +( + [CustomerId] [bigint] REFERENCES [billing].[Customers] ([CustomerId]), + [UserId] [bigint], + [CanEdit] [bit], + [CanInvite] [bit], + [CanBuy] [bit], + [BudgetAllowance] [int], + [CreatedAt] [datetime] DEFAULT CURRENT_TIMESTAMP, + [CreatedBy] [bigint], + [UpdatedAt] [datetime] DEFAULT CURRENT_TIMESTAMP, + [UpdatedBy] [bigint], + [DeletedAt] [datetime], + [DeletedBy] [bigint], + PRIMARY KEY ([CustomerId], [UserId]) +); +CREATE INDEX [IdxCustomerMembersDeletedAt] ON [billing].[CustomerMembers] ([DeletedAt]); + +CREATE TABLE [billing].[CustomerPaymentMethods] +( + [CustomerPaymentMethodId] [bigint] IDENTITY (1,1) PRIMARY KEY, + [CustomerId] [bigint] REFERENCES [billing].[Customers] ([CustomerId]), + [Name] [nvarchar](255) NOT NULL, + [Kind] [nvarchar](50) CHECK ([Kind] IN ('card', 'paypal')), + [Details] [nvarchar](MAX) CHECK (ISJSON([Details]) = 1), + [CreatedAt] [datetime] DEFAULT CURRENT_TIMESTAMP, + [CreatedBy] [bigint], + [UpdatedAt] [datetime] DEFAULT CURRENT_TIMESTAMP, + [UpdatedBy] [bigint], + [DeletedAt] [datetime], + [DeletedBy] [bigint] +); +CREATE INDEX [IdxCustomerPaymentMethodsDeletedAt] ON [billing].[CustomerPaymentMethods] ([DeletedAt]); + +CREATE TABLE [billing].[Invoices] +( + [InvoiceId] [bigint] IDENTITY (1,1) PRIMARY KEY, + [Reference] [nvarchar](50) UNIQUE NOT NULL, + [CartId] [bigint], + [CustomerId] [bigint] REFERENCES [billing].[Customers] ([CustomerId]), + [BillingAddress] [bigint] REFERENCES [billing].[CustomerAddresses] ([CustomerAddressesId]), + [TotalPrice] [float], + [Currency] [nvarchar](3) CHECK ([Currency] IN ('EUR', 'USD')), + [PaidAt] [datetime], + [CreatedAt] [datetime] DEFAULT CURRENT_TIMESTAMP, + [CreatedBy] [bigint] +); + +CREATE TABLE [billing].[InvoiceLines] +( + [InvoiceId] [bigint] REFERENCES [billing].[Invoices] ([InvoiceId]), + [Index] [int], + [ProductVersionId] [bigint], + [Description] [text], + [Price] [float], + [Quantity] [int], + PRIMARY KEY ([InvoiceId], [Index]) +); + +CREATE TABLE [billing].[Payments] +( + [PaymentId] [bigint] IDENTITY (1,1) PRIMARY KEY, + [InvoiceId] [bigint] REFERENCES [billing].[Invoices] ([InvoiceId]), + [PaymentMethodId] [bigint] REFERENCES [billing].[CustomerPaymentMethods] ([CustomerPaymentMethodId]), + [Amount] [float], + [Currency] [nvarchar](3) CHECK ([Currency] IN ('EUR', 'USD')), + [CreatedAt] [datetime] DEFAULT CURRENT_TIMESTAMP +); + + +-- insert some data +INSERT INTO [billing].[CustomerAddresses] ([Name], [Street], [City], [State], [ZipCode], [Country], [CreatedBy]) +VALUES ('Billing Address 1', '123 Main St', 'Anytown', 'Anystate', '12345', 1, 1), + ('Billing Address 2', '456 Elm St', 'Othertown', 'Otherstate', '67890', 2, 2); + +INSERT INTO [billing].[Customers] ([Name], [BillingAddress], [Siret], [TVA], [CreatedBy], [UpdatedBy]) +VALUES ('Customer A', NULL, '12345678901234', 'FR12345678901', 1, 1), + ('Customer B', NULL, '98765432109876', 'DE09876543210', 2, 2); + +INSERT INTO [billing].[CustomerMembers] ([CustomerId], [UserId], [CanEdit], [CanInvite], [CanBuy], [BudgetAllowance], + [CreatedBy], [UpdatedBy]) +VALUES (1, 1, 1, 1, 1, 1000, 1, 1), + (2, 2, 1, 0, 1, 500, 2, 2); + +INSERT INTO [billing].[CustomerPaymentMethods] ([CustomerId], [Name], [Kind], [Details], [CreatedBy], [UpdatedBy]) +VALUES (1, 'Credit Card', 'card', '{"card_number": "4111111111111111", "expiry_date": "12/23"}', 1, 1), + (2, 'PayPal', 'paypal', '{"paypal_account": "customer_b@paypal.com"}', 2, 2); + +INSERT INTO [billing].[Invoices] ([Reference], [CartId], [CustomerId], [BillingAddress], [TotalPrice], [Currency], + [CreatedBy]) +VALUES ('INV-001', 1, 1, 1, 200.00, 'USD', 1), + ('INV-002', 2, 2, 2, 300.00, 'EUR', 2); + +INSERT INTO [billing].[InvoiceLines] ([InvoiceId], [Index], [ProductVersionId], [Description], [Price], [Quantity]) +VALUES (1, 1, 1, 'Product 1 Description', 100.00, 2), + (2, 1, 2, 'Product 2 Description', 150.00, 2); + +INSERT INTO [billing].[Payments] ([InvoiceId], [PaymentMethodId], [Amount], [Currency]) +VALUES (1, 1, 200.00, 'USD'), + (2, 2, 300.00, 'EUR'); From e4ff52646a3e4e9b12fbcbb9339961debfc11d17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Knuchel?= Date: Sat, 17 Aug 2024 23:56:21 +0200 Subject: [PATCH 05/16] Add Shipping --- demos/ecommerce/README.md | 6 + demos/ecommerce/design.md | 56 ++++---- demos/ecommerce/script_7_shipping_mongo.sql | 145 ++++++++++++++++++++ libs/connector-mongodb/src/mongodb.ts | 2 +- 4 files changed, 180 insertions(+), 29 deletions(-) create mode 100644 demos/ecommerce/script_7_shipping_mongo.sql diff --git a/demos/ecommerce/README.md b/demos/ecommerce/README.md index c9201c21b..48bad94a0 100644 --- a/demos/ecommerce/README.md +++ b/demos/ecommerce/README.md @@ -55,5 +55,11 @@ You will have it at this url: `sqlserver://sa:azimutt_42@localhost:1433/Billing` You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) ## Shipping + +Import it in a [MongoDB database](../../libs/connector-mongodb/README.md#local-setup) with the [script_7_shipping_mongo.sql](./script_7_shipping_mongo.sql). +You will have it at this url: `mongodb://localhost:27017/shipping` + +You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) + ## CRM ## Analytics diff --git a/demos/ecommerce/design.md b/demos/ecommerce/design.md index cb5b69afe..06a337023 100644 --- a/demos/ecommerce/design.md +++ b/demos/ecommerce/design.md @@ -628,39 +628,39 @@ billing.Payments # Shipping shipping.Carriers - id bigint pk + id bigint registration varchar - cargo_width float - cargo_length float - cargo_height float - cargo_weight float - created_at timestamp - created_by bigint nullable fk identity.Users.id - updated_at timestamp - updated_by bigint nullable fk identity.Users.id - deleted_at timestamp nullable index - deleted_by bigint nullable fk identity.Users.id + cargoWidth float + cargoLength float + cargoHeight float + cargoWeight float + createdAt timestamp + createdBy bigint nullable fk identity.Users.id + updatedAt timestamp + updatedBy bigint nullable fk identity.Users.id + deletedAt timestamp nullable index + deletedBy bigint nullable fk identity.Users.id shipping.Shipments - id bigint pk - carrier_id bigint nullable fk shipping.Carriers.id - created_at timestamp - collected_at timestamp nullable - collected_by bigint nullable fk identity.Users.id - packaged_at timestamp nullable - packaged_by bigint nullable fk identity.Users.id - loaded_at timestamp nullable - loaded_by bigint nullable fk identity.Users.id - delivered_at timestamp nullable - delivered_by bigint nullable fk identity.Users.id + id bigint + carrierId bigint nullable fk shipping.Carriers.id + createdAt timestamp + collectedAt timestamp nullable + collectedBy bigint nullable fk identity.Users.id + packagedAt timestamp nullable + packagedBy bigint nullable fk identity.Users.id + loadedAt timestamp nullable + loadedBy bigint nullable fk identity.Users.id + deliveredAt timestamp nullable + deliveredBy bigint nullable fk identity.Users.id shipping.ShipmentItems - shipment_id bigint pk fk shipping.Shipments.id - physical_product_id bigint pk fk C##INVENTORY.PHYSICAL_PRODUCTS.ID - invoice_id bigint fk billing.InvoiceLines.InvoiceId - invoice_line int fk billing.InvoiceLines.Index - delivered_at timestamp nullable - delivered_to bigint nullable fk identity.Users.id + shipmentId bigint fk shipping.Shipments.id + physicalProductId bigint fk C##INVENTORY.PHYSICAL_PRODUCTS.ID + invoiceId bigint fk billing.InvoiceLines.InvoiceId + invoiceLine int fk billing.InvoiceLines.Index + deliveredAt timestamp nullable + deliveredTo bigint nullable fk identity.Users.id # CRM diff --git a/demos/ecommerce/script_7_shipping_mongo.sql b/demos/ecommerce/script_7_shipping_mongo.sql new file mode 100644 index 000000000..d86cafe3b --- /dev/null +++ b/demos/ecommerce/script_7_shipping_mongo.sql @@ -0,0 +1,145 @@ +use shipping; + +// drop everything +db.Carriers.drop(); +db.Shipments.drop(); +db.ShipmentItems.drop(); + + +// create the collections +db.createCollection('Carriers', { + validator: { + $jsonSchema: { + bsonType: "object", + required: ["id", "registration", "cargoWidth", "cargoLength", "cargoHeight", "cargoWeight", "createdAt", "updatedAt"], + properties: { + id: { bsonType: "number" }, + registration: { bsonType: "string" }, + cargoWidth: { bsonType: "number" }, + cargoLength: { bsonType: "number" }, + cargoHeight: { bsonType: "number" }, + cargoWeight: { bsonType: "number" }, + createdAt: { bsonType: "date" }, + createdBy: { bsonType: "number" }, + updatedAt: { bsonType: "date" }, + updatedBy: { bsonType: "number" }, + deletedAt: { bsonType: "date" }, + deletedBy: { bsonType: "number" } + } + } + } +}); + +db.createCollection('Shipments', { + validator: { + $jsonSchema: { + bsonType: "object", + required: ["id", "createdAt"], + properties: { + id: { bsonType: "number" }, + carrierId: { bsonType: "number" }, + createdAt: { bsonType: "date" }, + collectedAt: { bsonType: "date" }, + collectedBy: { bsonType: "number" }, + packagedAt: { bsonType: "date" }, + packagedBy: { bsonType: "number" }, + loadedAt: { bsonType: "date" }, + loadedBy: { bsonType: "number" }, + deliveredAt: { bsonType: "date" }, + deliveredBy: { bsonType: "number" } + } + } + } +}); + +db.createCollection('ShipmentItems', { + validator: { + $jsonSchema: { + bsonType: "object", + required: ["shipmentId", "physicalProductId", "invoiceId", "invoiceLine"], + properties: { + shipmentId: { bsonType: "number" }, + physicalProductId: { bsonType: "number" }, + invoiceId: { bsonType: "number" }, + invoiceLine: { bsonType: "int" }, + deliveredAt: { bsonType: "date" }, + deliveredTo: { bsonType: "number" } + } + } + } +}); + + +// insert some data +db.Carriers.insertMany([ + { + id: 1, + registration: "ABC123", + cargoWidth: 2.5, + cargoLength: 10.0, + cargoHeight: 3.0, + cargoWeight: 2000.0, + createdAt: new Date(), + createdBy: 1, + updatedAt: new Date(), + }, + { + id: 2, + registration: "XYZ789", + cargoWidth: 2.0, + cargoLength: 8.0, + cargoHeight: 2.5, + cargoWeight: 1500.0, + createdAt: new Date(), + createdBy: 2, + updatedAt: new Date(), + } +]); + +db.Shipments.insertMany([ + { + id: 1, + carrierId: 1, + createdAt: new Date(), + collectedAt: new Date(), + collectedBy: 1, + packagedAt: new Date(), + packagedBy: 1, + loadedAt: new Date(), + loadedBy: 1, + deliveredAt: new Date(), + deliveredBy: 1 + }, + { + id: 2, + carrierId: 2, + createdAt: new Date(), + collectedAt: new Date(), + collectedBy: 2, + packagedAt: new Date(), + packagedBy: 2, + loadedAt: new Date(), + loadedBy: 2, + deliveredAt: new Date(), + deliveredBy: 2 + } +]); + +db.ShipmentItems.insertMany([ + { + shipmentId: 1, + physicalProductId: 1, + invoiceId: 1, + invoiceLine: 1, + deliveredAt: new Date(), + deliveredTo: 1 + }, + { + shipmentId: 2, + physicalProductId: 2, + invoiceId: 2, + invoiceLine: 1, + deliveredAt: new Date(), + deliveredTo: 2 + } +]); diff --git a/libs/connector-mongodb/src/mongodb.ts b/libs/connector-mongodb/src/mongodb.ts index 9e053163c..230cbd9b6 100644 --- a/libs/connector-mongodb/src/mongodb.ts +++ b/libs/connector-mongodb/src/mongodb.ts @@ -105,7 +105,7 @@ async function inferCollectionMixed(collection: Collection, mixed: MixedCollecti const pk = attrs.find(a => a.name === '_id') const count = await countDocuments(collection, mixed, opts) return removeUndefined({ - database: collection.dbName, + schema: collection.dbName, name: mixed ? `${collection.collectionName}__${mixed.attribute}__${mixed.value}` : collection.collectionName, kind: undefined, def: undefined, From 26d33c4962b2327c26d26080ac3c91b8fabacc8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Knuchel?= Date: Sun, 18 Aug 2024 07:53:56 +0200 Subject: [PATCH 06/16] Add Crm --- demos/ecommerce/README.md | 20 +- .../{design.md => source_00_design.md} | 10 +- ...ql => source_01_referential_sqlserver.sql} | 0 ...adb.sql => source_02_identity_mariadb.sql} | 0 ...cle.sql => source_03_inventory_oracle.sql} | 0 ...res.sql => source_04_catalog_postgres.sql} | 0 ...es.sql => source_05_shopping_postgres.sql} | 0 ...er.sql => source_06_billing_sqlserver.sql} | 0 ...mongo.sql => source_07_shipping_mongo.sql} | 0 demos/ecommerce/source_08_crm_mysql.sql | 211 ++++++++++++++++++ libs/connector-mysql/src/index.ts | 2 +- 11 files changed, 230 insertions(+), 13 deletions(-) rename demos/ecommerce/{design.md => source_00_design.md} (99%) rename demos/ecommerce/{script_1_referential_sqlserver.sql => source_01_referential_sqlserver.sql} (100%) rename demos/ecommerce/{script_2_identity_mariadb.sql => source_02_identity_mariadb.sql} (100%) rename demos/ecommerce/{script_3_inventory_oracle.sql => source_03_inventory_oracle.sql} (100%) rename demos/ecommerce/{script_4_catalog_postgres.sql => source_04_catalog_postgres.sql} (100%) rename demos/ecommerce/{script_5_shopping_postgres.sql => source_05_shopping_postgres.sql} (100%) rename demos/ecommerce/{script_6_billing_sqlserver.sql => source_06_billing_sqlserver.sql} (100%) rename demos/ecommerce/{script_7_shipping_mongo.sql => source_07_shipping_mongo.sql} (100%) create mode 100644 demos/ecommerce/source_08_crm_mysql.sql diff --git a/demos/ecommerce/README.md b/demos/ecommerce/README.md index 48bad94a0..1248a97f7 100644 --- a/demos/ecommerce/README.md +++ b/demos/ecommerce/README.md @@ -12,7 +12,7 @@ Each domain has its own database, here is how to set them up: This domain is for general data. -Import it in a [SQL Server database](../../libs/connector-sqlserver/README.md#local-setup) with the [script_1_referential_sqlserver.sql](./script_1_referential_sqlserver.sql). +Import it in a [SQL Server database](../../libs/connector-sqlserver/README.md#local-setup) with the [source_01_referential_sqlserver.sql](./source_01_referential_sqlserver.sql). You will have it at this url: `sqlserver://sa:azimutt_42@localhost:1433/Referential` You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) @@ -21,45 +21,51 @@ You can then import it in your Azimutt project or explore it with the e-commerce This domain is user identity: who they are, what they can do. -Import it in a [MariaDB database](../../libs/connector-mariadb/README.md#local-setup) with the [script_2_identity_mariadb.sql](./script_2_identity_mariadb.sql). +Import it in a [MariaDB database](../../libs/connector-mariadb/README.md#local-setup) with the [source_02_identity_mariadb.sql](./source_02_identity_mariadb.sql). You will have it at this url: `mariadb://root:mariadb@localhost:3307/identity` You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) ## Inventory -Import it in a [Oracle database](../../libs/connector-oracle/README.md#local-setup) with the [script_3_inventory_oracle.sql](./script_3_inventory_oracle.sql). +Import it in a [Oracle database](../../libs/connector-oracle/README.md#local-setup) with the [source_03_inventory_oracle.sql](./source_03_inventory_oracle.sql). You will have it at this url: `oracle:thin:C##INVENTORY/inventory@localhost:1521/FREE` You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) ## Catalog -Import it in a [PostgreSQL database](../../libs/connector-postgres/README.md#local-setup) with the [script_4_catalog_postgres.sql](./script_4_catalog_postgres.sql). +Import it in a [PostgreSQL database](../../libs/connector-postgres/README.md#local-setup) with the [source_04_catalog_postgres.sql](./source_04_catalog_postgres.sql). You will have it at this url: `postgresql://postgres:postgres@localhost:5433/postgres?schema=catalog` You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) ## Shopping -Import it in a [PostgreSQL database](../../libs/connector-postgres/README.md#local-setup) with the [script_5_shopping_postgres.sql](./script_5_shopping_postgres.sql). +Import it in a [PostgreSQL database](../../libs/connector-postgres/README.md#local-setup) with the [source_05_shopping_postgres.sql](./source_05_shopping_postgres.sql). You will have it at this url: `postgresql://postgres:postgres@localhost:5433/postgres?schema=shopping` You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) ## Billing -Import it in a [SQL Server database](../../libs/connector-sqlserver/README.md#local-setup) with the [script_6_billing_sqlserver.sql](./script_6_billing_sqlserver.sql). +Import it in a [SQL Server database](../../libs/connector-sqlserver/README.md#local-setup) with the [source_06_billing_sqlserver.sql](./source_06_billing_sqlserver.sql). You will have it at this url: `sqlserver://sa:azimutt_42@localhost:1433/Billing` You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) ## Shipping -Import it in a [MongoDB database](../../libs/connector-mongodb/README.md#local-setup) with the [script_7_shipping_mongo.sql](./script_7_shipping_mongo.sql). +Import it in a [MongoDB database](../../libs/connector-mongodb/README.md#local-setup) with the [source_07_shipping_mongo.sql](./source_07_shipping_mongo.sql). You will have it at this url: `mongodb://localhost:27017/shipping` You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) ## CRM + +Import it in a [MySQL database](../../libs/connector-mysql/README.md#local-setup) with the [source_08_crm_mysql.sql](./source_08_crm_mysql.sql). +You will have it at this url: `mysql://root:mysql@localhost:3306/crm` + +You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) + ## Analytics diff --git a/demos/ecommerce/design.md b/demos/ecommerce/source_00_design.md similarity index 99% rename from demos/ecommerce/design.md rename to demos/ecommerce/source_00_design.md index 06a337023..7c975592a 100644 --- a/demos/ecommerce/design.md +++ b/demos/ecommerce/source_00_design.md @@ -628,7 +628,7 @@ billing.Payments # Shipping shipping.Carriers - id bigint + id bigint unique registration varchar cargoWidth float cargoLength float @@ -642,7 +642,7 @@ shipping.Carriers deletedBy bigint nullable fk identity.Users.id shipping.Shipments - id bigint + id bigint unique carrierId bigint nullable fk shipping.Carriers.id createdAt timestamp collectedAt timestamp nullable @@ -655,8 +655,8 @@ shipping.Shipments deliveredBy bigint nullable fk identity.Users.id shipping.ShipmentItems - shipmentId bigint fk shipping.Shipments.id - physicalProductId bigint fk C##INVENTORY.PHYSICAL_PRODUCTS.ID + shipmentId bigint unique=pk fk shipping.Shipments.id + physicalProductId bigint unique=pk fk C##INVENTORY.PHYSICAL_PRODUCTS.ID invoiceId bigint fk billing.InvoiceLines.InvoiceId invoiceLine int fk billing.InvoiceLines.Index deliveredAt timestamp nullable @@ -701,7 +701,7 @@ crm.SocialAccounts id bigint pk network social_network(twitter, linkedin, facebook, instagram, tiktok, snapchat) username varchar - owner_kind social_account_owner_kind(crm.People, crm.Organizations) nullable + owner_kind social_account_owner_kind(People, Organizations) nullable owner_id bigint nullable created_at timestamp created_by bigint nullable fk identity.Users.id diff --git a/demos/ecommerce/script_1_referential_sqlserver.sql b/demos/ecommerce/source_01_referential_sqlserver.sql similarity index 100% rename from demos/ecommerce/script_1_referential_sqlserver.sql rename to demos/ecommerce/source_01_referential_sqlserver.sql diff --git a/demos/ecommerce/script_2_identity_mariadb.sql b/demos/ecommerce/source_02_identity_mariadb.sql similarity index 100% rename from demos/ecommerce/script_2_identity_mariadb.sql rename to demos/ecommerce/source_02_identity_mariadb.sql diff --git a/demos/ecommerce/script_3_inventory_oracle.sql b/demos/ecommerce/source_03_inventory_oracle.sql similarity index 100% rename from demos/ecommerce/script_3_inventory_oracle.sql rename to demos/ecommerce/source_03_inventory_oracle.sql diff --git a/demos/ecommerce/script_4_catalog_postgres.sql b/demos/ecommerce/source_04_catalog_postgres.sql similarity index 100% rename from demos/ecommerce/script_4_catalog_postgres.sql rename to demos/ecommerce/source_04_catalog_postgres.sql diff --git a/demos/ecommerce/script_5_shopping_postgres.sql b/demos/ecommerce/source_05_shopping_postgres.sql similarity index 100% rename from demos/ecommerce/script_5_shopping_postgres.sql rename to demos/ecommerce/source_05_shopping_postgres.sql diff --git a/demos/ecommerce/script_6_billing_sqlserver.sql b/demos/ecommerce/source_06_billing_sqlserver.sql similarity index 100% rename from demos/ecommerce/script_6_billing_sqlserver.sql rename to demos/ecommerce/source_06_billing_sqlserver.sql diff --git a/demos/ecommerce/script_7_shipping_mongo.sql b/demos/ecommerce/source_07_shipping_mongo.sql similarity index 100% rename from demos/ecommerce/script_7_shipping_mongo.sql rename to demos/ecommerce/source_07_shipping_mongo.sql diff --git a/demos/ecommerce/source_08_crm_mysql.sql b/demos/ecommerce/source_08_crm_mysql.sql new file mode 100644 index 000000000..253ec990e --- /dev/null +++ b/demos/ecommerce/source_08_crm_mysql.sql @@ -0,0 +1,211 @@ +-- drop everything +DROP SCHEMA IF EXISTS crm; + +-- create the database +CREATE SCHEMA crm; +USE crm; + +CREATE TABLE People +( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + name VARCHAR(255) NOT NULL, + email VARCHAR(255), + phone VARCHAR(20), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + created_by BIGINT, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + updated_by BIGINT, + deleted_at TIMESTAMP, + deleted_by BIGINT, + INDEX idx_people_deleted_at (deleted_at) +); + +CREATE TABLE Organizations +( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + name VARCHAR(255) NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + created_by BIGINT, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + updated_by BIGINT, + deleted_at TIMESTAMP, + deleted_by BIGINT, + INDEX idx_organizations_deleted_at (deleted_at) +); + +CREATE TABLE OrganizationMembers +( + person_id BIGINT REFERENCES People (id), + organization_id BIGINT REFERENCES Organizations (id), + role VARCHAR(255) NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + created_by BIGINT, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + updated_by BIGINT, + deleted_at TIMESTAMP, + deleted_by BIGINT, + PRIMARY KEY (person_id, organization_id), + INDEX idx_organization_members_deleted_at (deleted_at) +); + +CREATE TABLE SocialAccounts +( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + network ENUM ('twitter', 'linkedin', 'facebook', 'instagram', 'tiktok', 'snapchat') NOT NULL, + username VARCHAR(255) NOT NULL, + owner_kind ENUM ('People', 'Organizations'), + owner_id BIGINT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + created_by BIGINT, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + updated_by BIGINT, + deleted_at TIMESTAMP, + deleted_by BIGINT, + INDEX idx_social_accounts_deleted_at (deleted_at) +); + +CREATE TABLE Campaigns +( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + name VARCHAR(255) NOT NULL, + status ENUM ('draft', 'live', 'paused') NOT NULL, + starts TIMESTAMP, + ends TIMESTAMP, + kind ENUM ('email', 'sms', 'push', 'twitter', 'linkedin', 'instagram', 'facebook') NOT NULL, + audience TEXT, + subject VARCHAR(255), + message TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + created_by BIGINT, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + updated_by BIGINT, + deleted_at TIMESTAMP, + deleted_by BIGINT, + INDEX idx_campaigns_deleted_at (deleted_at) +); + +CREATE TABLE CampaignMessages +( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + campaign_id BIGINT REFERENCES Campaigns (id), + contact_id BIGINT REFERENCES People (id), + social_id BIGINT REFERENCES SocialAccounts (id), + sent_to VARCHAR(255) NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + sent_at TIMESTAMP, + opened_at TIMESTAMP, + clicked_at TIMESTAMP +); + +CREATE TABLE Issues +( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + subject VARCHAR(255) NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + created_by BIGINT, + closed_at TIMESTAMP, + closed_by BIGINT, + INDEX idx_issues_closed_at (closed_at) +); + +CREATE TABLE IssueMessages +( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + issue_id BIGINT REFERENCES Issues (id), + content TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + created_by BIGINT, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + updated_by BIGINT +); + +CREATE TABLE IssueMessageReactions +( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + message_id BIGINT REFERENCES IssueMessages (id), + kind ENUM ('like', 'dislike') NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + created_by BIGINT, + deleted_at TIMESTAMP, + deleted_by BIGINT, + INDEX idx_issue_message_reactions_deleted_at (deleted_at) +); + +CREATE TABLE Discounts +( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + name VARCHAR(255) NOT NULL, + description VARCHAR(255), + kind ENUM ('percentage', 'amount') NOT NULL, + value DOUBLE NOT NULL, + enable_at TIMESTAMP, + expire_at TIMESTAMP, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + created_by BIGINT, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + updated_by BIGINT, + deleted_at TIMESTAMP, + deleted_by BIGINT, + INDEX idx_discounts_deleted_at (deleted_at) +); + +CREATE TABLE Coupons +( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + discount_id BIGINT REFERENCES Discounts (id), + code VARCHAR(255) UNIQUE NOT NULL, + expire_at TIMESTAMP, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + created_by BIGINT, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + updated_by BIGINT, + deleted_at TIMESTAMP, + deleted_by BIGINT, + INDEX idx_coupons_deleted_at (deleted_at) +); + + +-- insert some data +INSERT INTO People (name, email, phone, created_by, updated_by) +VALUES ('John Doe', 'john.doe@example.com', '1234567890', 1, 1), + ('Jane Smith', 'jane.smith@example.com', '0987654321', 2, 2); + +INSERT INTO Organizations (name, created_by, updated_by) +VALUES ('Tech Corp', 1, 1), + ('Business Inc', 2, 2); + +INSERT INTO OrganizationMembers (person_id, organization_id, role, created_by, updated_by) +VALUES (1, 1, 'Manager', 1, 1), + (2, 2, 'Director', 2, 2); + +INSERT INTO SocialAccounts (network, username, owner_kind, owner_id, created_by, updated_by) +VALUES ('twitter', 'john_doe', 'People', 1, 1, 1), + ('linkedin', 'jane_smith', 'Organizations', 2, 2, 2); + +INSERT INTO Campaigns (name, status, kind, audience, subject, message, created_by, updated_by) +VALUES ('Winter Sale', 'draft', 'email', 'All subscribers', 'Winter Sale 2024', '

Don\'t miss out on our Winter Sale!

', 1, 1), + ('Summer Promotion', 'live', 'sms', 'VIP customers', 'Summer Promotion', 'Get 50% off all items!', 2, 2); + +INSERT INTO CampaignMessages (campaign_id, contact_id, sent_to, created_at, sent_at) +VALUES (1, 1, 'john.doe@example.com', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + (2, 2, 'jane.smith@example.com', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); + +INSERT INTO Issues (subject, created_by) +VALUES ('Product not delivered', 1), + ('Refund request', 2); + +INSERT INTO IssueMessages (issue_id, content, created_by, updated_by) +VALUES (1, 'The product was supposed to arrive yesterday but it hasn\'t arrived yet.', 1, 1), + (2, 'I would like a refund for my recent purchase.', 2, 2); + +INSERT INTO IssueMessageReactions (message_id, kind, created_by) +VALUES (1, 'like', 1), + (2, 'dislike', 2); + +INSERT INTO Discounts (name, description, kind, value, enable_at, expire_at, created_by, updated_by) +VALUES ('New Year Discount', '10% off on all items', 'percentage', 10.00, '2024-01-01 00:00:00', '2024-01-31 23:59:59', 1, 1), + ('Black Friday Deal', 'Flat $50 off', 'amount', 50.00, '2024-11-29 00:00:00', '2024-11-29 23:59:59', 2, 2); + +INSERT INTO Coupons (discount_id, code, expire_at, created_by, updated_by) +VALUES (1, 'NY2024', '2024-01-31 23:59:59', 1, 1), + (2, 'BF2024', '2024-11-29 23:59:59', 2, 2); diff --git a/libs/connector-mysql/src/index.ts b/libs/connector-mysql/src/index.ts index e65870836..fe26f8e01 100644 --- a/libs/connector-mysql/src/index.ts +++ b/libs/connector-mysql/src/index.ts @@ -25,7 +25,7 @@ export const mysql: Connector = { const urlOptions = url.options || {} const options: ConnectorSchemaOpts = { ...opts, - schema: opts.schema || urlOptions['schema'], + schema: opts.schema || urlOptions['schema'] || url.db, entity: opts.entity || urlOptions['table'] } return connect(application, url, getSchema(options), options).then(zodParseAsync(Database)) From 909f54427cc0693d34e851133f510c477d7762f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Knuchel?= Date: Sun, 18 Aug 2024 09:37:19 +0200 Subject: [PATCH 07/16] Add Analytics --- demos/ecommerce/README.md | 5 + demos/ecommerce/source_00_design.md | 20 +-- demos/ecommerce/source_09_analytics_mongo.sql | 107 +++++++++++++++ .../source_10_additional_relations.md | 124 ++++++++++++++++++ 4 files changed, 246 insertions(+), 10 deletions(-) create mode 100644 demos/ecommerce/source_09_analytics_mongo.sql create mode 100644 demos/ecommerce/source_10_additional_relations.md diff --git a/demos/ecommerce/README.md b/demos/ecommerce/README.md index 1248a97f7..4d93aabe0 100644 --- a/demos/ecommerce/README.md +++ b/demos/ecommerce/README.md @@ -69,3 +69,8 @@ You will have it at this url: `mysql://root:mysql@localhost:3306/crm` You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) ## Analytics + +Import it in a [MongoDB database](../../libs/connector-mongodb/README.md#local-setup) with the [source_09_analytics_mongo.sql](./source_09_analytics_mongo.sql). +You will have it at this url: `mongodb://localhost:27017/analytics` + +You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) diff --git a/demos/ecommerce/source_00_design.md b/demos/ecommerce/source_00_design.md index 7c975592a..074d636d8 100644 --- a/demos/ecommerce/source_00_design.md +++ b/demos/ecommerce/source_00_design.md @@ -628,7 +628,7 @@ billing.Payments # Shipping shipping.Carriers - id bigint unique + id bigint unique=pk registration varchar cargoWidth float cargoLength float @@ -642,7 +642,7 @@ shipping.Carriers deletedBy bigint nullable fk identity.Users.id shipping.Shipments - id bigint unique + id bigint unique=pk carrierId bigint nullable fk shipping.Carriers.id createdAt timestamp collectedAt timestamp nullable @@ -799,17 +799,17 @@ crm.LoyaltyCards # Analytics analytics.Events - id uuid pk | UUIDv7 to be time ordered + id uuid unique=pk | UUIDv7 to be time ordered name string index | in form of `$context__$object__$action` source event_source(website, app, admin, job) | the name of the system which emitted this event - details json | any additional info for the event - entities json | {[kind: string]: {id: string, name: string}[]} - created_at timestamp + details json nullable | any additional info for the event + entities json nullable | {[kind: string]: {id: string, name: string}[]} + createdAt timestamp analytics.Entities - id string pk - kind string + kind string unique=pk + id string unique=pk name string properties json - created_at timestamp - updated_at timestamp + createdAt timestamp + updatedAt timestamp diff --git a/demos/ecommerce/source_09_analytics_mongo.sql b/demos/ecommerce/source_09_analytics_mongo.sql new file mode 100644 index 000000000..0c96a462d --- /dev/null +++ b/demos/ecommerce/source_09_analytics_mongo.sql @@ -0,0 +1,107 @@ +use analytics; + +// drop everything +db.Events.drop(); +db.Entities.drop(); + + +// create the collections +db.createCollection('Events', { + validator: { + $jsonSchema: { + bsonType: "object", + required: ["id", "name", "source", "createdAt"], + properties: { + id: { bsonType: "binData", description: "UUIDv7" }, + name: { bsonType: "string", description: "Name of the event in form of `$context__$object__$action`" }, + source: { bsonType: "string", enum: ["website", "app", "admin", "job"], description: "The name of the system which emitted this event" }, + details: { bsonType: "object", description: "Additional info for the event in JSON format" }, + entities: { + bsonType: "object", + description: "Entities related to the event in JSON format", + additionalProperties: { + bsonType: "array", + items: { + bsonType: "object", + required: ["id", "name"], + properties: { + id: { bsonType: "string" }, + name: { bsonType: "string" } + } + } + } + }, + createdAt: { bsonType: "date", description: "Timestamp when the event was created" } + } + } + } +}); + +db.createCollection('Entities', { + validator: { + $jsonSchema: { + bsonType: "object", + required: ["kind", "id", "name", "properties", "createdAt", "updatedAt"], + properties: { + kind: { bsonType: "string", description: "Type of the entity" }, + id: { bsonType: "string", description: "Unique identifier for the entity, for its kind" }, + name: { bsonType: "string", description: "Name of the entity" }, + properties: { bsonType: "object", description: "Additional properties for the entity in JSON format" }, + createdAt: { bsonType: "date", description: "Timestamp when the entity was created" }, + updatedAt: { bsonType: "date", description: "Timestamp when the entity was last updated" } + } + } + } +}); + + +// insert some data +db.Events.insertMany([ + { + id: UUID(), + name: "user__login__success", + source: "website", + details: { ip: "192.168.1.1", browser: "Chrome" }, + entities: { user: [{ id: "1", name: "Loïc Knuchel", email: "loic@azimutt.app" }] }, + createdAt: new Date() + }, + { + id: UUID(), + name: "order__purchase__completed", + source: "app", + details: { amount: 200 }, + entities: { + user: [{ id: "1", name: "Loïc Knuchel" }], + cart: [{ id: "1", name: "Cart 1", items: 2 }], + invoice: [{ id: "1", name: "INV-001", price: 200, currency: "USD", lines: 1 }], + }, + createdAt: new Date() + } +]); + +db.Entities.insertMany([ + { + kind: "user", + id: "1", + name: "Loïc Knuchel", + properties: { email: "loic@azimutt.app" }, + createdAt: new Date(), + updatedAt: new Date() + }, + { + kind: "cart", + id: "1", + name: "Cart 1", + properties: { items: 2 }, + createdAt: new Date(), + updatedAt: new Date() + }, + { + kind: "invoice", + id: "1", + name: "INV-001", + properties: { price: 200, currency: "USD", lines: 1 }, + createdAt: new Date(), + updatedAt: new Date() + } +]); diff --git a/demos/ecommerce/source_10_additional_relations.md b/demos/ecommerce/source_10_additional_relations.md new file mode 100644 index 000000000..bb2a52b67 --- /dev/null +++ b/demos/ecommerce/source_10_additional_relations.md @@ -0,0 +1,124 @@ +fk C##INVENTORY.EMPLOYEES.CREATED_BY -> identity.Users.id +fk C##INVENTORY.EMPLOYEES.UPDATED_BY -> identity.Users.id +fk C##INVENTORY.EMPLOYEES.DELETED_BY -> identity.Users.id +fk C##INVENTORY.WAREHOUSES.CREATED_BY -> identity.Users.id +fk C##INVENTORY.WAREHOUSES.UPDATED_BY -> identity.Users.id +fk C##INVENTORY.WAREHOUSES.DELETED_BY -> identity.Users.id +fk C##INVENTORY.HALLS.CREATED_BY -> identity.Users.id +fk C##INVENTORY.HALLS.UPDATED_BY -> identity.Users.id +fk C##INVENTORY.HALLS.DELETED_BY -> identity.Users.id +fk C##INVENTORY.AISLES.CREATED_BY -> identity.Users.id +fk C##INVENTORY.AISLES.UPDATED_BY -> identity.Users.id +fk C##INVENTORY.AISLES.DELETED_BY -> identity.Users.id +fk C##INVENTORY.RACKS.CREATED_BY -> identity.Users.id +fk C##INVENTORY.RACKS.UPDATED_BY -> identity.Users.id +fk C##INVENTORY.RACKS.DELETED_BY -> identity.Users.id +fk C##INVENTORY.SHELVES.CREATED_BY -> identity.Users.id +fk C##INVENTORY.SHELVES.UPDATED_BY -> identity.Users.id +fk C##INVENTORY.SHELVES.DELETED_BY -> identity.Users.id +fk C##INVENTORY.SHELF_POSITIONS.CREATED_BY -> identity.Users.id +fk C##INVENTORY.SHELF_POSITIONS.UPDATED_BY -> identity.Users.id +fk C##INVENTORY.SHELF_POSITIONS.DELETED_BY -> identity.Users.id +fk C##INVENTORY.WAREHOUSE_EMPLOYEES.CREATED_BY -> identity.Users.id +fk C##INVENTORY.WAREHOUSE_EMPLOYEES.UPDATED_BY -> identity.Users.id +fk C##INVENTORY.WAREHOUSE_EMPLOYEES.DELETED_BY -> identity.Users.id +fk C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS.CREATED_BY -> identity.Users.id +fk C##INVENTORY.SUPPLIER_EMPLOYEES.CREATED_BY -> identity.Users.id +fk C##INVENTORY.SUPPLIER_EMPLOYEES.UPDATED_BY -> identity.Users.id +fk C##INVENTORY.SUPPLIER_EMPLOYEES.DELETED_BY -> identity.Users.id +fk C##INVENTORY.PURCHASE_ORDERS.CREATED_BY -> identity.Users.id +fk C##INVENTORY.PURCHASE_ORDERS.UPDATED_BY -> identity.Users.id +fk C##INVENTORY.PURCHASE_ORDERS.SENT_BY -> identity.Users.id +fk C##INVENTORY.PURCHASE_ORDERS.VALIDATED_BY -> identity.Users.id +fk C##INVENTORY.PURCHASE_ORDER_ITEMS.CREATED_BY -> identity.Users.id +fk C##INVENTORY.PURCHASE_ORDER_ITEMS.UPDATED_BY -> identity.Users.id +fk C##INVENTORY.INVENTORIES.CREATED_BY -> identity.Users.id +fk C##INVENTORY.INVENTORIES.UPDATED_BY -> identity.Users.id +fk C##INVENTORY.INVENTORY_OBSERVATIONS.CREATED_BY -> identity.Users.id +fk C##INVENTORY.INVENTORY_OBSERVATIONS.UPDATED_BY -> identity.Users.id +fk C##INVENTORY.INVENTORY_OBSERVATIONS.DELETED_BY -> identity.Users.id +fk catalog.products.id -> C##INVENTORY.PRODUCTS.ID +fk catalog.product_versions.id -> C##INVENTORY.PRODUCT_VERSIONS.ID +fk catalog.product_reviews.invoice_id -> billing.Invoices.InvoiceId +fk catalog.product_reviews.physical_product_id -> C##INVENTORY.PHYSICAL_PRODUCTS.ID +fk catalog.product_reviews.created_by -> identity.Users.id +fk catalog.product_reviews.updated_by -> identity.Users.id +fk catalog.product_reviews.deleted_by -> identity.Users.id +fk catalog.product_review_assets.created_by -> identity.Users.id +fk catalog.product_review_assets.deleted_by -> identity.Users.id +fk catalog.product_review_feedbacks.created_by -> identity.Users.id +fk catalog.product_review_feedbacks.deleted_by -> identity.Users.id +fk shopping.cart_items.product_version_id -> catalog.product_versions.id +fk shopping.cart_items.created_by -> identity.Users.id +fk shopping.cart_items.updated_by -> identity.Users.id +fk shopping.cart_items.deleted_by -> identity.Users.id +fk shopping.wishlists.created_by -> identity.Users.id +fk shopping.wishlists.updated_by -> identity.Users.id +fk shopping.wishlists.deleted_by -> identity.Users.id +fk shopping.wishlist_items.product_id -> catalog.products.id +fk shopping.wishlist_items.created_by -> identity.Users.id +fk shopping.wishlist_items.deleted_by -> identity.Users.id +fk shopping.wishlist_members.user_id -> identity.Users.id +fk shopping.wishlist_members.created_by -> identity.Users.id +fk shopping.wishlist_members.updated_by -> identity.Users.id +fk shopping.wishlist_members.deleted_by -> identity.Users.id +fk billing.CustomerAddresses.Country -> referential.Countries.CountryId +fk billing.CustomerAddresses.CreatedBy -> identity.Users.id +fk billing.CustomerAddresses.DeletedBy -> identity.Users.id +fk billing.Customers.CreatedBy -> identity.Users.id +fk billing.Customers.UpdatedBy -> identity.Users.id +fk billing.Customers.DeletedBy -> identity.Users.id +fk billing.CustomerMembers.UserId -> identity.Users.id +fk billing.CustomerMembers.CreatedBy -> identity.Users.id +fk billing.CustomerMembers.UpdatedBy -> identity.Users.id +fk billing.CustomerMembers.DeletedBy -> identity.Users.id +fk billing.CustomerPaymentMethods.CreatedBy -> identity.Users.id +fk billing.CustomerPaymentMethods.UpdatedBy -> identity.Users.id +fk billing.CustomerPaymentMethods.DeletedBy -> identity.Users.id +fk billing.Invoices.CartId -> shopping.carts.id +fk billing.Invoices.CreatedBy -> identity.Users.id +fk billing.InvoiceLines.ProductVersionId -> catalog.product_versions.id +fk shipping.Carriers.createdBy -> identity.Users.id +fk shipping.Carriers.updatedBy -> identity.Users.id +fk shipping.Carriers.deletedBy -> identity.Users.id +fk shipping.Shipments.collectedBy -> identity.Users.id +fk shipping.Shipments.packagedBy -> identity.Users.id +fk shipping.Shipments.loadedBy -> identity.Users.id +fk shipping.Shipments.deliveredBy -> identity.Users.id +fk shipping.ShipmentItems.physicalProductId -> C##INVENTORY.PHYSICAL_PRODUCTS.ID +fk shipping.ShipmentItems.invoiceId -> billing.InvoiceLines.InvoiceId +fk shipping.ShipmentItems.invoiceLine -> billing.InvoiceLines.Index +fk shipping.ShipmentItems.deliveredTo -> identity.Users.id +fk crm.People.created_by -> identity.Users.id +fk crm.People.updated_by -> identity.Users.id +fk crm.People.deleted_by -> identity.Users.id +fk crm.Organizations.created_by -> identity.Users.id +fk crm.Organizations.updated_by -> identity.Users.id +fk crm.Organizations.deleted_by -> identity.Users.id +fk crm.OrganizationMembers.created_by -> identity.Users.id +fk crm.OrganizationMembers.updated_by -> identity.Users.id +fk crm.OrganizationMembers.deleted_by -> identity.Users.id +fk crm.SocialAccounts.created_by -> identity.Users.id +fk crm.SocialAccounts.updated_by -> identity.Users.id +fk crm.SocialAccounts.deleted_by -> identity.Users.id +fk crm.Campaigns.created_by -> identity.Users.id +fk crm.Campaigns.updated_by -> identity.Users.id +fk crm.Campaigns.deleted_by -> identity.Users.id +fk crm.Issues.created_by -> identity.Users.id +fk crm.Issues.closed_by -> identity.Users.id +fk crm.IssueMessages.created_by -> identity.Users.id +fk crm.IssueMessages.updated_by -> identity.Users.id +fk crm.IssueMessageReactions.created_by -> identity.Users.id +fk crm.IssueMessageReactions.deleted_by -> identity.Users.id +fk crm.Discounts.created_by -> identity.Users.id +fk crm.Discounts.updated_by -> identity.Users.id +fk crm.Discounts.deleted_by -> identity.Users.id +fk crm.Coupons.created_by -> identity.Users.id +fk crm.Coupons.updated_by -> identity.Users.id +fk crm.Coupons.deleted_by -> identity.Users.id +fk analytics.Events.entities:user:id -> identity.Users.id +fk analytics.Events.entities:cart:id -> shopping.carts.id +fk analytics.Events.entities:invoice:id -> billing.Invoices.InvoiceId +fk analytics.Entities.id -> identity.Users.id # when kind=user +fk analytics.Entities.id -> shopping.carts.id # when kind=cart +fk analytics.Entities.id -> billing.Invoices.InvoiceId # when kind=invoice From 345fc0fdb280574eaef72116ccdb538797125243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Knuchel?= Date: Sun, 18 Aug 2024 10:41:28 +0200 Subject: [PATCH 08/16] Better README --- demos/ecommerce/README.md | 87 ++++--------------- demos/ecommerce/source_00_design.md | 6 ++ .../source_10_additional_relations.md | 2 + .../Organization_/Project_/Views/Erd/Memo.elm | 2 +- 4 files changed, 26 insertions(+), 71 deletions(-) diff --git a/demos/ecommerce/README.md b/demos/ecommerce/README.md index 4d93aabe0..457896c45 100644 --- a/demos/ecommerce/README.md +++ b/demos/ecommerce/README.md @@ -1,76 +1,23 @@ -# Azimutt full demo +# E-commerce demo -Here are some technical explanations to setup the [e-commerce micro-services demo](https://azimutt.app/fe9aef15-febe-490b-a631-225367749278/91395eb9-bd5d-4205-a8d6-d03bd1968ec4) of Azimutt. +This is a medium demo (~80 tables) showcasing Azimutt ability to explore large schemas, even with several databases (micro-services for examples). -Have a look to the [associated blog](https://azimutt.app/blob/ecommerce-database-with-microservices-demo) post for more explanations of how to use it and what to look ;) +You can find this project at [xxx](https://azimutt.app...) and explore it yourself, you will see: -Each domain has its own database, here is how to set them up: +- an overview of the schema across several databases +- showcases per domain with sample rows +- documentation layouts -# Domains +The project will let you access the schema and loaded data but if you want to dig into the data, you will have to set up the databases you want using Docker: -## Referential +- **Referential** domain uses [SQL Server](../../libs/connector-sqlserver/README.md#local-setup) for [source_01_referential_sqlserver.sql](./source_01_referential_sqlserver.sql) (url `sqlserver://sa:azimutt_42@localhost:1433/Referential`) +- **Identity** domain uses [MariaDB](../../libs/connector-mariadb/README.md#local-setup) for [source_02_identity_mariadb.sql](./source_02_identity_mariadb.sql) (url `mariadb://root:mariadb@localhost:3307/identity`) +- **Inventory** domain uses [Oracle](../../libs/connector-oracle/README.md#local-setup) for [source_03_inventory_oracle.sql](./source_03_inventory_oracle.sql) (url `oracle:thin:C##INVENTORY/inventory@localhost:1521/FREE`) +- **Catalog** domain uses [PostgreSQL](../../libs/connector-postgres/README.md#local-setup) for [source_04_catalog_postgres.sql](./source_04_catalog_postgres.sql) (url `postgresql://postgres:postgres@localhost:5433/postgres?schema=catalog`) +- **Shopping** domain uses [PostgreSQL](../../libs/connector-postgres/README.md#local-setup) for [source_05_shopping_postgres.sql](./source_05_shopping_postgres.sql) (url `postgresql://postgres:postgres@localhost:5433/postgres?schema=shopping`) +- **Billing** domain uses [SQL Server](../../libs/connector-sqlserver/README.md#local-setup) for [source_06_billing_sqlserver.sql](./source_06_billing_sqlserver.sql) (url `sqlserver://sa:azimutt_42@localhost:1433/Billing`) +- **Shipping** domain uses [MongoDB](../../libs/connector-mongodb/README.md#local-setup) for [source_07_shipping_mongo.sql](./source_07_shipping_mongo.sql) (url `mongodb://localhost:27017/shipping`) +- **CRM** domain uses [MySQL](../../libs/connector-mysql/README.md#local-setup) for [source_08_crm_mysql.sql](./source_08_crm_mysql.sql) (url `mysql://root:mysql@localhost:3306/crm`) +- **Analytics** domain uses [MongoDB](../../libs/connector-mongodb/README.md#local-setup) for [source_09_analytics_mongo.sql](./source_09_analytics_mongo.sql) (url `mongodb://localhost:27017/analytics`) -This domain is for general data. - -Import it in a [SQL Server database](../../libs/connector-sqlserver/README.md#local-setup) with the [source_01_referential_sqlserver.sql](./source_01_referential_sqlserver.sql). -You will have it at this url: `sqlserver://sa:azimutt_42@localhost:1433/Referential` - -You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) - -## Identity - -This domain is user identity: who they are, what they can do. - -Import it in a [MariaDB database](../../libs/connector-mariadb/README.md#local-setup) with the [source_02_identity_mariadb.sql](./source_02_identity_mariadb.sql). -You will have it at this url: `mariadb://root:mariadb@localhost:3307/identity` - -You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) - -## Inventory - -Import it in a [Oracle database](../../libs/connector-oracle/README.md#local-setup) with the [source_03_inventory_oracle.sql](./source_03_inventory_oracle.sql). -You will have it at this url: `oracle:thin:C##INVENTORY/inventory@localhost:1521/FREE` - -You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) - -## Catalog - -Import it in a [PostgreSQL database](../../libs/connector-postgres/README.md#local-setup) with the [source_04_catalog_postgres.sql](./source_04_catalog_postgres.sql). -You will have it at this url: `postgresql://postgres:postgres@localhost:5433/postgres?schema=catalog` - -You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) - -## Shopping - -Import it in a [PostgreSQL database](../../libs/connector-postgres/README.md#local-setup) with the [source_05_shopping_postgres.sql](./source_05_shopping_postgres.sql). -You will have it at this url: `postgresql://postgres:postgres@localhost:5433/postgres?schema=shopping` - -You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) - -## Billing - -Import it in a [SQL Server database](../../libs/connector-sqlserver/README.md#local-setup) with the [source_06_billing_sqlserver.sql](./source_06_billing_sqlserver.sql). -You will have it at this url: `sqlserver://sa:azimutt_42@localhost:1433/Billing` - -You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) - -## Shipping - -Import it in a [MongoDB database](../../libs/connector-mongodb/README.md#local-setup) with the [source_07_shipping_mongo.sql](./source_07_shipping_mongo.sql). -You will have it at this url: `mongodb://localhost:27017/shipping` - -You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) - -## CRM - -Import it in a [MySQL database](../../libs/connector-mysql/README.md#local-setup) with the [source_08_crm_mysql.sql](./source_08_crm_mysql.sql). -You will have it at this url: `mysql://root:mysql@localhost:3306/crm` - -You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) - -## Analytics - -Import it in a [MongoDB database](../../libs/connector-mongodb/README.md#local-setup) with the [source_09_analytics_mongo.sql](./source_09_analytics_mongo.sql). -You will have it at this url: `mongodb://localhost:27017/analytics` - -You can then import it in your Azimutt project or explore it with the e-commerce demo after starting your local gateway (`npx azimutt@latest gateway`) +Once your database(s) are set up, you can launch the local gateway (`npx azimutt@latest gateway`) and navigate the project data or set up your own. diff --git a/demos/ecommerce/source_00_design.md b/demos/ecommerce/source_00_design.md index 074d636d8..5ee43d265 100644 --- a/demos/ecommerce/source_00_design.md +++ b/demos/ecommerce/source_00_design.md @@ -805,6 +805,9 @@ analytics.Events details json nullable | any additional info for the event entities json nullable | {[kind: string]: {id: string, name: string}[]} createdAt timestamp +fk analytics.Events.entities:user:id -> identity.Users.id +fk analytics.Events.entities:cart:id -> shopping.carts.id +fk analytics.Events.entities:invoice:id -> billing.Invoices.InvoiceId analytics.Entities kind string unique=pk @@ -813,3 +816,6 @@ analytics.Entities properties json createdAt timestamp updatedAt timestamp +fk analytics.Entities.id -> identity.Users.id # when kind=user +fk analytics.Entities.id -> shopping.carts.id # when kind=cart +fk analytics.Entities.id -> billing.Invoices.InvoiceId # when kind=invoice diff --git a/demos/ecommerce/source_10_additional_relations.md b/demos/ecommerce/source_10_additional_relations.md index bb2a52b67..9d94587e6 100644 --- a/demos/ecommerce/source_10_additional_relations.md +++ b/demos/ecommerce/source_10_additional_relations.md @@ -48,6 +48,8 @@ fk catalog.product_review_assets.created_by -> identity.Users.id fk catalog.product_review_assets.deleted_by -> identity.Users.id fk catalog.product_review_feedbacks.created_by -> identity.Users.id fk catalog.product_review_feedbacks.deleted_by -> identity.Users.id +fk shopping.carts.owner_id -> identity.Devices.id +fk shopping.carts.owner_id -> identity.Users.id fk shopping.cart_items.product_version_id -> catalog.product_versions.id fk shopping.cart_items.created_by -> identity.Users.id fk shopping.cart_items.updated_by -> identity.Users.id diff --git a/frontend/src/PagesComponents/Organization_/Project_/Views/Erd/Memo.elm b/frontend/src/PagesComponents/Organization_/Project_/Views/Erd/Memo.elm index 3d199e528..d98e97f12 100644 --- a/frontend/src/PagesComponents/Organization_/Project_/Views/Erd/Memo.elm +++ b/frontend/src/PagesComponents/Organization_/Project_/Views/Erd/Memo.elm @@ -75,7 +75,7 @@ viewMemo platform conf cursorMode editM memo = viewMarkdown : String -> Html msg viewMarkdown content = - Markdown.prose "prose-img:pointer-events-none" content + Markdown.prose "prose-img:pointer-events-none max-w-full" content handlePointerDown : HtmlId -> PointerEvent -> Msg From 44798088b47941b5e1c59240d56af0318970bf64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Knuchel?= Date: Sun, 18 Aug 2024 23:33:05 +0200 Subject: [PATCH 09/16] Comments & better data on Referential and Identity --- demos/ecommerce/README.md | 18 +- demos/ecommerce/source_00_design.md | 20 +- .../source_01_referential_sqlserver.sql | 3 + .../ecommerce/source_02_identity_mariadb.sql | 296 +++++++++++++----- .../connector-sqlserver/src/sqlserver.test.ts | 7 +- libs/connector-sqlserver/src/sqlserver.ts | 21 +- 6 files changed, 260 insertions(+), 105 deletions(-) diff --git a/demos/ecommerce/README.md b/demos/ecommerce/README.md index 457896c45..f4ef880e3 100644 --- a/demos/ecommerce/README.md +++ b/demos/ecommerce/README.md @@ -10,14 +10,14 @@ You can find this project at [xxx](https://azimutt.app...) and explore it yourse The project will let you access the schema and loaded data but if you want to dig into the data, you will have to set up the databases you want using Docker: -- **Referential** domain uses [SQL Server](../../libs/connector-sqlserver/README.md#local-setup) for [source_01_referential_sqlserver.sql](./source_01_referential_sqlserver.sql) (url `sqlserver://sa:azimutt_42@localhost:1433/Referential`) -- **Identity** domain uses [MariaDB](../../libs/connector-mariadb/README.md#local-setup) for [source_02_identity_mariadb.sql](./source_02_identity_mariadb.sql) (url `mariadb://root:mariadb@localhost:3307/identity`) -- **Inventory** domain uses [Oracle](../../libs/connector-oracle/README.md#local-setup) for [source_03_inventory_oracle.sql](./source_03_inventory_oracle.sql) (url `oracle:thin:C##INVENTORY/inventory@localhost:1521/FREE`) -- **Catalog** domain uses [PostgreSQL](../../libs/connector-postgres/README.md#local-setup) for [source_04_catalog_postgres.sql](./source_04_catalog_postgres.sql) (url `postgresql://postgres:postgres@localhost:5433/postgres?schema=catalog`) -- **Shopping** domain uses [PostgreSQL](../../libs/connector-postgres/README.md#local-setup) for [source_05_shopping_postgres.sql](./source_05_shopping_postgres.sql) (url `postgresql://postgres:postgres@localhost:5433/postgres?schema=shopping`) -- **Billing** domain uses [SQL Server](../../libs/connector-sqlserver/README.md#local-setup) for [source_06_billing_sqlserver.sql](./source_06_billing_sqlserver.sql) (url `sqlserver://sa:azimutt_42@localhost:1433/Billing`) -- **Shipping** domain uses [MongoDB](../../libs/connector-mongodb/README.md#local-setup) for [source_07_shipping_mongo.sql](./source_07_shipping_mongo.sql) (url `mongodb://localhost:27017/shipping`) -- **CRM** domain uses [MySQL](../../libs/connector-mysql/README.md#local-setup) for [source_08_crm_mysql.sql](./source_08_crm_mysql.sql) (url `mysql://root:mysql@localhost:3306/crm`) -- **Analytics** domain uses [MongoDB](../../libs/connector-mongodb/README.md#local-setup) for [source_09_analytics_mongo.sql](./source_09_analytics_mongo.sql) (url `mongodb://localhost:27017/analytics`) +- **Referential** needs [SQL Server](../../libs/connector-sqlserver/README.md#local-setup) with [referential script](./source_01_referential_sqlserver.sql) (url `sqlserver://sa:azimutt_42@localhost:1433/Referential`) +- **Identity** needs [MariaDB](../../libs/connector-mariadb/README.md#local-setup) with [identity script](./source_02_identity_mariadb.sql) (url `mariadb://root:mariadb@localhost:3307/identity`) +- **Inventory** needs [Oracle](../../libs/connector-oracle/README.md#local-setup) with [inventory script](./source_03_inventory_oracle.sql) (url `oracle:thin:C##INVENTORY/inventory@localhost:1521/FREE`) +- **Catalog** needs [PostgreSQL](../../libs/connector-postgres/README.md#local-setup) with [catalog script](./source_04_catalog_postgres.sql) (url `postgresql://postgres:postgres@localhost:5433/postgres?schema=catalog`) +- **Shopping** needs [PostgreSQL](../../libs/connector-postgres/README.md#local-setup) with [shopping script](./source_05_shopping_postgres.sql) (url `postgresql://postgres:postgres@localhost:5433/postgres?schema=shopping`) +- **Billing** needs [SQL Server](../../libs/connector-sqlserver/README.md#local-setup) with [billing script](./source_06_billing_sqlserver.sql) (url `sqlserver://sa:azimutt_42@localhost:1433/Billing`) +- **Shipping** needs [MongoDB](../../libs/connector-mongodb/README.md#local-setup) with [shipping script](./source_07_shipping_mongo.sql) (url `mongodb://localhost:27017/shipping`) +- **CRM** needs [MySQL](../../libs/connector-mysql/README.md#local-setup) with [crm script](./source_08_crm_mysql.sql) (url `mysql://root:mysql@localhost:3306/crm`) +- **Analytics** needs [MongoDB](../../libs/connector-mongodb/README.md#local-setup) with [analytics script](./source_09_analytics_mongo.sql) (url `mongodb://localhost:27017/analytics`) Once your database(s) are set up, you can launch the local gateway (`npx azimutt@latest gateway`) and navigate the project data or set up your own. diff --git a/demos/ecommerce/source_00_design.md b/demos/ecommerce/source_00_design.md index 5ee43d265..a3152051f 100644 --- a/demos/ecommerce/source_00_design.md +++ b/demos/ecommerce/source_00_design.md @@ -65,6 +65,16 @@ identity.UserDevices | created on user login to know which users are using which linked_at timestamp | on login unlinked_at timestamp nullable | on logout +identity.TrustedDevices | users can add a device to their trusted ones, so they will have longer session and less security validations + user_id bigint pk fk identity.Users.id + device_id bigint fk identity.Devices.id + name varchar nullable + kind device_kind(desktop, tablet, phone) nullable + usage device_usage(perso, pro) nullable + used_last timestamp + created_at timestamp + deleted_at timestamp nullable index + identity.AuthLogs id bigint pk user_id bigint nullable fk identity.Users.id @@ -76,16 +86,6 @@ identity.AuthLogs device_id bigint fk identity.Devices.id created_at timestamp -identity.TrustedDevices | users can add a device to their trusted ones, so they will have longer session and less security validations - user_id bigint pk fk identity.Users.id - device_id bigint fk identity.Devices.id - name varchar nullable - kind device_kind(desktop, tablet, phone) nullable - usage device_usage(perso, pro) nullable - used_last timestamp - created_at timestamp - deleted_at timestamp nullable index - # Inventory C##INVENTORY.EMPLOYEES diff --git a/demos/ecommerce/source_01_referential_sqlserver.sql b/demos/ecommerce/source_01_referential_sqlserver.sql index 12c7d6d49..38522469d 100644 --- a/demos/ecommerce/source_01_referential_sqlserver.sql +++ b/demos/ecommerce/source_01_referential_sqlserver.sql @@ -18,6 +18,7 @@ CREATE TABLE [referential].[Countries] ); CREATE INDEX [IDX_Countries_Code] ON [referential].[Countries] ([Code]); CREATE INDEX [IDX_Countries_Name] ON [referential].[Countries] ([Name]); +EXEC sp_addextendedproperty 'MS_Description', 'needs to be referenced for legal reasons', 'SCHEMA', 'referential', 'TABLE', 'Countries'; CREATE TABLE [referential].[States] ( @@ -32,6 +33,7 @@ CREATE TABLE [referential].[States] CREATE INDEX [IDX_States_CountryId] ON [referential].[States] ([CountryId]); CREATE INDEX [IDX_States_Code] ON [referential].[States] ([Code]); CREATE INDEX [IDX_States_Name] ON [referential].[States] ([Name]); +EXEC sp_addextendedproperty 'MS_Description', 'used for auto-competes', 'SCHEMA', 'referential', 'TABLE', 'States'; CREATE TABLE [referential].[Cities] ( @@ -44,6 +46,7 @@ CREATE TABLE [referential].[Cities] ); CREATE INDEX [IDX_Cities_StateId] ON [referential].[Cities] ([StateId]); CREATE INDEX [IDX_Cities_Name] ON [referential].[Cities] ([Name]); +EXEC sp_addextendedproperty 'MS_Description', 'used for auto-competes', 'SCHEMA', 'referential', 'TABLE', 'Cities'; -- insert some data diff --git a/demos/ecommerce/source_02_identity_mariadb.sql b/demos/ecommerce/source_02_identity_mariadb.sql index 5c4053b9f..4f065bb0b 100644 --- a/demos/ecommerce/source_02_identity_mariadb.sql +++ b/demos/ecommerce/source_02_identity_mariadb.sql @@ -23,23 +23,22 @@ CREATE TABLE identity.Users CREATE TABLE identity.Credentials ( - user_id BIGINT NOT NULL, - provider ENUM ('password', 'google', 'linkedin', 'facebook', 'twitter') NOT NULL, - provider_id VARCHAR(255) NOT NULL, + user_id BIGINT NOT NULL REFERENCES identity.Users (id), + provider ENUM ('password', 'google', 'linkedin', 'facebook', 'twitter') NOT NULL COMMENT 'the used provider', + provider_id VARCHAR(255) NOT NULL COMMENT 'the user id from the provider, in case of password, stores the hashed password with the salt', provider_data JSON CHECK (JSON_VALID(provider_data)), used_last TIMESTAMP, used_count INT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (user_id, provider, provider_id), - FOREIGN KEY (user_id) REFERENCES identity.Users (id) + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'for password change mostly', + PRIMARY KEY (user_id, provider, provider_id) ); CREATE TABLE identity.PasswordResets ( id BIGINT PRIMARY KEY AUTO_INCREMENT, email VARCHAR(255) NOT NULL, - token VARCHAR(255) NOT NULL, + token VARCHAR(255) NOT NULL COMMENT 'the key sent by email to allow to change the password without being logged', requested_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, expire_at TIMESTAMP, used_at TIMESTAMP, @@ -50,41 +49,24 @@ CREATE TABLE identity.PasswordResets CREATE TABLE identity.Devices ( id BIGINT PRIMARY KEY AUTO_INCREMENT, - sid CHAR(36) NOT NULL UNIQUE, + sid CHAR(36) NOT NULL UNIQUE COMMENT 'a unique id stored in the browser to track it when not logged', user_agent VARCHAR(255) NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -); + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'first time this device is seen' +) COMMENT 'a device is a browser tagged by a random id in its session'; CREATE TABLE identity.UserDevices ( - user_id BIGINT NOT NULL, - device_id BIGINT NOT NULL, - linked_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - unlinked_at TIMESTAMP, - PRIMARY KEY (user_id, device_id), - FOREIGN KEY (user_id) REFERENCES identity.Users (id), - FOREIGN KEY (device_id) REFERENCES identity.Devices (id) -); - -CREATE TABLE identity.AuthLogs -( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - user_id BIGINT, - email VARCHAR(255), - event ENUM ('signup', 'login_success', 'login_failure', 'password_reset_asked', 'password_reset_used') NOT NULL, - ip VARCHAR(45) NOT NULL, - ip_location POINT, - user_agent VARCHAR(255) NOT NULL, - device_id BIGINT NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (user_id) REFERENCES identity.Users (id), - FOREIGN KEY (device_id) REFERENCES identity.Devices (id) -); + user_id BIGINT NOT NULL REFERENCES identity.Users (id), + device_id BIGINT NOT NULL REFERENCES identity.Devices (id), + linked_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'on login', + unlinked_at TIMESTAMP COMMENT 'on logout', + PRIMARY KEY (user_id, device_id) +) COMMENT 'created on user login to know which users are using which devices'; CREATE TABLE identity.TrustedDevices ( - user_id BIGINT NOT NULL, - device_id BIGINT NOT NULL, + user_id BIGINT NOT NULL REFERENCES identity.Users (id), + device_id BIGINT NOT NULL REFERENCES identity.Devices (id), name VARCHAR(255), kind ENUM ('desktop', 'tablet', 'phone'), `usage` ENUM ('perso', 'pro'), @@ -92,55 +74,225 @@ CREATE TABLE identity.TrustedDevices created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, deleted_at TIMESTAMP, PRIMARY KEY (user_id, device_id), - FOREIGN KEY (user_id) REFERENCES identity.Users (id), - FOREIGN KEY (device_id) REFERENCES identity.Devices (id), INDEX idx_deleted_at (deleted_at) +) COMMENT 'users can add a device to their trusted ones, so they will have longer session and less security validations'; + +CREATE TABLE identity.AuthLogs +( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + user_id BIGINT REFERENCES identity.Users (id), + email VARCHAR(255), + event ENUM ('signup', 'login_success', 'login_failure', 'password_reset_asked', 'password_reset_used') NOT NULL, + ip VARCHAR(45) NOT NULL, + ip_location POINT, + user_agent VARCHAR(255) NOT NULL, + device_id BIGINT NOT NULL REFERENCES identity.Devices (id), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- insert some data -INSERT INTO identity.Users (first_name, last_name, username, email, settings) -VALUES ('Loïc', 'Knuchel', 'loicknuchel', 'loic@azimutt.app', '{"theme": "dark", "language": "fr"}'), - ('John', 'Doe', 'johndoe', 'john.doe@example.com', '{"theme": "dark", "language": "en"}'), - ('Jane', 'Smith', 'janesmith', 'jane.smith@example.com', '{"theme": "light", "language": "fr"}'), - ('Alice', 'Brown', 'alicebrown', 'alice.brown@example.com', '{"theme": "dark", "language": "es"}'), - ('Bob', 'Davis', 'bobdavis', 'bob.davis@example.com', '{"theme": "light", "language": "de"}'); +INSERT INTO identity.Users (id, first_name, last_name, username, email, settings) +VALUES (1, 'John', 'Doe', 'johndoe', 'johndoe@example.com', '{"theme": "dark", "language": "en"}'), + (2, 'Jane', 'Doe', 'janedoe', 'janedoe@example.com', '{"theme": "light", "language": "en"}'), + (3, 'James', 'Bond', 'jamesbond', 'james.bond@mi6.co.uk', '{"theme": "dark", "language": "en"}'), + (4, 'Bruce', 'Wayne', 'brucewayne', 'bruce.wayne@wayneenterprises.com', '{"theme": "dark", "language": "en"}'), + (5, 'Clark', 'Kent', 'clarkkent', 'clark.kent@dailyplanet.com', '{"theme": "light", "language": "en"}'), + (6, 'Diana', 'Prince', 'dianaprince', 'diana.prince@themyscira.gov', '{"theme": "light", "language": "en"}'), + (7, 'Peter', 'Parker', 'peterparker', 'peter.parker@dailybugle.com', '{"theme": "light", "language": "en"}'), + (8, 'Tony', 'Stark', 'tonystark', 'tony.stark@starkindustries.com', '{"theme": "dark", "language": "en"}'), + (9, 'Natasha', 'Romanoff', 'natasharomanoff', 'natasha.romanoff@shield.gov', '{"theme": "dark", "language": "ru"}'), + (10, 'Steve', 'Rogers', 'steverogers', 'steve.rogers@avengers.com', '{"theme": "light", "language": "en"}'), + (11, 'Bruce', 'Banner', 'brucebanner', 'bruce.banner@avengers.com', '{"theme": "dark", "language": "en"}'), + (12, 'Wanda', 'Maximoff', 'wandamaximoff', 'wanda.maximoff@avengers.com', '{"theme": "dark", "language": "en"}'), + (13, 'Harry', 'Potter', 'harrypotter', 'harry.potter@hogwarts.ac.uk', '{"theme": "light", "language": "en"}'), + (14, 'Hermione', 'Granger', 'hermionegranger', 'hermione.granger@hogwarts.ac.uk', '{"theme": "light", "language": "en"}'), + (15, 'Ron', 'Weasley', 'ronweasley', 'ron.weasley@hogwarts.ac.uk', '{"theme": "light", "language": "en"}'), + (16, 'Albus', 'Dumbledore', 'albusdumbledore', 'albus.dumbledore@hogwarts.ac.uk', '{"theme": "dark", "language": "en"}'), + (17, 'Severus', 'Snape', 'severussnape', 'severus.snape@hogwarts.ac.uk', '{"theme": "dark", "language": "en"}'), + (18, 'Frodo', 'Baggins', 'frodobaggins', 'frodo.baggins@shire.me', '{"theme": "light", "language": "en"}'), + (19, 'Samwise', 'Gamgee', 'samwisegamgee', 'samwise.gamgee@shire.me', '{"theme": "light", "language": "en"}'), + (20, 'Gandalf', 'the Grey', 'gandalfthegrey', 'gandalf@middleearth.me', '{"theme": "dark", "language": "en"}'), + (21, 'Aragorn', 'Elessar', 'aragornelessar', 'aragorn@middleearth.me', '{"theme": "dark", "language": "en"}'), + (22, 'Legolas', 'Greenleaf', 'legolasgreenleaf', 'legolas@woodlandrealm.me', '{"theme": "light", "language": "en"}'), + (23, 'Gimli', 'Son of Glóin', 'gimlisonofgloin', 'gimli@lonelymountain.me', '{"theme": "dark", "language": "en"}'), + (24, 'Sherlock', 'Holmes', 'sherlockholmes', 'sherlock.holmes@bakerstreet.com', '{"theme": "dark", "language": "en"}'), + (25, 'John', 'Watson', 'johnwatson', 'john.watson@bakerstreet.com', '{"theme": "light", "language": "en"}'), + (26, 'Bilbo', 'Baggins', 'bilbobaggins', 'bilbo.baggins@shire.me', '{"theme": "light", "language": "en"}'), + (27, 'Tony', 'Montana', 'tonymontana', 'tony.montana@scarface.com', '{"theme": "dark", "language": "en"}'), + (28, 'Michael', 'Corleone', 'michaelcorleone', 'michael.corleone@corleone.com', '{"theme": "dark", "language": "en"}'), + (29, 'Vito', 'Corleone', 'vitocorleone', 'vito.corleone@corleone.com', '{"theme": "dark", "language": "it"}'), + (30, 'Ellen', 'Ripley', 'ellenripley', 'ellen.ripley@weylandyutani.com', '{"theme": "dark", "language": "en"}'), + (31, 'Sarah', 'Connor', 'sarahconnor', 'sarah.connor@skynet.com', '{"theme": "dark", "language": "en"}'), + (32, 'Neo', 'Anderson', 'neoanderson', 'neo.anderson@matrix.com', '{"theme": "dark", "language": "en"}'), + (33, 'Trinity', '', 'trinity', 'trinity@matrix.com', '{"theme": "dark", "language": "en"}'), + (34, 'Morpheus', '', 'morpheus', 'morpheus@matrix.com', '{"theme": "dark", "language": "en"}'), + (35, 'Ethan', 'Hunt', 'ethanhunt', 'ethan.hunt@imf.gov', '{"theme": "dark", "language": "en"}'), + (36, 'Indiana', 'Jones', 'indianajones', 'indiana.jones@archeology.com', '{"theme": "dark", "language": "en"}'), + (37, 'Han', 'Solo', 'hansolo', 'han.solo@rebellion.com', '{"theme": "dark", "language": "en"}'), + (38, 'Luke', 'Skywalker', 'lukeskywalker', 'luke.skywalker@rebellion.com', '{"theme": "light", "language": "en"}'), + (39, 'Leia', 'Organa', 'leiaorgana', 'leia.organa@rebellion.com', '{"theme": "light", "language": "en"}'), + (40, 'Yoda', '', 'yoda', 'yoda@jediorder.com', '{"theme": "dark", "language": "en"}'), + (41, 'Obi-Wan', 'Kenobi', 'obiwankenobi', 'obi-wan.kenobi@jediorder.com', '{"theme": "light", "language": "en"}'), + (42, 'Anakin', 'Skywalker', 'anakinskywalker', 'anakin.skywalker@jediorder.com', '{"theme": "dark", "language": "en"}'), + (43, 'Darth', 'Vader', 'darthvader', 'darth.vader@empire.com', '{"theme": "dark", "language": "en"}'), + (44, 'Kylo', 'Ren', 'kyloren', 'kylo.ren@firstorder.com', '{"theme": "dark", "language": "en"}'), + (45, 'Rey', '', 'rey', 'rey@resistance.com', '{"theme": "light", "language": "en"}'), + (46, 'Finn', '', 'finn', 'finn@resistance.com', '{"theme": "light", "language": "en"}'), + (47, 'Poe', 'Dameron', 'poedameron', 'poe.dameron@resistance.com', '{"theme": "light", "language": "en"}'), + (48, 'Arthur', 'Dent', 'arthurdent', 'arthur.dent@hitchhikersguide.com', '{"theme": "light", "language": "en"}'), + (49, 'Zaphod', 'Beeblebrox', 'zaphodbeeblebrox', 'zaphod.beeblebrox@hitchhikersguide.com', '{"theme": "dark", "language": "en"}'), + (50, 'Ford', 'Prefect', 'fordprefect', 'ford.prefect@hitchhikersguide.com', '{"theme": "light", "language": "en"}'), + (51, 'Marvin', 'the Paranoid Android', 'marvinandroid', 'marvin@hitchhikersguide.com', '{"theme": "dark", "language": "en"}'), + (52, 'Arthur', 'Morgan', 'arthurmorgan', 'arthur.morgan@reddead.com', '{"theme": "dark", "language": "en"}'), + (53, 'John', 'Marston', 'johnmarston', 'john.marston@reddead.com', '{"theme": "dark", "language": "en"}'), + (54, 'Tommy', 'Vercetti', 'tommyvercetti', 'tommy.vercetti@vicecity.com', '{"theme": "dark", "language": "en"}'), + (55, 'Carl', 'Johnson', 'carljohnson', 'carl.johnson@sweet.com', '{"theme": "dark", "language": "en"}'), + (56, 'Lara', 'Croft', 'laracroft', 'lara.croft@tombraider.com', '{"theme": "dark", "language": "en"}'), + (57, 'Nathan', 'Drake', 'nathandrake', 'nathan.drake@uncharted.com', '{"theme": "light", "language": "en"}'), + (58, 'Kratos', '', 'kratos', 'kratos@godofwar.com', '{"theme": "dark", "language": "en"}'), + (59, 'Atreus', '', 'atreus', 'atreus@godofwar.com', '{"theme": "light", "language": "en"}'), + (60, 'Geralt', 'of Rivia', 'geraltofrivia', 'geralt@witcher.com', '{"theme": "dark", "language": "en"}'), + (61, 'Ciri', '', 'ciri', 'ciri@witcher.com', '{"theme": "light", "language": "en"}'), + (62, 'Yennefer', 'of Vengerberg', 'yennefer', 'yennefer@witcher.com', '{"theme": "dark", "language": "en"}'), + (63, 'Batman', '', 'batman', 'batman@gotham.com', '{"theme": "dark", "language": "en"}'), + (64, 'Superman', '', 'superman', 'superman@metropolis.com', '{"theme": "light", "language": "en"}'), + (65, 'Wolverine', '', 'wolverine', 'wolverine@xmen.com', '{"theme": "dark", "language": "en"}'), + (66, 'Charles', 'Xavier', 'charlesxavier', 'charles.xavier@xmen.com', '{"theme": "light", "language": "en"}'), + (67, 'Logan', '', 'logan', 'logan@xmen.com', '{"theme": "dark", "language": "en"}'), + (68, 'Jean', 'Grey', 'jeangrey', 'jean.grey@xmen.com', '{"theme": "light", "language": "en"}'), + (69, 'Magneto', '', 'magneto', 'magneto@brotherhood.com', '{"theme": "dark", "language": "en"}'), + (70, 'Deadpool', '', 'deadpool', 'deadpool@xmen.com', '{"theme": "dark", "language": "en"}'), + (71, 'Thanos', '', 'thanos', 'thanos@titan.com', '{"theme": "dark", "language": "en"}'), + (72, 'Rocket', 'Raccoon', 'rocketraccoon', 'rocket.raccoon@guardians.com', '{"theme": "light", "language": "en"}'), + (73, 'Groot', '', 'groot', 'groot@guardians.com', '{"theme": "light", "language": "en"}'), + (74, 'Gamora', '', 'gamora', 'gamora@guardians.com', '{"theme": "dark", "language": "en"}'), + (75, 'Star-Lord', '', 'starlord', 'star-lord@guardians.com', '{"theme": "light", "language": "en"}'), + (76, 'Drax', 'the Destroyer', 'drax', 'drax@guardians.com', '{"theme": "dark", "language": "en"}'), + (77, 'Sheldon', 'Cooper', 'sheldoncooper', 'sheldon.cooper@caltech.edu', '{"theme": "light", "language": "en"}'), + (78, 'Leonard', 'Hofstadter', 'leonardhofstadter', 'leonard.hofstadter@caltech.edu', '{"theme": "light", "language": "en"}'), + (79, 'Penny', '', 'penny', 'penny@thecheesecakefactory.com', '{"theme": "light", "language": "en"}'), + (80, 'Howard', 'Wolowitz', 'howardwolowitz', 'howard.wolowitz@caltech.edu', '{"theme": "light", "language": "en"}'), + (81, 'Raj', 'Koothrappali', 'rajkoothrappali', 'raj.koothrappali@caltech.edu', '{"theme": "light", "language": "en"}'), + (82, 'Jesse', 'Pinkman', 'jessepinkman', 'jesse.pinkman@lospolloshermanos.com', '{"theme": "dark", "language": "en"}'), + (83, 'Walter', 'White', 'walterwhite', 'walter.white@lospolloshermanos.com', '{"theme": "dark", "language": "en"}'), + (84, 'Saul', 'Goodman', 'saulgoodman', 'saul.goodman@law.com', '{"theme": "dark", "language": "en"}'), + (85, 'Homer', 'Simpson', 'homersimpson', 'homer.simpson@thesimpsons.com', '{"theme": "light", "language": "en"}'), + (86, 'Marge', 'Simpson', 'margesimpson', 'marge.simpson@thesimpsons.com', '{"theme": "light", "language": "en"}'), + (87, 'Bart', 'Simpson', 'bartsimpson', 'bart.simpson@thesimpsons.com', '{"theme": "light", "language": "en"}'), + (88, 'Lisa', 'Simpson', 'lisasimpson', 'lisa.simpson@thesimpsons.com', '{"theme": "light", "language": "en"}'), + (89, 'Maggie', 'Simpson', 'maggiesimpson', 'maggie.simpson@thesimpsons.com', '{"theme": "light", "language": "en"}'), + (90, 'Rick', 'Sanchez', 'ricksanchez', 'rick.sanchez@rickandmorty.com', '{"theme": "dark", "language": "en"}'), + (91, 'Morty', 'Smith', 'mortysmith', 'morty.smith@rickandmorty.com', '{"theme": "light", "language": "en"}'), + (92, 'Jerry', 'Smith', 'jerrysmith', 'jerry.smith@rickandmorty.com', '{"theme": "light", "language": "en"}'), + (93, 'Summer', 'Smith', 'summersmith', 'summer.smith@rickandmorty.com', '{"theme": "light", "language": "en"}'), + (94, 'Beth', 'Smith', 'bethsmith', 'beth.smith@rickandmorty.com', '{"theme": "light", "language": "en"}'), + (95, 'Fry', 'Phillip J.', 'fry', 'fry@planetexpress.com', '{"theme": "light", "language": "en"}'), + (96, 'Bender', 'Rodriguez', 'bender', 'bender@planetexpress.com', '{"theme": "dark", "language": "en"}'), + (97, 'Leela', 'Turanga', 'leela', 'leela@planetexpress.com', '{"theme": "light", "language": "en"}'), + (98, 'Zoidberg', 'John A.', 'zoidberg', 'zoidberg@planetexpress.com', '{"theme": "light", "language": "en"}'), + (99, 'Professor', 'Farnsworth', 'farnsworth', 'farnsworth@planetexpress.com', '{"theme": "dark", "language": "en"}'), + (100, 'Hermes', 'Conrad', 'hermes', 'hermes@planetexpress.com', '{"theme": "light", "language": "en"}'), + (101, 'Amy', 'Wong', 'amy', 'amy@planetexpress.com', '{"theme": "light", "language": "en"}'), + (102, 'SpongeBob', 'SquarePants', 'spongebob', 'spongebob@bikinibottom.com', '{"theme": "light", "language": "en"}'), + (103, 'Patrick', 'Star', 'patrickstar', 'patrick@bikinibottom.com', '{"theme": "light", "language": "en"}'), + (104, 'Squidward', 'Tentacles', 'squidward', 'squidward@bikinibottom.com', '{"theme": "dark", "language": "en"}'), + (105, 'Mr.', 'Krabs', 'mrkrabs', 'mr.krabs@bikinibottom.com', '{"theme": "dark", "language": "en"}'), + (106, 'Plankton', 'Sheldon J.', 'plankton', 'plankton@bikinibottom.com', '{"theme": "dark", "language": "en"}'), + (107, 'Sandy', 'Cheeks', 'sandycheeks', 'sandy.cheeks@bikinibottom.com', '{"theme": "light", "language": "en"}'), + (108, 'Michael', 'Scott', 'michaelscott', 'michael.scott@dundermifflin.com', '{"theme": "light", "language": "en"}'), + (109, 'Dwight', 'Schrute', 'dwightschrute', 'dwight.schrute@dundermifflin.com', '{"theme": "dark", "language": "en"}'), + (110, 'Jim', 'Halpert', 'jimhalpert', 'jim.halpert@dundermifflin.com', '{"theme": "light", "language": "en"}'), + (111, 'Pam', 'Beesly', 'pambeesly', 'pam.beesly@dundermifflin.com', '{"theme": "light", "language": "en"}'), + (112, 'Stanley', 'Hudson', 'stanleyhudson', 'stanley.hudson@dundermifflin.com', '{"theme": "dark", "language": "en"}'), + (113, 'Kevin', 'Malone', 'kevinmalone', 'kevin.malone@dundermifflin.com', '{"theme": "light", "language": "en"}'), + (114, 'Oscar', 'Martinez', 'oscarmartinez', 'oscar.martinez@dundermifflin.com', '{"theme": "light", "language": "en"}'), + (115, 'Phyllis', 'Vance', 'phyllisvance', 'phyllis.vance@dundermifflin.com', '{"theme": "light", "language": "en"}'), + (116, 'Angela', 'Martin', 'angelamartin', 'angela.martin@dundermifflin.com', '{"theme": "dark", "language": "en"}'), + (117, 'Andy', 'Bernard', 'andybernard', 'andy.bernard@dundermifflin.com', '{"theme": "light", "language": "en"}'), + (118, 'Creed', 'Bratton', 'creedbratton', 'creed.bratton@dundermifflin.com', '{"theme": "dark", "language": "en"}'), + (119, 'Meredith', 'Palmer', 'meredithpalmer', 'meredith.palmer@dundermifflin.com', '{"theme": "dark", "language": "en"}'), + (120, 'Ryan', 'Howard', 'ryanhoward', 'ryan.howard@dundermifflin.com', '{"theme": "dark", "language": "en"}'), + (121, 'Kelly', 'Kapoor', 'kellykapoor', 'kelly.kapoor@dundermifflin.com', '{"theme": "light", "language": "en"}'), + (122, 'Toby', 'Flenderson', 'tobyflenderson', 'toby.flenderson@dundermifflin.com', '{"theme": "dark", "language": "en"}'), + (123, 'Daryl', 'Philbin', 'darylphilbin', 'daryl.philbin@dundermifflin.com', '{"theme": "light", "language": "en"}'); INSERT INTO identity.Credentials (user_id, provider, provider_id, provider_data, used_last, used_count) -VALUES (1, 'twitter', 'loicknuchel', '{"refresh_token": "xxx"}', CURRENT_TIMESTAMP, 42), - (2, 'password', 'hashed_password_1', NULL, CURRENT_TIMESTAMP, 10), - (3, 'password', 'hashed_password_2', NULL, CURRENT_TIMESTAMP, 5), - (4, 'google', 'superalice', '{"refresh_token": "refresh_token_3"}', CURRENT_TIMESTAMP, 15), - (5, 'facebook', 'bobisking', '{"access_token": "access_token_4"}', CURRENT_TIMESTAMP, 20); +VALUES (1, 'password', '$2a$10$IphbkzyF2NZlEvvFXrQw5eELqiTV3U.u7Hx4QMCA0yhpubUsUMNnW', '{"algorithm": "bcrypt", "salt": "a8f5f167f44f4964e6c998dee827110c"}', CURRENT_TIMESTAMP, 5), + (1, 'twitter', '192837465', '{"id_str": "192837465", "name": "John Doe", "screen_name": "johndoe", "location": "Metropolis, USA", "profile_image_url_https": "https://pbs.twimg.com/profile_images/123456789/johndoe_400x400.jpg", "email": "johndoe@example.com", "verified": true}', CURRENT_TIMESTAMP, 15), + (2, 'password', '$2a$10$PEK5WPg5qxKOmntN8sT4bOzOf/omzk0.CVNJAKp2MBdS4o2Mpgq2G', '{"algorithm": "bcrypt", "salt": "7b9c1c8d5b3e469fb6d4e98b9578efc5"}', CURRENT_TIMESTAMP, 4), + (3, 'password', '$2a$10$Fot3cix5fRC7HMqXN7jTvuqfsVVCM5Wp5G2RSeVkf1U1NdkfBG6Jy', '{"algorithm": "bcrypt", "salt": "1d6f82c8b3494fda8b183a8e47d66d14"}', CURRENT_TIMESTAMP, 7), + (4, 'google', '108947621839247391020', '{"sub": "108947621839247391020", "name": "Bruce Wayne", "given_name": "Bruce", "family_name": "Wayne", "picture": "https://lh3.googleusercontent.com/a-/AOh14Gg-batmanprofilepic/AAAAAAAAAAA/photo.jpg", "email": "bruce.wayne@wayneenterprises.com", "email_verified": true, "locale": "en"}', CURRENT_TIMESTAMP, 12), + (5, 'facebook', '10293847561234567', '{"id": "10293847561234567", "name": "Clark Kent", "first_name": "Clark", "last_name": "Kent", "email": "clark.kent@dailyplanet.com", "picture": {"data": {"url": "https://graph.facebook.com/10293847561234567/picture?type=large"}}, "locale": "en_US"}', CURRENT_TIMESTAMP, 3), + (6, 'linkedin', 'diana-prince-123456789', '{"id": "diana-prince-123456789", "localizedFirstName": "Diana", "localizedLastName": "Prince", "profilePicture": {"displayImage": "https://media-exp1.licdn.com/dms/image/C4E03AQFZ8DqeOgx5YA/profile-displayphoto-shrink_200_200/0/1517436071201?e=1624320000&v=beta&t=LQyE8g4BLwNxYc6GZJ9Nz4u8MJE1z3kJDcF6Gf9OMwY"}, "emailAddress": "diana.prince@themyscira.gov"}', CURRENT_TIMESTAMP, 6), + (7, 'password', '$2a$10$kf2vdK9OY8mnTiT5VQYK2u80PhxTIJmKc1y/9UUphrI2vPUougX/W', '{"algorithm": "bcrypt", "salt": "4c6e2bbad3f74a4cbf50e08f7e9a2951"}', CURRENT_TIMESTAMP, 9), + (8, 'twitter', '25073877', '{"id_str": "25073877", "name": "Tony Stark", "screen_name": "IronMan", "location": "Stark Tower, NYC", "profile_image_url_https": "https://pbs.twimg.com/profile_images/875400512/tonystark_400x400.jpg", "email": "tony.stark@starkindustries.com", "verified": true}', CURRENT_TIMESTAMP, 20), + (9, 'password', '$2a$10$mXyJ3ERqiZFnDUzWoe/BqOTji0VSRAPHu5CHmQCnXcNvjB3dAagne', '{"algorithm": "bcrypt", "salt": "9f8e7c9d3b414f5e94b4670b8e5a2b19"}', CURRENT_TIMESTAMP, 11), + (10, 'password', '$2a$10$l5c6QaTo/dIJOcUCoooWaOJrD7IvKH52PNCcGxONn5rPD5JLa/ZsC', '{"algorithm": "bcrypt", "salt": "e3c0d5f6a1f84f45b6c3e8e17d8c925b"}', CURRENT_TIMESTAMP, 8), + (11, 'google', '116834789476231098765', '{"sub": "116834789476231098765", "name": "Bruce Banner", "given_name": "Bruce", "family_name": "Banner", "picture": "https://lh3.googleusercontent.com/a-/AOh14Gg-hulkprofilepic/AAAAAAAAAAA/photo.jpg", "email": "bruce.banner@avengers.com", "email_verified": true, "locale": "en"}', CURRENT_TIMESTAMP, 14), + (12, 'password', '$2a$10$kVnyLvCybOAxcB7zF/g.W.628fux.jbNoCN8tfIZnt8Ct9/liMer.', '{"algorithm": "bcrypt", "salt": "b7d9e4c5a6f34d88b6c3f1a7c0e2b839"}', CURRENT_TIMESTAMP, 6), + (13, 'facebook', '20394857618234567', '{"id": "20394857618234567", "name": "Harry Potter", "first_name": "Harry", "last_name": "Potter", "email": "harry.potter@hogwarts.ac.uk", "picture": {"data": {"url": "https://graph.facebook.com/20394857618234567/picture?type=large"}}, "locale": "en_GB"}', CURRENT_TIMESTAMP, 2), + (14, 'linkedin', 'hermione-granger-234567890', '{"id": "hermione-granger-234567890", "localizedFirstName": "Hermione", "localizedLastName": "Granger", "profilePicture": {"displayImage": "https://media-exp1.licdn.com/dms/image/C4E03AQGxZSDdfx3Y5A/profile-displayphoto-shrink_200_200/0/1517535071201?e=1624320000&v=beta&t=KJ2F8w5IZKx5BsAUbjf8_YD3X9O9s3kFDZpD2aZ3PfM"}, "emailAddress": "hermione.granger@hogwarts.ac.uk"}', CURRENT_TIMESTAMP, 5), + (15, 'twitter', '33421598', '{"id_str": "33421598", "name": "Ron Weasley", "screen_name": "TheWeasel", "location": "The Burrow, Ottery St Catchpole", "profile_image_url_https": "https://pbs.twimg.com/profile_images/378800000/ronweasley_400x400.jpg", "email": "ron.weasley@hogwarts.ac.uk", "verified": true}', CURRENT_TIMESTAMP, 4), + (16, 'password', '$2a$10$pLnLSBoC1Ucrkh9QQzSlQO9BS5oeLqiZR2tymbuoZRED430p7euwG', '{"algorithm": "bcrypt", "salt": "c3a7e2d8f1b74b56b9c8f4d9e6a7c235"}', CURRENT_TIMESTAMP, 10), + (17, 'google', '109865432198765432109', '{"sub": "109865432198765432109", "name": "Severus Snape", "given_name": "Severus", "family_name": "Snape", "picture": "https://lh3.googleusercontent.com/a-/AOh14Gg-snapepic/AAAAAAAAAAA/photo.jpg", "email": "severus.snape@hogwarts.ac.uk", "email_verified": true, "locale": "en"}', CURRENT_TIMESTAMP, 13), + (18, 'password', '$2a$10$OpNiFmlD2oPCLMSgxvCnDev1ROrahuH4S.nqbvX3VFSnkxWuTHKIe', '{"algorithm": "bcrypt", "salt": "5a6c8f9d2e3b4f17c6e7b9f8d5a2c3e4"}', CURRENT_TIMESTAMP, 6), + (19, 'password', '$2a$10$rqge0CSMuq1b2lluLF5EKO7eOP19YX0qn2Ikmd/OKN.sMLIqPCE5u', '{"algorithm": "bcrypt", "salt": "2f3e5d6c7b4a1d8e9c2f7b5e6a4d9c13"}', CURRENT_TIMESTAMP, 7), + (20, 'linkedin', 'gandalf-grey-345678901', '{"id": "gandalf-grey-345678901", "localizedFirstName": "Gandalf", "localizedLastName": "the Grey", "profilePicture": {"displayImage": "https://media-exp1.licdn.com/dms/image/C4E03AQFZ8DqeOgx5YA/profile-displayphoto-shrink_200_200/0/1517436071201?e=1624320000&v=beta&t=LQyE8g4BLwNxYc6GZJ9Nz4u8MJE1z3kJDcF6Gf9OMwY"}, "emailAddress": "gandalf@middleearth.me"}', CURRENT_TIMESTAMP, 9), + (21, 'facebook', '30495876123456789', '{"id": "30495876123456789", "name": "Aragorn Elessar", "first_name": "Aragorn", "last_name": "Elessar", "email": "aragorn@middleearth.me", "picture": {"data": {"url": "https://graph.facebook.com/30495876123456789/picture?type=large"}}, "locale": "en_US"}', CURRENT_TIMESTAMP, 8), + (22, 'password', '$2a$10$r.AQAnbsSTB6VVU2I.pF6u4/qc1Z.rHNUXnxqwxLjNyMIhHnyfuWK', '{"algorithm": "bcrypt", "salt": "3b4d6e7f5a2c1e8f9d7c3b6a4f5e9d18"}', CURRENT_TIMESTAMP, 5), + (23, 'password', '$2a$10$Ojml6vqxh.YemFguenicBedeoJN7quOhSrk7839dSR8GGA7rjyuOe', '{"algorithm": "bcrypt", "salt": "1e2f3b4a6d7c5e9f8b3c7d6a4f2e5b19"}', CURRENT_TIMESTAMP, 4); -INSERT INTO identity.PasswordResets (email, token, requested_at, expire_at) -VALUES ('loic@azimutt.app', 'token_1', CURRENT_TIMESTAMP, DATE_ADD(CURRENT_TIMESTAMP, INTERVAL 1 HOUR)), - ('jane.smith@example.com', 'token_2', CURRENT_TIMESTAMP, DATE_ADD(CURRENT_TIMESTAMP, INTERVAL 1 HOUR)); +INSERT INTO identity.PasswordResets (email, token, requested_at, expire_at, used_at) +VALUES ('johndoe@example.com', 'a1b2c3d4e5f6g7h8i9j0', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP + INTERVAL 1 HOUR, NULL), + ('janedoe@example.com', 'f1e2d3c4b5a6g7h8i9j0', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP + INTERVAL 1 HOUR, CURRENT_TIMESTAMP + INTERVAL 10 MINUTE); INSERT INTO identity.Devices (sid, user_agent) -VALUES (UUID(), 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'), - (UUID(), 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15'), - (UUID(), 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Mobile/15E148 Safari/604.1'), - (UUID(), 'Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36'), - (UUID(), 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15'); +VALUES ('550e8400-e29b-41d4-a716-446655440000', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'), + ('66eebccb-8d67-4b3e-b218-8a4d24c3f5d3', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Safari/605.1.15'), + ('123e4567-e89b-12d3-a456-426614174000', 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1'), + ('92ef1ac7-7391-4b9b-abc7-5f1f0ec9f93b', 'Mozilla/5.0 (Linux; Android 11; SM-G998B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Mobile Safari/537.36'), + ('b019fd28-7e8c-4c7d-b432-d3e2b5c74221', 'Mozilla/5.0 (iPad; CPU OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1'), + ('f47ac10b-58cc-4372-a567-0e02b2c3d479', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0'), + ('21bffb99-78a1-4b92-b162-81cfd8b3bcec', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'), + ('77bfcc0d-98d1-4c43-88b2-f3c1e8d3f939', 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1'), + ('c9bde7a0-6f79-4a88-b2cb-274abf1d4a62', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36'), + ('b43ae61a-4f34-445d-b0d9-6eb8c5e7b13b', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0'); INSERT INTO identity.UserDevices (user_id, device_id, linked_at) VALUES (1, 1, CURRENT_TIMESTAMP), - (2, 2, CURRENT_TIMESTAMP), - (3, 3, CURRENT_TIMESTAMP), - (4, 4, CURRENT_TIMESTAMP), - (5, 5, CURRENT_TIMESTAMP); - -INSERT INTO identity.AuthLogs (user_id, email, event, ip, ip_location, user_agent, device_id) -VALUES (1, 'loic@azimutt.app', 'login_success', '192.168.1.1', ST_GeomFromText('POINT(48.8588443 2.2943506)'), 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', 1), - (2, 'john.doe@example.com', 'login_success', '192.168.1.1', ST_GeomFromText('POINT(48.8588443 2.2943506)'), 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', 1), - (3, 'jane.smith@example.com', 'login_failure', '192.168.1.2', ST_GeomFromText('POINT(51.507351 -0.127758)'), 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15', 2), - (4, 'alice.brown@example.com', 'password_reset_asked', '192.168.1.3', ST_GeomFromText('POINT(40.712776 -74.005974)'), 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Mobile/15E148 Safari/604.1', 3), - (5, 'bob.davis@example.com', 'signup', '192.168.1.4', ST_GeomFromText('POINT(34.052235 -118.243683)'), 'Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36', 4); + (1, 2, CURRENT_TIMESTAMP), + (1, 3, CURRENT_TIMESTAMP), + (2, 3, CURRENT_TIMESTAMP), + (3, 4, CURRENT_TIMESTAMP), + (4, 5, CURRENT_TIMESTAMP), + (5, 6, CURRENT_TIMESTAMP), + (6, 7, CURRENT_TIMESTAMP), + (7, 8, CURRENT_TIMESTAMP), + (8, 9, CURRENT_TIMESTAMP), + (9, 10, CURRENT_TIMESTAMP); INSERT INTO identity.TrustedDevices (user_id, device_id, name, kind, `usage`, used_last, created_at) -VALUES (1, 1, 'Dell perso', 'desktop', 'perso', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), - (2, 2, 'John\'s Laptop', 'desktop', 'perso', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), - (3, 3, 'Jane\'s MacBook', 'desktop', 'pro', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), - (4, 4, 'Alice\'s iPhone', 'phone', 'perso', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), - (5, 5, 'Bob\'s Pixel', 'phone', 'pro', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +VALUES (1, 1, 'John\'s Windows PC', 'desktop', 'perso', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + (1, 2, 'John\'s MacBook Pro', 'desktop', 'pro', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + (3, 4, 'James\' Android Phone', 'phone', 'perso', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + (4, 5, 'Bruce\'s iPad', 'tablet', 'pro', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); + +INSERT INTO identity.AuthLogs (user_id, email, event, ip, ip_location, user_agent, device_id, created_at) +VALUES (1, 'johndoe@example.com', 'signup', '192.168.1.10', ST_GeomFromText('POINT(48.8588443 2.2943506)'), 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36', 1, CURRENT_TIMESTAMP - INTERVAL 30 DAY), + (2, 'janedoe@example.com', 'signup', '172.16.0.15', ST_GeomFromText('POINT(51.507351 -0.127758)'), 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1', 3, CURRENT_TIMESTAMP - INTERVAL 30 DAY), + (1, 'johndoe@example.com', 'login_success', '192.168.1.10', NULL, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36', 1, CURRENT_TIMESTAMP - INTERVAL 29 DAY), + (2, 'janedoe@example.com', 'login_success', '172.16.0.15', NULL, 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1', 3, CURRENT_TIMESTAMP - INTERVAL 29 DAY), + (1, 'johndoe@example.com', 'login_failure', '192.168.1.11', NULL, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Safari/605.1.15', 2, CURRENT_TIMESTAMP - INTERVAL 20 DAY), + (1, 'johndoe@example.com', 'login_success', '192.168.1.11', NULL, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Safari/605.1.15', 2, CURRENT_TIMESTAMP - INTERVAL 20 DAY), + (2, 'janedoe@example.com', 'login_failure', '172.16.0.16', NULL, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36', 1, CURRENT_TIMESTAMP - INTERVAL 20 DAY), + (2, 'janedoe@example.com', 'login_success', '172.16.0.16', NULL, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36', 1, CURRENT_TIMESTAMP - INTERVAL 20 DAY), + (1, 'johndoe@example.com', 'login_failure', '192.168.1.12', NULL, 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1', 3, CURRENT_TIMESTAMP - INTERVAL 10 DAY), + (1, 'johndoe@example.com', 'login_success', '192.168.1.12', NULL, 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1', 3, CURRENT_TIMESTAMP - INTERVAL 10 DAY), + (2, 'janedoe@example.com', 'password_reset_asked', '172.16.0.15', NULL, 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1', 3, CURRENT_TIMESTAMP - INTERVAL 10 DAY), + (2, 'janedoe@example.com', 'password_reset_used', '172.16.0.15', NULL, 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1', 3, CURRENT_TIMESTAMP - INTERVAL 9 DAY), + (1, 'johndoe@example.com', 'password_reset_asked', '192.168.1.10', NULL, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36', 1, CURRENT_TIMESTAMP - INTERVAL 5 DAY), + (2, 'janedoe@example.com', 'login_success', '172.16.0.16', NULL, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36', 1, CURRENT_TIMESTAMP - INTERVAL 5 DAY), + (1, 'johndoe@example.com', 'password_reset_used', '192.168.1.10', NULL, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36', 1, CURRENT_TIMESTAMP - INTERVAL 4 DAY), + (1, 'johndoe@example.com', 'login_success', '192.168.1.10', NULL, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36', 1, CURRENT_TIMESTAMP - INTERVAL 1 DAY), + (2, 'janedoe@example.com', 'login_success', '172.16.0.15', NULL, 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1', 3, CURRENT_TIMESTAMP - INTERVAL 1 DAY); diff --git a/libs/connector-sqlserver/src/sqlserver.test.ts b/libs/connector-sqlserver/src/sqlserver.test.ts index e8c42a91a..7af535a1d 100644 --- a/libs/connector-sqlserver/src/sqlserver.test.ts +++ b/libs/connector-sqlserver/src/sqlserver.test.ts @@ -1,7 +1,7 @@ import {describe, expect, test} from "@jest/globals"; import {ConnectorSchemaOpts, DatabaseUrlParsed, parseDatabaseUrl} from "@azimutt/models"; import {connect} from "./connect"; -import {getSchema} from "./sqlserver"; +import {getComments, getSchema} from "./sqlserver"; import {application, logger} from "./constants.test"; describe('sqlserver', () => { @@ -14,4 +14,9 @@ describe('sqlserver', () => { console.log('schema', schema) expect(schema.entities?.length).toEqual(13) }) + test.skip('getComments', async () => { + const comments = await connect(application, url, getComments(opts), opts) + console.log(`${comments.length} comments`, comments) + expect(comments.length).toEqual(4) + }) }) diff --git a/libs/connector-sqlserver/src/sqlserver.ts b/libs/connector-sqlserver/src/sqlserver.ts index bfed3d27e..56e9204fa 100644 --- a/libs/connector-sqlserver/src/sqlserver.ts +++ b/libs/connector-sqlserver/src/sqlserver.ts @@ -124,8 +124,7 @@ const getColumns = (opts: ConnectorSchemaOpts) => async (conn: Conn): Promise async (conn: Conn): Promi , ic.key_ordinal as column_index FROM sys.indexes i JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id - WHERE ${scopeWhere({schema: 'OBJECT_SCHEMA_NAME(i.object_id)', entity: 'OBJECT_NAME(i.object_id)'}, opts)} - ORDER BY table_schema, table_name, constraint_name;`, [], 'getIndexColumns' + WHERE ${scopeWhere({schema: 'OBJECT_SCHEMA_NAME(i.object_id)', entity: 'OBJECT_NAME(i.object_id)'}, opts)};`, [], 'getIndexColumns' ).catch(handleError(`Failed to get index columns (pks, uniques & indexes)`, [], opts)) } @@ -240,8 +238,7 @@ const getChecks = (opts: ConnectorSchemaOpts) => async (conn: Conn): Promise async (conn: Conn): Promise => { +export const getComments = (opts: ConnectorSchemaOpts) => async (conn: Conn): Promise => { // https://learn.microsoft.com/sql/relational-databases/system-catalog-views/extended-properties-catalog-views-sys-extended-properties // https://learn.microsoft.com/sql/relational-databases/system-catalog-views/sys-objects-transact-sql - // https://learn.microsoft.com/sql/relational-databases/system-compatibility-views/sys-sysusers-transact-sql + // https://learn.microsoft.com/sql/relational-databases/system-catalog-views/schemas-catalog-views-sys-schemas?view=sql-server-ver16 // https://learn.microsoft.com/sql/relational-databases/system-catalog-views/sys-columns-transact-sql return conn.query(` SELECT s.name AS table_schema @@ -281,14 +278,13 @@ const getComments = (opts: ConnectorSchemaOpts) => async (conn: Conn): Promise async (conn: Conn): JOIN sys.tables tab2 ON tab2.object_id = fkc.referenced_object_id JOIN sys.schemas sch2 ON tab2.schema_id = sch2.schema_id JOIN sys.columns col2 ON col2.column_id = referenced_column_id AND col2.object_id = tab2.object_id - WHERE ${scopeWhere({schema: 'sch1.name', entity: 'tab1.name'}, opts)} - ORDER BY src_schema, src_table, src_column;`, [], 'getForeignKeyColumns' + WHERE ${scopeWhere({schema: 'sch1.name', entity: 'tab1.name'}, opts)};`, [], 'getForeignKeyColumns' ).catch(handleError(`Failed to get foreign keys`, [], opts)) } From e12dbef88b6347f212ef1261f9b68939fa5273fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Knuchel?= Date: Tue, 20 Aug 2024 17:09:57 +0200 Subject: [PATCH 10/16] Add db comments --- demos/ecommerce/source_00_design.md | 8 +- .../source_01_referential_sqlserver.sql | 9 +- .../ecommerce/source_02_identity_mariadb.sql | 21 +-- .../ecommerce/source_03_inventory_oracle.sql | 176 +++++++----------- .../ecommerce/source_04_catalog_postgres.sql | 55 ++---- .../ecommerce/source_05_shopping_postgres.sql | 23 +-- .../ecommerce/source_06_billing_sqlserver.sql | 21 +-- demos/ecommerce/source_08_crm_mysql.sql | 41 ++-- demos/ecommerce/source_09_analytics_mongo.sql | 24 +-- 9 files changed, 146 insertions(+), 232 deletions(-) diff --git a/demos/ecommerce/source_00_design.md b/demos/ecommerce/source_00_design.md index a3152051f..15b651d0a 100644 --- a/demos/ecommerce/source_00_design.md +++ b/demos/ecommerce/source_00_design.md @@ -207,10 +207,10 @@ C##INVENTORY.PRODUCTS BRAND BIGINT nullable fk C##INVENTORY.BRANDS.ID CATEGORY VARCHAR nullable | ex: "Phones" SUBCATEGORY VARCHAR nullable | ex: "Smartphones" - WIDTH FLOAT | typical width of the product, see PRODUCTS for the real one - LENGTH FLOAT | typical length of the product, see PRODUCTS for the real one - HEIGHT FLOAT | typical height of the product, see PRODUCTS for the real one - WEIGHT FLOAT | typical weight of the product, see PRODUCTS for the real one + WIDTH FLOAT | typical width of the product, see PRODUCT_VERSIONS for the real one + LENGTH FLOAT | typical length of the product, see PRODUCT_VERSIONS for the real one + HEIGHT FLOAT | typical height of the product, see PRODUCT_VERSIONS for the real one + WEIGHT FLOAT | typical weight of the product, see PRODUCT_VERSIONS for the real one REMARKS TEXT nullable | ex: fragile CREATED_AT TIMESTAMP UPDATED_AT TIMESTAMP diff --git a/demos/ecommerce/source_01_referential_sqlserver.sql b/demos/ecommerce/source_01_referential_sqlserver.sql index 38522469d..a1a38cf34 100644 --- a/demos/ecommerce/source_01_referential_sqlserver.sql +++ b/demos/ecommerce/source_01_referential_sqlserver.sql @@ -8,8 +8,7 @@ USE Referential; CREATE SCHEMA [referential]; -CREATE TABLE [referential].[Countries] -( +CREATE TABLE [referential].[Countries] ( [CountryId] [bigint] IDENTITY (1,1) PRIMARY KEY, [Code] [nvarchar](5) NOT NULL, [Name] [nvarchar](255) NOT NULL, @@ -20,8 +19,7 @@ CREATE INDEX [IDX_Countries_Code] ON [referential].[Countries] ([Code]); CREATE INDEX [IDX_Countries_Name] ON [referential].[Countries] ([Name]); EXEC sp_addextendedproperty 'MS_Description', 'needs to be referenced for legal reasons', 'SCHEMA', 'referential', 'TABLE', 'Countries'; -CREATE TABLE [referential].[States] -( +CREATE TABLE [referential].[States] ( [StateId] [bigint] IDENTITY (1,1) PRIMARY KEY, [CountryId] [bigint] NOT NULL, [Code] [nvarchar](5) NOT NULL, @@ -35,8 +33,7 @@ CREATE INDEX [IDX_States_Code] ON [referential].[States] ([Code]); CREATE INDEX [IDX_States_Name] ON [referential].[States] ([Name]); EXEC sp_addextendedproperty 'MS_Description', 'used for auto-competes', 'SCHEMA', 'referential', 'TABLE', 'States'; -CREATE TABLE [referential].[Cities] -( +CREATE TABLE [referential].[Cities] ( [CityId] [bigint] IDENTITY (1,1) PRIMARY KEY, [StateId] [bigint] NOT NULL, [Name] [nvarchar](255) NOT NULL, diff --git a/demos/ecommerce/source_02_identity_mariadb.sql b/demos/ecommerce/source_02_identity_mariadb.sql index 4f065bb0b..062c7838b 100644 --- a/demos/ecommerce/source_02_identity_mariadb.sql +++ b/demos/ecommerce/source_02_identity_mariadb.sql @@ -6,8 +6,7 @@ CREATE DATABASE identity; USE identity; -CREATE TABLE identity.Users -( +CREATE TABLE identity.Users ( id BIGINT PRIMARY KEY AUTO_INCREMENT, first_name VARCHAR(255) NOT NULL, last_name VARCHAR(255) NOT NULL, @@ -21,8 +20,7 @@ CREATE TABLE identity.Users INDEX idx_deleted_at (deleted_at) ); -CREATE TABLE identity.Credentials -( +CREATE TABLE identity.Credentials ( user_id BIGINT NOT NULL REFERENCES identity.Users (id), provider ENUM ('password', 'google', 'linkedin', 'facebook', 'twitter') NOT NULL COMMENT 'the used provider', provider_id VARCHAR(255) NOT NULL COMMENT 'the user id from the provider, in case of password, stores the hashed password with the salt', @@ -34,8 +32,7 @@ CREATE TABLE identity.Credentials PRIMARY KEY (user_id, provider, provider_id) ); -CREATE TABLE identity.PasswordResets -( +CREATE TABLE identity.PasswordResets ( id BIGINT PRIMARY KEY AUTO_INCREMENT, email VARCHAR(255) NOT NULL, token VARCHAR(255) NOT NULL COMMENT 'the key sent by email to allow to change the password without being logged', @@ -46,16 +43,14 @@ CREATE TABLE identity.PasswordResets INDEX idx_token (token) ); -CREATE TABLE identity.Devices -( +CREATE TABLE identity.Devices ( id BIGINT PRIMARY KEY AUTO_INCREMENT, sid CHAR(36) NOT NULL UNIQUE COMMENT 'a unique id stored in the browser to track it when not logged', user_agent VARCHAR(255) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'first time this device is seen' ) COMMENT 'a device is a browser tagged by a random id in its session'; -CREATE TABLE identity.UserDevices -( +CREATE TABLE identity.UserDevices ( user_id BIGINT NOT NULL REFERENCES identity.Users (id), device_id BIGINT NOT NULL REFERENCES identity.Devices (id), linked_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'on login', @@ -63,8 +58,7 @@ CREATE TABLE identity.UserDevices PRIMARY KEY (user_id, device_id) ) COMMENT 'created on user login to know which users are using which devices'; -CREATE TABLE identity.TrustedDevices -( +CREATE TABLE identity.TrustedDevices ( user_id BIGINT NOT NULL REFERENCES identity.Users (id), device_id BIGINT NOT NULL REFERENCES identity.Devices (id), name VARCHAR(255), @@ -77,8 +71,7 @@ CREATE TABLE identity.TrustedDevices INDEX idx_deleted_at (deleted_at) ) COMMENT 'users can add a device to their trusted ones, so they will have longer session and less security validations'; -CREATE TABLE identity.AuthLogs -( +CREATE TABLE identity.AuthLogs ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT REFERENCES identity.Users (id), email VARCHAR(255), diff --git a/demos/ecommerce/source_03_inventory_oracle.sql b/demos/ecommerce/source_03_inventory_oracle.sql index 4a27c8b7c..7b5086d33 100644 --- a/demos/ecommerce/source_03_inventory_oracle.sql +++ b/demos/ecommerce/source_03_inventory_oracle.sql @@ -9,9 +9,7 @@ CREATE ROLE C##INVENTORY_ROLE; GRANT CREATE SESSION, CREATE TABLE, CREATE SEQUENCE, CREATE VIEW, CREATE MATERIALIZED VIEW, CREATE TYPE, CREATE TRIGGER to C##inventory_role; GRANT C##INVENTORY_ROLE TO C##INVENTORY; - -CREATE TABLE C##INVENTORY.EMPLOYEES -( +CREATE TABLE C##INVENTORY.EMPLOYEES ( ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, FIRST_NAME VARCHAR2(255), LAST_NAME VARCHAR2(255), @@ -24,13 +22,11 @@ CREATE TABLE C##INVENTORY.EMPLOYEES DELETED_AT TIMESTAMP, DELETED_BY NUMBER ); - CREATE INDEX IDX_EMPLOYEES_NAME ON C##INVENTORY.EMPLOYEES (FIRST_NAME, LAST_NAME); CREATE INDEX IDX_EMPLOYEES_EMAIL ON C##INVENTORY.EMPLOYEES (EMAIL); CREATE INDEX IDX_EMPLOYEES_DELETED_AT ON C##INVENTORY.EMPLOYEES (DELETED_AT); -CREATE TABLE C##INVENTORY.WAREHOUSES -( +CREATE TABLE C##INVENTORY.WAREHOUSES ( ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, NAME VARCHAR2(255) UNIQUE, ADDRESS CLOB, @@ -42,11 +38,9 @@ CREATE TABLE C##INVENTORY.WAREHOUSES DELETED_AT TIMESTAMP, DELETED_BY NUMBER ); - CREATE INDEX IDX_WAREHOUSES_DELETED_AT ON C##INVENTORY.WAREHOUSES (DELETED_AT); -CREATE TABLE C##INVENTORY.HALLS -( +CREATE TABLE C##INVENTORY.HALLS ( ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, WAREHOUSE_ID NUMBER REFERENCES C##INVENTORY.WAREHOUSES (ID), NAME VARCHAR2(255), @@ -58,11 +52,9 @@ CREATE TABLE C##INVENTORY.HALLS DELETED_AT TIMESTAMP, DELETED_BY NUMBER ); - CREATE INDEX IDX_HALLS_DELETED_AT ON C##INVENTORY.HALLS (DELETED_AT); -CREATE TABLE C##INVENTORY.AISLES -( +CREATE TABLE C##INVENTORY.AISLES ( ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, HALL_ID NUMBER REFERENCES C##INVENTORY.HALLS (ID), NAME VARCHAR2(255), @@ -74,11 +66,9 @@ CREATE TABLE C##INVENTORY.AISLES DELETED_AT TIMESTAMP, DELETED_BY NUMBER ); - CREATE INDEX IDX_AISLES_DELETED_AT ON C##INVENTORY.AISLES (DELETED_AT); -CREATE TABLE C##INVENTORY.RACKS -( +CREATE TABLE C##INVENTORY.RACKS ( ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, AISLE_ID NUMBER REFERENCES C##INVENTORY.AISLES (ID), NAME VARCHAR2(255), @@ -89,11 +79,9 @@ CREATE TABLE C##INVENTORY.RACKS DELETED_AT TIMESTAMP, DELETED_BY NUMBER ); - CREATE INDEX IDX_RACKS_DELETED_AT ON C##INVENTORY.RACKS (DELETED_AT); -CREATE TABLE C##INVENTORY.SHELVES -( +CREATE TABLE C##INVENTORY.SHELVES ( ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, RACK_ID NUMBER REFERENCES C##INVENTORY.RACKS (ID), NAME VARCHAR2(255), @@ -104,11 +92,9 @@ CREATE TABLE C##INVENTORY.SHELVES DELETED_AT TIMESTAMP, DELETED_BY NUMBER ); - CREATE INDEX IDX_SHELVES_DELETED_AT ON C##INVENTORY.SHELVES (DELETED_AT); -CREATE TABLE C##INVENTORY.SHELF_POSITIONS -( +CREATE TABLE C##INVENTORY.SHELF_POSITIONS ( ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, SHELF_ID NUMBER REFERENCES C##INVENTORY.SHELVES (ID), NAME VARCHAR2(255), @@ -119,13 +105,11 @@ CREATE TABLE C##INVENTORY.SHELF_POSITIONS DELETED_AT TIMESTAMP, DELETED_BY NUMBER ); - CREATE INDEX IDX_SHELF_POSITIONS_DELETED_AT ON C##INVENTORY.SHELF_POSITIONS (DELETED_AT); -CREATE TABLE C##INVENTORY.WAREHOUSE_EMPLOYEES -( - WAREHOUSE_ID NUMBER, - EMPLOYEE_ID NUMBER, +CREATE TABLE C##INVENTORY.WAREHOUSE_EMPLOYEES ( + WAREHOUSE_ID NUMBER REFERENCES C##INVENTORY.WAREHOUSES (ID), + EMPLOYEE_ID NUMBER REFERENCES C##INVENTORY.EMPLOYEES (ID), ROLE VARCHAR2(255), "START" TIMESTAMP, END TIMESTAMP, @@ -135,29 +119,23 @@ CREATE TABLE C##INVENTORY.WAREHOUSE_EMPLOYEES UPDATED_BY NUMBER, DELETED_AT TIMESTAMP, DELETED_BY NUMBER, - PRIMARY KEY (WAREHOUSE_ID, EMPLOYEE_ID), - FOREIGN KEY (WAREHOUSE_ID) REFERENCES C##INVENTORY.WAREHOUSES (ID), - FOREIGN KEY (EMPLOYEE_ID) REFERENCES C##INVENTORY.EMPLOYEES (ID) + PRIMARY KEY (WAREHOUSE_ID, EMPLOYEE_ID) ); - CREATE INDEX IDX_WAREHOUSE_EMPLOYEES_DELETED_AT ON C##INVENTORY.WAREHOUSE_EMPLOYEES (DELETED_AT); -CREATE TABLE C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS -( - WAREHOUSE_ID NUMBER, - EMPLOYEES_ID NUMBER, +CREATE TABLE C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS ( + WAREHOUSE_ID NUMBER REFERENCES C##INVENTORY.WAREHOUSES (ID), + EMPLOYEES_ID NUMBER REFERENCES C##INVENTORY.EMPLOYEES (ID), KIND VARCHAR2(255), VALUE VARCHAR2(255), EXPIRE TIMESTAMP, CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, CREATED_BY NUMBER, - PRIMARY KEY (WAREHOUSE_ID, EMPLOYEES_ID, KIND), - FOREIGN KEY (WAREHOUSE_ID) REFERENCES C##INVENTORY.WAREHOUSES (ID), - FOREIGN KEY (EMPLOYEES_ID) REFERENCES C##INVENTORY.EMPLOYEES (ID) + PRIMARY KEY (WAREHOUSE_ID, EMPLOYEES_ID, KIND) ); +COMMENT ON TABLE C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS IS 'how to check the employee is identified, can be several'; -CREATE TABLE C##INVENTORY.BRANDS -( +CREATE TABLE C##INVENTORY.BRANDS ( ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, SLUG VARCHAR2(255) UNIQUE, NAME VARCHAR2(255) UNIQUE, @@ -165,11 +143,11 @@ CREATE TABLE C##INVENTORY.BRANDS UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, DELETED_AT TIMESTAMP ); - CREATE INDEX IDX_BRANDS_DELETED_AT ON C##INVENTORY.BRANDS (DELETED_AT); +COMMENT ON COLUMN C##INVENTORY.BRANDS.SLUG IS 'ex: "google"'; +COMMENT ON COLUMN C##INVENTORY.BRANDS.NAME IS 'ex: "Google"'; -CREATE TABLE C##INVENTORY.PRODUCTS -( +CREATE TABLE C##INVENTORY.PRODUCTS ( ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, SLUG VARCHAR2(255) UNIQUE, NAME VARCHAR2(255) UNIQUE, @@ -185,11 +163,18 @@ CREATE TABLE C##INVENTORY.PRODUCTS UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, DELETED_AT TIMESTAMP ); - CREATE INDEX IDX_PRODUCTS_DELETED_AT ON C##INVENTORY.PRODUCTS (DELETED_AT); - -CREATE TABLE C##INVENTORY.PRODUCT_VERSIONS -( +COMMENT ON COLUMN C##INVENTORY.PRODUCTS.SLUG IS 'ex: "pixel-8-pro"'; +COMMENT ON COLUMN C##INVENTORY.PRODUCTS.NAME IS 'ex: "Pixel 8 Pro"'; +COMMENT ON COLUMN C##INVENTORY.PRODUCTS.CATEGORY IS 'ex: "Phones"'; +COMMENT ON COLUMN C##INVENTORY.PRODUCTS.SUBCATEGORY IS 'ex: "Smartphones"'; +COMMENT ON COLUMN C##INVENTORY.PRODUCTS.WIDTH IS 'typical width of the product, see PRODUCT_VERSIONS for the real one'; +COMMENT ON COLUMN C##INVENTORY.PRODUCTS.LENGTH IS 'typical length of the product, see PRODUCT_VERSIONS for the real one'; +COMMENT ON COLUMN C##INVENTORY.PRODUCTS.HEIGHT IS 'typical height of the product, see PRODUCT_VERSIONS for the real one'; +COMMENT ON COLUMN C##INVENTORY.PRODUCTS.WEIGHT IS 'typical weight of the product, see PRODUCT_VERSIONS for the real one'; +COMMENT ON COLUMN C##INVENTORY.PRODUCTS.REMARKS IS 'ex: fragile'; + +CREATE TABLE C##INVENTORY.PRODUCT_VERSIONS ( ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, PRODUCT_ID NUMBER REFERENCES C##INVENTORY.PRODUCTS (ID), SKU VARCHAR2(12) UNIQUE, @@ -205,11 +190,13 @@ CREATE TABLE C##INVENTORY.PRODUCT_VERSIONS UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, DELETED_AT TIMESTAMP ); - CREATE INDEX IDX_PRODUCT_VERSIONS_DELETED_AT ON C##INVENTORY.PRODUCT_VERSIONS (DELETED_AT); +COMMENT ON COLUMN C##INVENTORY.PRODUCT_VERSIONS.SKU IS 'internal id'; +COMMENT ON COLUMN C##INVENTORY.PRODUCT_VERSIONS.EAN IS 'european id'; +COMMENT ON COLUMN C##INVENTORY.PRODUCT_VERSIONS.NAME IS 'ex: "Pixel 8 Pro Menthe 128 Go"'; +COMMENT ON COLUMN C##INVENTORY.PRODUCT_VERSIONS.SPECS IS 'specificities of this version, ex: `{color: "Menthe", storage: 128}`'; -CREATE TABLE C##INVENTORY.PHYSICAL_PRODUCTS -( +CREATE TABLE C##INVENTORY.PHYSICAL_PRODUCTS ( ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, PRODUCT_VERSION_ID NUMBER REFERENCES C##INVENTORY.PRODUCT_VERSIONS (ID), SNID VARCHAR2(12) UNIQUE, @@ -220,11 +207,11 @@ CREATE TABLE C##INVENTORY.PHYSICAL_PRODUCTS UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, DELETED_AT TIMESTAMP ); - CREATE INDEX IDX_PHYSICAL_PRODUCTS_DELETED_AT ON C##INVENTORY.PHYSICAL_PRODUCTS (DELETED_AT); +COMMENT ON COLUMN C##INVENTORY.PHYSICAL_PRODUCTS.SNID IS 'serial number of this product'; +COMMENT ON COLUMN C##INVENTORY.PHYSICAL_PRODUCTS.EXPIRATION IS 'when Product has an expiration date, null otherwise'; -CREATE TABLE C##INVENTORY.SUPPLIERS -( +CREATE TABLE C##INVENTORY.SUPPLIERS ( ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, NAME VARCHAR2(255), "LEVEL" NUMBER, @@ -233,29 +220,24 @@ CREATE TABLE C##INVENTORY.SUPPLIERS UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, DELETED_AT TIMESTAMP ); - CREATE INDEX IDX_SUPPLIERS_NAME ON C##INVENTORY.SUPPLIERS (NAME); CREATE INDEX IDX_SUPPLIERS_DELETED_AT ON C##INVENTORY.SUPPLIERS (DELETED_AT); +COMMENT ON COLUMN C##INVENTORY.SUPPLIERS.LEVEL IS 'the lower, the more priority is given to this supplier'; -CREATE TABLE C##INVENTORY.SUPPLIER_PRICES -( - SUPPLIER_ID NUMBER, - PRODUCT_VERSION_ID NUMBER, +CREATE TABLE C##INVENTORY.SUPPLIER_PRICES ( + SUPPLIER_ID NUMBER REFERENCES C##INVENTORY.SUPPLIERS (ID), + PRODUCT_VERSION_ID NUMBER REFERENCES C##INVENTORY.PRODUCT_VERSIONS (ID), PRICE FLOAT, CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, DELETED_AT TIMESTAMP, - PRIMARY KEY (SUPPLIER_ID, PRODUCT_VERSION_ID), - FOREIGN KEY (SUPPLIER_ID) REFERENCES C##INVENTORY.SUPPLIERS (ID), - FOREIGN KEY (PRODUCT_VERSION_ID) REFERENCES C##INVENTORY.PRODUCT_VERSIONS (ID) + PRIMARY KEY (SUPPLIER_ID, PRODUCT_VERSION_ID) ); - CREATE INDEX IDX_SUPPLIER_PRICES_DELETED_AT ON C##INVENTORY.SUPPLIER_PRICES (DELETED_AT); -CREATE TABLE C##INVENTORY.SUPPLIER_EMPLOYEES -( - SUPPLIER_ID NUMBER, - EMPLOYEE_ID NUMBER, +CREATE TABLE C##INVENTORY.SUPPLIER_EMPLOYEES ( + SUPPLIER_ID NUMBER REFERENCES C##INVENTORY.SUPPLIERS (ID), + EMPLOYEE_ID NUMBER REFERENCES C##INVENTORY.EMPLOYEES (ID), ROLE VARCHAR2(255), "START" TIMESTAMP, END TIMESTAMP, @@ -265,15 +247,11 @@ CREATE TABLE C##INVENTORY.SUPPLIER_EMPLOYEES UPDATED_BY NUMBER, DELETED_AT TIMESTAMP, DELETED_BY NUMBER, - PRIMARY KEY (SUPPLIER_ID, EMPLOYEE_ID), - FOREIGN KEY (SUPPLIER_ID) REFERENCES C##INVENTORY.SUPPLIERS (ID), - FOREIGN KEY (EMPLOYEE_ID) REFERENCES C##INVENTORY.EMPLOYEES (ID) + PRIMARY KEY (SUPPLIER_ID, EMPLOYEE_ID) ); - CREATE INDEX IDX_SUPPLIER_EMPLOYEES_DELETED_AT ON C##INVENTORY.SUPPLIER_EMPLOYEES (DELETED_AT); -CREATE TABLE C##INVENTORY.PURCHASE_ORDERS -( +CREATE TABLE C##INVENTORY.PURCHASE_ORDERS ( ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, SUPPLIER_ID NUMBER REFERENCES C##INVENTORY.SUPPLIERS (ID), PRICE FLOAT, @@ -291,24 +269,24 @@ CREATE TABLE C##INVENTORY.PURCHASE_ORDERS VALIDATED_AT TIMESTAMP, VALIDATED_BY NUMBER ); +COMMENT ON COLUMN C##INVENTORY.PURCHASE_ORDERS.PRICE IS 'total price, computed from items price x quantity'; +COMMENT ON COLUMN C##INVENTORY.PURCHASE_ORDERS.DETAILS IS 'additional text for the supplier'; +COMMENT ON COLUMN C##INVENTORY.PURCHASE_ORDERS.NOTES IS 'internal text for employees'; +COMMENT ON COLUMN C##INVENTORY.PURCHASE_ORDERS.SENT_AT IS 'can''t be updated once sent'; -CREATE TABLE C##INVENTORY.PURCHASE_ORDER_ITEMS -( - PURCHASE_ORDER_ID NUMBER, - PRODUCT_VERSION_ID NUMBER, +CREATE TABLE C##INVENTORY.PURCHASE_ORDER_ITEMS ( + PURCHASE_ORDER_ID NUMBER REFERENCES C##INVENTORY.PURCHASE_ORDERS (ID), + PRODUCT_VERSION_ID NUMBER REFERENCES C##INVENTORY.PRODUCT_VERSIONS (ID), QUANTITY NUMBER, PRICE FLOAT, CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, CREATED_BY NUMBER, UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UPDATED_BY NUMBER, - PRIMARY KEY (PURCHASE_ORDER_ID, PRODUCT_VERSION_ID), - FOREIGN KEY (PURCHASE_ORDER_ID) REFERENCES C##INVENTORY.PURCHASE_ORDERS (ID), - FOREIGN KEY (PRODUCT_VERSION_ID) REFERENCES C##INVENTORY.PRODUCT_VERSIONS (ID) + PRIMARY KEY (PURCHASE_ORDER_ID, PRODUCT_VERSION_ID) ); -CREATE TABLE C##INVENTORY.DELIVERIES -( +CREATE TABLE C##INVENTORY.DELIVERIES ( ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, REASON VARCHAR2(255), ACCEPTED CHAR(1) CHECK (ACCEPTED IN ('Y', 'N')), @@ -322,17 +300,13 @@ CREATE TABLE C##INVENTORY.DELIVERIES FOREIGN KEY (SUPPLIER_ID, SUPPLIER_EMPLOYEE_ID) REFERENCES C##INVENTORY.SUPPLIER_EMPLOYEES (SUPPLIER_ID, EMPLOYEE_ID) ); -CREATE TABLE C##INVENTORY.DELIVERY_ITEMS -( - DELIVERY_ID NUMBER, - PHYSICAL_PRODUCT_ID NUMBER, - PRIMARY KEY (DELIVERY_ID, PHYSICAL_PRODUCT_ID), - FOREIGN KEY (DELIVERY_ID) REFERENCES C##INVENTORY.DELIVERIES (ID), - FOREIGN KEY (PHYSICAL_PRODUCT_ID) REFERENCES C##INVENTORY.PHYSICAL_PRODUCTS (ID) +CREATE TABLE C##INVENTORY.DELIVERY_ITEMS ( + DELIVERY_ID NUMBER REFERENCES C##INVENTORY.DELIVERIES (ID), + PHYSICAL_PRODUCT_ID NUMBER REFERENCES C##INVENTORY.PHYSICAL_PRODUCTS (ID), + PRIMARY KEY (DELIVERY_ID, PHYSICAL_PRODUCT_ID) ); -CREATE TABLE C##INVENTORY.PICKUPS -( +CREATE TABLE C##INVENTORY.PICKUPS ( ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, REASON VARCHAR2(255), ACCEPTED CHAR(1) CHECK (ACCEPTED IN ('Y', 'N')), @@ -345,17 +319,13 @@ CREATE TABLE C##INVENTORY.PICKUPS FOREIGN KEY (SUPPLIER_ID, SUPPLIER_EMPLOYEE_ID) REFERENCES C##INVENTORY.SUPPLIER_EMPLOYEES (SUPPLIER_ID, EMPLOYEE_ID) ); -CREATE TABLE C##INVENTORY.PICKUP_ITEMS -( - PICKUP_ID NUMBER, - PHYSICAL_PRODUCT_ID NUMBER, - PRIMARY KEY (PICKUP_ID, PHYSICAL_PRODUCT_ID), - FOREIGN KEY (PICKUP_ID) REFERENCES C##INVENTORY.PICKUPS (ID), - FOREIGN KEY (PHYSICAL_PRODUCT_ID) REFERENCES C##INVENTORY.PHYSICAL_PRODUCTS (ID) +CREATE TABLE C##INVENTORY.PICKUP_ITEMS ( + PICKUP_ID NUMBER REFERENCES C##INVENTORY.PICKUPS (ID), + PHYSICAL_PRODUCT_ID NUMBER REFERENCES C##INVENTORY.PHYSICAL_PRODUCTS (ID), + PRIMARY KEY (PICKUP_ID, PHYSICAL_PRODUCT_ID) ); -CREATE TABLE C##INVENTORY.INVENTORIES -( +CREATE TABLE C##INVENTORY.INVENTORIES ( ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, NAME VARCHAR2(255), WAREHOUSE_ID NUMBER REFERENCES C##INVENTORY.WAREHOUSES (ID), @@ -369,18 +339,15 @@ CREATE TABLE C##INVENTORY.INVENTORIES UPDATED_BY NUMBER ); -CREATE TABLE C##INVENTORY.INVENTORY_MEMBERS -( - INVENTORY_ID NUMBER, +CREATE TABLE C##INVENTORY.INVENTORY_MEMBERS ( + INVENTORY_ID NUMBER REFERENCES C##INVENTORY.INVENTORIES (ID), WAREHOUSE_ID NUMBER, EMPLOYEE_ID NUMBER, PRIMARY KEY (INVENTORY_ID, WAREHOUSE_ID, EMPLOYEE_ID), - FOREIGN KEY (INVENTORY_ID) REFERENCES C##INVENTORY.INVENTORIES (ID), FOREIGN KEY (WAREHOUSE_ID, EMPLOYEE_ID) REFERENCES C##INVENTORY.WAREHOUSE_EMPLOYEES (WAREHOUSE_ID, EMPLOYEE_ID) ); -CREATE TABLE C##INVENTORY.INVENTORY_OBSERVATIONS -( +CREATE TABLE C##INVENTORY.INVENTORY_OBSERVATIONS ( ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, INVENTORY_ID NUMBER REFERENCES C##INVENTORY.INVENTORIES (ID), PHYSICAL_PRODUCT_ID NUMBER REFERENCES C##INVENTORY.PHYSICAL_PRODUCTS (ID), @@ -393,7 +360,6 @@ CREATE TABLE C##INVENTORY.INVENTORY_OBSERVATIONS DELETED_AT TIMESTAMP, DELETED_BY NUMBER ); - CREATE INDEX IDX_INVENTORY_OBSERVATIONS_DELETED_AT ON C##INVENTORY.INVENTORY_OBSERVATIONS (DELETED_AT); diff --git a/demos/ecommerce/source_04_catalog_postgres.sql b/demos/ecommerce/source_04_catalog_postgres.sql index e11ba452d..7101a1686 100644 --- a/demos/ecommerce/source_04_catalog_postgres.sql +++ b/demos/ecommerce/source_04_catalog_postgres.sql @@ -4,8 +4,7 @@ CREATE SCHEMA catalog; -- create the database -CREATE TABLE catalog.categories -( +CREATE TABLE catalog.categories ( id BIGINT PRIMARY KEY, parent BIGINT REFERENCES catalog.categories (id), depth INT, @@ -17,11 +16,10 @@ CREATE TABLE catalog.categories updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, deleted_at TIMESTAMP ); - CREATE INDEX idx_categories_deleted_at ON catalog.categories (deleted_at); +COMMENT ON COLUMN catalog.categories.depth IS 'easily accessible information of number of parents'; -CREATE TABLE catalog.products -( +CREATE TABLE catalog.products ( id BIGINT PRIMARY KEY, slug VARCHAR(255) UNIQUE, name VARCHAR(255), @@ -35,11 +33,13 @@ CREATE TABLE catalog.products updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, deleted_at TIMESTAMP ); - CREATE INDEX idx_products_deleted_at ON catalog.products (deleted_at); +COMMENT ON COLUMN catalog.products.description IS 'TODO: handle i18n'; +COMMENT ON COLUMN catalog.products.versions IS 'ex: `[{key: "color", label: "Couleur", values: [{name: "Bleu Azur", value: "#95bbe2"}]}, {key: "storage", name: "Taille", values: [{name: "128GB", value: 128}]}]`'; +COMMENT ON COLUMN catalog.products.attributes IS 'ex: `[{key: "Marque", value: "Google"}]`'; +COMMENT ON COLUMN catalog.products.stock IS 'informative stock, may not be accurate'; -CREATE TABLE catalog.product_versions -( +CREATE TABLE catalog.product_versions ( id BIGINT PRIMARY KEY, product_id BIGINT REFERENCES catalog.products (id), name VARCHAR(255), @@ -50,11 +50,11 @@ CREATE TABLE catalog.product_versions updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, deleted_at TIMESTAMP ); - CREATE INDEX idx_product_versions_deleted_at ON catalog.product_versions (deleted_at); +COMMENT ON COLUMN catalog.product_versions.specs IS 'ex: `{color: "Bleu Azur", storage: 128}`'; +COMMENT ON COLUMN catalog.product_versions.stock IS 'informative stock, may not be accurate'; -CREATE TABLE catalog.product_cross_sell_options -( +CREATE TABLE catalog.product_cross_sell_options ( product_id BIGINT REFERENCES catalog.products (id), product_version_id BIGINT REFERENCES catalog.product_versions (id), label VARCHAR(255), @@ -63,11 +63,9 @@ CREATE TABLE catalog.product_cross_sell_options deleted_at TIMESTAMP, PRIMARY KEY (product_id, product_version_id) ); - CREATE INDEX idx_product_cross_sell_options_deleted_at ON catalog.product_cross_sell_options (deleted_at); -CREATE TABLE catalog.product_alternatives -( +CREATE TABLE catalog.product_alternatives ( product_id BIGINT REFERENCES catalog.products (id), alternative_product_id BIGINT REFERENCES catalog.products (id), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, @@ -75,11 +73,9 @@ CREATE TABLE catalog.product_alternatives deleted_at TIMESTAMP, PRIMARY KEY (product_id, alternative_product_id) ); - CREATE INDEX idx_product_alternatives_deleted_at ON catalog.product_alternatives (deleted_at); -CREATE TABLE catalog.assets -( +CREATE TABLE catalog.assets ( id BIGINT PRIMARY KEY, kind VARCHAR(50), format VARCHAR(10), @@ -93,11 +89,9 @@ CREATE TABLE catalog.assets updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, deleted_at TIMESTAMP ); - CREATE INDEX idx_assets_deleted_at ON catalog.assets (deleted_at); -CREATE TABLE catalog.category_assets -( +CREATE TABLE catalog.category_assets ( category_id BIGINT REFERENCES catalog.categories (id), asset_id BIGINT REFERENCES catalog.assets (id), placement VARCHAR(50), @@ -106,11 +100,9 @@ CREATE TABLE catalog.category_assets deleted_at TIMESTAMP, PRIMARY KEY (category_id, asset_id) ); - CREATE INDEX idx_category_assets_deleted_at ON catalog.category_assets (deleted_at); -CREATE TABLE catalog.product_assets -( +CREATE TABLE catalog.product_assets ( product_id BIGINT REFERENCES catalog.products (id), asset_id BIGINT REFERENCES catalog.assets (id), placement VARCHAR(50), @@ -119,11 +111,9 @@ CREATE TABLE catalog.product_assets deleted_at TIMESTAMP, PRIMARY KEY (product_id, asset_id) ); - CREATE INDEX idx_product_assets_deleted_at ON catalog.product_assets (deleted_at); -CREATE TABLE catalog.product_version_assets -( +CREATE TABLE catalog.product_version_assets ( product_version_id BIGINT REFERENCES catalog.product_versions (id), asset_id BIGINT REFERENCES catalog.assets (id), placement VARCHAR(50), @@ -132,11 +122,9 @@ CREATE TABLE catalog.product_version_assets deleted_at TIMESTAMP, PRIMARY KEY (product_version_id, asset_id) ); - CREATE INDEX idx_product_version_assets_deleted_at ON catalog.product_version_assets (deleted_at); -CREATE TABLE catalog.product_reviews -( +CREATE TABLE catalog.product_reviews ( id BIGINT PRIMARY KEY, product_id BIGINT REFERENCES catalog.products (id), product_version_id BIGINT REFERENCES catalog.product_versions (id), @@ -151,11 +139,9 @@ CREATE TABLE catalog.product_reviews deleted_at TIMESTAMP, deleted_by BIGINT ); - CREATE INDEX idx_product_reviews_deleted_at ON catalog.product_reviews (deleted_at); -CREATE TABLE catalog.product_review_assets -( +CREATE TABLE catalog.product_review_assets ( product_review_id BIGINT REFERENCES catalog.product_reviews (id), asset_id BIGINT REFERENCES catalog.assets (id), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, @@ -164,11 +150,9 @@ CREATE TABLE catalog.product_review_assets deleted_by BIGINT, PRIMARY KEY (product_review_id, asset_id) ); - CREATE INDEX idx_product_review_assets_deleted_at ON catalog.product_review_assets (deleted_at); -CREATE TABLE catalog.product_review_feedbacks -( +CREATE TABLE catalog.product_review_feedbacks ( product_review_id BIGINT REFERENCES catalog.product_reviews (id), kind VARCHAR(50), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, @@ -177,7 +161,6 @@ CREATE TABLE catalog.product_review_feedbacks deleted_by BIGINT, PRIMARY KEY (product_review_id, created_by, kind) ); - CREATE INDEX idx_product_review_feedbacks_deleted_at ON catalog.product_review_feedbacks (deleted_at); diff --git a/demos/ecommerce/source_05_shopping_postgres.sql b/demos/ecommerce/source_05_shopping_postgres.sql index 3a801dfc7..61d263377 100644 --- a/demos/ecommerce/source_05_shopping_postgres.sql +++ b/demos/ecommerce/source_05_shopping_postgres.sql @@ -4,8 +4,7 @@ CREATE SCHEMA shopping; -- create the database -CREATE TABLE shopping.carts -( +CREATE TABLE shopping.carts ( id BIGINT PRIMARY KEY, owner_kind VARCHAR(255), owner_id BIGINT, @@ -14,11 +13,10 @@ CREATE TABLE shopping.carts updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, deleted_at TIMESTAMP ); - CREATE INDEX idx_carts_deleted_at ON shopping.carts (deleted_at); +COMMENT ON COLUMN shopping.carts.owner_kind IS 'Devices are used for anonymous carts, otherwise it''s Users'; -CREATE TABLE shopping.cart_items -( +CREATE TABLE shopping.cart_items ( cart_id BIGINT REFERENCES shopping.carts (id), product_version_id BIGINT, quantity INT, @@ -31,11 +29,10 @@ CREATE TABLE shopping.cart_items deleted_by BIGINT, PRIMARY KEY (cart_id, product_version_id) ); - CREATE INDEX idx_cart_items_deleted_at ON shopping.cart_items (deleted_at); +COMMENT ON COLUMN shopping.cart_items.price IS 'at the time the product was added to the card, prevent price changes after a product has been added to a cart'; -CREATE TABLE shopping.wishlists -( +CREATE TABLE shopping.wishlists ( id BIGINT PRIMARY KEY, name VARCHAR(255), description TEXT, @@ -47,11 +44,9 @@ CREATE TABLE shopping.wishlists deleted_at TIMESTAMP, deleted_by BIGINT ); - CREATE INDEX idx_wishlists_deleted_at ON shopping.wishlists (deleted_at); -CREATE TABLE shopping.wishlist_items -( +CREATE TABLE shopping.wishlist_items ( wishlist_id BIGINT REFERENCES shopping.wishlists (id), product_id BIGINT, specs JSON, @@ -61,11 +56,10 @@ CREATE TABLE shopping.wishlist_items deleted_by BIGINT, PRIMARY KEY (wishlist_id, product_id) ); - CREATE INDEX idx_wishlist_items_deleted_at ON shopping.wishlist_items (deleted_at); +COMMENT ON COLUMN shopping.wishlist_items.specs IS 'if the user saved specific configuration'; -CREATE TABLE shopping.wishlist_members -( +CREATE TABLE shopping.wishlist_members ( wishlist_id BIGINT REFERENCES shopping.wishlists (id), user_id BIGINT, rights VARCHAR(50), @@ -77,7 +71,6 @@ CREATE TABLE shopping.wishlist_members deleted_by BIGINT, PRIMARY KEY (wishlist_id, user_id) ); - CREATE INDEX idx_wishlist_members_deleted_at ON shopping.wishlist_members (deleted_at); diff --git a/demos/ecommerce/source_06_billing_sqlserver.sql b/demos/ecommerce/source_06_billing_sqlserver.sql index be17edc61..8721959c5 100644 --- a/demos/ecommerce/source_06_billing_sqlserver.sql +++ b/demos/ecommerce/source_06_billing_sqlserver.sql @@ -8,8 +8,7 @@ USE Billing; CREATE SCHEMA [billing]; -CREATE TABLE [billing].[CustomerAddresses] -( +CREATE TABLE [billing].[CustomerAddresses] ( [CustomerAddressesId] [bigint] IDENTITY (1,1) PRIMARY KEY, [Name] [nvarchar](255) NOT NULL, [Street] [nvarchar](255) NOT NULL, @@ -25,8 +24,7 @@ CREATE TABLE [billing].[CustomerAddresses] ); CREATE INDEX [IdxCustomerAddressesDeletedAt] ON [billing].[CustomerAddresses] ([DeletedAt]); -CREATE TABLE [billing].[Customers] -( +CREATE TABLE [billing].[Customers] ( [CustomerId] [bigint] IDENTITY (1,1) PRIMARY KEY, [Name] [nvarchar](255) NOT NULL, [BillingAddress] [bigint] REFERENCES [billing].[CustomerAddresses] ([CustomerAddressesId]), @@ -41,8 +39,7 @@ CREATE TABLE [billing].[Customers] ); CREATE INDEX [IdxCustomersDeletedAt] ON [billing].[Customers] ([DeletedAt]); -CREATE TABLE [billing].[CustomerMembers] -( +CREATE TABLE [billing].[CustomerMembers] ( [CustomerId] [bigint] REFERENCES [billing].[Customers] ([CustomerId]), [UserId] [bigint], [CanEdit] [bit], @@ -59,8 +56,7 @@ CREATE TABLE [billing].[CustomerMembers] ); CREATE INDEX [IdxCustomerMembersDeletedAt] ON [billing].[CustomerMembers] ([DeletedAt]); -CREATE TABLE [billing].[CustomerPaymentMethods] -( +CREATE TABLE [billing].[CustomerPaymentMethods] ( [CustomerPaymentMethodId] [bigint] IDENTITY (1,1) PRIMARY KEY, [CustomerId] [bigint] REFERENCES [billing].[Customers] ([CustomerId]), [Name] [nvarchar](255) NOT NULL, @@ -75,8 +71,7 @@ CREATE TABLE [billing].[CustomerPaymentMethods] ); CREATE INDEX [IdxCustomerPaymentMethodsDeletedAt] ON [billing].[CustomerPaymentMethods] ([DeletedAt]); -CREATE TABLE [billing].[Invoices] -( +CREATE TABLE [billing].[Invoices] ( [InvoiceId] [bigint] IDENTITY (1,1) PRIMARY KEY, [Reference] [nvarchar](50) UNIQUE NOT NULL, [CartId] [bigint], @@ -89,8 +84,7 @@ CREATE TABLE [billing].[Invoices] [CreatedBy] [bigint] ); -CREATE TABLE [billing].[InvoiceLines] -( +CREATE TABLE [billing].[InvoiceLines] ( [InvoiceId] [bigint] REFERENCES [billing].[Invoices] ([InvoiceId]), [Index] [int], [ProductVersionId] [bigint], @@ -100,8 +94,7 @@ CREATE TABLE [billing].[InvoiceLines] PRIMARY KEY ([InvoiceId], [Index]) ); -CREATE TABLE [billing].[Payments] -( +CREATE TABLE [billing].[Payments] ( [PaymentId] [bigint] IDENTITY (1,1) PRIMARY KEY, [InvoiceId] [bigint] REFERENCES [billing].[Invoices] ([InvoiceId]), [PaymentMethodId] [bigint] REFERENCES [billing].[CustomerPaymentMethods] ([CustomerPaymentMethodId]), diff --git a/demos/ecommerce/source_08_crm_mysql.sql b/demos/ecommerce/source_08_crm_mysql.sql index 253ec990e..c94e68585 100644 --- a/demos/ecommerce/source_08_crm_mysql.sql +++ b/demos/ecommerce/source_08_crm_mysql.sql @@ -5,8 +5,7 @@ DROP SCHEMA IF EXISTS crm; CREATE SCHEMA crm; USE crm; -CREATE TABLE People -( +CREATE TABLE People ( id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL, email VARCHAR(255), @@ -20,8 +19,7 @@ CREATE TABLE People INDEX idx_people_deleted_at (deleted_at) ); -CREATE TABLE Organizations -( +CREATE TABLE Organizations ( id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, @@ -33,8 +31,7 @@ CREATE TABLE Organizations INDEX idx_organizations_deleted_at (deleted_at) ); -CREATE TABLE OrganizationMembers -( +CREATE TABLE OrganizationMembers ( person_id BIGINT REFERENCES People (id), organization_id BIGINT REFERENCES Organizations (id), role VARCHAR(255) NOT NULL, @@ -48,8 +45,7 @@ CREATE TABLE OrganizationMembers INDEX idx_organization_members_deleted_at (deleted_at) ); -CREATE TABLE SocialAccounts -( +CREATE TABLE SocialAccounts ( id BIGINT PRIMARY KEY AUTO_INCREMENT, network ENUM ('twitter', 'linkedin', 'facebook', 'instagram', 'tiktok', 'snapchat') NOT NULL, username VARCHAR(255) NOT NULL, @@ -64,17 +60,16 @@ CREATE TABLE SocialAccounts INDEX idx_social_accounts_deleted_at (deleted_at) ); -CREATE TABLE Campaigns -( +CREATE TABLE Campaigns ( id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL, status ENUM ('draft', 'live', 'paused') NOT NULL, starts TIMESTAMP, ends TIMESTAMP, kind ENUM ('email', 'sms', 'push', 'twitter', 'linkedin', 'instagram', 'facebook') NOT NULL, - audience TEXT, + audience TEXT COMMENT 'DSL for selecting the audience, from crm.People for email & sms or from crm.SocialAccounts for others', subject VARCHAR(255), - message TEXT, + message TEXT COMMENT 'HTML with templating using recipient info', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_by BIGINT, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, @@ -84,21 +79,19 @@ CREATE TABLE Campaigns INDEX idx_campaigns_deleted_at (deleted_at) ); -CREATE TABLE CampaignMessages -( +CREATE TABLE CampaignMessages ( id BIGINT PRIMARY KEY AUTO_INCREMENT, campaign_id BIGINT REFERENCES Campaigns (id), contact_id BIGINT REFERENCES People (id), social_id BIGINT REFERENCES SocialAccounts (id), - sent_to VARCHAR(255) NOT NULL, + sent_to VARCHAR(255) NOT NULL COMMENT 'can be email, phone number, social account... depending on campaign kind', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, sent_at TIMESTAMP, opened_at TIMESTAMP, clicked_at TIMESTAMP ); -CREATE TABLE Issues -( +CREATE TABLE Issues ( id BIGINT PRIMARY KEY AUTO_INCREMENT, subject VARCHAR(255) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, @@ -108,8 +101,7 @@ CREATE TABLE Issues INDEX idx_issues_closed_at (closed_at) ); -CREATE TABLE IssueMessages -( +CREATE TABLE IssueMessages ( id BIGINT PRIMARY KEY AUTO_INCREMENT, issue_id BIGINT REFERENCES Issues (id), content TEXT NOT NULL, @@ -119,8 +111,7 @@ CREATE TABLE IssueMessages updated_by BIGINT ); -CREATE TABLE IssueMessageReactions -( +CREATE TABLE IssueMessageReactions ( id BIGINT PRIMARY KEY AUTO_INCREMENT, message_id BIGINT REFERENCES IssueMessages (id), kind ENUM ('like', 'dislike') NOT NULL, @@ -131,8 +122,7 @@ CREATE TABLE IssueMessageReactions INDEX idx_issue_message_reactions_deleted_at (deleted_at) ); -CREATE TABLE Discounts -( +CREATE TABLE Discounts ( id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL, description VARCHAR(255), @@ -149,11 +139,10 @@ CREATE TABLE Discounts INDEX idx_discounts_deleted_at (deleted_at) ); -CREATE TABLE Coupons -( +CREATE TABLE Coupons ( id BIGINT PRIMARY KEY AUTO_INCREMENT, discount_id BIGINT REFERENCES Discounts (id), - code VARCHAR(255) UNIQUE NOT NULL, + code VARCHAR(255) UNIQUE NOT NULL COMMENT 'public code to use the discount', expire_at TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_by BIGINT, diff --git a/demos/ecommerce/source_09_analytics_mongo.sql b/demos/ecommerce/source_09_analytics_mongo.sql index 0c96a462d..c764471cb 100644 --- a/demos/ecommerce/source_09_analytics_mongo.sql +++ b/demos/ecommerce/source_09_analytics_mongo.sql @@ -12,13 +12,13 @@ db.createCollection('Events', { bsonType: "object", required: ["id", "name", "source", "createdAt"], properties: { - id: { bsonType: "binData", description: "UUIDv7" }, - name: { bsonType: "string", description: "Name of the event in form of `$context__$object__$action`" }, - source: { bsonType: "string", enum: ["website", "app", "admin", "job"], description: "The name of the system which emitted this event" }, - details: { bsonType: "object", description: "Additional info for the event in JSON format" }, + id: { bsonType: "binData", description: "UUIDv7 to be time ordered" }, + name: { bsonType: "string", description: "in form of `$context__$object__$action`" }, + source: { bsonType: "string", enum: ["website", "app", "admin", "job"], description: "the name of the system which emitted this event" }, + details: { bsonType: "object", description: "any additional info for the event" }, entities: { bsonType: "object", - description: "Entities related to the event in JSON format", + description: "{[kind: string]: {id: string, name: string}[]}", additionalProperties: { bsonType: "array", items: { @@ -31,7 +31,7 @@ db.createCollection('Events', { } } }, - createdAt: { bsonType: "date", description: "Timestamp when the event was created" } + createdAt: { bsonType: "date" } } } } @@ -43,12 +43,12 @@ db.createCollection('Entities', { bsonType: "object", required: ["kind", "id", "name", "properties", "createdAt", "updatedAt"], properties: { - kind: { bsonType: "string", description: "Type of the entity" }, - id: { bsonType: "string", description: "Unique identifier for the entity, for its kind" }, - name: { bsonType: "string", description: "Name of the entity" }, - properties: { bsonType: "object", description: "Additional properties for the entity in JSON format" }, - createdAt: { bsonType: "date", description: "Timestamp when the entity was created" }, - updatedAt: { bsonType: "date", description: "Timestamp when the entity was last updated" } + kind: { bsonType: "string" }, + id: { bsonType: "string" }, + name: { bsonType: "string" }, + properties: { bsonType: "object" }, + createdAt: { bsonType: "date" }, + updatedAt: { bsonType: "date" } } } } From 69ed9b1c08fa2296e73964e8509edd69db1f87f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Knuchel?= Date: Sat, 24 Aug 2024 10:58:56 +0200 Subject: [PATCH 11/16] Better data on Inventory, Catalog, Shopping, Billing and Shipping --- demos/ecommerce/source_00_design.md | 27 +- .../ecommerce/source_03_inventory_oracle.sql | 381 +++++++++++++----- .../ecommerce/source_04_catalog_postgres.sql | 143 ++++++- .../ecommerce/source_05_shopping_postgres.sql | 23 +- .../ecommerce/source_06_billing_sqlserver.sql | 36 +- demos/ecommerce/source_07_shipping_mongo.sql | 90 +---- demos/ecommerce/source_09_analytics_mongo.sql | 49 +-- .../src/Components/Organisms/TableRow.elm | 2 +- 8 files changed, 471 insertions(+), 280 deletions(-) diff --git a/demos/ecommerce/source_00_design.md b/demos/ecommerce/source_00_design.md index 15b651d0a..b5df68a3e 100644 --- a/demos/ecommerce/source_00_design.md +++ b/demos/ecommerce/source_00_design.md @@ -207,10 +207,10 @@ C##INVENTORY.PRODUCTS BRAND BIGINT nullable fk C##INVENTORY.BRANDS.ID CATEGORY VARCHAR nullable | ex: "Phones" SUBCATEGORY VARCHAR nullable | ex: "Smartphones" - WIDTH FLOAT | typical width of the product, see PRODUCT_VERSIONS for the real one - LENGTH FLOAT | typical length of the product, see PRODUCT_VERSIONS for the real one - HEIGHT FLOAT | typical height of the product, see PRODUCT_VERSIONS for the real one - WEIGHT FLOAT | typical weight of the product, see PRODUCT_VERSIONS for the real one + WIDTH FLOAT | typical width of the product in millis, see PRODUCT_VERSIONS for the real one + LENGTH FLOAT | typical length of the product in millis, see PRODUCT_VERSIONS for the real one + HEIGHT FLOAT | typical height of the product in millis, see PRODUCT_VERSIONS for the real one + WEIGHT FLOAT | typical weight of the product in grams, see PRODUCT_VERSIONS for the real one REMARKS TEXT nullable | ex: fragile CREATED_AT TIMESTAMP UPDATED_AT TIMESTAMP @@ -223,10 +223,10 @@ C##INVENTORY.PRODUCT_VERSIONS EAN VARCHAR(13) unique | european id NAME VARCHAR unique | ex: "Pixel 8 Pro Menthe 128 Go" SPECS JSON | specificities of this version, ex: `{color: "Menthe", storage: 128}` - WIDTH FLOAT - LENGTH FLOAT - HEIGHT FLOAT - WEIGHT FLOAT + WIDTH FLOAT | in millis + LENGTH FLOAT | in millis + HEIGHT FLOAT | in millis + WEIGHT FLOAT | in grams REMARKS TEXT nullable CREATED_AT TIMESTAMP UPDATED_AT TIMESTAMP @@ -630,10 +630,11 @@ billing.Payments shipping.Carriers id bigint unique=pk registration varchar - cargoWidth float - cargoLength float - cargoHeight float - cargoWeight float + licensePlate varchar + cargoWidth float | inner cargo width in millimeters + cargoLength float | inner cargo length in millimeters + cargoHeight float | inner cargo height in millimeters + cargoWeight float | maximum weight for the cargo, in kilograms createdAt timestamp createdBy bigint nullable fk identity.Users.id updatedAt timestamp @@ -660,7 +661,7 @@ shipping.ShipmentItems invoiceId bigint fk billing.InvoiceLines.InvoiceId invoiceLine int fk billing.InvoiceLines.Index deliveredAt timestamp nullable - deliveredTo bigint nullable fk identity.Users.id + deliveredTo bigint nullable fk identity.Users.id | the User who got the delivered package # CRM diff --git a/demos/ecommerce/source_03_inventory_oracle.sql b/demos/ecommerce/source_03_inventory_oracle.sql index 7b5086d33..6a4bac101 100644 --- a/demos/ecommerce/source_03_inventory_oracle.sql +++ b/demos/ecommerce/source_03_inventory_oracle.sql @@ -8,17 +8,18 @@ GRANT UNLIMITED TABLESPACE TO C##INVENTORY; CREATE ROLE C##INVENTORY_ROLE; GRANT CREATE SESSION, CREATE TABLE, CREATE SEQUENCE, CREATE VIEW, CREATE MATERIALIZED VIEW, CREATE TYPE, CREATE TRIGGER to C##inventory_role; GRANT C##INVENTORY_ROLE TO C##INVENTORY; +ALTER SESSION SET current_schema = C##INVENTORY; CREATE TABLE C##INVENTORY.EMPLOYEES ( - ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, - FIRST_NAME VARCHAR2(255), - LAST_NAME VARCHAR2(255), + ID NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + FIRST_NAME VARCHAR2(255) NOT NULL, + LAST_NAME VARCHAR2(255) NOT NULL, EMAIL VARCHAR2(255), PHONE VARCHAR2(20), - CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - CREATED_BY NUMBER, - UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - UPDATED_BY NUMBER, + CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, + CREATED_BY NUMBER NOT NULL, + UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, + UPDATED_BY NUMBER NOT NULL, DELETED_AT TIMESTAMP, DELETED_BY NUMBER ); @@ -27,7 +28,7 @@ CREATE INDEX IDX_EMPLOYEES_EMAIL ON C##INVENTORY.EMPLOYEES (EMAIL); CREATE INDEX IDX_EMPLOYEES_DELETED_AT ON C##INVENTORY.EMPLOYEES (DELETED_AT); CREATE TABLE C##INVENTORY.WAREHOUSES ( - ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + ID NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, NAME VARCHAR2(255) UNIQUE, ADDRESS CLOB, MANAGER NUMBER REFERENCES C##INVENTORY.EMPLOYEES (ID), @@ -41,7 +42,7 @@ CREATE TABLE C##INVENTORY.WAREHOUSES ( CREATE INDEX IDX_WAREHOUSES_DELETED_AT ON C##INVENTORY.WAREHOUSES (DELETED_AT); CREATE TABLE C##INVENTORY.HALLS ( - ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + ID NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, WAREHOUSE_ID NUMBER REFERENCES C##INVENTORY.WAREHOUSES (ID), NAME VARCHAR2(255), MANAGER NUMBER REFERENCES C##INVENTORY.EMPLOYEES (ID), @@ -55,7 +56,7 @@ CREATE TABLE C##INVENTORY.HALLS ( CREATE INDEX IDX_HALLS_DELETED_AT ON C##INVENTORY.HALLS (DELETED_AT); CREATE TABLE C##INVENTORY.AISLES ( - ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + ID NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, HALL_ID NUMBER REFERENCES C##INVENTORY.HALLS (ID), NAME VARCHAR2(255), MANAGER NUMBER REFERENCES C##INVENTORY.EMPLOYEES (ID), @@ -69,7 +70,7 @@ CREATE TABLE C##INVENTORY.AISLES ( CREATE INDEX IDX_AISLES_DELETED_AT ON C##INVENTORY.AISLES (DELETED_AT); CREATE TABLE C##INVENTORY.RACKS ( - ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + ID NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, AISLE_ID NUMBER REFERENCES C##INVENTORY.AISLES (ID), NAME VARCHAR2(255), CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, @@ -82,7 +83,7 @@ CREATE TABLE C##INVENTORY.RACKS ( CREATE INDEX IDX_RACKS_DELETED_AT ON C##INVENTORY.RACKS (DELETED_AT); CREATE TABLE C##INVENTORY.SHELVES ( - ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + ID NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, RACK_ID NUMBER REFERENCES C##INVENTORY.RACKS (ID), NAME VARCHAR2(255), CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, @@ -95,7 +96,7 @@ CREATE TABLE C##INVENTORY.SHELVES ( CREATE INDEX IDX_SHELVES_DELETED_AT ON C##INVENTORY.SHELVES (DELETED_AT); CREATE TABLE C##INVENTORY.SHELF_POSITIONS ( - ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + ID NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, SHELF_ID NUMBER REFERENCES C##INVENTORY.SHELVES (ID), NAME VARCHAR2(255), CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, @@ -136,7 +137,7 @@ CREATE TABLE C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS ( COMMENT ON TABLE C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS IS 'how to check the employee is identified, can be several'; CREATE TABLE C##INVENTORY.BRANDS ( - ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + ID NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, SLUG VARCHAR2(255) UNIQUE, NAME VARCHAR2(255) UNIQUE, CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, @@ -148,7 +149,7 @@ COMMENT ON COLUMN C##INVENTORY.BRANDS.SLUG IS 'ex: "google"'; COMMENT ON COLUMN C##INVENTORY.BRANDS.NAME IS 'ex: "Google"'; CREATE TABLE C##INVENTORY.PRODUCTS ( - ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + ID NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, SLUG VARCHAR2(255) UNIQUE, NAME VARCHAR2(255) UNIQUE, BRAND NUMBER REFERENCES C##INVENTORY.BRANDS (ID), @@ -168,14 +169,14 @@ COMMENT ON COLUMN C##INVENTORY.PRODUCTS.SLUG IS 'ex: "pixel-8-pro"'; COMMENT ON COLUMN C##INVENTORY.PRODUCTS.NAME IS 'ex: "Pixel 8 Pro"'; COMMENT ON COLUMN C##INVENTORY.PRODUCTS.CATEGORY IS 'ex: "Phones"'; COMMENT ON COLUMN C##INVENTORY.PRODUCTS.SUBCATEGORY IS 'ex: "Smartphones"'; -COMMENT ON COLUMN C##INVENTORY.PRODUCTS.WIDTH IS 'typical width of the product, see PRODUCT_VERSIONS for the real one'; -COMMENT ON COLUMN C##INVENTORY.PRODUCTS.LENGTH IS 'typical length of the product, see PRODUCT_VERSIONS for the real one'; -COMMENT ON COLUMN C##INVENTORY.PRODUCTS.HEIGHT IS 'typical height of the product, see PRODUCT_VERSIONS for the real one'; -COMMENT ON COLUMN C##INVENTORY.PRODUCTS.WEIGHT IS 'typical weight of the product, see PRODUCT_VERSIONS for the real one'; +COMMENT ON COLUMN C##INVENTORY.PRODUCTS.WIDTH IS 'typical width of the product in millis, see PRODUCT_VERSIONS for the real one'; +COMMENT ON COLUMN C##INVENTORY.PRODUCTS.LENGTH IS 'typical length of the product in millis, see PRODUCT_VERSIONS for the real one'; +COMMENT ON COLUMN C##INVENTORY.PRODUCTS.HEIGHT IS 'typical height of the product in millis, see PRODUCT_VERSIONS for the real one'; +COMMENT ON COLUMN C##INVENTORY.PRODUCTS.WEIGHT IS 'typical weight of the product in grams, see PRODUCT_VERSIONS for the real one'; COMMENT ON COLUMN C##INVENTORY.PRODUCTS.REMARKS IS 'ex: fragile'; CREATE TABLE C##INVENTORY.PRODUCT_VERSIONS ( - ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + ID NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, PRODUCT_ID NUMBER REFERENCES C##INVENTORY.PRODUCTS (ID), SKU VARCHAR2(12) UNIQUE, EAN VARCHAR2(13) UNIQUE, @@ -195,9 +196,13 @@ COMMENT ON COLUMN C##INVENTORY.PRODUCT_VERSIONS.SKU IS 'internal id'; COMMENT ON COLUMN C##INVENTORY.PRODUCT_VERSIONS.EAN IS 'european id'; COMMENT ON COLUMN C##INVENTORY.PRODUCT_VERSIONS.NAME IS 'ex: "Pixel 8 Pro Menthe 128 Go"'; COMMENT ON COLUMN C##INVENTORY.PRODUCT_VERSIONS.SPECS IS 'specificities of this version, ex: `{color: "Menthe", storage: 128}`'; +COMMENT ON COLUMN C##INVENTORY.PRODUCT_VERSIONS.WIDTH IS 'in millis'; +COMMENT ON COLUMN C##INVENTORY.PRODUCT_VERSIONS.LENGTH IS 'in millis'; +COMMENT ON COLUMN C##INVENTORY.PRODUCT_VERSIONS.HEIGHT IS 'in millis'; +COMMENT ON COLUMN C##INVENTORY.PRODUCT_VERSIONS.WEIGHT IS 'in grams'; CREATE TABLE C##INVENTORY.PHYSICAL_PRODUCTS ( - ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + ID NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, PRODUCT_VERSION_ID NUMBER REFERENCES C##INVENTORY.PRODUCT_VERSIONS (ID), SNID VARCHAR2(12) UNIQUE, EXPIRATION TIMESTAMP, @@ -212,7 +217,7 @@ COMMENT ON COLUMN C##INVENTORY.PHYSICAL_PRODUCTS.SNID IS 'serial number of this COMMENT ON COLUMN C##INVENTORY.PHYSICAL_PRODUCTS.EXPIRATION IS 'when Product has an expiration date, null otherwise'; CREATE TABLE C##INVENTORY.SUPPLIERS ( - ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + ID NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, NAME VARCHAR2(255), "LEVEL" NUMBER, CURRENCY VARCHAR2(3), @@ -222,7 +227,7 @@ CREATE TABLE C##INVENTORY.SUPPLIERS ( ); CREATE INDEX IDX_SUPPLIERS_NAME ON C##INVENTORY.SUPPLIERS (NAME); CREATE INDEX IDX_SUPPLIERS_DELETED_AT ON C##INVENTORY.SUPPLIERS (DELETED_AT); -COMMENT ON COLUMN C##INVENTORY.SUPPLIERS.LEVEL IS 'the lower, the more priority is given to this supplier'; +COMMENT ON COLUMN C##INVENTORY.SUPPLIERS."LEVEL" IS 'the lower, the more priority is given to this supplier'; CREATE TABLE C##INVENTORY.SUPPLIER_PRICES ( SUPPLIER_ID NUMBER REFERENCES C##INVENTORY.SUPPLIERS (ID), @@ -252,7 +257,7 @@ CREATE TABLE C##INVENTORY.SUPPLIER_EMPLOYEES ( CREATE INDEX IDX_SUPPLIER_EMPLOYEES_DELETED_AT ON C##INVENTORY.SUPPLIER_EMPLOYEES (DELETED_AT); CREATE TABLE C##INVENTORY.PURCHASE_ORDERS ( - ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + ID NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, SUPPLIER_ID NUMBER REFERENCES C##INVENTORY.SUPPLIERS (ID), PRICE FLOAT, CURRENCY VARCHAR2(3), @@ -287,12 +292,12 @@ CREATE TABLE C##INVENTORY.PURCHASE_ORDER_ITEMS ( ); CREATE TABLE C##INVENTORY.DELIVERIES ( - ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, - REASON VARCHAR2(255), - ACCEPTED CHAR(1) CHECK (ACCEPTED IN ('Y', 'N')), + ID NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + REASON VARCHAR2(255) NOT NULL, + ACCEPTED CHAR(1) NOT NULL CHECK (ACCEPTED IN ('Y', 'N')), PURCHASE_ORDER_ID NUMBER REFERENCES C##INVENTORY.PURCHASE_ORDERS (ID), - WAREHOUSE_ID NUMBER, - WAREHOUSE_EMPLOYEE_ID NUMBER, + WAREHOUSE_ID NUMBER NOT NULL, + WAREHOUSE_EMPLOYEE_ID NUMBER NOT NULL, SUPPLIER_ID NUMBER, SUPPLIER_EMPLOYEE_ID NUMBER, DELIVERED_AT TIMESTAMP, @@ -307,7 +312,7 @@ CREATE TABLE C##INVENTORY.DELIVERY_ITEMS ( ); CREATE TABLE C##INVENTORY.PICKUPS ( - ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + ID NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, REASON VARCHAR2(255), ACCEPTED CHAR(1) CHECK (ACCEPTED IN ('Y', 'N')), WAREHOUSE_ID NUMBER, @@ -326,7 +331,7 @@ CREATE TABLE C##INVENTORY.PICKUP_ITEMS ( ); CREATE TABLE C##INVENTORY.INVENTORIES ( - ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + ID NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, NAME VARCHAR2(255), WAREHOUSE_ID NUMBER REFERENCES C##INVENTORY.WAREHOUSES (ID), HALL_ID NUMBER REFERENCES C##INVENTORY.HALLS (ID), @@ -348,7 +353,7 @@ CREATE TABLE C##INVENTORY.INVENTORY_MEMBERS ( ); CREATE TABLE C##INVENTORY.INVENTORY_OBSERVATIONS ( - ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + ID NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, INVENTORY_ID NUMBER REFERENCES C##INVENTORY.INVENTORIES (ID), PHYSICAL_PRODUCT_ID NUMBER REFERENCES C##INVENTORY.PHYSICAL_PRODUCTS (ID), STATUS VARCHAR2(255), @@ -364,77 +369,255 @@ CREATE INDEX IDX_INVENTORY_OBSERVATIONS_DELETED_AT ON C##INVENTORY.INVENTORY_OBS -- insert some data -INSERT INTO C##INVENTORY.EMPLOYEES (FIRST_NAME, LAST_NAME, EMAIL, PHONE, CREATED_BY, UPDATED_BY) VALUES ('John', 'Doe', 'john.doe@example.com', '1234567890', 1, 1); -INSERT INTO C##INVENTORY.EMPLOYEES (FIRST_NAME, LAST_NAME, EMAIL, PHONE, CREATED_BY, UPDATED_BY) VALUES ('Jane', 'Smith', 'jane.smith@example.com', '0987654321', 1, 1); - -INSERT INTO C##INVENTORY.WAREHOUSES (NAME, ADDRESS, MANAGER, CREATED_BY, UPDATED_BY) VALUES ('Main Warehouse', '1234 Warehouse St.', 1, 1, 1); -INSERT INTO C##INVENTORY.WAREHOUSES (NAME, ADDRESS, MANAGER, CREATED_BY, UPDATED_BY) VALUES ('Secondary Warehouse', '5678 Warehouse Ave.', 2, 1, 1); - -INSERT INTO C##INVENTORY.HALLS (WAREHOUSE_ID, NAME, MANAGER, CREATED_BY, UPDATED_BY) VALUES (1, 'Hall A', 1, 1, 1); -INSERT INTO C##INVENTORY.HALLS (WAREHOUSE_ID, NAME, MANAGER, CREATED_BY, UPDATED_BY) VALUES (2, 'Hall B', 2, 1, 1); - -INSERT INTO C##INVENTORY.AISLES (HALL_ID, NAME, MANAGER, CREATED_BY, UPDATED_BY) VALUES (1, 'Aisle 1', 1, 1, 1); -INSERT INTO C##INVENTORY.AISLES (HALL_ID, NAME, MANAGER, CREATED_BY, UPDATED_BY) VALUES (2, 'Aisle 2', 2, 1, 1); - -INSERT INTO C##INVENTORY.RACKS (AISLE_ID, NAME, CREATED_BY, UPDATED_BY) VALUES (1, 'Rack 1', 1, 1); -INSERT INTO C##INVENTORY.RACKS (AISLE_ID, NAME, CREATED_BY, UPDATED_BY) VALUES (2, 'Rack 2', 1, 1); - -INSERT INTO C##INVENTORY.SHELVES (RACK_ID, NAME, CREATED_BY, UPDATED_BY) VALUES (1, 'Shelf 1', 1, 1); -INSERT INTO C##INVENTORY.SHELVES (RACK_ID, NAME, CREATED_BY, UPDATED_BY) VALUES (2, 'Shelf 2', 1, 1); - -INSERT INTO C##INVENTORY.SHELF_POSITIONS (SHELF_ID, NAME, CREATED_BY, UPDATED_BY) VALUES (1, 'Position 1', 1, 1); -INSERT INTO C##INVENTORY.SHELF_POSITIONS (SHELF_ID, NAME, CREATED_BY, UPDATED_BY) VALUES (2, 'Position 2', 1, 1); - -INSERT INTO C##INVENTORY.WAREHOUSE_EMPLOYEES (WAREHOUSE_ID, EMPLOYEE_ID, ROLE, CREATED_BY, UPDATED_BY) VALUES (1, 1, 'manager', 1, 1); -INSERT INTO C##INVENTORY.WAREHOUSE_EMPLOYEES (WAREHOUSE_ID, EMPLOYEE_ID, ROLE, CREATED_BY, UPDATED_BY) VALUES (2, 2, 'stocker', 1, 1); - -INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, CREATED_BY) VALUES (1, 1, 'badge', '123456', 1); -INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, CREATED_BY) VALUES (2, 2, 'cni', '987654', 1); +INSERT INTO C##INVENTORY.EMPLOYEES (ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE, CREATED_BY, UPDATED_BY) VALUES (1, 'Harry', 'Potter', 'harry.potter@hogwarts.ac.uk', '+1-202-555-0173', 3, 3); +INSERT INTO C##INVENTORY.EMPLOYEES (ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE, CREATED_BY, UPDATED_BY) VALUES (2, 'Hermione', 'Granger', 'hermione.granger@hogwarts.ac.uk', '+44-20-7946-0958', 3, 3); +INSERT INTO C##INVENTORY.EMPLOYEES (ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE, CREATED_BY, UPDATED_BY) VALUES (3, 'Ron', 'Weasley', 'ron.weasley@hogwarts.ac.uk', '+33-1-45-67-89-01', 3, 3); +INSERT INTO C##INVENTORY.EMPLOYEES (ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE, CREATED_BY, UPDATED_BY) VALUES (4, 'Albus', 'Dumbledore', 'albus.dumbledore@hogwarts.ac.uk', '+49-30-1234567', 3, 3); +INSERT INTO C##INVENTORY.EMPLOYEES (ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE, CREATED_BY, UPDATED_BY) VALUES (5, 'Severus', 'Snape', 'severus.snape@hogwarts.ac.uk', '+61-2-9374-4000', 3, 3); +INSERT INTO C##INVENTORY.EMPLOYEES (ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE, CREATED_BY, UPDATED_BY) VALUES (6, 'Frodo', 'Baggins', 'frodo.baggins@shire.me', NULL, 3, 3); +INSERT INTO C##INVENTORY.EMPLOYEES (ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE, CREATED_BY, UPDATED_BY) VALUES (7, 'Samwise', 'Gamgee', 'samwise.gamgee@shire.me', NULL, 3, 3); +INSERT INTO C##INVENTORY.EMPLOYEES (ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE, CREATED_BY, UPDATED_BY) VALUES (8, 'Gandalf', 'the Grey', 'gandalf@middleearth.me', NULL, 3, 3); +INSERT INTO C##INVENTORY.EMPLOYEES (ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE, CREATED_BY, UPDATED_BY) VALUES (9, 'Aragorn', 'Elessar', 'aragorn@middleearth.me', NULL, 3, 3); +INSERT INTO C##INVENTORY.EMPLOYEES (ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE, CREATED_BY, UPDATED_BY) VALUES (10, 'Legolas', 'Greenleaf', 'legolas@woodlandrealm.me', NULL, 3, 3); +INSERT INTO C##INVENTORY.EMPLOYEES (ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE, CREATED_BY, UPDATED_BY) VALUES (11, 'Gimli', 'Son of Glóin', 'gimli@lonelymountain.me', NULL, 3, 3); +INSERT INTO C##INVENTORY.EMPLOYEES (ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE, CREATED_BY, UPDATED_BY) VALUES (12, 'Steve', 'Rogers', 'steve.rogers@avengers.com', NULL, 3, 3); +INSERT INTO C##INVENTORY.EMPLOYEES (ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE, CREATED_BY, UPDATED_BY) VALUES (13, 'Bruce', 'Banner', 'bruce.banner@avengers.com', NULL, 3, 3); +INSERT INTO C##INVENTORY.EMPLOYEES (ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE, CREATED_BY, UPDATED_BY) VALUES (14, 'Natasha', 'Romanoff', 'natasha.romanoff@shield.gov', NULL, 3, 3); + +INSERT INTO C##INVENTORY.WAREHOUSES (NAME, ADDRESS, MANAGER, CREATED_BY, UPDATED_BY) VALUES ('Hogwarts Central Warehouse', 'Hogwarts School of Witchcraft and Wizardry, Highlands, Scotland', 4, 16, 16); +INSERT INTO C##INVENTORY.WAREHOUSES (NAME, ADDRESS, MANAGER, CREATED_BY, UPDATED_BY) VALUES ('Shire Storage Facility', 'The Shire, Westfarthing, Middle-earth', 8, 20, 20); + +INSERT INTO C##INVENTORY.HALLS (WAREHOUSE_ID, NAME, MANAGER, CREATED_BY, UPDATED_BY) VALUES (1, 'Main Hall', 4, 16, 16); +INSERT INTO C##INVENTORY.HALLS (WAREHOUSE_ID, NAME, MANAGER, CREATED_BY, UPDATED_BY) VALUES (1, 'Potion Storage', 5, 16, 16); + +INSERT INTO C##INVENTORY.AISLES (HALL_ID, NAME, MANAGER, CREATED_BY, UPDATED_BY) VALUES (1, 'Wand Aisle', 2, 16, 16); +INSERT INTO C##INVENTORY.AISLES (HALL_ID, NAME, MANAGER, CREATED_BY, UPDATED_BY) VALUES (1, 'Book Aisle', 2, 16, 16); +INSERT INTO C##INVENTORY.AISLES (HALL_ID, NAME, MANAGER, CREATED_BY, UPDATED_BY) VALUES (2, 'Ingredients Aisle', 3, 16, 16); +INSERT INTO C##INVENTORY.AISLES (HALL_ID, NAME, MANAGER, CREATED_BY, UPDATED_BY) VALUES (2, 'Cauldron Aisle', 3, 16, 16); + +INSERT INTO C##INVENTORY.RACKS (AISLE_ID, NAME, CREATED_BY, UPDATED_BY) VALUES (1, 'Phoenix Feather Rack', 16, 16); +INSERT INTO C##INVENTORY.RACKS (AISLE_ID, NAME, CREATED_BY, UPDATED_BY) VALUES (1, 'Dragon Heartstring Rack', 16, 16); +INSERT INTO C##INVENTORY.RACKS (AISLE_ID, NAME, CREATED_BY, UPDATED_BY) VALUES (2, 'Ancient Texts Rack', 16, 16); +INSERT INTO C##INVENTORY.RACKS (AISLE_ID, NAME, CREATED_BY, UPDATED_BY) VALUES (2, 'Modern Spellbooks Rack', 16, 16); +INSERT INTO C##INVENTORY.RACKS (AISLE_ID, NAME, CREATED_BY, UPDATED_BY) VALUES (3, 'Herbs Rack', 16, 16); +INSERT INTO C##INVENTORY.RACKS (AISLE_ID, NAME, CREATED_BY, UPDATED_BY) VALUES (3, 'Potions Ingredients Rack', 16, 16); +INSERT INTO C##INVENTORY.RACKS (AISLE_ID, NAME, CREATED_BY, UPDATED_BY) VALUES (4, 'Small Cauldrons Rack', 16, 16); +INSERT INTO C##INVENTORY.RACKS (AISLE_ID, NAME, CREATED_BY, UPDATED_BY) VALUES (4, 'Large Cauldrons Rack', 16, 16); + +BEGIN + FOR rack IN (SELECT ID FROM C##INVENTORY.RACKS) LOOP + FOR i IN 1..3 LOOP + DECLARE + v_shelf_id NUMBER; + BEGIN + INSERT INTO C##INVENTORY.SHELVES (RACK_ID, NAME, CREATED_BY, UPDATED_BY) + VALUES (rack.ID, CASE WHEN i = 1 THEN 'Top Shelf' WHEN i = 2 THEN 'Middle Shelf' ELSE 'Bottom Shelf' END, 16, 16) + RETURNING ID INTO v_shelf_id; + + FOR j IN 1..3 LOOP + INSERT INTO C##INVENTORY.SHELF_POSITIONS (SHELF_ID, NAME, CREATED_BY, UPDATED_BY) + VALUES (v_shelf_id, CASE WHEN j = 1 THEN 'Position A' WHEN j = 2 THEN 'Position B' ELSE 'Position C' END, 16, 16); + END LOOP; + END; + END LOOP; + END LOOP; +END; + +INSERT INTO C##INVENTORY.WAREHOUSE_EMPLOYEES (WAREHOUSE_ID, EMPLOYEE_ID, ROLE, CREATED_BY, UPDATED_BY) VALUES (1, 1, 'stocker', 3, 3); +INSERT INTO C##INVENTORY.WAREHOUSE_EMPLOYEES (WAREHOUSE_ID, EMPLOYEE_ID, ROLE, CREATED_BY, UPDATED_BY) VALUES (1, 2, 'stocker', 3, 3); +INSERT INTO C##INVENTORY.WAREHOUSE_EMPLOYEES (WAREHOUSE_ID, EMPLOYEE_ID, ROLE, CREATED_BY, UPDATED_BY) VALUES (1, 3, 'loader', 3, 3); +INSERT INTO C##INVENTORY.WAREHOUSE_EMPLOYEES (WAREHOUSE_ID, EMPLOYEE_ID, ROLE, CREATED_BY, UPDATED_BY) VALUES (1, 4, 'manager', 3, 3); +INSERT INTO C##INVENTORY.WAREHOUSE_EMPLOYEES (WAREHOUSE_ID, EMPLOYEE_ID, ROLE, CREATED_BY, UPDATED_BY) VALUES (1, 5, 'receiver', 3, 3); +INSERT INTO C##INVENTORY.WAREHOUSE_EMPLOYEES (WAREHOUSE_ID, EMPLOYEE_ID, ROLE, CREATED_BY, UPDATED_BY) VALUES (2, 6, 'stocker', 3, 3); +INSERT INTO C##INVENTORY.WAREHOUSE_EMPLOYEES (WAREHOUSE_ID, EMPLOYEE_ID, ROLE, CREATED_BY, UPDATED_BY) VALUES (2, 7, 'stocker', 3, 3); +INSERT INTO C##INVENTORY.WAREHOUSE_EMPLOYEES (WAREHOUSE_ID, EMPLOYEE_ID, ROLE, CREATED_BY, UPDATED_BY) VALUES (2, 8, 'manager', 3, 3); +INSERT INTO C##INVENTORY.WAREHOUSE_EMPLOYEES (WAREHOUSE_ID, EMPLOYEE_ID, ROLE, CREATED_BY, UPDATED_BY) VALUES (2, 9, 'receiver', 3, 3); +INSERT INTO C##INVENTORY.WAREHOUSE_EMPLOYEES (WAREHOUSE_ID, EMPLOYEE_ID, ROLE, CREATED_BY, UPDATED_BY) VALUES (2, 10, 'loader', 3, 3); +INSERT INTO C##INVENTORY.WAREHOUSE_EMPLOYEES (WAREHOUSE_ID, EMPLOYEE_ID, ROLE, CREATED_BY, UPDATED_BY) VALUES (2, 11, 'loader', 3, 3); + +INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 1, 'name', 'Harry Potter', NULL, 16); +INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 1, 'badge', 'HP1234', NULL, 16); +INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 1, 'cni', '01 23 45 678 901', NULL, 16); +INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 2, 'badge', 'HG5678', NULL, 16); +INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 2, 'cni', '02 34 56 789 012', NULL, 16); +INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 3, 'badge', 'RW9101', NULL, 16); +INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 3, 'cni', '03 45 67 890 123', NULL, 16); +INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 4, 'badge', 'AD1213', NULL, 16); +INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 4, 'cni', '04 56 78 901 234', NULL, 16); +INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 5, 'badge', 'SS1415', NULL, 16); +INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 5, 'cni', '05 67 89 012 345', NULL, 16); INSERT INTO C##INVENTORY.BRANDS (SLUG, NAME) VALUES ('google', 'Google'); INSERT INTO C##INVENTORY.BRANDS (SLUG, NAME) VALUES ('apple', 'Apple'); -INSERT INTO C##INVENTORY.PRODUCTS (SLUG, NAME, BRAND, CATEGORY, SUBCATEGORY, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES ('pixel-8-pro', 'Pixel 8 Pro', 1, 'Phones', 'Smartphones', 2.8, 5.8, 0.3, 0.5); -INSERT INTO C##INVENTORY.PRODUCTS (SLUG, NAME, BRAND, CATEGORY, SUBCATEGORY, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES ('iphone-14', 'iPhone 14', 2, 'Phones', 'Smartphones', 2.7, 5.7, 0.3, 0.4); - -INSERT INTO C##INVENTORY.PRODUCT_VERSIONS (PRODUCT_ID, SKU, EAN, NAME, SPECS, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (1, 'P8P128', '1234567890123', 'Pixel 8 Pro Menthe 128 Go', '{"color": "Menthe", "storage": 128}', 2.8, 5.8, 0.3, 0.5); -INSERT INTO C##INVENTORY.PRODUCT_VERSIONS (PRODUCT_ID, SKU, EAN, NAME, SPECS, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (2, 'I14128', '1234567890124', 'iPhone 14 Bleu 128 Go', '{"color": "Bleu", "storage": 128}', 2.7, 5.7, 0.3, 0.4); - -INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (PRODUCT_VERSION_ID, SNID, EXPIRATION) VALUES (1, 'SN1234567890', TO_TIMESTAMP('2025-12-31 23:59:59', 'YYYY-MM-DD HH24:MI:SS')); -INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (PRODUCT_VERSION_ID, SNID) VALUES (1, 'SN1234567891'); - -INSERT INTO C##INVENTORY.SUPPLIERS (NAME, "LEVEL", CURRENCY) VALUES ('Supplier A', 1, 'USD'); -INSERT INTO C##INVENTORY.SUPPLIERS (NAME, "LEVEL", CURRENCY) VALUES ('Supplier B', 2, 'EUR'); - -INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (1, 1, 70.00); -INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (2, 2, 80.00); - -INSERT INTO C##INVENTORY.SUPPLIER_EMPLOYEES (SUPPLIER_ID, EMPLOYEE_ID, ROLE, CREATED_BY, UPDATED_BY) VALUES (1, 1, 'delivery', 1, 1); -INSERT INTO C##INVENTORY.SUPPLIER_EMPLOYEES (SUPPLIER_ID, EMPLOYEE_ID, ROLE, CREATED_BY, UPDATED_BY) VALUES (2, 2, 'sale', 1, 1); - -INSERT INTO C##INVENTORY.PURCHASE_ORDERS (SUPPLIER_ID, PRICE, CURRENCY, DETAILS, NOTES, CREATED_BY, UPDATED_BY) VALUES (1, 700.00, 'USD', 'Order details for Supplier A', 'Internal notes', 1, 1); -INSERT INTO C##INVENTORY.PURCHASE_ORDERS (SUPPLIER_ID, PRICE, CURRENCY, DETAILS, NOTES, CREATED_BY, UPDATED_BY) VALUES (2, 800.00, 'EUR', 'Order details for Supplier B', 'Internal notes', 1, 1); - -INSERT INTO C##INVENTORY.PURCHASE_ORDER_ITEMS (PURCHASE_ORDER_ID, PRODUCT_VERSION_ID, QUANTITY, PRICE, CREATED_BY, UPDATED_BY) VALUES (1, 1, 10, 70.00, 1, 1); -INSERT INTO C##INVENTORY.PURCHASE_ORDER_ITEMS (PURCHASE_ORDER_ID, PRODUCT_VERSION_ID, QUANTITY, PRICE, CREATED_BY, UPDATED_BY) VALUES (2, 2, 5, 160.00, 1, 1); - -INSERT INTO C##INVENTORY.DELIVERIES (REASON, ACCEPTED, PURCHASE_ORDER_ID, WAREHOUSE_ID, WAREHOUSE_EMPLOYEE_ID, SUPPLIER_ID, SUPPLIER_EMPLOYEE_ID, DELIVERED_AT) VALUES ('supplier_delivery', 'Y', 1, 1, 1, 1, 1, CURRENT_TIMESTAMP); -INSERT INTO C##INVENTORY.DELIVERIES (REASON, ACCEPTED, PURCHASE_ORDER_ID, WAREHOUSE_ID, WAREHOUSE_EMPLOYEE_ID, SUPPLIER_ID, SUPPLIER_EMPLOYEE_ID, DELIVERED_AT) VALUES ('customer_return', 'N', 2, 2, 2, 2, 2, CURRENT_TIMESTAMP); - +INSERT INTO C##INVENTORY.PRODUCTS (ID, SLUG, NAME, BRAND, CATEGORY, SUBCATEGORY, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (1, 'pixel-8', 'Pixel 8', 1, 'Phones', 'Smartphones', 150.5, 70.8, 8.9, 187); +INSERT INTO C##INVENTORY.PRODUCT_VERSIONS (ID, PRODUCT_ID, SKU, EAN, NAME, SPECS, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (1, 1, 'GGLPX8O128', '0840244706692', 'Pixel 8 Obsidian 128 Go', '{"color": "Obsidian", "storage": 128}', 150.5, 70.8, 8.9, 187); +INSERT INTO C##INVENTORY.PRODUCT_VERSIONS (ID, PRODUCT_ID, SKU, EAN, NAME, SPECS, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (2, 1, 'GGLPX8O256', '0840244706906', 'Pixel 8 Obsidian 256 Go', '{"color": "Obsidian", "storage": 256}', 150.5, 70.8, 8.9, 187); +INSERT INTO C##INVENTORY.PRODUCT_VERSIONS (ID, PRODUCT_ID, SKU, EAN, NAME, SPECS, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (3, 1, 'GGLPX8H128', '0840244706807', 'Pixel 8 Hazel 128 Go', '{"color": "Hazel", "storage": 128}', 150.5, 70.8, 8.9, 187); +INSERT INTO C##INVENTORY.PRODUCT_VERSIONS (ID, PRODUCT_ID, SKU, EAN, NAME, SPECS, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (4, 1, 'GGLPX8H256', '0840244707118', 'Pixel 8 Hazel 256 Go', '{"color": "Hazel", "storage": 256}', 150.5, 70.8, 8.9, 187); +INSERT INTO C##INVENTORY.PRODUCT_VERSIONS (ID, PRODUCT_ID, SKU, EAN, NAME, SPECS, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (5, 1, 'GGLPX8R128', '0840244706982', 'Pixel 8 Rose 128 Go', '{"color": "Rose", "storage": 128}', 150.5, 70.8, 8.9, 187); +INSERT INTO C##INVENTORY.PRODUCT_VERSIONS (ID, PRODUCT_ID, SKU, EAN, NAME, SPECS, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (6, 1, 'GGLPX8R256', '0840244707231', 'Pixel 8 Rose 256 Go', '{"color": "Rose", "storage": 256}', 150.5, 70.8, 8.9, 187); +INSERT INTO C##INVENTORY.PRODUCT_VERSIONS (ID, PRODUCT_ID, SKU, EAN, NAME, SPECS, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (7, 1, 'GGLPX8M128', '0840244707071', 'Pixel 8 Mint 128 Go', '{"color": "Mint", "storage": 128}', 150.5, 70.8, 8.9, 187); +INSERT INTO C##INVENTORY.PRODUCTS (ID, SLUG, NAME, BRAND, CATEGORY, SUBCATEGORY, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (2, 'pixel-8-pro', 'Pixel 8 Pro', 1, 'Phones', 'Smartphones', 162.6, 76.5, 8.8, 213); +INSERT INTO C##INVENTORY.PRODUCT_VERSIONS (ID, PRODUCT_ID, SKU, EAN, NAME, SPECS, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (8, 2, 'GGLPX8PO128', '0840244705046', 'Pixel 8 Pro Obsidian 128 Go', '{"color": "Obsidian", "storage": 128}', 162.6, 76.5, 8.8, 213); +INSERT INTO C##INVENTORY.PRODUCT_VERSIONS (ID, PRODUCT_ID, SKU, EAN, NAME, SPECS, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (9, 2, 'GGLPX8PO256', '0840244705299', 'Pixel 8 Pro Obsidian 256 Go', '{"color": "Obsidian", "storage": 256}', 162.6, 76.5, 8.8, 213); +INSERT INTO C##INVENTORY.PRODUCT_VERSIONS (ID, PRODUCT_ID, SKU, EAN, NAME, SPECS, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (10, 2, 'GGLPX8PO512', '0840244705565', 'Pixel 8 Pro Obsidian 512 Go', '{"color": "Obsidian", "storage": 512}', 162.6, 76.5, 8.8, 213); +INSERT INTO C##INVENTORY.PRODUCT_VERSIONS (ID, PRODUCT_ID, SKU, EAN, NAME, SPECS, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (11, 2, 'GGLPX8PB128', '0840244705206', 'Pixel 8 Pro Bay 128 Go', '{"color": "Bay", "storage": 128}', 162.6, 76.5, 8.8, 213); +INSERT INTO C##INVENTORY.PRODUCT_VERSIONS (ID, PRODUCT_ID, SKU, EAN, NAME, SPECS, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (12, 2, 'GGLPX8PB256', '0840244705473', 'Pixel 8 Pro Bay 256 Go', '{"color": "Bay", "storage": 256}', 162.6, 76.5, 8.8, 213); +INSERT INTO C##INVENTORY.PRODUCT_VERSIONS (ID, PRODUCT_ID, SKU, EAN, NAME, SPECS, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (13, 2, 'GGLPX8PP128', '0840244705121', 'Pixel 8 Pro Porcelain 128 Go', '{"color": "Porcelain", "storage": 128}', 162.6, 76.5, 8.8, 213); +INSERT INTO C##INVENTORY.PRODUCT_VERSIONS (ID, PRODUCT_ID, SKU, EAN, NAME, SPECS, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (14, 2, 'GGLPX8PP256', '0840244705381', 'Pixel 8 Pro Porcelain 256 Go', '{"color": "Porcelain", "storage": 256}', 162.6, 76.5, 8.8, 213); +INSERT INTO C##INVENTORY.PRODUCTS (ID, SLUG, NAME, BRAND, CATEGORY, SUBCATEGORY, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (3, 'pixel-8a', 'Pixel 8a', 1, 'Phones', 'Smartphones', 162.6, 76.5, 8.8, 213); +INSERT INTO C##INVENTORY.PRODUCTS (ID, SLUG, NAME, BRAND, CATEGORY, SUBCATEGORY, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (4, 'pixel-9', 'Pixel 9', 1, 'Phones', 'Smartphones', 162.6, 76.5, 8.8, 213); +INSERT INTO C##INVENTORY.PRODUCTS (ID, SLUG, NAME, BRAND, CATEGORY, SUBCATEGORY, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (6, 'pixel-9-pro', 'Pixel 9 Pro', 1, 'Phones', 'Smartphones', 162.6, 76.5, 8.8, 213); +INSERT INTO C##INVENTORY.PRODUCTS (ID, SLUG, NAME, BRAND, CATEGORY, SUBCATEGORY, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (5, 'pixel-9-pro-xl', 'Pixel 9 Pro XL', 1, 'Phones', 'Smartphones', 162.6, 76.5, 8.8, 213); +INSERT INTO C##INVENTORY.PRODUCTS (ID, SLUG, NAME, BRAND, CATEGORY, SUBCATEGORY, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (7, 'pixel-9-pro-fold', 'Pixel 9 Pro Fold', 1, 'Phones', 'Smartphones', 162.6, 76.5, 8.8, 213); +INSERT INTO C##INVENTORY.PRODUCTS (ID, SLUG, NAME, BRAND, CATEGORY, SUBCATEGORY, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (8, 'pixel-8-case', 'Pixel 8 Case', 1, 'Phones', 'Accessories', 154.8, 75.1, 13.4, 27.3); +INSERT INTO C##INVENTORY.PRODUCT_VERSIONS (ID, PRODUCT_ID, SKU, EAN, NAME, SPECS, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (15, 8, 'GGLPX8CH', '0840244703806', 'Pixel 8 Case Hazel', '{"color": "Hazel"}', 154.8, 75.1, 13.4, 27.3); +INSERT INTO C##INVENTORY.PRODUCT_VERSIONS (ID, PRODUCT_ID, SKU, EAN, NAME, SPECS, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (16, 8, 'GGLPX8CC', '0840244703807', 'Pixel 8 Case Coral', '{"color": "Coral"}', 154.8, 75.1, 13.4, 27.3); +INSERT INTO C##INVENTORY.PRODUCT_VERSIONS (ID, PRODUCT_ID, SKU, EAN, NAME, SPECS, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (17, 8, 'GGLPX8CM', '0840244703783', 'Pixel 8 Case Mint', '{"color": "Mint"}', 154.8, 75.1, 13.4, 27.3); +INSERT INTO C##INVENTORY.PRODUCT_VERSIONS (ID, PRODUCT_ID, SKU, EAN, NAME, SPECS, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (18, 8, 'GGLPX8CR', '0840244703813', 'Pixel 8 Case Rose', '{"color": "Rose"}', 154.8, 75.1, 13.4, 27.3); +INSERT INTO C##INVENTORY.PRODUCT_VERSIONS (ID, PRODUCT_ID, SKU, EAN, NAME, SPECS, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (19, 8, 'GGLPX8CCH', '0840244703790', 'Pixel 8 Case Charcoal', '{"color": "Charcoal"}', 154.8, 75.1, 13.4, 27.3); +INSERT INTO C##INVENTORY.PRODUCTS (ID, SLUG, NAME, BRAND, CATEGORY, SUBCATEGORY, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (9, 'pixel-8-casemate-signature', 'Pixel 8 Case Signature', 1, 'Phones', 'Accessories', 155.7, 76.5, 13.7, 1.7); +INSERT INTO C##INVENTORY.PRODUCT_VERSIONS (ID, PRODUCT_ID, SKU, EAN, NAME, SPECS, WIDTH, LENGTH, HEIGHT, WEIGHT) VALUES (20, 9, 'GGLPX8CS', '0840244703900', 'Pixel 8 Case Signature Clear', '{}', 155.7, 76.5, 13.7, 1.7); + +INSERT INTO C##INVENTORY.SUPPLIERS (NAME, "LEVEL", CURRENCY) VALUES ('Google', 1, 'USD'); +INSERT INTO C##INVENTORY.SUPPLIERS (NAME, "LEVEL", CURRENCY) VALUES ('FNAC', 2, 'EUR'); + +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (1, 1, 699); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (1, 2, 759); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (1, 3, 699); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (1, 4, 759); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (1, 5, 699); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (1, 6, 759); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (1, 7, 699); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (1, 8, 999); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (1, 9, 1059); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (1, 10, 1179); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (1, 11, 999); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (1, 12, 1059); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (1, 13, 999); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (1, 14, 1059); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (1, 15, 34.99); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (1, 16, 34.99); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (1, 17, 34.99); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (1, 18, 34.99); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (1, 19, 34.99); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (1, 20, 29.99); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (2, 1, 549); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (2, 2, 609); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (2, 3, 549); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (2, 4, 609); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (2, 5, 549); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (2, 6, 609); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (2, 7, 549); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (2, 8, 749); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (2, 9, 809); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (2, 10, 949); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (2, 11, 749); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (2, 12, 809); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (2, 13, 749); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (2, 14, 809); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (2, 15, 39.99); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (2, 17, 39.99); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (2, 18, 39.99); +INSERT INTO C##INVENTORY.SUPPLIER_PRICES (SUPPLIER_ID, PRODUCT_VERSION_ID, PRICE) VALUES (2, 19, 39.99); + +INSERT INTO C##INVENTORY.SUPPLIER_EMPLOYEES (SUPPLIER_ID, EMPLOYEE_ID, ROLE, CREATED_BY, UPDATED_BY) VALUES (1, 12, 'sale', 3, 3); +INSERT INTO C##INVENTORY.SUPPLIER_EMPLOYEES (SUPPLIER_ID, EMPLOYEE_ID, ROLE, CREATED_BY, UPDATED_BY) VALUES (1, 13, 'delivery', 3, 3); +INSERT INTO C##INVENTORY.SUPPLIER_EMPLOYEES (SUPPLIER_ID, EMPLOYEE_ID, ROLE, CREATED_BY, UPDATED_BY) VALUES (2, 14, 'delivery', 3, 3); + +INSERT INTO C##INVENTORY.PURCHASE_ORDERS (SUPPLIER_ID, PRICE, CURRENCY, DETAILS, NOTES, CREATED_BY, UPDATED_BY) VALUES (1, 9471.92, 'USD', 'Order 1 from Google', 'Make initial stock', 16, 16); +INSERT INTO C##INVENTORY.PURCHASE_ORDER_ITEMS (PURCHASE_ORDER_ID, PRODUCT_VERSION_ID, QUANTITY, PRICE, CREATED_BY, UPDATED_BY) VALUES (1, 1, 3, 699, 16, 16); +INSERT INTO C##INVENTORY.PURCHASE_ORDER_ITEMS (PURCHASE_ORDER_ID, PRODUCT_VERSION_ID, QUANTITY, PRICE, CREATED_BY, UPDATED_BY) VALUES (1, 2, 2, 759, 16, 16); +INSERT INTO C##INVENTORY.PURCHASE_ORDER_ITEMS (PURCHASE_ORDER_ID, PRODUCT_VERSION_ID, QUANTITY, PRICE, CREATED_BY, UPDATED_BY) VALUES (1, 3, 2, 699, 16, 16); +INSERT INTO C##INVENTORY.PURCHASE_ORDER_ITEMS (PURCHASE_ORDER_ID, PRODUCT_VERSION_ID, QUANTITY, PRICE, CREATED_BY, UPDATED_BY) VALUES (1, 5, 2, 699, 16, 16); +INSERT INTO C##INVENTORY.PURCHASE_ORDER_ITEMS (PURCHASE_ORDER_ID, PRODUCT_VERSION_ID, QUANTITY, PRICE, CREATED_BY, UPDATED_BY) VALUES (1, 7, 2, 699, 16, 16); +INSERT INTO C##INVENTORY.PURCHASE_ORDER_ITEMS (PURCHASE_ORDER_ID, PRODUCT_VERSION_ID, QUANTITY, PRICE, CREATED_BY, UPDATED_BY) VALUES (1, 15, 3, 34.99, 16, 16); +INSERT INTO C##INVENTORY.PURCHASE_ORDER_ITEMS (PURCHASE_ORDER_ID, PRODUCT_VERSION_ID, QUANTITY, PRICE, CREATED_BY, UPDATED_BY) VALUES (1, 16, 2, 34.99, 16, 16); +INSERT INTO C##INVENTORY.PURCHASE_ORDER_ITEMS (PURCHASE_ORDER_ID, PRODUCT_VERSION_ID, QUANTITY, PRICE, CREATED_BY, UPDATED_BY) VALUES (1, 20, 3, 29.99, 16, 16); + +INSERT INTO C##INVENTORY.PURCHASE_ORDERS (SUPPLIER_ID, PRICE, CURRENCY, DETAILS, NOTES, CREATED_BY, UPDATED_BY) VALUES (2, 7121, 'EUR', 'Order 1 from FNAC', 'Make initial stock', 16, 16); +INSERT INTO C##INVENTORY.PURCHASE_ORDER_ITEMS (PURCHASE_ORDER_ID, PRODUCT_VERSION_ID, QUANTITY, PRICE, CREATED_BY, UPDATED_BY) VALUES (2, 8, 3, 749, 16, 16); +INSERT INTO C##INVENTORY.PURCHASE_ORDER_ITEMS (PURCHASE_ORDER_ID, PRODUCT_VERSION_ID, QUANTITY, PRICE, CREATED_BY, UPDATED_BY) VALUES (2, 9, 1, 809, 16, 16); +INSERT INTO C##INVENTORY.PURCHASE_ORDER_ITEMS (PURCHASE_ORDER_ID, PRODUCT_VERSION_ID, QUANTITY, PRICE, CREATED_BY, UPDATED_BY) VALUES (2, 10, 1, 949, 16, 16); +INSERT INTO C##INVENTORY.PURCHASE_ORDER_ITEMS (PURCHASE_ORDER_ID, PRODUCT_VERSION_ID, QUANTITY, PRICE, CREATED_BY, UPDATED_BY) VALUES (2, 11, 1, 749, 16, 16); +INSERT INTO C##INVENTORY.PURCHASE_ORDER_ITEMS (PURCHASE_ORDER_ID, PRODUCT_VERSION_ID, QUANTITY, PRICE, CREATED_BY, UPDATED_BY) VALUES (2, 12, 1, 809, 16, 16); +INSERT INTO C##INVENTORY.PURCHASE_ORDER_ITEMS (PURCHASE_ORDER_ID, PRODUCT_VERSION_ID, QUANTITY, PRICE, CREATED_BY, UPDATED_BY) VALUES (2, 13, 1, 749, 16, 16); +INSERT INTO C##INVENTORY.PURCHASE_ORDER_ITEMS (PURCHASE_ORDER_ID, PRODUCT_VERSION_ID, QUANTITY, PRICE, CREATED_BY, UPDATED_BY) VALUES (2, 14, 1, 809, 16, 16); + +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (1, 1, 'F2ST123456', NULL, NULL, NULL); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (2, 1, 'F2ST123457', NULL, NULL, 1); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (3, 1, 'F2ST123458', NULL, NULL, 1); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (4, 2, 'F2ST123459', NULL, NULL, NULL); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (5, 2, 'F2ST123460', NULL, NULL, 2); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (6, 3, 'FK3B789012', NULL, NULL, 2); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (7, 3, 'FK3B789013', NULL, NULL, 2); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (8, 5, 'FK3B789014', NULL, NULL, 3); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (9, 5, 'FK3B789015', NULL, NULL, 3); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (10, 7, 'FK3B789016', NULL, NULL, 3); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (11, 7, 'FG8N456789', NULL, NULL, 3); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (12, 15, 'FG8N456790', NULL, NULL, NULL); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (13, 15, 'FG8N456791', NULL, NULL, 28); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (14, 15, 'FG8N456792', NULL, NULL, 28); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (15, 16, 'FG8N456793', NULL, NULL, 29); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (16, 16, 'FL5H345678', NULL, NULL, 29); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (17, 20, 'FL5H345679', NULL, NULL, NULL); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (18, 20, 'FL5H345680', NULL, NULL, 30); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (19, 20, 'FL5H345681', NULL, NULL, 30); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (20, 8, 'FM7J234567', NULL, NULL, 10); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (21, 8, 'FM7J234568', NULL, NULL, 10); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (22, 8, 'FM7J234569', NULL, NULL, 10); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (23, 9, 'FM7J234570', NULL, NULL, 11); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (24, 10, 'FM7J234571', NULL, NULL, 11); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (25, 11, 'FM7J234572', NULL, NULL, 11); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (26, 12, 'FM7J234573', NULL, NULL, 12); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (27, 13, 'FM7J234574', NULL, NULL, 12); +INSERT INTO C##INVENTORY.PHYSICAL_PRODUCTS (ID, PRODUCT_VERSION_ID, SNID, EXPIRATION, REMARKS, STORED) VALUES (28, 14, 'FM7J234575', NULL, NULL, 12); + +INSERT INTO C##INVENTORY.DELIVERIES (REASON, ACCEPTED, PURCHASE_ORDER_ID, WAREHOUSE_ID, WAREHOUSE_EMPLOYEE_ID, SUPPLIER_ID, SUPPLIER_EMPLOYEE_ID, DELIVERED_AT) VALUES ('supplier_delivery', 'Y', 1, 1, 4, 1, 13, CURRENT_TIMESTAMP); INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 1); -INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (2, 2); - -INSERT INTO C##INVENTORY.PICKUPS (REASON, ACCEPTED, WAREHOUSE_ID, WAREHOUSE_EMPLOYEE_ID, SUPPLIER_ID, SUPPLIER_EMPLOYEE_ID, DELIVERED_AT) VALUES ('customer_delivery', 'Y', 1, 1, 1, 1, CURRENT_TIMESTAMP); -INSERT INTO C##INVENTORY.PICKUPS (REASON, ACCEPTED, WAREHOUSE_ID, WAREHOUSE_EMPLOYEE_ID, SUPPLIER_ID, SUPPLIER_EMPLOYEE_ID, DELIVERED_AT) VALUES ('supplier_return', 'N', 2, 2, 2, 2, CURRENT_TIMESTAMP); - -INSERT INTO C##INVENTORY.PICKUP_ITEMS (PICKUP_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 1); -INSERT INTO C##INVENTORY.PICKUP_ITEMS (PICKUP_ID, PHYSICAL_PRODUCT_ID) VALUES (2, 2); - -INSERT INTO C##INVENTORY.INVENTORIES (NAME, WAREHOUSE_ID, PLANNED, CREATED_BY, UPDATED_BY) VALUES ('Inventory 1', 1, TO_TIMESTAMP('2022-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 1, 1); -INSERT INTO C##INVENTORY.INVENTORIES (NAME, WAREHOUSE_ID, PLANNED, CREATED_BY, UPDATED_BY) VALUES ('Inventory 2', 2, TO_TIMESTAMP('2022-01-02 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 1, 1); - +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 2); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 3); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 4); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 5); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 6); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 7); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 8); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 9); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 10); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 11); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 12); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 13); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 14); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 15); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 16); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 17); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 18); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 19); + +INSERT INTO C##INVENTORY.DELIVERIES (REASON, ACCEPTED, PURCHASE_ORDER_ID, WAREHOUSE_ID, WAREHOUSE_EMPLOYEE_ID, SUPPLIER_ID, SUPPLIER_EMPLOYEE_ID, DELIVERED_AT) VALUES ('supplier_delivery', 'Y', 2, 1, 4, 2, 14, CURRENT_TIMESTAMP); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (2, 20); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (2, 21); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (2, 22); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (2, 23); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (2, 24); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (2, 25); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (2, 26); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (2, 27); +INSERT INTO C##INVENTORY.DELIVERY_ITEMS (DELIVERY_ID, PHYSICAL_PRODUCT_ID) VALUES (2, 28); + +INSERT INTO C##INVENTORY.DELIVERIES (REASON, ACCEPTED, PURCHASE_ORDER_ID, WAREHOUSE_ID, WAREHOUSE_EMPLOYEE_ID, SUPPLIER_ID, SUPPLIER_EMPLOYEE_ID, DELIVERED_AT) VALUES ('customer_return', 'N', NULL, 1, 5, NULL, NULL, CURRENT_TIMESTAMP); + +INSERT INTO C##INVENTORY.INVENTORIES (NAME, WAREHOUSE_ID, PLANNED, CREATED_BY, UPDATED_BY) VALUES ('Initial inventory', 1, TO_TIMESTAMP('2022-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 16, 16); INSERT INTO C##INVENTORY.INVENTORY_MEMBERS (INVENTORY_ID, WAREHOUSE_ID, EMPLOYEE_ID) VALUES (1, 1, 1); -INSERT INTO C##INVENTORY.INVENTORY_MEMBERS (INVENTORY_ID, WAREHOUSE_ID, EMPLOYEE_ID) VALUES (2, 2, 2); +INSERT INTO C##INVENTORY.INVENTORY_MEMBERS (INVENTORY_ID, WAREHOUSE_ID, EMPLOYEE_ID) VALUES (1, 1, 2); +INSERT INTO C##INVENTORY.INVENTORY_MEMBERS (INVENTORY_ID, WAREHOUSE_ID, EMPLOYEE_ID) VALUES (1, 1, 3); +INSERT INTO C##INVENTORY.INVENTORY_OBSERVATIONS (INVENTORY_ID, PHYSICAL_PRODUCT_ID, STATUS, MESSAGE, CREATED_BY, UPDATED_BY) VALUES (1, 1, 'missing', 'Item not found', 13, 13); +INSERT INTO C##INVENTORY.INVENTORY_OBSERVATIONS (INVENTORY_ID, PHYSICAL_PRODUCT_ID, STATUS, MESSAGE, CREATED_BY, UPDATED_BY) VALUES (1, 2, 'broken', 'Item damaged', 14, 14); +INSERT INTO C##INVENTORY.INVENTORY_OBSERVATIONS (INVENTORY_ID, PHYSICAL_PRODUCT_ID, STATUS, MESSAGE, CREATED_BY, UPDATED_BY) VALUES (1, 3, 'misplaced', 'Moved at the right place', 14, 14); -INSERT INTO C##INVENTORY.INVENTORY_OBSERVATIONS (INVENTORY_ID, PHYSICAL_PRODUCT_ID, STATUS, MESSAGE, CREATED_BY, UPDATED_BY) VALUES (1, 1, 'missing', 'Item not found', 1, 1); -INSERT INTO C##INVENTORY.INVENTORY_OBSERVATIONS (INVENTORY_ID, PHYSICAL_PRODUCT_ID, STATUS, MESSAGE, CREATED_BY, UPDATED_BY) VALUES (2, 2, 'broken', 'Item damaged', 1, 1); +INSERT INTO C##INVENTORY.PICKUPS (REASON, ACCEPTED, WAREHOUSE_ID, WAREHOUSE_EMPLOYEE_ID, SUPPLIER_ID, SUPPLIER_EMPLOYEE_ID, DELIVERED_AT) VALUES ('customer_delivery', 'Y', 1, 2, NULL, NULL, CURRENT_TIMESTAMP); +INSERT INTO C##INVENTORY.PICKUP_ITEMS (PICKUP_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 1); +INSERT INTO C##INVENTORY.PICKUP_ITEMS (PICKUP_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 4); +INSERT INTO C##INVENTORY.PICKUP_ITEMS (PICKUP_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 12); +INSERT INTO C##INVENTORY.PICKUP_ITEMS (PICKUP_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 17); diff --git a/demos/ecommerce/source_04_catalog_postgres.sql b/demos/ecommerce/source_04_catalog_postgres.sql index 7101a1686..589b58f12 100644 --- a/demos/ecommerce/source_04_catalog_postgres.sql +++ b/demos/ecommerce/source_04_catalog_postgres.sql @@ -167,48 +167,147 @@ CREATE INDEX idx_product_review_feedbacks_deleted_at ON catalog.product_review_f -- insert some data INSERT INTO catalog.categories (id, parent, depth, slug, name, description, description_html) VALUES (1, NULL, 0, 'electronics', 'Electronics', 'All electronic items', '

All electronic items

'), - (2, 1, 1, 'phones', 'Phones', 'All kinds of phones', '

All kinds of phones

'); + (2, 1, 1, 'phones', 'Phones', 'All kinds of phones', '

All kinds of phones

'), + (3, 2, 2, 'smartphones', 'SmartPhones', 'Most advanced phones', '

Most advanced phones

'), + (4, 1, 1, 'accessories', 'Accessories', 'Useful accessories', '

Useful accessories

'); INSERT INTO catalog.products (id, slug, name, category_id, description, description_html, versions, attributes, stock) -VALUES (1, 'pixel-8-pro', 'Pixel 8 Pro', 2, 'A high-end smartphone by Google', '

A high-end smartphone by Google

','[{"key": "color", "label": "Couleur", "values": [{"name": "Bleu Azur", "value": "#95bbe2"}]}, {"key": "storage", "label": "Taille", "values": [{"name": "128GB", "value": 128}]}]', '[{"key": "Marque", "value": "Google"}]', 100), - (2, 'iphone-14', 'iPhone 14', 2, 'The latest iPhone by Apple', '

The latest iPhone by Apple

', '[{"key": "color", "label": "Couleur", "values": [{"name": "Noir", "value": "#000000"}]}, {"key": "storage", "label": "Taille", "values": [{"name": "256GB", "value": 256}]}]', '[{"key": "Marque", "value": "Apple"}]', 50); +VALUES (1, 'pixel-8', 'Pixel 8', 3, 'A high-end smartphone by Google', '

A high-end smartphone by Google

','[{"key": "color", "label": "Color", "values": [{"name": "Obsidian", "value": "#202020"}, {"name": "Hazel", "value": "#8B8D8B"}, {"name": "Rose", "value": "#F1DDD2"}, {"name": "Mint", "value": "#DDF2E5"}]}, {"key": "storage", "label": "Storage", "values": [{"name": "128 GB", "value": 128}, {"name": "256 GB", "value": 256}]}]', '[{"key": "Brand", "value": "Google"}, {"key": "Screen size", "value": "6,2\""}, {"key": "RAM", "value": "8 Go"}, {"key": "Weight", "value": "187 g"}]', 11), + (2, 'pixel-8-pro', 'Pixel 8 Pro', 3, 'A high-end smartphone by Google', '

A high-end smartphone by Google

','[]', '[]', 9), + (3, 'pixel-8a', 'Pixel 8a', 3, 'A high-end smartphone by Google', '

A high-end smartphone by Google

','[]', '[]', 0), + (4, 'pixel-9', 'Pixel 9', 3, 'A high-end smartphone by Google', '

A high-end smartphone by Google

','[]', '[]', 0), + (5, 'pixel-9-pro', 'Pixel 9 Pro', 3, 'A high-end smartphone by Google', '

A high-end smartphone by Google

','[]', '[]', 0), + (6, 'pixel-9-pro-xl', 'Pixel 9 Pro XL', 3, 'A high-end smartphone by Google', '

A high-end smartphone by Google

','[]', '[]', 0), + (7, 'pixel-9-pro-fold', 'Pixel 9 Pro Fold', 3, 'A high-end smartphone by Google', '

A high-end smartphone by Google

','[]', '[]', 0), + (8, 'pixel-8-case', 'Pixel 8 Case', 4, 'Protect your phone with class!', '

Protect your phone with class!

','[]', '[]', 5), + (9, 'pixel-8-casemate-signature', 'Pixel 8 Case Signature', 4, 'Protect your phone with class!', '

Protect your phone with class!

','[]', '[]', 3); INSERT INTO catalog.product_versions (id, product_id, name, specs, price, stock) -VALUES (1, 1, 'Pixel 8 Pro Menthe 128 Go', '{"color": "Menthe", "storage": 128}', 899.99, 50), - (2, 2, 'iPhone 14 Noir 256 Go', '{"color": "Noir", "storage": 256}', 1099.99, 25); +VALUES (1, 1, 'Pixel 8 Obsidian 128 Go', '{"color": "Obsidian", "storage": 128}', 599, 2), + (2, 1, 'Pixel 8 Obsidian 256 Go', '{"color": "Obsidian", "storage": 256}', 659, 1), + (3, 1, 'Pixel 8 Hazel 128 Go', '{"color": "Hazel", "storage": 128}', 599, 2), + (4, 1, 'Pixel 8 Hazel 256 Go', '{"color": "Hazel", "storage": 256}', 659, 0), + (5, 1, 'Pixel 8 Rose 128 Go', '{"color": "Rose", "storage": 128}', 599, 2), + (6, 1, 'Pixel 8 Rose 256 Go', '{"color": "Rose", "storage": 256}', 659, 0), + (7, 1, 'Pixel 8 Mint 128 Go', '{"color": "Mint", "storage": 128}', 599, 2), + (8, 2, 'Pixel 8 Pro Obsidian 128 Go', '{"color": "Obsidian", "storage": 128}', 899, 3), + (9, 2, 'Pixel 8 Pro Obsidian 256 Go', '{"color": "Obsidian", "storage": 256}', 959, 1), + (10, 2, 'Pixel 8 Pro Obsidian 512 Go', '{"color": "Obsidian", "storage": 512}', 1099, 1), + (11, 2, 'Pixel 8 Pro Bay 128 Go', '{"color": "Bay", "storage": 128}', 899, 1), + (12, 2, 'Pixel 8 Pro Bay 256 Go', '{"color": "Bay", "storage": 256}', 959, 1), + (13, 2, 'Pixel 8 Pro Porcelain 128 Go', '{"color": "Porcelain", "storage": 128}', 899, 1), + (14, 2, 'Pixel 8 Pro Porcelain 256 Go', '{"color": "Porcelain", "storage": 256}', 959, 1), + (15, 8, 'Pixel 8 Case Hazel', '{"color": "Hazel"}', 35, 2), + (16, 8, 'Pixel 8 Case Coral', '{"color": "Coral"}', 35, 2), + (17, 8, 'Pixel 8 Case Mint', '{"color": "Mint"}', 35, 0), + (18, 8, 'Pixel 8 Case Rose', '{"color": "Rose"}', 35, 0), + (19, 8, 'Pixel 8 Case Charcoal', '{"color": "Charcoal"}', 35, 0), + (20, 9, 'Pixel 8 Case Signature Clear', '{}', 30, 2); INSERT INTO catalog.product_cross_sell_options (product_id, product_version_id, label) -VALUES (1, 2, 'Buy with iPhone 14 case'), - (2, 1, 'Buy with Pixel 8 Pro case'); +VALUES (1, 15, 'Protect your phone'), + (1, 20, 'Protect your phone'); INSERT INTO catalog.product_alternatives (product_id, alternative_product_id) VALUES (1, 2), - (2, 1); + (1, 3), + (1, 4), + (2, 1), + (2, 3), + (2, 4), + (3, 1), + (3, 2), + (3, 4), + (4, 1), + (4, 5), + (4, 6), + (4, 7), + (5, 1), + (5, 4), + (5, 6), + (5, 7), + (6, 1), + (6, 4), + (6, 5), + (6, 7), + (7, 1), + (7, 4), + (7, 5), + (7, 6); INSERT INTO catalog.assets (id, kind, format, size, path, alt, width, height, weight) -VALUES (1, 'picture', '1:1', 'high', '/images/pixel-8-pro.png', 'Pixel 8 Pro Image', 1024, 1024, 500), - (2, 'picture', '1:1', 'high', '/images/iphone-14.png', 'iPhone 14 Image', 1024, 1024, 500); +VALUES (1, 'picture', '16:9', 'high', '/images/categories/electronics/banner.png', 'Electronics banner', 1600, 900, 500), + (2, 'picture', '16:9', 'high', '/images/categories/electronics/phones/banner.png', 'Phones banner', 1600, 900, 500), + (3, 'picture', '16:9', 'high', '/images/categories/electronics/phones/smartphones/banner.png', 'SmartPhones banner', 1600, 900, 500), + (4, 'picture', '16:9', 'high', '/images/categories/electronics/accessories/banner.png', 'Accessories banner', 1600, 900, 500), + (5, 'picture', '1:1', 'high', '/images/categories/electronics/icon.png', 'Electronics icon', 150, 150, 345), + (6, 'picture', '3:4', 'high', '/images/products/pixel-8/obsidian/shot.png', 'Pixel 8 Obsidian shot', 360, 480, 474), + (7, 'picture', '3:4', 'high', '/images/products/pixel-8/hazel/shot.png', 'Pixel 8 Hazel shot', 360, 480, 474), + (8, 'picture', '3:4', 'high', '/images/products/pixel-8/rose/shot.png', 'Pixel 8 Rose shot', 360, 480, 474), + (9, 'picture', '3:4', 'high', '/images/products/pixel-8/mint/shot.png', 'Pixel 8 Mint shot', 360, 480, 474), + (10, 'picture', '3:4', 'high', '/images/products/pixel-8-pro/obsidian/shot.png', 'Pixel 8 Pro Obsidian shot', 360, 480, 474), + (11, 'picture', '3:4', 'high', '/images/products/pixel-8-pro/bay/shot.png', 'Pixel 8 Pro Bay shot', 360, 480, 474), + (12, 'picture', '3:4', 'high', '/images/products/pixel-8-pro/porcelain/shot.png', 'Pixel 8 Pro Porcelain shot', 360, 480, 474), + (13, 'picture', '3:4', 'high', '/images/products/pixel-8a/shot.png', 'Pixel 8a shot', 360, 480, 474), + (14, 'picture', '3:4', 'high', '/images/products/pixel-9/shot.png', 'Pixel 9 shot', 360, 480, 474), + (15, 'picture', '3:4', 'high', '/images/products/pixel-9-pro/shot.png', 'Pixel 9 Pro shot', 360, 480, 474), + (16, 'picture', '3:4', 'high', '/images/products/pixel-9-pro-xl/shot.png', 'Pixel 9 Pro XL shot', 360, 480, 474), + (17, 'picture', '3:4', 'high', '/images/products/pixel-9-pro-fold/shot.png', 'Pixel 9 Pro Fold shot', 360, 480, 474), + (18, 'picture', '3:4', 'high', '/images/products/pixel-8-case/hazel/shot.png', 'Pixel 8 Case Hazel shot', 360, 480, 474), + (19, 'picture', '3:4', 'high', '/images/products/pixel-8-case/coral/shot.png', 'Pixel 8 Case Coral shot', 360, 480, 474), + (20, 'picture', '3:4', 'high', '/images/products/pixel-8-case/mint/shot.png', 'Pixel 8 Case Mint shot', 360, 480, 474), + (21, 'picture', '3:4', 'high', '/images/products/pixel-8-case/rose/shot.png', 'Pixel 8 Case Rose shot', 360, 480, 474), + (22, 'picture', '3:4', 'high', '/images/products/pixel-8-case/charcoal/shot.png', 'Pixel 8 Case Charcoal shot', 360, 480, 474), + (23, 'picture', '3:4', 'high', '/images/products/pixel-8-casemate-signature/shot.png', 'Pixel 8 Case Signature shot', 360, 480, 474), + (24, 'picture', '16:9', 'high', '/uploads/users/102/2024-08-24/9ab74d.jpg', 'User upload', 1280, 720, 12845); INSERT INTO catalog.category_assets (category_id, asset_id, placement) VALUES (1, 1, 'banner'), - (2, 2, 'icon'); + (2, 2, 'banner'), + (3, 3, 'banner'), + (4, 4, 'banner'), + (1, 5, 'icon'); INSERT INTO catalog.product_assets (product_id, asset_id, placement) -VALUES (1, 1, 'banner'), - (2, 2, 'icon'); +VALUES (1, 6, 'main'), + (2, 10, 'main'), + (3, 13, 'main'), + (4, 14, 'main'), + (5, 15, 'main'), + (6, 16, 'main'), + (7, 17, 'main'), + (8, 18, 'main'), + (9, 23, 'main'); INSERT INTO catalog.product_version_assets (product_version_id, asset_id, placement) -VALUES (1, 1, 'banner'), - (2, 2, 'icon'); +VALUES (1, 6, 'main'), + (2, 6, 'main'), + (3, 7, 'main'), + (4, 7, 'main'), + (5, 8, 'main'), + (6, 8, 'main'), + (7, 9, 'main'), + (8, 10, 'main'), + (9, 10, 'main'), + (10, 10, 'main'), + (11, 11, 'main'), + (12, 11, 'main'), + (13, 12, 'main'), + (14, 12, 'main'), + (15, 18, 'main'), + (16, 19, 'main'), + (17, 20, 'main'), + (18, 21, 'main'), + (19, 22, 'main'), + (20, 23, 'main'); -INSERT INTO catalog.product_reviews (id, product_id, product_version_id, rating, review, created_by, updated_by) -VALUES (1, 1, 1, 5, 'Amazing phone!', 1, 1), - (2, 2, 2, 4, 'Great, but too expensive.', 2, 2); +INSERT INTO catalog.product_reviews (id, product_id, product_version_id, invoice_id, physical_product_id, rating, review, created_by, updated_by) +VALUES (1, 1, 1, 1, 1, 5, 'Amazing phone!', 102, 102), + (2, 2, 2, 1, 4, 4, 'Great, but too expensive.', 103, 103); INSERT INTO catalog.product_review_assets (product_review_id, asset_id, created_by) -VALUES (1, 1, 1), - (2, 2, 2); +VALUES (1, 24, 102); INSERT INTO catalog.product_review_feedbacks (product_review_id, kind, created_by) -VALUES (1, 'like', 1), - (2, 'report', 2); +VALUES (1, 'like', 104), + (2, 'report', 105); diff --git a/demos/ecommerce/source_05_shopping_postgres.sql b/demos/ecommerce/source_05_shopping_postgres.sql index 61d263377..24ab6c016 100644 --- a/demos/ecommerce/source_05_shopping_postgres.sql +++ b/demos/ecommerce/source_05_shopping_postgres.sql @@ -76,21 +76,24 @@ CREATE INDEX idx_wishlist_members_deleted_at ON shopping.wishlist_members (delet -- insert some data INSERT INTO shopping.carts (id, owner_kind, owner_id, expire_at) -VALUES (1, 'identity.Users', 1, CURRENT_TIMESTAMP + INTERVAL '1 day'), - (2, 'identity.Devices', 1, CURRENT_TIMESTAMP + INTERVAL '1 day'); +VALUES (1, 'Users', 102, CURRENT_TIMESTAMP + INTERVAL '1 day'), + (2, 'Devices', 1, CURRENT_TIMESTAMP + INTERVAL '1 day'); INSERT INTO shopping.cart_items (cart_id, product_version_id, quantity, price, created_by, updated_by) -VALUES (1, 1, 2, 899.99, 1, 1), - (2, 2, 1, 1099.99, 2, 2); +VALUES (1, 1, 1, 599, 102, 102), + (1, 2, 1, 659, 102, 102), + (1, 15, 1, 35, 102, 102), + (1, 20, 1, 30, 102, 102), + (2, 7, 2, 599, NULL, NULL); INSERT INTO shopping.wishlists (id, name, description, public, created_by, updated_by) -VALUES (1, 'John''s Wishlist', 'John''s favorite products', TRUE, 1, 1), - (2, 'Jane''s Wishlist', 'Jane''s favorite products', FALSE, 2, 2); +VALUES (1, 'Bob''s Wishlist', 'Bob''s favorite products', TRUE, 102, 102); INSERT INTO shopping.wishlist_items (wishlist_id, product_id, specs, created_by) -VALUES (1, 1, '{"color": "Menthe", "storage": 128}', 1), - (2, 2, '{"color": "Noir", "storage": 256}', 2); +VALUES (1, 1, '{"color": "Obsidian", "storage": 128}', 102), + (1, 2, '{"color": "Obsidian", "storage": 256}', 102), + (1, 8, '{"color": "Coral"}', 102); INSERT INTO shopping.wishlist_members (wishlist_id, user_id, rights, created_by, updated_by) -VALUES (1, 1, 'edit', 1, 1), - (2, 2, 'view', 2, 2); +VALUES (1, 102, 'edit', 102, 102), + (1, 103, 'view', 102, 102); diff --git a/demos/ecommerce/source_06_billing_sqlserver.sql b/demos/ecommerce/source_06_billing_sqlserver.sql index 8721959c5..4e2b523ed 100644 --- a/demos/ecommerce/source_06_billing_sqlserver.sql +++ b/demos/ecommerce/source_06_billing_sqlserver.sql @@ -105,32 +105,30 @@ CREATE TABLE [billing].[Payments] ( -- insert some data -INSERT INTO [billing].[CustomerAddresses] ([Name], [Street], [City], [State], [ZipCode], [Country], [CreatedBy]) -VALUES ('Billing Address 1', '123 Main St', 'Anytown', 'Anystate', '12345', 1, 1), - ('Billing Address 2', '456 Elm St', 'Othertown', 'Otherstate', '67890', 2, 2); +INSERT INTO [billing].[CustomerAddresses] ([Name], [Street], [City], [State], [ZipCode], [Country], [Complements], [CreatedBy]) +VALUES ('SpongeHome', '124 Conch Street', 'Bikini Bottom', 'Pacific Ocean', '12345', 1, 'Pineapple house next to Squidward', 102); INSERT INTO [billing].[Customers] ([Name], [BillingAddress], [Siret], [TVA], [CreatedBy], [UpdatedBy]) -VALUES ('Customer A', NULL, '12345678901234', 'FR12345678901', 1, 1), - ('Customer B', NULL, '98765432109876', 'DE09876543210', 2, 2); +VALUES ('SpongeBob', 1, NULL, NULL, 102, 102), + ('Krusty Enterprises', 1, '12345678900010', 'FR12345678901', 102, 102); -INSERT INTO [billing].[CustomerMembers] ([CustomerId], [UserId], [CanEdit], [CanInvite], [CanBuy], [BudgetAllowance], - [CreatedBy], [UpdatedBy]) -VALUES (1, 1, 1, 1, 1, 1000, 1, 1), - (2, 2, 1, 0, 1, 500, 2, 2); +INSERT INTO [billing].[CustomerMembers] ([CustomerId], [UserId], [CanEdit], [CanInvite], [CanBuy], [BudgetAllowance], [CreatedBy], [UpdatedBy]) +VALUES (1, 102, 1, 1, 1, NULL, 102, 102), + (2, 102, 1, 1, 1, NULL, 102, 102), + (2, 103, 1, 0, 1, 500, 102, 102); INSERT INTO [billing].[CustomerPaymentMethods] ([CustomerId], [Name], [Kind], [Details], [CreatedBy], [UpdatedBy]) -VALUES (1, 'Credit Card', 'card', '{"card_number": "4111111111111111", "expiry_date": "12/23"}', 1, 1), - (2, 'PayPal', 'paypal', '{"paypal_account": "customer_b@paypal.com"}', 2, 2); +VALUES (1, 'PayPal perso', 'paypal', '{"paypal_account": "spongebob@bikinibottom.com"}', 102, 102), + (2, 'Company Card', 'card', '{"card_number": "4111111111111111", "expiry_date": "12/28"}', 102, 102); -INSERT INTO [billing].[Invoices] ([Reference], [CartId], [CustomerId], [BillingAddress], [TotalPrice], [Currency], - [CreatedBy]) -VALUES ('INV-001', 1, 1, 1, 200.00, 'USD', 1), - ('INV-002', 2, 2, 2, 300.00, 'EUR', 2); +INSERT INTO [billing].[Invoices] ([Reference], [CartId], [CustomerId], [BillingAddress], [TotalPrice], [Currency], [CreatedBy]) +VALUES ('INV-001', 1, 1, 1, 1323, 'EUR', 102); INSERT INTO [billing].[InvoiceLines] ([InvoiceId], [Index], [ProductVersionId], [Description], [Price], [Quantity]) -VALUES (1, 1, 1, 'Product 1 Description', 100.00, 2), - (2, 1, 2, 'Product 2 Description', 150.00, 2); +VALUES (1, 1, 1, 'Pixel 8 Obsidian 128 Go', 599, 1), + (1, 2, 2, 'Pixel 8 Obsidian 256 Go', 659, 1), + (1, 3, 15, 'Pixel 8 Case Hazel', 35, 1), + (1, 4, 20, 'Pixel 8 Case Signature Clear', 30, 1); INSERT INTO [billing].[Payments] ([InvoiceId], [PaymentMethodId], [Amount], [Currency]) -VALUES (1, 1, 200.00, 'USD'), - (2, 2, 300.00, 'EUR'); +VALUES (1, 1, 1323, 'EUR'); diff --git a/demos/ecommerce/source_07_shipping_mongo.sql b/demos/ecommerce/source_07_shipping_mongo.sql index d86cafe3b..5c1f9e204 100644 --- a/demos/ecommerce/source_07_shipping_mongo.sql +++ b/demos/ecommerce/source_07_shipping_mongo.sql @@ -1,9 +1,9 @@ use shipping; // drop everything -db.Carriers.drop(); -db.Shipments.drop(); db.ShipmentItems.drop(); +db.Shipments.drop(); +db.Carriers.drop(); // create the collections @@ -11,14 +11,15 @@ db.createCollection('Carriers', { validator: { $jsonSchema: { bsonType: "object", - required: ["id", "registration", "cargoWidth", "cargoLength", "cargoHeight", "cargoWeight", "createdAt", "updatedAt"], + required: ["id", "registration", "licensePlate", "cargoWidth", "cargoLength", "cargoHeight", "cargoWeight", "createdAt", "updatedAt"], properties: { id: { bsonType: "number" }, registration: { bsonType: "string" }, - cargoWidth: { bsonType: "number" }, - cargoLength: { bsonType: "number" }, - cargoHeight: { bsonType: "number" }, - cargoWeight: { bsonType: "number" }, + licensePlate: { bsonType: "string" }, + cargoWidth: { bsonType: "number", description: "inner cargo width in millimeters" }, + cargoLength: { bsonType: "number", description: "inner cargo length in millimeters" }, + cargoHeight: { bsonType: "number", description: "inner cargo height in millimeters" }, + cargoWeight: { bsonType: "number", description: "maximum weight for the cargo, in kilograms" }, createdAt: { bsonType: "date" }, createdBy: { bsonType: "number" }, updatedAt: { bsonType: "date" }, @@ -63,7 +64,7 @@ db.createCollection('ShipmentItems', { invoiceId: { bsonType: "number" }, invoiceLine: { bsonType: "int" }, deliveredAt: { bsonType: "date" }, - deliveredTo: { bsonType: "number" } + deliveredTo: { bsonType: "number", description: "the User who got the delivered package" } } } } @@ -72,74 +73,19 @@ db.createCollection('ShipmentItems', { // insert some data db.Carriers.insertMany([ - { - id: 1, - registration: "ABC123", - cargoWidth: 2.5, - cargoLength: 10.0, - cargoHeight: 3.0, - cargoWeight: 2000.0, - createdAt: new Date(), - createdBy: 1, - updatedAt: new Date(), - }, - { - id: 2, - registration: "XYZ789", - cargoWidth: 2.0, - cargoLength: 8.0, - cargoHeight: 2.5, - cargoWeight: 1500.0, - createdAt: new Date(), - createdBy: 2, - updatedAt: new Date(), - } + {_id: ObjectId("66cb179dfdd0405e567c1938"), id: 1, registration: "KR123456789", licensePlate: "KR-PLATE-001", cargoWidth: 2500, cargoLength: 12000, cargoHeight: 3000, cargoWeight: 24000, createdAt: new Date(), createdBy: 24, updatedAt: new Date(), updatedBy: 24}, + {_id: ObjectId("66cb179dfdd0405e567c1939"), id: 2, registration: "KR987654321", licensePlate: "KR-PLATE-002", cargoWidth: 2600, cargoLength: 13000, cargoHeight: 3200, cargoWeight: 25000, createdAt: new Date(), createdBy: 24, updatedAt: new Date(), updatedBy: 24}, + {_id: ObjectId("66cb179dfdd0405e567c193a"), id: 3, registration: "KR112233445", licensePlate: "KR-PLATE-003", cargoWidth: 2400, cargoLength: 11500, cargoHeight: 2900, cargoWeight: 23000, createdAt: new Date(), createdBy: 24, updatedAt: new Date(), updatedBy: 24}, + {_id: ObjectId("66cb179dfdd0405e567c193b"), id: 4, registration: "KR556677889", licensePlate: "KR-PLATE-004", cargoWidth: 2550, cargoLength: 12500, cargoHeight: 3100, cargoWeight: 24500, createdAt: new Date(), createdBy: 24, updatedAt: new Date(), updatedBy: 24}, ]); db.Shipments.insertMany([ - { - id: 1, - carrierId: 1, - createdAt: new Date(), - collectedAt: new Date(), - collectedBy: 1, - packagedAt: new Date(), - packagedBy: 1, - loadedAt: new Date(), - loadedBy: 1, - deliveredAt: new Date(), - deliveredBy: 1 - }, - { - id: 2, - carrierId: 2, - createdAt: new Date(), - collectedAt: new Date(), - collectedBy: 2, - packagedAt: new Date(), - packagedBy: 2, - loadedAt: new Date(), - loadedBy: 2, - deliveredAt: new Date(), - deliveredBy: 2 - } + {_id: ObjectId("66cb17a0fdd0405e567c193d"), id: 1, carrierId: 1, createdAt: new Date(), collectedAt: new Date(), collectedBy: 14, packagedAt: new Date(), packagedBy: 14, loadedAt: new Date(), loadedBy: 24, deliveredAt: new Date(), deliveredBy: 24}, ]); db.ShipmentItems.insertMany([ - { - shipmentId: 1, - physicalProductId: 1, - invoiceId: 1, - invoiceLine: 1, - deliveredAt: new Date(), - deliveredTo: 1 - }, - { - shipmentId: 2, - physicalProductId: 2, - invoiceId: 2, - invoiceLine: 1, - deliveredAt: new Date(), - deliveredTo: 2 - } + {_id: ObjectId("66cb17a3fdd0405e567c193f"), shipmentId: 1, physicalProductId: 1, invoiceId: 1, invoiceLine: 1, deliveredAt: new Date(), deliveredTo: 102}, + {_id: ObjectId("66cb17a3fdd0405e567c1940"), shipmentId: 1, physicalProductId: 4, invoiceId: 1, invoiceLine: 2, deliveredAt: new Date(), deliveredTo: 102}, + {_id: ObjectId("66cb17a3fdd0405e567c1941"), shipmentId: 1, physicalProductId: 12, invoiceId: 1, invoiceLine: 3, deliveredAt: new Date(), deliveredTo: 102}, + {_id: ObjectId("66cb17a3fdd0405e567c1942"), shipmentId: 1, physicalProductId: 17, invoiceId: 1, invoiceLine: 4, deliveredAt: new Date(), deliveredTo: 102}, ]); diff --git a/demos/ecommerce/source_09_analytics_mongo.sql b/demos/ecommerce/source_09_analytics_mongo.sql index c764471cb..1682b37ad 100644 --- a/demos/ecommerce/source_09_analytics_mongo.sql +++ b/demos/ecommerce/source_09_analytics_mongo.sql @@ -57,51 +57,12 @@ db.createCollection('Entities', { // insert some data db.Events.insertMany([ - { - id: UUID(), - name: "user__login__success", - source: "website", - details: { ip: "192.168.1.1", browser: "Chrome" }, - entities: { user: [{ id: "1", name: "Loïc Knuchel", email: "loic@azimutt.app" }] }, - createdAt: new Date() - }, - { - id: UUID(), - name: "order__purchase__completed", - source: "app", - details: { amount: 200 }, - entities: { - user: [{ id: "1", name: "Loïc Knuchel" }], - cart: [{ id: "1", name: "Cart 1", items: 2 }], - invoice: [{ id: "1", name: "INV-001", price: 200, currency: "USD", lines: 1 }], - }, - createdAt: new Date() - } + {_id: ObjectId("66c19109ab46f11e824ed6a9"), id: "af099435-b2ed-4871-8f27-8bc88e15b68c", name: "user__login__success", source: "website", details: { ip: "192.168.1.1", browser: "Chrome" }, entities: { user: [{ id: "1", name: "Loïc Knuchel", email: "loic@azimutt.app" }] }, createdAt: new Date()}, + {_id: ObjectId("66c19109ab46f11e824ed6aa"), id: "f35afcfa-92e4-491e-9e51-ed8ac51a9e20", name: "order__purchase__completed", source: "app", details: { amount: 200 }, entities: {user: [{id: "1", name: "Loïc Knuchel"}], cart: [{id: "1", name: "Cart 1", items: 2}], invoice: [{id: "1", name: "INV-001", price: 200, currency: "USD", lines: 1}]}, createdAt: new Date()}, ]); db.Entities.insertMany([ - { - kind: "user", - id: "1", - name: "Loïc Knuchel", - properties: { email: "loic@azimutt.app" }, - createdAt: new Date(), - updatedAt: new Date() - }, - { - kind: "cart", - id: "1", - name: "Cart 1", - properties: { items: 2 }, - createdAt: new Date(), - updatedAt: new Date() - }, - { - kind: "invoice", - id: "1", - name: "INV-001", - properties: { price: 200, currency: "USD", lines: 1 }, - createdAt: new Date(), - updatedAt: new Date() - } + {kind: "user", id: "1", name: "Loïc Knuchel", properties: { email: "loic@azimutt.app" }, createdAt: new Date(), updatedAt: new Date()}, + {kind: "cart", id: "1", name: "Cart 1", properties: { items: 2 }, createdAt: new Date(), updatedAt: new Date()}, + {kind: "invoice", id: "1", name: "INV-001", properties: { price: 200, currency: "USD", lines: 1 }, createdAt: new Date(), updatedAt: new Date()}, ]); diff --git a/frontend/src/Components/Organisms/TableRow.elm b/frontend/src/Components/Organisms/TableRow.elm index 924984f2c..23be39184 100644 --- a/frontend/src/Components/Organisms/TableRow.elm +++ b/frontend/src/Components/Organisms/TableRow.elm @@ -811,7 +811,7 @@ viewFooter now source row = StateSuccess s -> s.loadedAt in - div [ class "px-3 py-1 bg-default-50 text-right italic border-t border-gray-200" ] + div [ class "px-3 py-1 bg-default-50 text-right italic border-t border-gray-200 truncate" ] [ text "from " , source |> Maybe.mapOrElse (\s -> text s.name) (span [ title (SourceId.toString row.source) ] [ text "unknown source" ]) , text ", " From 588a658722194979ac61aac6c62f09506a1ddeec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Knuchel?= Date: Tue, 27 Aug 2024 17:53:04 +0200 Subject: [PATCH 12/16] Improve CRM data --- .../ecommerce/source_03_inventory_oracle.sql | 6 +- demos/ecommerce/source_08_crm_mysql.sql | 187 +++++++++++++++--- 2 files changed, 165 insertions(+), 28 deletions(-) diff --git a/demos/ecommerce/source_03_inventory_oracle.sql b/demos/ecommerce/source_03_inventory_oracle.sql index 6a4bac101..f1576bc1e 100644 --- a/demos/ecommerce/source_03_inventory_oracle.sql +++ b/demos/ecommerce/source_03_inventory_oracle.sql @@ -612,9 +612,9 @@ INSERT INTO C##INVENTORY.INVENTORIES (NAME, WAREHOUSE_ID, PLANNED, CREATED_BY, U INSERT INTO C##INVENTORY.INVENTORY_MEMBERS (INVENTORY_ID, WAREHOUSE_ID, EMPLOYEE_ID) VALUES (1, 1, 1); INSERT INTO C##INVENTORY.INVENTORY_MEMBERS (INVENTORY_ID, WAREHOUSE_ID, EMPLOYEE_ID) VALUES (1, 1, 2); INSERT INTO C##INVENTORY.INVENTORY_MEMBERS (INVENTORY_ID, WAREHOUSE_ID, EMPLOYEE_ID) VALUES (1, 1, 3); -INSERT INTO C##INVENTORY.INVENTORY_OBSERVATIONS (INVENTORY_ID, PHYSICAL_PRODUCT_ID, STATUS, MESSAGE, CREATED_BY, UPDATED_BY) VALUES (1, 1, 'missing', 'Item not found', 13, 13); -INSERT INTO C##INVENTORY.INVENTORY_OBSERVATIONS (INVENTORY_ID, PHYSICAL_PRODUCT_ID, STATUS, MESSAGE, CREATED_BY, UPDATED_BY) VALUES (1, 2, 'broken', 'Item damaged', 14, 14); -INSERT INTO C##INVENTORY.INVENTORY_OBSERVATIONS (INVENTORY_ID, PHYSICAL_PRODUCT_ID, STATUS, MESSAGE, CREATED_BY, UPDATED_BY) VALUES (1, 3, 'misplaced', 'Moved at the right place', 14, 14); +INSERT INTO C##INVENTORY.INVENTORY_OBSERVATIONS (INVENTORY_ID, PHYSICAL_PRODUCT_ID, STATUS, MESSAGE, CREATED_BY, UPDATED_BY) VALUES (1, 2, 'missing', 'Item not found', 13, 13); +INSERT INTO C##INVENTORY.INVENTORY_OBSERVATIONS (INVENTORY_ID, PHYSICAL_PRODUCT_ID, STATUS, MESSAGE, CREATED_BY, UPDATED_BY) VALUES (1, 3, 'broken', 'Item damaged', 14, 14); +INSERT INTO C##INVENTORY.INVENTORY_OBSERVATIONS (INVENTORY_ID, PHYSICAL_PRODUCT_ID, STATUS, MESSAGE, CREATED_BY, UPDATED_BY) VALUES (1, 4, 'misplaced', 'Moved at the right place', 14, 14); INSERT INTO C##INVENTORY.PICKUPS (REASON, ACCEPTED, WAREHOUSE_ID, WAREHOUSE_EMPLOYEE_ID, SUPPLIER_ID, SUPPLIER_EMPLOYEE_ID, DELIVERED_AT) VALUES ('customer_delivery', 'Y', 1, 2, NULL, NULL, CURRENT_TIMESTAMP); INSERT INTO C##INVENTORY.PICKUP_ITEMS (PICKUP_ID, PHYSICAL_PRODUCT_ID) VALUES (1, 1); diff --git a/demos/ecommerce/source_08_crm_mysql.sql b/demos/ecommerce/source_08_crm_mysql.sql index c94e68585..547a030b7 100644 --- a/demos/ecommerce/source_08_crm_mysql.sql +++ b/demos/ecommerce/source_08_crm_mysql.sql @@ -155,41 +155,178 @@ CREATE TABLE Coupons ( -- insert some data -INSERT INTO People (name, email, phone, created_by, updated_by) -VALUES ('John Doe', 'john.doe@example.com', '1234567890', 1, 1), - ('Jane Smith', 'jane.smith@example.com', '0987654321', 2, 2); +INSERT INTO People (id, name, email, phone, created_by, updated_by) +VALUES (1, 'Han Solo', 'han.solo@rebellion.com', '+33-1-45-67-89-01', 41, 41), + (2, 'Luke Skywalker', 'luke.skywalker@rebellion.com', NULL, 41, 41), + (3, 'Leia Organa', 'leia.organa@rebellion.com', '+33-2-98-23-45-67', 41, 41), + (4, 'Yoda', 'yoda@jediorder.com', NULL, 41, 41), + (5, 'Obi-Wan Kenobi', 'obi-wan.kenobi@jediorder.com', '+33-4-72-39-56-78', 41, 41), + (6, 'Anakin Skywalker', 'anakin.skywalker@jediorder.com', NULL, 41, 41), + (7, 'Darth Vader', 'darth.vader@empire.com', NULL, 41, 41), + (8, 'Kylo Ren', 'kylo.ren@firstorder.com', NULL, 41, 41), + (9, 'Rey', 'rey@resistance.com', '+33-5-56-23-45-67', 41, 41), + (10, 'Finn', 'finn@resistance.com', NULL, 41, 41), + (11, 'Poe Dameron', 'poe.dameron@resistance.com', NULL, 41, 41), + (12, 'SpongeBob SquarePants', 'spongebob@bikinibottom.com', '+44-20-7946-0958', 41, 41), + (13, 'Patrick Star', 'patrick@bikinibottom.com', '+44-20-7946-0321', 41, 41), + (14, 'Squidward Tentacles', 'squidward@bikinibottom.com', '+44-161-555-3456', 41, 41), + (15, 'Mr Krabs', 'mr.krabs@bikinibottom.com', '+44-121-555-6789', 41, 41), + (16, 'Plankton Sheldon', 'plankton@bikinibottom.com', '+44-113-555-4321', 41, 41), + (17, 'Sandy Cheeks', 'sandy.cheeks@bikinibottom.com', NULL, 41, 41), + (18, 'Michael Scott', 'michael.scott@dundermifflin.com', '+1-202-555-0173', 41, 41), + (19, 'Dwight Schrute', 'dwight.schrute@dundermifflin.com', '+1-202-555-0198', 41, 41), + (20, 'Jim Halpert', 'jim.halpert@dundermifflin.com', '+1-415-555-1234', 41, 41), + (21, 'Pam Beesly', 'pam.beesly@dundermifflin.com', '+1-718-555-5678', 41, 41), + (22, 'Stanley Hudson', 'stanley.hudson@dundermifflin.com', '+1-213-555-9012', 41, 41), + (23, 'Kevin Malone', 'kevin.malone@dundermifflin.com', '+49-30-1234567', 41, 41), + (24, 'Oscar Martinez', 'oscar.martinez@dundermifflin.com', '+49-40-7654321', 41, 41), + (25, 'Phyllis Vance', 'phyllis.vance@dundermifflin.com', '+49-69-9876543', 41, 41), + (26, 'Angela Martin', 'angela.martin@dundermifflin.com', '+49-89-3456789', 41, 41), + (27, 'Andy Bernard', 'andy.bernard@dundermifflin.com', '+49-221-1234567', 41, 41), + (28, 'Creed Bratton', 'creed.bratton@dundermifflin.com', NULL, 41, 41), + (29, 'Meredith Palmer', 'meredith.palmer@dundermifflin.com', NULL, 41, 41), + (30, 'Ryan Howard', 'ryan.howard@dundermifflin.com', NULL, 41, 41), + (31, 'Kelly Kapoor', 'kelly.kapoor@dundermifflin.com', NULL, 41, 41), + (32, 'Toby Flenderson', 'toby.flenderson@dundermifflin.com', NULL, 41, 41), + (33, 'Daryl Philbin', 'daryl.philbin@dundermifflin.com', NULL, 41, 41); -INSERT INTO Organizations (name, created_by, updated_by) -VALUES ('Tech Corp', 1, 1), - ('Business Inc', 2, 2); +INSERT INTO Organizations (id, name, created_by, updated_by) +VALUES (1, 'Rebellion', 41, 41), + (2, 'Jedi Order', 41, 41), + (3, 'Empire', 41, 41), + (4, 'First Order', 41, 41), + (5, 'Resistance', 41, 41), + (6, 'Bikini Bottom Businesses', 41, 41), + (7, 'Dunder Mifflin', 41, 41); -INSERT INTO OrganizationMembers (person_id, organization_id, role, created_by, updated_by) -VALUES (1, 1, 'Manager', 1, 1), - (2, 2, 'Director', 2, 2); +INSERT INTO OrganizationMembers (organization_id, person_id, role, created_by, updated_by) +VALUES (1, 1, 'Captain', 41, 41), + (1, 2, 'Jedi Knight', 41, 41), + (1, 3, 'Princess', 41, 41), + (2, 2, 'Jedi Knight', 41, 41), + (2, 4, 'Jedi Master', 41, 41), + (2, 5, 'Jedi Master', 41, 41), + (2, 6, 'Jedi Knight', 41, 41), + (3, 7, 'Sith Lord', 41, 41), + (4, 8, 'Supreme Leader', 41, 41), + (5, 9, 'Jedi', 41, 41), + (5, 10, 'Soldier', 41, 41), + (5, 11, 'Pilot', 41, 41), + (6, 12, 'Fry Cook', 41, 41), + (6, 13, 'Best Friend', 41, 41), + (6, 14, 'Cashier', 41, 41), + (6, 15, 'Owner', 41, 41), + (6, 16, 'Rival Business Owner', 41, 41), + (7, 18, 'Regional Manager', 41, 41), + (7, 19, 'Assistant to the Regional Manager', 41, 41), + (7, 20, 'Sales Representative', 41, 41), + (7, 21, 'Receptionist', 41, 41), + (7, 22, 'Sales Representative', 41, 41), + (7, 23, 'Accountant', 41, 41), + (7, 24, 'Accountant', 41, 41), + (7, 25, 'Sales Representative', 41, 41), + (7, 26, 'Head of Accounting', 41, 41), + (7, 27, 'Sales Representative', 41, 41), + (7, 28, 'Quality Assurance', 41, 41), + (7, 29, 'Supplier Relations', 41, 41), + (7, 30, 'Temp', 41, 41), + (7, 31, 'Customer Service', 41, 41), + (7, 32, 'HR Representative', 41, 41), + (7, 33, 'Warehouse Foreman', 41, 41); -INSERT INTO SocialAccounts (network, username, owner_kind, owner_id, created_by, updated_by) -VALUES ('twitter', 'john_doe', 'People', 1, 1, 1), - ('linkedin', 'jane_smith', 'Organizations', 2, 2, 2); +INSERT INTO SocialAccounts (owner_kind, owner_id, network, username, created_by, updated_by) +VALUES ('People', 1, 'twitter', 'han_solo_official', 41, 41), + ('People', 1, 'linkedin', 'han-solo-smuggler', 41, 41), + ('People', 1, 'instagram', 'captain_solo', 41, 41), + ('People', 2, 'twitter', 'luke_skywalker_jedi', 41, 41), + ('People', 2, 'facebook', 'luke.skywalker.jedi', 41, 41), + ('People', 2, 'instagram', 'jedi_luke', 41, 41), + ('People', 3, 'twitter', 'leia_organa_senator', 41, 41), + ('People', 3, 'linkedin', 'leia-organa', 41, 41), + ('People', 3, 'facebook', 'princess.leia', 41, 41), + ('People', 4, 'twitter', 'master_yoda', 41, 41), + ('People', 4, 'linkedin', 'yoda-jedi-master', 41, 41), + ('People', 4, 'tiktok', 'wise_yoda', 41, 41), + ('People', 5, 'twitter', 'obi_wan_kenobi', 41, 41), + ('People', 5, 'linkedin', 'obi-wan-kenobi', 41, 41), + ('People', 5, 'instagram', 'ben_kenobi', 41, 41), + ('People', 6, 'twitter', 'anakin_skywalker', 41, 41), + ('People', 6, 'instagram', 'chosen_one_anakin', 41, 41), + ('People', 7, 'twitter', 'darth_vader_sith', 41, 41), + ('People', 7, 'linkedin', 'darth-vader', 41, 41), + ('People', 7, 'tiktok', 'sith_lord_vader', 41, 41), + ('People', 8, 'twitter', 'kylo_ren_sith', 41, 41), + ('People', 8, 'instagram', 'dark_kylo', 41, 41), + ('People', 9, 'twitter', 'rey_jedi', 41, 41), + ('People', 9, 'instagram', 'rey.of.light', 41, 41), + ('People', 9, 'tiktok', 'rey_skywalker', 41, 41), + ('People', 10, 'twitter', 'fn2187_finn', 41, 41), + ('People', 10, 'instagram', 'finn_rebellion', 41, 41), + ('People', 11, 'twitter', 'poe_dameron_pilot', 41, 41), + ('People', 11, 'instagram', 'black_leader_poe', 41, 41), + ('Organizations', 1, 'twitter', 'rebellion_alliance', 41, 41), + ('Organizations', 1, 'linkedin', 'rebellion-alliance', 41, 41), + ('Organizations', 1, 'facebook', 'rebellion.alliance', 41, 41), + ('Organizations', 2, 'twitter', 'jedi_order', 41, 41), + ('Organizations', 2, 'linkedin', 'jedi-order', 41, 41), + ('Organizations', 2, 'facebook', 'jedi.order', 41, 41), + ('Organizations', 3, 'twitter', 'galactic_empire', 41, 41), + ('Organizations', 3, 'linkedin', 'galactic-empire', 41, 41), + ('Organizations', 3, 'instagram', 'galactic_empire', 41, 41), + ('Organizations', 4, 'twitter', 'first_order', 41, 41), + ('Organizations', 4, 'linkedin', 'first-order', 41, 41), + ('Organizations', 4, 'instagram', 'first.order', 41, 41), + ('Organizations', 5, 'twitter', 'resistance_alliance', 41, 41), + ('Organizations', 5, 'linkedin', 'resistance-alliance', 41, 41), + ('Organizations', 5, 'facebook', 'resistance.alliance', 41, 41), + ('Organizations', 6, 'twitter', 'bikini_bottom_biz', 41, 41), + ('Organizations', 6, 'linkedin', 'bikini-bottom-businesses', 41, 41), + ('Organizations', 6, 'instagram', 'bikini_bottom_biz', 41, 41), + ('Organizations', 7, 'twitter', 'dunder_mifflin_inc', 41, 41), + ('Organizations', 7, 'linkedin', 'dunder-mifflin', 41, 41), + ('Organizations', 7, 'facebook', 'dunder.mifflin', 41, 41); -INSERT INTO Campaigns (name, status, kind, audience, subject, message, created_by, updated_by) -VALUES ('Winter Sale', 'draft', 'email', 'All subscribers', 'Winter Sale 2024', '

Don\'t miss out on our Winter Sale!

', 1, 1), - ('Summer Promotion', 'live', 'sms', 'VIP customers', 'Summer Promotion', 'Get 50% off all items!', 2, 2); +INSERT INTO Campaigns (name, status, starts, ends, kind, audience, subject, message, created_by, updated_by) +VALUES ('Rebellion Recruitment Drive', 'live', '2024-09-01 08:00:00', '2024-09-15 23:59:59', 'email', 'organization=Rebellion', 'Join the Rebellion!', '

Dear Rebel,

The Rebellion needs you! Join us in the fight against the Empire.

', 41, 41), + ('Summer Promotion', 'live', NULL, NULL, 'sms', 'VIP customers', 'Summer Promotion', 'Get 50% off all items!', 41, 41), + ('Winter Sale', 'draft', NULL, NULL, 'email', 'all', 'Winter Sale 2024', '

Don\'t miss out on our Winter Sale!

', 41, 41); -INSERT INTO CampaignMessages (campaign_id, contact_id, sent_to, created_at, sent_at) -VALUES (1, 1, 'john.doe@example.com', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), - (2, 2, 'jane.smith@example.com', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO CampaignMessages (campaign_id, contact_id, social_id, sent_to, created_at, sent_at, opened_at, clicked_at) +VALUES (1, 1, NULL, 'han.solo@rebellion.com', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL), + (1, 2, NULL, 'luke.skywalker@rebellion.com', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + (1, 3, NULL, 'leia.organa@rebellion.com', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL), + (2, 1, NULL, '+33-1-45-67-89-01', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL); -INSERT INTO Issues (subject, created_by) -VALUES ('Product not delivered', 1), - ('Refund request', 2); +INSERT INTO Issues (subject, created_by, closed_at, closed_by) +VALUES ('Delayed Shipment of Krabby Patties', 102, '2024-08-05 10:00:00', 105), + ('Rebellion Supply Shortage', 37, NULL, NULL), + ('Jedi Training Materials Not Delivered', 41, NULL, NULL), + ('Empire Recruitment Process Feedback', 43, '2024-08-10 16:30:00', 43), + ('First Order Propaganda Issues', 44, NULL, NULL), + ('Printer Issues in Scranton Office', 108, '2024-08-06 09:15:00', 108), + ('Plankton Complaining About Chum Bucket Sales', 106, NULL, NULL); INSERT INTO IssueMessages (issue_id, content, created_by, updated_by) -VALUES (1, 'The product was supposed to arrive yesterday but it hasn\'t arrived yet.', 1, 1), - (2, 'I would like a refund for my recent purchase.', 2, 2); +VALUES (1, 'Shipment of Krabby Patties was delayed by 3 days. Customers are getting impatient.', 102, 102), + (1, 'I''ll look into it and make sure it gets sorted out.', 105, 105), + (1, 'The issue has been resolved. The shipment is on its way.', 105, 105), + (2, 'We are experiencing a shortage of supplies needed for the next mission.', 37, 37), + (2, 'We need to secure a new supplier as soon as possible.', 39, 39), + (3, 'The training materials for the new Jedi recruits haven''t arrived yet.', 41, 41), + (3, 'We need these materials urgently for the next training session.', 38, 38), + (4, 'The current recruitment process is too slow and needs to be streamlined.', 43, 43), + (4, 'Implemented changes to speed up the process. Issue closed.', 43, 43), + (5, 'The propaganda materials sent out last week were not well received.', 44, 44), + (5, 'We need to revise our messaging to better align with our core values.', 44, 44), + (6, 'The printer on the second floor is constantly jamming. It needs to be replaced.', 108, 108), + (6, 'Ordered a new printer. It should arrive tomorrow.', 108, 108), + (6, 'Printer issue resolved. New printer installed.', 108, 108), + (7, 'Chum Bucket sales have been abysmal. We need a new marketing strategy.', 106, 106), + (7, 'Perhaps we could focus on new product offerings or promotions.', 102, 102); INSERT INTO IssueMessageReactions (message_id, kind, created_by) -VALUES (1, 'like', 1), - (2, 'dislike', 2); +VALUES (2, 'like', 102), + (5, 'dislike', 37); INSERT INTO Discounts (name, description, kind, value, enable_at, expire_at, created_by, updated_by) VALUES ('New Year Discount', '10% off on all items', 'percentage', 10.00, '2024-01-01 00:00:00', '2024-01-31 23:59:59', 1, 1), From 731796a05a8183c0174f2d51dd97c6e8e98d17fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Knuchel?= Date: Tue, 27 Aug 2024 18:37:46 +0200 Subject: [PATCH 13/16] Code review --- demos/ecommerce/README.md | 2 +- demos/ecommerce/source_00_design.md | 20 ++++++------- .../source_01_referential_sqlserver.sql | 4 +-- .../ecommerce/source_03_inventory_oracle.sql | 30 +++++++++---------- demos/ecommerce/source_07_shipping_mongo.sql | 3 ++ demos/ecommerce/source_09_analytics_mongo.sql | 3 ++ 6 files changed, 34 insertions(+), 28 deletions(-) diff --git a/demos/ecommerce/README.md b/demos/ecommerce/README.md index f4ef880e3..cbc10332f 100644 --- a/demos/ecommerce/README.md +++ b/demos/ecommerce/README.md @@ -2,7 +2,7 @@ This is a medium demo (~80 tables) showcasing Azimutt ability to explore large schemas, even with several databases (micro-services for examples). -You can find this project at [xxx](https://azimutt.app...) and explore it yourself, you will see: +You can find this project directly on [Azimutt](https://azimutt.app...) and explore it yourself, you will see: - an overview of the schema across several databases - showcases per domain with sample rows diff --git a/demos/ecommerce/source_00_design.md b/demos/ecommerce/source_00_design.md index b5df68a3e..41e97b046 100644 --- a/demos/ecommerce/source_00_design.md +++ b/demos/ecommerce/source_00_design.md @@ -2,23 +2,23 @@ referential.Countries | needs to be referenced for legal reasons CountryId bigint pk - Code varchar - Name varchar + Code varchar unique + Name varchar unique CreatedAt timestamp DeletedAt timestamp nullable referential.States | used for auto-competes StateId bigint pk CountryId bigint fk referential.Countries.CountryId - Code varchar - Name varchar + Code varchar index + Name varchar index CreatedAt timestamp DeletedAt timestamp nullable referential.Cities | used for auto-competes CityId bigint pk StateId bigint fk referential.States.StateId - Name varchar + Name varchar index CreatedAt timestamp DeletedAt timestamp nullable @@ -185,7 +185,7 @@ C##INVENTORY.WAREHOUSE_EMPLOYEES C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS | how to check the employee is identified, can be several WAREHOUSE_ID BIGINT pk fk C##INVENTORY.WAREHOUSES.ID - EMPLOYEES_ID BIGINT pk fk C##INVENTORY.EMPLOYEES.ID + EMPLOYEE_ID BIGINT pk fk C##INVENTORY.EMPLOYEES.ID KIND identity_proof_kind(name, cni, badge) pk VALUE VARCHAR EXPIRE TIMESTAMP nullable @@ -629,7 +629,7 @@ billing.Payments shipping.Carriers id bigint unique=pk - registration varchar + registration varchar index licensePlate varchar cargoWidth float | inner cargo width in millimeters cargoLength float | inner cargo length in millimeters @@ -658,7 +658,7 @@ shipping.Shipments shipping.ShipmentItems shipmentId bigint unique=pk fk shipping.Shipments.id physicalProductId bigint unique=pk fk C##INVENTORY.PHYSICAL_PRODUCTS.ID - invoiceId bigint fk billing.InvoiceLines.InvoiceId + invoiceId bigint index fk billing.InvoiceLines.InvoiceId invoiceLine int fk billing.InvoiceLines.Index deliveredAt timestamp nullable deliveredTo bigint nullable fk identity.Users.id | the User who got the delivered package @@ -805,7 +805,7 @@ analytics.Events source event_source(website, app, admin, job) | the name of the system which emitted this event details json nullable | any additional info for the event entities json nullable | {[kind: string]: {id: string, name: string}[]} - createdAt timestamp + createdAt timestamp index fk analytics.Events.entities:user:id -> identity.Users.id fk analytics.Events.entities:cart:id -> shopping.carts.id fk analytics.Events.entities:invoice:id -> billing.Invoices.InvoiceId @@ -813,7 +813,7 @@ fk analytics.Events.entities:invoice:id -> billing.Invoices.InvoiceId analytics.Entities kind string unique=pk id string unique=pk - name string + name string index properties json createdAt timestamp updatedAt timestamp diff --git a/demos/ecommerce/source_01_referential_sqlserver.sql b/demos/ecommerce/source_01_referential_sqlserver.sql index a1a38cf34..85f30ea3f 100644 --- a/demos/ecommerce/source_01_referential_sqlserver.sql +++ b/demos/ecommerce/source_01_referential_sqlserver.sql @@ -15,8 +15,8 @@ CREATE TABLE [referential].[Countries] ( [CreatedAt] [datetime] NOT NULL DEFAULT GETDATE(), [DeletedAt] [datetime] ); -CREATE INDEX [IDX_Countries_Code] ON [referential].[Countries] ([Code]); -CREATE INDEX [IDX_Countries_Name] ON [referential].[Countries] ([Name]); +CREATE UNIQUE INDEX [IDX_Countries_Code] ON [referential].[Countries] ([Code]); +CREATE UNIQUE INDEX [IDX_Countries_Name] ON [referential].[Countries] ([Name]); EXEC sp_addextendedproperty 'MS_Description', 'needs to be referenced for legal reasons', 'SCHEMA', 'referential', 'TABLE', 'Countries'; CREATE TABLE [referential].[States] ( diff --git a/demos/ecommerce/source_03_inventory_oracle.sql b/demos/ecommerce/source_03_inventory_oracle.sql index f1576bc1e..e3197cbed 100644 --- a/demos/ecommerce/source_03_inventory_oracle.sql +++ b/demos/ecommerce/source_03_inventory_oracle.sql @@ -126,13 +126,13 @@ CREATE INDEX IDX_WAREHOUSE_EMPLOYEES_DELETED_AT ON C##INVENTORY.WAREHOUSE_EMPLOY CREATE TABLE C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS ( WAREHOUSE_ID NUMBER REFERENCES C##INVENTORY.WAREHOUSES (ID), - EMPLOYEES_ID NUMBER REFERENCES C##INVENTORY.EMPLOYEES (ID), + EMPLOYEE_ID NUMBER REFERENCES C##INVENTORY.EMPLOYEES (ID), KIND VARCHAR2(255), VALUE VARCHAR2(255), EXPIRE TIMESTAMP, CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, CREATED_BY NUMBER, - PRIMARY KEY (WAREHOUSE_ID, EMPLOYEES_ID, KIND) + PRIMARY KEY (WAREHOUSE_ID, EMPLOYEE_ID, KIND) ); COMMENT ON TABLE C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS IS 'how to check the employee is identified, can be several'; @@ -220,7 +220,7 @@ CREATE TABLE C##INVENTORY.SUPPLIERS ( ID NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, NAME VARCHAR2(255), "LEVEL" NUMBER, - CURRENCY VARCHAR2(3), + CURRENCY VARCHAR2(3) CHECK (CURRENCY IN ('USD', 'EUR')), CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, DELETED_AT TIMESTAMP @@ -260,7 +260,7 @@ CREATE TABLE C##INVENTORY.PURCHASE_ORDERS ( ID NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, SUPPLIER_ID NUMBER REFERENCES C##INVENTORY.SUPPLIERS (ID), PRICE FLOAT, - CURRENCY VARCHAR2(3), + CURRENCY VARCHAR2(3) CHECK (CURRENCY IN ('USD', 'EUR')), DETAILS CLOB, NOTES CLOB, CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP, @@ -435,17 +435,17 @@ INSERT INTO C##INVENTORY.WAREHOUSE_EMPLOYEES (WAREHOUSE_ID, EMPLOYEE_ID, ROLE, C INSERT INTO C##INVENTORY.WAREHOUSE_EMPLOYEES (WAREHOUSE_ID, EMPLOYEE_ID, ROLE, CREATED_BY, UPDATED_BY) VALUES (2, 10, 'loader', 3, 3); INSERT INTO C##INVENTORY.WAREHOUSE_EMPLOYEES (WAREHOUSE_ID, EMPLOYEE_ID, ROLE, CREATED_BY, UPDATED_BY) VALUES (2, 11, 'loader', 3, 3); -INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 1, 'name', 'Harry Potter', NULL, 16); -INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 1, 'badge', 'HP1234', NULL, 16); -INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 1, 'cni', '01 23 45 678 901', NULL, 16); -INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 2, 'badge', 'HG5678', NULL, 16); -INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 2, 'cni', '02 34 56 789 012', NULL, 16); -INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 3, 'badge', 'RW9101', NULL, 16); -INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 3, 'cni', '03 45 67 890 123', NULL, 16); -INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 4, 'badge', 'AD1213', NULL, 16); -INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 4, 'cni', '04 56 78 901 234', NULL, 16); -INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 5, 'badge', 'SS1415', NULL, 16); -INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEES_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 5, 'cni', '05 67 89 012 345', NULL, 16); +INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEE_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 1, 'name', 'Harry Potter', NULL, 16); +INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEE_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 1, 'badge', 'HP1234', NULL, 16); +INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEE_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 1, 'cni', '01 23 45 678 901', NULL, 16); +INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEE_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 2, 'badge', 'HG5678', NULL, 16); +INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEE_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 2, 'cni', '02 34 56 789 012', NULL, 16); +INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEE_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 3, 'badge', 'RW9101', NULL, 16); +INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEE_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 3, 'cni', '03 45 67 890 123', NULL, 16); +INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEE_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 4, 'badge', 'AD1213', NULL, 16); +INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEE_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 4, 'cni', '04 56 78 901 234', NULL, 16); +INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEE_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 5, 'badge', 'SS1415', NULL, 16); +INSERT INTO C##INVENTORY.WAREHOUSE_IDENTITY_PROOFS (WAREHOUSE_ID, EMPLOYEE_ID, KIND, VALUE, EXPIRE, CREATED_BY) VALUES (1, 5, 'cni', '05 67 89 012 345', NULL, 16); INSERT INTO C##INVENTORY.BRANDS (SLUG, NAME) VALUES ('google', 'Google'); INSERT INTO C##INVENTORY.BRANDS (SLUG, NAME) VALUES ('apple', 'Apple'); diff --git a/demos/ecommerce/source_07_shipping_mongo.sql b/demos/ecommerce/source_07_shipping_mongo.sql index 5c1f9e204..90f9d8632 100644 --- a/demos/ecommerce/source_07_shipping_mongo.sql +++ b/demos/ecommerce/source_07_shipping_mongo.sql @@ -30,6 +30,7 @@ db.createCollection('Carriers', { } } }); +db.Carriers.createIndex({ registration: 1 }); db.createCollection('Shipments', { validator: { @@ -69,6 +70,8 @@ db.createCollection('ShipmentItems', { } } }); +db.ShipmentItems.createIndex({ shipmentId: 1 }); +db.ShipmentItems.createIndex({ invoiceId: 1 }); // insert some data diff --git a/demos/ecommerce/source_09_analytics_mongo.sql b/demos/ecommerce/source_09_analytics_mongo.sql index 1682b37ad..88ebc5c91 100644 --- a/demos/ecommerce/source_09_analytics_mongo.sql +++ b/demos/ecommerce/source_09_analytics_mongo.sql @@ -36,6 +36,8 @@ db.createCollection('Events', { } } }); +db.Events.createIndex({ name: 1 }); +db.Events.createIndex({ createdAt: 1 }); db.createCollection('Entities', { validator: { @@ -53,6 +55,7 @@ db.createCollection('Entities', { } } }); +db.Entities.createIndex({ name: 1 }); // insert some data From 9c11ec4f081fc5cabe9dae02a77c16e0f7bd0d2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Knuchel?= Date: Tue, 27 Aug 2024 18:53:31 +0200 Subject: [PATCH 14/16] publish libs --- cli/package.json | 2 +- cli/src/version.ts | 2 +- gateway/package-lock.json | 72 ++++++++++++------------- gateway/package.json | 14 ++--- libs/connector-mariadb/package.json | 2 +- libs/connector-mongodb/package.json | 2 +- libs/connector-mysql/package.json | 2 +- libs/connector-oracle/package.json | 2 +- libs/connector-sqlserver/package.json | 2 +- libs/models/package.json | 2 +- pnpm-lock.yaml | 78 +++++++++++++-------------- 11 files changed, 90 insertions(+), 90 deletions(-) diff --git a/cli/package.json b/cli/package.json index 97ba39373..c98a83e0d 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "azimutt", - "version": "0.1.24", + "version": "0.1.25", "description": "Export database schema from relational or document databases. Import it to https://azimutt.app", "keywords": [ "database", diff --git a/cli/src/version.ts b/cli/src/version.ts index 3a0a2277d..c8c19954a 100644 --- a/cli/src/version.ts +++ b/cli/src/version.ts @@ -1 +1 @@ -export const version = '0.1.24' // FIXME: `process.env.npm_package_version` is not available :/ +export const version = '0.1.25' // FIXME: `process.env.npm_package_version` is not available :/ diff --git a/gateway/package-lock.json b/gateway/package-lock.json index e3a640299..25a493f9b 100644 --- a/gateway/package-lock.json +++ b/gateway/package-lock.json @@ -1,24 +1,24 @@ { "name": "@azimutt/gateway", - "version": "0.1.16", + "version": "0.1.17", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@azimutt/gateway", - "version": "0.1.16", + "version": "0.1.17", "license": "MIT", "dependencies": { "@azimutt/connector-bigquery": "^0.1.1", "@azimutt/connector-couchbase": "^0.1.1", - "@azimutt/connector-mariadb": "^0.1.4", - "@azimutt/connector-mongodb": "^0.1.2", - "@azimutt/connector-mysql": "^0.1.3", - "@azimutt/connector-oracle": "^0.1.1", + "@azimutt/connector-mariadb": "^0.1.5", + "@azimutt/connector-mongodb": "^0.1.3", + "@azimutt/connector-mysql": "^0.1.4", + "@azimutt/connector-oracle": "^0.1.2", "@azimutt/connector-postgres": "^0.1.9", "@azimutt/connector-snowflake": "^0.1.1", - "@azimutt/connector-sqlserver": "^0.1.2", - "@azimutt/models": "^0.1.13", + "@azimutt/connector-sqlserver": "^0.1.3", + "@azimutt/models": "^0.1.14", "@azimutt/utils": "^0.1.5", "@fastify/cors": "9.0.1", "@sinclair/typebox": "0.29.6", @@ -1049,42 +1049,42 @@ } }, "node_modules/@azimutt/connector-mariadb": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@azimutt/connector-mariadb/-/connector-mariadb-0.1.4.tgz", - "integrity": "sha512-BPJn9pQH2vUW+vTMzustGIaCBLu+9OXRMotEz59htXLNYgg7nYjyoai9br+N8Tt6jbMRSHKAen43tIljK8UhDg==", + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@azimutt/connector-mariadb/-/connector-mariadb-0.1.5.tgz", + "integrity": "sha512-t+LUFDekbtYvcGgb/jASWV0LGMkB4c/bEMEacy6qcoq7u0KssN3JrTOOHCBo8IgURvAGBZ1qA/+FlpKdenCgqg==", "dependencies": { - "@azimutt/models": "^0.1.12", - "@azimutt/utils": "^0.1.4", + "@azimutt/models": "^0.1.14", + "@azimutt/utils": "^0.1.5", "mariadb": "3.3.1" } }, "node_modules/@azimutt/connector-mongodb": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@azimutt/connector-mongodb/-/connector-mongodb-0.1.2.tgz", - "integrity": "sha512-gjdfIOMEzvOA1k3KBo5Ba/ZpC0uXohnA/MPGgU7kBlEZ/p6HAOgrtAothRvrJ56XApAoW0UHp09BtB6uWJmDaw==", + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@azimutt/connector-mongodb/-/connector-mongodb-0.1.3.tgz", + "integrity": "sha512-AzHQ4zK5zhIOTo3b7X53pCxq5LKRHx1I/VS16kT5X1JrpjnkMOXKXvWpm8deJhYtVmIzdvmrtxSprO66YK8pZQ==", "dependencies": { - "@azimutt/models": "^0.1.12", - "@azimutt/utils": "^0.1.4", + "@azimutt/models": "^0.1.14", + "@azimutt/utils": "^0.1.5", "mongodb": "6.8.0" } }, "node_modules/@azimutt/connector-mysql": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@azimutt/connector-mysql/-/connector-mysql-0.1.3.tgz", - "integrity": "sha512-q3RhGgH2UONi9piyQquwNiFirkCxvWo+uNoSGLSh7sebwXMczDZLNrtK/4HYbjCXDTnBXcx/OGGB8vspGXQcNQ==", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@azimutt/connector-mysql/-/connector-mysql-0.1.4.tgz", + "integrity": "sha512-ImKpIOvX+i7BnjU1zZBNG+RBYhfFrHM7d0btYMeBzfVI7S9ixFiDERYlDPeuIvZ5D0w2mDZqTzWZemGYJ0p2sg==", "dependencies": { - "@azimutt/models": "^0.1.12", - "@azimutt/utils": "^0.1.4", + "@azimutt/models": "^0.1.14", + "@azimutt/utils": "^0.1.5", "mysql2": "3.3.5" } }, "node_modules/@azimutt/connector-oracle": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@azimutt/connector-oracle/-/connector-oracle-0.1.1.tgz", - "integrity": "sha512-lsuDN49RzUyzqCyX0Mzca5sAJKh0Ru02zdCENOivbZ+q5OkOkRJm5qg0eiNJDxlz30kfSY/CPzGEyu8eEtTigw==", + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@azimutt/connector-oracle/-/connector-oracle-0.1.2.tgz", + "integrity": "sha512-/aHOZibcORwL2c6bSnefGB5p8cuFayIZA498EVSYLoXlctZhXwbd/KfDS5WXDhNc7YABsUfMUOH08zNmh9hgAA==", "dependencies": { - "@azimutt/models": "^0.1.12", - "@azimutt/utils": "^0.1.4", + "@azimutt/models": "^0.1.14", + "@azimutt/utils": "^0.1.5", "oracledb": "6.6.0" } }, @@ -1110,19 +1110,19 @@ } }, "node_modules/@azimutt/connector-sqlserver": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@azimutt/connector-sqlserver/-/connector-sqlserver-0.1.2.tgz", - "integrity": "sha512-idBQtULAvKuXUoI7JfWAoMCXWfVolPMNAbogxe/oxXqLKjKHbDuohyLwgyFmBpEEwr2dwSayucIp1Zfw8zh5AQ==", + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@azimutt/connector-sqlserver/-/connector-sqlserver-0.1.3.tgz", + "integrity": "sha512-gFvHYZRyRRHigQt2Aw586Nr8qA9rtg10jN1hmjVZXck0m1f6tZzBjd9dTBWR3fEIMZYse4qiv1XwxYyBykSYhg==", "dependencies": { - "@azimutt/models": "^0.1.12", - "@azimutt/utils": "^0.1.4", + "@azimutt/models": "^0.1.14", + "@azimutt/utils": "^0.1.5", "mssql": "11.0.1" } }, "node_modules/@azimutt/models": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/@azimutt/models/-/models-0.1.13.tgz", - "integrity": "sha512-ppElflwEJdeFaiqh0NhpY0foI/mcN5W3V5wWyHDMwAYYqw0C1WLcL2KHsgQGWGbRNFTN96bjkzZG57S8U+M3Tg==", + "version": "0.1.14", + "resolved": "https://registry.npmjs.org/@azimutt/models/-/models-0.1.14.tgz", + "integrity": "sha512-rzF1OYLZufeBlf6v32eZ/9HI5+muCO1oJ4a6iS3j5b4J5hjJoN3jWwPUmA3+n0Wp2VY16UV/whWiWM+hlsL+/Q==", "dependencies": { "@azimutt/utils": "^0.1.5", "openai": "4.54.0", diff --git a/gateway/package.json b/gateway/package.json index 5d034f7c5..4e654e33b 100644 --- a/gateway/package.json +++ b/gateway/package.json @@ -1,6 +1,6 @@ { "name": "@azimutt/gateway", - "version": "0.1.16", + "version": "0.1.17", "description": "A Gateway to proxy database access for Azimutt frontend", "keywords": [ "database", @@ -42,14 +42,14 @@ "dependencies": { "@azimutt/connector-bigquery": "^0.1.1", "@azimutt/connector-couchbase": "^0.1.1", - "@azimutt/connector-mariadb": "^0.1.4", - "@azimutt/connector-mongodb": "^0.1.2", - "@azimutt/connector-mysql": "^0.1.3", - "@azimutt/connector-oracle": "^0.1.1", + "@azimutt/connector-mariadb": "^0.1.5", + "@azimutt/connector-mongodb": "^0.1.3", + "@azimutt/connector-mysql": "^0.1.4", + "@azimutt/connector-oracle": "^0.1.2", "@azimutt/connector-postgres": "^0.1.9", "@azimutt/connector-snowflake": "^0.1.1", - "@azimutt/connector-sqlserver": "^0.1.2", - "@azimutt/models": "^0.1.13", + "@azimutt/connector-sqlserver": "^0.1.3", + "@azimutt/models": "^0.1.14", "@azimutt/utils": "^0.1.5", "@fastify/cors": "9.0.1", "@sinclair/typebox": "0.29.6", diff --git a/libs/connector-mariadb/package.json b/libs/connector-mariadb/package.json index f1d25274f..19e804d2f 100644 --- a/libs/connector-mariadb/package.json +++ b/libs/connector-mariadb/package.json @@ -1,6 +1,6 @@ { "name": "@azimutt/connector-mariadb", - "version": "0.1.4", + "version": "0.1.5", "description": "Connect to MariaDB, extract schema, run analysis and queries", "keywords": [], "homepage": "https://azimutt.app", diff --git a/libs/connector-mongodb/package.json b/libs/connector-mongodb/package.json index 0f58c5f66..f0535c698 100644 --- a/libs/connector-mongodb/package.json +++ b/libs/connector-mongodb/package.json @@ -1,6 +1,6 @@ { "name": "@azimutt/connector-mongodb", - "version": "0.1.2", + "version": "0.1.3", "description": "Connect to MongoDB, extract schema, run analysis and queries", "keywords": [], "homepage": "https://azimutt.app", diff --git a/libs/connector-mysql/package.json b/libs/connector-mysql/package.json index ee5b67fec..6aed50b62 100644 --- a/libs/connector-mysql/package.json +++ b/libs/connector-mysql/package.json @@ -1,6 +1,6 @@ { "name": "@azimutt/connector-mysql", - "version": "0.1.3", + "version": "0.1.4", "description": "Connect to MySQL, extract schema, run analysis and queries", "keywords": [], "homepage": "https://azimutt.app", diff --git a/libs/connector-oracle/package.json b/libs/connector-oracle/package.json index 13efda742..5c4fa29ac 100644 --- a/libs/connector-oracle/package.json +++ b/libs/connector-oracle/package.json @@ -1,6 +1,6 @@ { "name": "@azimutt/connector-oracle", - "version": "0.1.1", + "version": "0.1.2", "description": "Connect to Oracle, extract schema, run analysis and queries", "keywords": [], "homepage": "https://azimutt.app", diff --git a/libs/connector-sqlserver/package.json b/libs/connector-sqlserver/package.json index 93ba63b1a..b373437d6 100644 --- a/libs/connector-sqlserver/package.json +++ b/libs/connector-sqlserver/package.json @@ -1,6 +1,6 @@ { "name": "@azimutt/connector-sqlserver", - "version": "0.1.2", + "version": "0.1.3", "description": "Connect to SQL Server, extract schema, run analysis and queries", "keywords": [], "homepage": "https://azimutt.app", diff --git a/libs/models/package.json b/libs/models/package.json index a30c6f2ef..1cc863545 100644 --- a/libs/models/package.json +++ b/libs/models/package.json @@ -1,6 +1,6 @@ { "name": "@azimutt/models", - "version": "0.1.13", + "version": "0.1.14", "description": "Define a standard database models for Azimutt.", "keywords": [], "homepage": "https://azimutt.app", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 92381bb74..722d660d3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -397,17 +397,17 @@ importers: specifier: ^0.1.1 version: 0.1.1 '@azimutt/connector-mariadb': - specifier: ^0.1.4 - version: 0.1.4 + specifier: ^0.1.5 + version: 0.1.5 '@azimutt/connector-mongodb': - specifier: ^0.1.2 - version: 0.1.2(socks@2.8.3) - '@azimutt/connector-mysql': specifier: ^0.1.3 - version: 0.1.3 + version: 0.1.3(socks@2.8.3) + '@azimutt/connector-mysql': + specifier: ^0.1.4 + version: 0.1.4 '@azimutt/connector-oracle': - specifier: ^0.1.1 - version: 0.1.1 + specifier: ^0.1.2 + version: 0.1.2 '@azimutt/connector-postgres': specifier: ^0.1.9 version: 0.1.9(pg-native@3.0.1) @@ -415,11 +415,11 @@ importers: specifier: ^0.1.1 version: 0.1.1(asn1.js@5.4.1) '@azimutt/connector-sqlserver': - specifier: ^0.1.2 - version: 0.1.2 + specifier: ^0.1.3 + version: 0.1.3 '@azimutt/models': - specifier: ^0.1.13 - version: 0.1.13 + specifier: ^0.1.14 + version: 0.1.14 '@azimutt/utils': specifier: ^0.1.5 version: 0.1.5 @@ -1198,17 +1198,17 @@ packages: '@azimutt/connector-couchbase@0.1.1': resolution: {integrity: sha512-c0ZSWRqR+I6qzrgROUpoAuzkTWdPEz6Jz/Na+0Lt/1Uqyr9Vj1JSm4dwgh53RN0G8kC4HPJWpD8gC58Z0tyErA==} - '@azimutt/connector-mariadb@0.1.4': - resolution: {integrity: sha512-BPJn9pQH2vUW+vTMzustGIaCBLu+9OXRMotEz59htXLNYgg7nYjyoai9br+N8Tt6jbMRSHKAen43tIljK8UhDg==} + '@azimutt/connector-mariadb@0.1.5': + resolution: {integrity: sha512-t+LUFDekbtYvcGgb/jASWV0LGMkB4c/bEMEacy6qcoq7u0KssN3JrTOOHCBo8IgURvAGBZ1qA/+FlpKdenCgqg==} - '@azimutt/connector-mongodb@0.1.2': - resolution: {integrity: sha512-gjdfIOMEzvOA1k3KBo5Ba/ZpC0uXohnA/MPGgU7kBlEZ/p6HAOgrtAothRvrJ56XApAoW0UHp09BtB6uWJmDaw==} + '@azimutt/connector-mongodb@0.1.3': + resolution: {integrity: sha512-AzHQ4zK5zhIOTo3b7X53pCxq5LKRHx1I/VS16kT5X1JrpjnkMOXKXvWpm8deJhYtVmIzdvmrtxSprO66YK8pZQ==} - '@azimutt/connector-mysql@0.1.3': - resolution: {integrity: sha512-q3RhGgH2UONi9piyQquwNiFirkCxvWo+uNoSGLSh7sebwXMczDZLNrtK/4HYbjCXDTnBXcx/OGGB8vspGXQcNQ==} + '@azimutt/connector-mysql@0.1.4': + resolution: {integrity: sha512-ImKpIOvX+i7BnjU1zZBNG+RBYhfFrHM7d0btYMeBzfVI7S9ixFiDERYlDPeuIvZ5D0w2mDZqTzWZemGYJ0p2sg==} - '@azimutt/connector-oracle@0.1.1': - resolution: {integrity: sha512-lsuDN49RzUyzqCyX0Mzca5sAJKh0Ru02zdCENOivbZ+q5OkOkRJm5qg0eiNJDxlz30kfSY/CPzGEyu8eEtTigw==} + '@azimutt/connector-oracle@0.1.2': + resolution: {integrity: sha512-/aHOZibcORwL2c6bSnefGB5p8cuFayIZA498EVSYLoXlctZhXwbd/KfDS5WXDhNc7YABsUfMUOH08zNmh9hgAA==} '@azimutt/connector-postgres@0.1.9': resolution: {integrity: sha512-ZVl0/R741vMU1E7wwvXaAWnvvfuiwvPR1/MklaVXhG4ijCzjpi0T+vvk7qlX8W0uJeSqG+z/1UMBF1sxRPE27Q==} @@ -1216,11 +1216,11 @@ packages: '@azimutt/connector-snowflake@0.1.1': resolution: {integrity: sha512-S8zM9fppxFGDb5hLO6o0lUfY/5MELncjy7KuK9VBcpKbf7OLO+YWpj8pnc0NloeEemdSyL8G4CKyXzEEgN36ZQ==} - '@azimutt/connector-sqlserver@0.1.2': - resolution: {integrity: sha512-idBQtULAvKuXUoI7JfWAoMCXWfVolPMNAbogxe/oxXqLKjKHbDuohyLwgyFmBpEEwr2dwSayucIp1Zfw8zh5AQ==} + '@azimutt/connector-sqlserver@0.1.3': + resolution: {integrity: sha512-gFvHYZRyRRHigQt2Aw586Nr8qA9rtg10jN1hmjVZXck0m1f6tZzBjd9dTBWR3fEIMZYse4qiv1XwxYyBykSYhg==} - '@azimutt/models@0.1.13': - resolution: {integrity: sha512-ppElflwEJdeFaiqh0NhpY0foI/mcN5W3V5wWyHDMwAYYqw0C1WLcL2KHsgQGWGbRNFTN96bjkzZG57S8U+M3Tg==} + '@azimutt/models@0.1.14': + resolution: {integrity: sha512-rzF1OYLZufeBlf6v32eZ/9HI5+muCO1oJ4a6iS3j5b4J5hjJoN3jWwPUmA3+n0Wp2VY16UV/whWiWM+hlsL+/Q==} '@azimutt/utils@0.1.5': resolution: {integrity: sha512-QhfsGJqlfnUP+nOyhVXANNhBvMqYnQO6B6KoaOnZ+f0BpDGchs4BjMYy81rFYIPzoNSRg7qiQGmbw+zLjpZtBg==} @@ -9709,7 +9709,7 @@ snapshots: '@azimutt/connector-bigquery@0.1.1': dependencies: - '@azimutt/models': 0.1.13 + '@azimutt/models': 0.1.14 '@azimutt/utils': 0.1.5 '@google-cloud/bigquery': 7.7.0(encoding@0.1.13) transitivePeerDependencies: @@ -9718,24 +9718,24 @@ snapshots: '@azimutt/connector-couchbase@0.1.1': dependencies: - '@azimutt/models': 0.1.13 + '@azimutt/models': 0.1.14 '@azimutt/utils': 0.1.5 couchbase: 4.3.1 transitivePeerDependencies: - encoding - supports-color - '@azimutt/connector-mariadb@0.1.4': + '@azimutt/connector-mariadb@0.1.5': dependencies: - '@azimutt/models': 0.1.13 + '@azimutt/models': 0.1.14 '@azimutt/utils': 0.1.5 mariadb: 3.3.1 transitivePeerDependencies: - encoding - '@azimutt/connector-mongodb@0.1.2(socks@2.8.3)': + '@azimutt/connector-mongodb@0.1.3(socks@2.8.3)': dependencies: - '@azimutt/models': 0.1.13 + '@azimutt/models': 0.1.14 '@azimutt/utils': 0.1.5 mongodb: 6.8.0(socks@2.8.3) transitivePeerDependencies: @@ -9748,17 +9748,17 @@ snapshots: - snappy - socks - '@azimutt/connector-mysql@0.1.3': + '@azimutt/connector-mysql@0.1.4': dependencies: - '@azimutt/models': 0.1.13 + '@azimutt/models': 0.1.14 '@azimutt/utils': 0.1.5 mysql2: 3.3.5 transitivePeerDependencies: - encoding - '@azimutt/connector-oracle@0.1.1': + '@azimutt/connector-oracle@0.1.2': dependencies: - '@azimutt/models': 0.1.13 + '@azimutt/models': 0.1.14 '@azimutt/utils': 0.1.5 oracledb: 6.6.0 transitivePeerDependencies: @@ -9766,7 +9766,7 @@ snapshots: '@azimutt/connector-postgres@0.1.9(pg-native@3.0.1)': dependencies: - '@azimutt/models': 0.1.13 + '@azimutt/models': 0.1.14 '@azimutt/utils': 0.1.5 pg: 8.12.0(pg-native@3.0.1) postgres-array: 3.0.2 @@ -9776,7 +9776,7 @@ snapshots: '@azimutt/connector-snowflake@0.1.1(asn1.js@5.4.1)': dependencies: - '@azimutt/models': 0.1.13 + '@azimutt/models': 0.1.14 '@azimutt/utils': 0.1.5 snowflake-sdk: 1.10.1(asn1.js@5.4.1)(encoding@0.1.13) transitivePeerDependencies: @@ -9785,16 +9785,16 @@ snapshots: - encoding - supports-color - '@azimutt/connector-sqlserver@0.1.2': + '@azimutt/connector-sqlserver@0.1.3': dependencies: - '@azimutt/models': 0.1.13 + '@azimutt/models': 0.1.14 '@azimutt/utils': 0.1.5 mssql: 11.0.1 transitivePeerDependencies: - encoding - supports-color - '@azimutt/models@0.1.13': + '@azimutt/models@0.1.14': dependencies: '@azimutt/utils': 0.1.5 openai: 4.54.0(encoding@0.1.13) From fd932d6a5bd50b6c43019021b8afb9ebc32fdd24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Knuchel?= Date: Wed, 28 Aug 2024 13:40:50 +0200 Subject: [PATCH 15/16] Update screenshots --- README.md | 2 +- .../templates/website/index.html.heex | 4 +++- .../images/screenshots/azimutt-ecommerce.png | Bin 0 -> 94500 bytes .../{azimutt.png => azimutt-gospeak.png} | Bin demos/ecommerce/README.md | 4 ++-- docs/_assets/azimutt.png | Bin 79324 -> 94500 bytes 6 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 backend/priv/static/images/screenshots/azimutt-ecommerce.png rename backend/priv/static/images/screenshots/{azimutt.png => azimutt-gospeak.png} (100%) diff --git a/README.md b/README.md index 0b41712be..a0133a0a9 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Azimutt is a full-stack database exploration tool, from modern ERD made for real world databases (big & messy), to fast data navigation, but also documentation everywhere and whole database analysis. -[![Azimutt screenshot](docs/_assets/azimutt.png)](https://azimutt.app/gallery/gospeak) +[![Azimutt screenshot](docs/_assets/azimutt.png)](https://azimutt.app/45f571a6-d9b8-4752-8a13-93ac0d2b7984/c00d0c45-8db2-46b7-9b51-eba661640c3c?token=59166798-32de-4f46-a1b4-0f7327a91336) **Why building Azimutt?** diff --git a/backend/lib/azimutt_web/templates/website/index.html.heex b/backend/lib/azimutt_web/templates/website/index.html.heex index 2c91fd386..70a3a6a14 100644 --- a/backend/lib/azimutt_web/templates/website/index.html.heex +++ b/backend/lib/azimutt_web/templates/website/index.html.heex @@ -84,7 +84,9 @@
- App screenshot + + App screenshot + diff --git a/backend/priv/static/images/screenshots/azimutt-ecommerce.png b/backend/priv/static/images/screenshots/azimutt-ecommerce.png new file mode 100644 index 0000000000000000000000000000000000000000..989db7da76acbb3d5a8da7ce97b8e9a911ec30a7 GIT binary patch literal 94500 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 literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/screenshots/azimutt.png b/backend/priv/static/images/screenshots/azimutt-gospeak.png similarity index 100% rename from backend/priv/static/images/screenshots/azimutt.png rename to backend/priv/static/images/screenshots/azimutt-gospeak.png diff --git a/demos/ecommerce/README.md b/demos/ecommerce/README.md index cbc10332f..63ab99eca 100644 --- a/demos/ecommerce/README.md +++ b/demos/ecommerce/README.md @@ -2,13 +2,13 @@ This is a medium demo (~80 tables) showcasing Azimutt ability to explore large schemas, even with several databases (micro-services for examples). -You can find this project directly on [Azimutt](https://azimutt.app...) and explore it yourself, you will see: +You can find this project directly on [Azimutt](https://azimutt.app/45f571a6-d9b8-4752-8a13-93ac0d2b7984/c00d0c45-8db2-46b7-9b51-eba661640c3c?token=59166798-32de-4f46-a1b4-0f7327a91336) and explore it yourself, you will see: - an overview of the schema across several databases - showcases per domain with sample rows - documentation layouts -The project will let you access the schema and loaded data but if you want to dig into the data, you will have to set up the databases you want using Docker: +The project will let you access the schema and loaded data, but if you want to dig into the data, you will have to set up the databases you want using Docker: - **Referential** needs [SQL Server](../../libs/connector-sqlserver/README.md#local-setup) with [referential script](./source_01_referential_sqlserver.sql) (url `sqlserver://sa:azimutt_42@localhost:1433/Referential`) - **Identity** needs [MariaDB](../../libs/connector-mariadb/README.md#local-setup) with [identity script](./source_02_identity_mariadb.sql) (url `mariadb://root:mariadb@localhost:3307/identity`) diff --git a/docs/_assets/azimutt.png b/docs/_assets/azimutt.png index 99488eedf288fd1c79c9cef486a8f54e1fe7bc9e..989db7da76acbb3d5a8da7ce97b8e9a911ec30a7 100644 GIT binary patch literal 94500 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 literal 79324 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�)8-Ri?{IrkK5zdHF@4GN5kGChz~5F_aB z?6me1j=g;^V*;{Yo8@Ff6#AUeR-+pEiFB5KYEe@2?$Q!kr8sv1iiO2F+wZDO<>Ew2 zqx?H!vJ4KNoiIj_ZnL=Cyx>!ZCWy(3x`pda;b12pamcJ~1 z8{eN6xGik2T-`k!U%B-@J{@G0u33Stqb zLhk+|%`m2_Q7F`ph0)lQ(`mrF4{MZ+m%+FygzN9p-M7S3m1;)#n-ucklwTVb6fc@D z6CSV5r?4v7-Ev;DdXO%eX+J&|YW{=n@ zaIK{mpEMVQy+1N*COdh(_njCci_Hcg10FEGDBX!YG~a=?5eK!@P{O&p&`8d65WE5r z{$%KuOBPi!2;7Xc)%pn)ed_R!mH`l~7hqTDGPH2@3v&&b!KDKTuNK$0Q|>G6Xm7*S zo|FYAO)|@x@wHGc)p(eb17KATXb)CE0UtLGvFZ%4z&s=tpSY{7>k(S;&vqoXU^HQg zD`2_{d&Mn+PMARKh)nRo&HE}H+K02idOxENS$EleCeL~Zd?|_IR6pqg$rrJNA|irdz+&88JT?*pQlkO!OkxCd^BA$t{{ZBXkEnL@wn zgb}lxyx*!4cd<-n+B`6;z7GQY$Mo>{2nz}0e$^?0e>&nPeC5HGGooW0lbp~Nl!oUI zg{$Yy%@QDfDRW4V{ilq0o9PTiy#>&ejupY)doAv+iMyANR%FBDT)%KX1W|DgPUnlmfwY9uv1Uj&mW0RH>-q+WVa=^ricvG6R5<-Yyj zLeW9J&6L2X3*|c}hm%rML(Nf>%nLJZr9SP7T=6No(+wykV3_&$TXm{Xc(3ah)$hq@ z;wV2a@)(^%h8;}+UR}F{IsiWX$3UZ_0)y+&>wv>mKazi+;?-1RDqnC_e$oyE`iU_P zhX%&P;uR0o>*kC8oUQaV>de{uq=jRK8+W3}A%-P@X(sb3Eyk1jYsP?Pa^EzX35Sf7 za@duMA8jq}So(BP3Iy5v@h)4mw46!*mikWF>~+jrQuq^>_b0Xb`Mz*DKH?#LzU9BA ze$uPbh$znbA)S-!=DfF+JcO&-T;!Axfc;WZ!(X6%jqdN!>kcyjo}t}%Mh4%+8=)C6 zY#ODlx1b)#(_-Xn4F;T51h5cy_#TkSI0LoPJZRv3WEBroA<-rL)k56lk6`E9W73_& z0MwI!x3!Am+i~uJ3J;)`UG%`H#=qYP5NN8ffj@$>;q+@u#&>}UOf7G@yueyj0K6a; z!ZC?qTvDEBHhd^MR{xWb592MhshH=g6~!Gzlin^^t4(`P<70;T`HdcN3xs#VgKE~X zz!PQ`x!09fuajwADByBh_FraMz-aA?g#m$yMcyqq(+;B=#sH5X@GcckzSe^s`*3;- z|As>KDga3VlCS4w?g%#s>HKxcHsJ0qfb9(xao5Pxzc2SuQRZS;st-ZKYa4Snl$l`I zNu+uc_e-Nd76X3TCW|G;!ZkWl@s@dp>_936jwPW;QSc@A4UGZYQ_C*9MEAv*^8tG$ zAK|4pzIg@IV+h?U%Hhy+e^n4f*@j}Upos{!7H_{rzuKKp_s-F@0s>?sa3w};wm>7J z`OsIdypYWbI-~VsWCA{sR;iQ2H1FM~3D}zUu_|^yJxL@*Op1&AH9D~A>?6x=vXdc& zV!Cc0%BKTJas2V&n^=2~5UoNHrNRhpsa!`mxA~fQBUVT3#j#EOA2)}v7_5>jS~fh3 zel5yxRh&YK33DaJOdkxa2+vYjo#5jB*Pki=()WwEp@r>#?p|aA5;AVP_aX&MKNPy(x!5f2T?agUzG&2=^60+t z{=}&O1IUKGj4wV#x|Ke8(-YKe^Q#jP9ybz=E;HS}yc)(`-#QuJ^^y}xF?{3E4h+Ay z%Xy3+-g#s+YnA=*vBZte%1=L?8EwF3uANbSUH1Ov7$9D1>*)wips^`Ex(I-%ucZCd z6BOwPj|a%_PYR)&I|)2&Y_>dp0B5&<4g07)jb5j?Qdr2I_U|sZ;U55gd?vjL9|$q1 zN7UMdlZJM(-1@gl*`6 zIR5I^Ba9X?u`r*OBi1HfAsjKjmtNd+i<3E|91~BkPXn**c31&{KQb68fgy_bsn`(= zpAMwAZMq&4CjKo?=nK|Z5(CHmC87jCw0>REN?=9V{P_TgW5Uh;u^Bi2Oyma^x3-4g zzr5CFbEdbKPK;KN-WNM;m@vxF$?zoRR26VTG zFzMLZ6SD-BP$r}(B~nA5Z7KU!_=@61*O68#5e1^~(@7SEWSF40JT%;z_wU?1E~q;l zfC#_TlMA;#qu|-L=w{8jKPnZf^($2j4u@9apft^*|-S$=g-`yi$Q$s4J^U0C1B zqw5CXh>NN$W-e#^%(~LiNfsp=cRN(SdVyg6*BDdK@Vk#5L4TqtOK#MJF*WT+0Mw7F zwsTCU`F_F&y`0Bdo}16-G$sHD#gCLf5m{DMc;Rte)$2V%V(AYMaN7fqQb9o#n^L~H zvxsK~M8xIRZ9Iu?n^?^MY=e&D^{~!>J=U=BWKqBI&t=*dr`-isL?HWX$C~yt(K6mR z%Ijyx!V4=P?t{VyqORfqWR)ueJkufDbhf_ON8wY1E@!YQ5K{I65%Wd=$2Q}|!Ycx^ zp|^2ZzZ1&Itn%-F6Cyfg(1|Nak2=p@$DYbBjw>sVW9@k#%Fjy5Oe0bidj;tD)=T~; zBW(h*C07@O}D>_iF{pK#x^+uMDLb>G`jcxmkKP%ry0U+X;s z3uwM971!Xs_uMTTpY`nkqSp^b_x4oC{%s7I6j{>H#sTUdlQTlWH@#`6lJ^K=zRfa)5$KEwwKdmlTGdiWLa)1xOs_(c1=V z{>vZ6G(wu%l-oj>fL|@cmB>RHqh+ClpnBu~WAFG#_|ySY_h7*ZGy1h%vKj*ZFZ z+a>NQ&4A&_NveV$mz$q&J$GKb_PpNWvJQ9uzc;VJ* z!7%tqcQcU9I7zA~g91Eks32+dcP#1f^RgWV_b^lwP+Lh!4lDaxym=k5Yyj!}BKk9L zcLMjv+WwC_5L@oEL!X2l&QgXUuy)|93I6XyG8AKfd}+IFwCDI>cyQW%$E2ISudRcW z!Vut1d#0BQALb-KpG7D9w0kjdhw9th%cWr!0;Z50?M^-0;2?{!1=`oZ}GlYz?X z0L=?0tSoiWj2BknuebPG=^NC&rw4HbTEz4X9KH;Pp}(3>9X>8!qr><2tb>C3^XFt; zdiBC3?-0tJ4G+T^Xn-(vA7T(Vl-(VKtflpRUu}P56Xn=GHS*Bx@j*169kr~SzU46aM8lFI&92Y3BI({tnG{P+-Bf3r%2qTHc<~TREIedT% zVe_!!?OLRdHt4^<_B{e(Y=*v$a3Z_ln@=V^$hJV{|Bc^>z&wH?7Y>&&#YK()gFm9t zfHWUPQ6L*;Wa5%k%VeX>u&ym2_*Lx_OR(E%mMTN#nYZ2ZP7wF04`bZw645_s`M_@@ zr#HQ1qoj0sPWsR{`t5&HH=`*ezfE#_4vu?##B&6Qt2)KcF^oTfVrtt#2Nyf|E*`4g!(}_Tl7uc4db?%mn}eD ziH~3)Xu{?C&(O+3|Dc8EAg}@(THSm(eXY2brfRI zi*tjpoT87Vsi*MH*M^!-29$jn;?#P7TRu)N;GXUIM)PA=(BW`R%L^S*81>KlJW7$T zb8xh&wF&YePpoJYqnhc1R-Dz`SolD-)X8R?_Q{~bDZSgK<5(r`1HaySL{j6vk(0|Ixf#>^|0LxNcW^ur;} z+&90Yn`9k5leKBkh(qTm-!FIgE;1kflNbIH%x#YMD~;B{y=D=p3=cMG$tr;lO6;R2@b zKSaiBH5*~YXU3G#O)7GP=l7ao%P+KxGD&U$9RNepj|E){5r3ZLT~T3+B-3Hex3y%` zz9Igue?^sBb)97J;j2ERm}ok!CWXuswb#x1qB>{ao;-0a4q6B z3d&Yn^aOtMz6m`zAGe#H463jjJplp6Mps-NSzI6iRG1d8cm0jwO5@zMD2^VZ2$BMQ=31Lyi zt$l-nTuKAu+=Ue7e~S2`j7^vgaM^Tzk;g65W67Z=pYb-{eCqvlCr+3pM^vR;f!K^z zIC|@Yizh`kh56;Kf%iPNJOg2G5vZX6t>Ht*OlBZh-p7w)nBa%Sxwz$I;^dGbGnp0> z3YF)W34Bnk5pjsLL3sS9WdZb5mgQ&H;#FtTRf2y*TdzvumiP&Ix*cwDc#C!TKr}=? z!qK4`>th+%x>Ww`Fya3HrX5LzENRpxM|$H-!!nbJ?KeiffW5CFB8CL5+Ae*DC$q#WT)$x?9&u{VZ) z;dn;&X_&FSSsxz6fM*w)jmR8AXtO62su0-g9u0k$jCH&ce0pM7|G~Bt>~p$|+wi!^ zRYohI(B7So9oC)@`^(oEzw?Y4rUs{0|7-`pj@adfS%@Ku-DE&Cl#m%MNf!jMm|%&D zMgJ3Q`4WzFNR*+?b73?BjX`sC&d<+moZB61YVk+CqF|Gx6BO9>E3TvG#tW1tJLAVJ zLs2a6KdymLcCA$>UlLRJB$Ti6uU)r4q&~027sQ^HIiE7qdoza3# zEml*{*{$*LExf*QYi&WmUoP20a_O;bFuZPKdYtDnHcgt>AoLlL0W z8qZbDE@BPvQ16bG?qI`%ayeWm6}X7zr0qd!$@NL+~UYauQO@D51WVJ~rhMkoN{rXSpSZSMqOc$Z5CKI>!jF zKB^S?u=g^;l0hbpEc zMA`7og`eY+&=PJJ(kfIJB`WI@UzJi%^2~%D9V2)Q_6P7ZM#Zgm3 z9;m$gK-*ulLR&0rki3`yxeD9#0I#GUOsxA2`3ZiRP__x~ssU)m#L{pgA0@JMm|*>9 zQw+|4<&Z>dwQO()HcOoEt5HXI<)TjoLVw#o9^rM+`v|)@9+73u>)#oU-FL`%ypSl^ zZD-|XXPQPDr*59(_CoT$@r!HMl+1UAu2H*m%)mVxoMvQZ2-5jaLV5As zc5n%MaK(0_bhupu;LTW6^Y+se?;pQso7r6|wv35YH|gXo)T|5*ZDfwGK0Vhh72Q90nTtdloH< z;Mo@~)|1AKbXp3a`GS1bNH4N*NtKhHuIo@yI@bs_ic>-wHujbi8{$-a>)mjC>V7MC zTa&i@lJQ$x2q-6JC=h^v!@5>v&apDSmGCPVlr+fTq#4LS?GSko^F>8dDoSXHDKZj9 zSloT1;!-I)iM4O~J#rt?Z;eSKm~i{R<73yA=^g?2@j=q#ligRuj2N@xf?bUJcP2&u zYDHFh{IVaC?bVL1$lXtJ}8d4PPh8Mx8uOedeh~^{&J#J7B$VNgJ{$R{F2+RK!5{QU5kjRUC>EX!@cnw zsL%!~1G2caKo`tdmHk~#aHmK9n*^KIJ1TtszZRZ1;X`Zv*TwY*Q}>Dyn%&pG1Xnk{ zVy#XstTOEJX|Y`}*i;!9n>OR~QVN8#gOWNtwe@Mt#ZdVG&p4yvw5vSmZY)1i<4FY_(*|t_l?rR06P+#Fuv-}*0+W0$^3J3 zy}w8wzYL$8p7g^43_!uF(KjHg0&Wc_*Br$!dR*!f+ z;ypZMP)TpVl9xB>L zNO5TiP^1dHVMCcKV0C#w;-Dax7dCm3!|wN#d}MS^q$)~I0BsBdBB!a@ymNkwM1pOf zLBVv=J&ZPf1`1aS9~@2~_Rr=aTgM$8Tn7bzWukhv&)x>^uOiU0C`Lz2m&?BD16$IBfjUzh(jE5ePxc`>(1ki`uP z7sVZX(1a82qPC+i-X&5)OxkCnL{O7Fe1bSEgIxeMea+$F z=73`B-YSzwpZxLP+>UyukDp`a#uT`_`T~>X@!4T>{tRm!?}?NSTeVQIRE-ogM_Vf|Jf$yMJg~45NaQwLykNq)&`~C?dLrLaHeS4wxwu=R|fmNzYkA(7^s$M z88d37`E0yXc|t{V!%X=D!<*fAw>oydKCAh;n97EfI`2n+NvXzPAv_ud<&-T0&sqM2 z?JQ!WCc!;pdIDc20cH@A<%WY|gx|d5Zjv-H!jTZ9Ls1$e(*E<8*Mbx!^=ly3tz$ayihl37h=K#x{3cqj6*m(#KX{W?@|*zw>SDC(?-$v>hVV_|d1+|> zG1i>Qs)br_%pb{{x}|9U$>a@tPH=>)KVw5NDc;*zA{L950Ny0?9n1b zXp#maoZxH5`VpD(34^VGY;0)Bl_DC^9I`?b@i~-gz*p{Fy#{G#KLI7OTomICyTmW2 zx{k1%pLvNGJ(JF3s{L-Q``5u$Cyrp9S{bO#L>!?08$d z%pdT&8`uVp!2LWSdL!MjkyQ$o0_ZF+^;k zfJF39OVp%XCkXFz)TI!|PU%g|ZhEmw7Qb6IJzM8flXOu(4rBOA417+&PR^EjJArkF zx2R;8c9rQTZ`exm7EhXbu;&1Mu}nY||c&ZnoI8H1y3fSbNT{u};JmQO8|G47o?IxVV1o@)OLD z8hD`4l7BK$#tS$SCoNgEL5UdzY?pjS@A0ODku(@;~M#b|Y;RsvP__Q@$2vc|`l<0lLb2ys!XLZih?` z5faNj+lbhm%~TzK0^IGG>&qwCmz%bie04;u|iC-}^M z%97)KnSO{J(UeOk*UJWRP_~TM`YWkz*(6CG&KXl%yePi`#y%JI%a?^kyac2MnN0w- z^xwUF#hgJ4pAlZ1xT<}g!J1s$^~%iXeQ9|E_^+W;JvLZ~_Ae@=25H4`dmjx%G-d7i zgllWaYR>)2A+M%v$yTMgw=2ClsMk62mU{;Cq<~E_;{68gk$S>)-pXrAdy1g}`Y zSCZk82i{-s*ty-RDdLbKRiNG!y;Q~q?0PzlbwP}rXr{Jc7-MEE5O0W7l9P5J?^Vbm zkngv>mYhv*d7{k#!5G390{bLZ^h39Rl2qdVSbIY=?EZ!ZiMfKI%2qApq9fG{+6$!R zL?h$k!1#*z3&^B4oMs=@xUEz#y%qf6+Q+Z4jhyHHK#lSVz>zQU8#N6s?BOh**-ReL z42N-I;lbh_#=jg{tL;w6#5IO9Xnq3MA9>}qHgO~2k>0sJSYY`mvl!SXzD9Y^9gecG zj$bCmo?oWbD@oN7s&ycWY}tX&=h#CALMaUk5sIXE&#`)X$YuGeOj-Itd-k-=b53(- z;M8$>KrpEU)1M54=@%B}17a$MhF1Jis8m8L9)m-oAuYGOYN|Ls#)8j(+nwTvEvc!4 zuvyZE8ySIU5uB!PVxRcXnq>nLiIyb@)3qyK=sj8X^T{t1x8?re74=k?h_yDMz+Dl{ z#*B-LF`QuL3nmY7VAhaAW9o?pTt+rdQ?{R8#R|;WG#W?yP&}jLmymhBE5e}szaQ5m zWt@Ux*K^1ps91qdn7zdM~Bd+&C@Yc$9>D$g(DM}rx#QKadU?=xNrtlpUB zkJ}haF7iHE8~VLy`4=lgqnwHvw!jRuY!q8TDqBiYFt)2d`~$Yib+<38CI9y@c|JR z*O`Es``|yG26d7%`{NM{vlEl4 z^~hgyy(vF%WIp*r6#eWpcbPjsE5f-)>+z7rh8StN{}Y#OC&>FAXy!Cv`DU&>)^X_w z=ffLri({)4(9QeG9qSeu)1b~@EIl!ONJnS-hxV1OEC-axt1wqp;}nFVq@!Lm`aO{C z)%*)QKuO7Gg)A2*%%<9iFqV!(E?Zzc4MuBD$q2_OCTdK*ev`VgD{X-umS|m+Qd0V< zida+tULtrp*tu|poo_1Xd3?2TfGyq=aaL`)-e&a+D|vay&y?{-AR#&An-~25<``|P z05T7FBaM3g{?Ey}v^NaH$6f5e#t%{SFwb3D%E#p-;cnM^UOKkBiS zv^V_BIM95z}R#)HWiSi+YR#OOyw0JeQk_V=AcbFBPe-W!B8OUN7CL( zln-9}jEF)Ut~k6S$-&!jdxleg<}#9tB2S*p|Nr8?>tp6G#r_!Nu07K&W0baZpiK)hHepOuCO&HSGlZF#S=%?^lQ=)e@Eid?)yq&W8e8 zH4RxB6AA`!p?GN72i;cz(9=Kh-XX^uwU@qE2aiHJ%;1e&W_hi|iIj1>gVh`^V!Uwv zG5a)9>YIPEuEBe!t;W6AiR6(O;buTt%TeBSf_e*dzahx5%BZ;KMD3CJe3>g)HThUTFrRa4l|D}7bGqgHp2epxK;8ItZ262do8U4jV*7?7aJ zViT>JID$us9GamK5)#tC*Gamya?~H`%=({pHik5#m@hGzM1Jc#7bhXUW+| z1FWwntor^X-D;s9yfCBxUqCjP|172q{}+gVcw#X8_M4LQ-*0q(Krng1{O_3g0zUi3 zfE(*05DBX6m7VT*ywrBrQ1p7!-JkN)_Wu`*5z=pSZ7?tY#fZXUTpTG4imo(?d+vYm zVD?5a@#~pG5yj%~dv%}Px`VS6WevBB8&yCkNvhPyeub#u5lU z3!#w+FRbAO4hw{aFa3>lNCTMM^p5^cV5V?b)&nW>43ayLR1(A7g2!F}?G4 zAseed;0dN@r~4-9qT77RpaG_Rxkz^sp46wXfY2-VmM=Z zF|_U&9kWv5>CC7HTsQZ0*`3y0Yrrqfx)JEIlUk^g2A~Z>FEd}g{T}ku^ihqDVV9GM znz+E9EnTl&$)OP@J_kVDfUQ)msc-?ucUfMS*k#!7-_6_+YE9Yh*$qxfk~W!u)C7JS zV)&K5 zmEVfe11%qRw7joyqDSOqEt!oU{}KRYRN`pA|1tnruPQ5-;qpIxf4qEb9^F#<=(@-d z(boqKy7}0QAbdi>6e^{y2H2}}hR1e9RaNuJh?rB#`DFV4owj(!`KUPo+|A950WqLEU^3ll?^VGngsJA< z#L;+I<2l%H<$V5V5NciQG4&u^TeLe8x(y^je#rBgP`VsD$bAyYk-OcZYi1i%>1Mcf ze&{>pB~Is%ZcOxYS(^}_i_=n7ATZ^}bgf5L={&`QXx0|Tt=2zvA*&msKG=YDI?eVq z-Ox{WfG=7jOqoC3)c6QvV?Kg3BY@MjQc^m?g^nVKVSk~~kbH2Q{^3YCKqqLq4FGwx z&B1ov-KV!`C0B6?KpZn2KG^vI=v}Zik_WlM1ifJ5Ab_0csIlRSY=Area9{kXu+8U0+J#?k-fwO0HA_nl$i&&3pf#7v{SUT=$F2VifmaRAQeFvXqZu(zAp)dTG z6C-0m*6|R;x{q${kyA21mWMW35Bg{?ML*$B8z_QJpM0BuPnKJzwr z=G=}XN&fx4bduVqTW>TT^6mN0oUdO?kc9FOIGUj!srk{SS<39SQ2BiQjHn1ZqQn-_ z4v2rsk+u+4sU{rFGZmHr=&hc4E~yMJ_^4ZCL?3wjVr|?ZGFCuox8LK++#Nh!(1-u$ z9j2gx@;AxwJggRk(kRIM^6~Bg0<6E%aQ`R;{o`-%S#Amrq5A8>MI6U;;Z|#7okRS* z;%W3b0jyph0KWVl9G)mJ_>xD6QwU_UYR-cIP!6D{4+?TL>R989~ z9w}7XRZeJ=%0BpjsAL3r&|m9p7d9jR92=3UeH9)k zTFBZ@ZGVvPyuv6pB{WgxkqA9KyzO-je%>^|XZ!7@+90Ooi1WUap0xld?wm<&jF$zs z_#SotIiBh3sd{#3tB!ENMLXvL8#FwQ=pi9Mb!0NAdYN+QeyScLMj~6+!=pQA^sm2HIEYye_M>jRyjR~GUZ6+dT zpaE+d8|GEab(J};8yGvotenATInQUTvm;wdxu}UJ+bd{gX7@&AOtX}<{ysi!VAL~? zg7TH$hBiG*zyimi0F;pa9@qv`lNy!C-wr<9GjgTszCPe(t~80`uw0zw)uzN}FznbP z?5YVHb6D!BHrlu#0!Gw-Ve0_LrJt4(!$uSnE=u;m=CaS$=_V{=6o8M>d14_aG=PG% zPW*60*J3dI7!^t#2%uFF-f5)td{OPac7c^|=@xr?79CuOOOqOMus6{In4mH^PIcdx zp@=#kt5R6Oy2<#68&QOOZ_2j1|LAviaZ~gl?%o)ogh1`=8~Wv;RV)`TL8FsQ-0|m` zRju=_Q0gD$4-g@^t98apAKSkwYAA(fuQTyP}b%TuKI-u?Md|#hzKn@G* z;s~3{@(3G)6zpZTINA1t;ADQzC;!oq3Xi+k9MY040!29qe!_(fRPzw=)n!wF;_`6g z{FN5m)ODYC+Zm#wdMBxDK+^O7p_FNChy#mK z&{>U>?>Bk~#n~W+omiSKHpd>~fBd}Ec=Dfy z9)*X~aqqdP;tgvqE?gMMXsK#S;eVc&N%M*6c>YFqJ8g>;Zd9FglS{!};gTK}m7rdN z)MBCWxpJEbk%-02{+{!gbOgUj_yYO7iXG8~yIYM{scrOe<#XEO1~q1;npzIA5<7JF(@ z2N7ljpNeek3MN-zfj@Kx2zp;`r||71=YKPF+uq&Dmj|cX zfg&}zHxBSwFSb8gsXyO?WZG)PUc5!$9{GXTE@&UUzpU;!v2i;13S9qbS0lZU`%AcF z9yF}rKah02Ta!>6`?I%<@Tp2G_Bk8ER@Vq0Z3q1+u+-pwMqx__|I?l9zLwp${!mW3 z%I?6S?=>cnS)aT9$u8G_w6cA<$@3@pd$q^42yfPYXWz4huF}}s{DwvRw$+{OvE87j zoxxl-xRs1P@7&iPN-T2soTi33+Jy^Z*+2NikZ1L9@Yjwvcaf42t zV0o~Z765F~+?GzYGuOjV&@||blPNy&b5u2pi-hd=KZJ@M=Or}}@c0{3AY&qI0~Ob^ zUtLf1HO?z4uO)AY$b?^I@wEXGO>sM91s6F}1S1Yi64~#E6mH7TNmz?rya^|{1G3~v zWA<6Dxf+$bx13sKLN~aslVasHDxg)>tP^zI~zd-?pS1Gscw* z=o|9$lkd^;&aT9Z7l-|ZMWY#`36KWIK)+J-Wrg>ZUnPbUaYsZtXPE_U#M&=6N8XwA;Cl?w7I>?&;$$L^&yrLxHIUSx* ze=H>)UY)aA=|0dLcZ$-k&wGixTkH9*D<(+v8IFYpb{r@-`nf1mS!Pduw%bui-Wrb% zZ~VnW@lxq$zbGDZaIt*JS!mqT0Vtk_QFcSX=sOQuM+P(A>+buqJaZ+)tc7YpW>6fWZN{ zBnExzQMgP7Sd0l4emIx3kp(1I242_k57)f+-i}fl?56Fd%ZYCt(>UdDxATNsSMvfQ z9*evG=>A>cpda2I!)m>vE(?sw&fyhlEAlSV?%x5U9H%TlkPIjQ<&)Nwf3dSwudnq9>WlzH*bv5ARI?G}n0YrMHUU$8IskB+ zYkdvj|LN>2qv8m*ZhIJ92M<12a0%`VPVnGPa0nJ$f(#ZMhJ@e{ED#bLf=hx04^DvK z?(PKMUK!Y{V+s16~6mlHX*NU2$9QqsvFs3!Pj zcoqL-n5G02@(~LQOX(yn+CF0I9!1vpI0qFhulwRi)@2+qev~UM?fI9+m#pR%8HN4`J1pXgzm_|%70U~`$57O0JE*{q754cVi%8d`iV_lS5l>)m zQTzVp!Fh#CLlHJ052#wfbp(=GSB0+n%dc9-RiX_6{qsQt@Z;zp z@q`gVXe9x;01=6y5E26Uy_@+8PFqPqQ@fC73|6K9>TrvvD6AVZ0>k1Mb6tx)Wdk!n zF@*q0tnuFtS@D%or}UsyZFqBN$bS-iko=!??YA6%;Gkb=2*Qa16ruQ8Ne)z#W11y+ zW*3US=uV#*y&l?|N@rDtEdzXVzf0BJE+h;=#CBL$A^9|wJDq_k%!#ZdBBsiDY9@Y3mrZrI$#Ijqw(%BOmz#lG56{LJq^f;*tK zt3ZF$Q0G%x@A#2dh#ZNf7vxYYQZgRmXkh#Whu`ag*kwWxOD5Uj_GquzujX2Ebi%+n zc23$rWyWz29<5Sx`(}#=pL_lSVGH#y(c)OhCEcB%0wKpftw{__>a=8V)0&3P#(SJf zi$CKId_VSZ#Sj1JHy)Y*HZ*~~;4 zHtzYWFvVc}7AYL6v?c;SE|Mn~cAFOK$G!)tPCxguOZb{c{Otvd1%t05n%Aiq?ZAb# z#9#W(*T6_p+zBc5L{c)1RBar4@<~~uF_;?5bd`OL`!SkS{nkKYK}P_rG3ThPa`BC_9jC8<97a<(k@ZEwD; z&>A~L)5+`X+CC!bS5%xh7W%)6%c@hJ;(7l)Y}(wJG;l?-(;42YZWhmvnt&jeQIn^^ zfX$W?Pg`p`%TyNuqz~VUsbqjx<#9^o~Jm?fsnJ_X+Ux&AB;ATGYRnEml!vpM7}8Gi9;m%t!#L? z+Y~5JBfEDCRb~b%y8{g8Yx9eCCs=e|^&hOH!+$<)jF14sBW4JgSn%iq(cvZkGRT?= zGU!t%>J1_q9Pw^@CgUIm%ZLJ*H@|Zs(`iNR>)6i;QJb`-{@KxB{oM!DxdQ_I3`K3y zrZ0B(CgD((S4mNkf4;ywk)dET4&e=1@BXOs_HD(O_VL#Eu#nDEp^^%r5`6ni&o$}! z+m?>olB=^DsU-qm3lY&K@nxJ}Z^AWlTi&$0{PL`P6CC(4ZQxpySJG=^H!7nbq`*mN zV`}p74Mlj;fRld|P8T*p1QW9sO`>MOCyT{|`}r4hk$iq<_~@5~!DI}~`jfCH0+F`L z>F=rCRUE(a$q>mCaD_bflk64-%t#s*!Oh|X$gWwb2=48*v4oi7fY&i8L$v{ zC8kuGxg3eCuxrIm5hWk(_(2zbrXdaA01soUqO8Mv8}+yz&7#wkxNlx&?2Lcpe5a&X z>u-SdsVfs_jAz(b{ICL=7=ine%GYeq8C%eaF78DnRR?w{p2BK0)>m^870TtI$1k4x z-@bV2XbAq1K8xU;pE%P#t%>qX={G?Obxm@4vK>{5Xc$&}>KnBPjl7$dao)RT{g2l-YY39_mVCz2&mL92-@zjgW5 z2SQccgbF&BP=DhImlD5V}=b)Rfkxd9BxTvSfLRLNnm9;FE=qqw(4z=EIk^Q z-q$m*Y(-5^d4*5wqwj3|QtE9bnIG@9^4Z{qJlIfdD7&?&j5;5WN&5&L)TlPD!vB?i z6ft!9EkBp&GqSJmcdTyNjk%w{#YK2H8fgL5FP}bv8PC5=H(RP?Oxt~pP>{y?*-|M( z_6+uVh(8F`w+3h`$&&2b5blwLA3YedtW!C^uzM86na)QdAi0J#Ai1GZjih?`Pi4Wq z?aZL@Jmp0pxxvccH*}N_-n(I5-KhdxgH{n=Lgke1iR=V{2wW^hGxlj!Ex_OXN0XH_ ze7UN5E}}s0pq_ULWA(Coc3iulN2AQEiHYJ1agLy*L!ZQl$YS-&lMk!Pr9L#!DjF}m ziU$M0Ka~}ZO9x$4p*M7WNzfdU7H>bwzAdZ3wi4%P>7+zA(07QW^O(*h^5Jj^EAkBM2W5aqzAs zF-gID6s5{}jt=xE_+#TJ?0XzmM$1Rz`DxNXM{`K8uV*Nb>8awgHfJnFos(5^EZ2B8 z&I;8Y4~hd?${Z1SS>J-RM~Fppq3Yw?NU4S$L6SY($FjF* zxb9D6W3<_bX)?76FN_y{T@&|r?=SF7ZBSQ@zAU>b!lKcS81|W)bddQ~9q65qysUQt z<4psv^^`1Es)R#75?7o=z zJ_dBmpz@zAyf}zqTASOt63vi$*4oEx7j!@TsS&g2xZfN5CWL0VV4H_Yv7-a-u8t8P zx!ATaJx{POzB_I65TLjy0{dkAm2ed)f zu8fBQ@e%b@04qX2@3HIi_H}4nsKBcnGh)5#xZ3Zh*Gc1e3hjwt<_18u-#>(`$(Q`O z(7%g^U5c3XwVjfd(}`(L#t`;(Esas3ls*SU zuj%BggG0+_R(w0cvqpF3jtc>+1H-Z?{GTxzO{T^Q<)o=+8Yhfzl` zdDPXx;wCQlpDXNYPG~?yIcG-OCr5?=hQXb0zA7(OgklGN)zxo3ng*ct%~B_MOJYAC z+`Fp5n5Ba{zes)Xv_QtJXeAmceFtuqwy+r1AhCib9=EZ!m z+b73a*3?R;>_jJ-sZ5RUz4)zRd&Wg%jXW+l=Oppm+RXznQ_p%R z0;I(Q6}m8sy4}AWre~v@Ya<~XGQ4*!_K7HfVM$`iHP@ADOvIxT6S5-U>calAqcIkjtM>DN3z$(-fLyWaghpZbWVTdub+BLs@z8W;~*B!J9Gui8g$GW_exw>nK%KEekU z_v8j%Z+Pxz&U*B&f{mc+gQi2mwmWYc&o45BPOvNXYMKj2Us1RL6x;GV9~YwP+vU`n z7ehDhpNH<-w{_S!7@9>@w<;X5`nFA=8$4PomdWT~NhZ7HV!T#6S7z#$iNOL8>vhQz z$^qtXdfP1RTyu57*Q5!KC(W^J*w8NQpp6&R`n|8t)I8Ri7{@@s>JaTSc$t^!LNha? zJp7M`Y4$U&$yiy<8;U8p^3>`%IZ~Kz?`x#F!}-z}MxUdY4!u0wncJ!D9pNj5eEWwH zSM?raiVw7z|3sH^H~k+An-qqV+>OtZYrjQ)&}&XOe(3MqB+GKK4YKqUZ}^6ZB0uQU zQd@WeW#Q?`VMS_FaV2@=m&QNFOTbh$$tKXRrI1dnpP5%M8~*^vn~ zIbF);%&s&Uce`*60Wk@QiS>Ix_14D5dgEF5$BCz!L?P~C)>f;!6M7Vn$lvS4)|MY{ z?-w2f;AIuTnf95)QD-Fmhnvr9?0DkUYev2$j-lE!WjDRf5y)Q?ZqHjzaj>L?%)w(&V&r~Ha? ze2K?`DH8`rVNyvAp@*%Qbli zyl(aK>BwXyzV+=xEx^hrZ(=7hR5ojBn5u9+hF-2C1pd0*5}(~nV)SBquC&xpOzv{D zLnuGKTDJ-IWjKImJKJ#n5_ zX;re-3E!T&i2Tsv`SnNo-M4d;;P1e5&t{!dA~aYL15GXXIT>o-*+&rcqnWlf;ssTx zgqqyD7m4yjPzjV6_oAOYc2TGhpFFvdA@LFvsq*Ue&Ncfv?wZp=SD!M1%nl#n*X3P^ zQVe_=R=1H2MKnkpOS;}b!Ufi9+O?JMUW%tZeWQEu%6VCMy0y@0;#x}ri^Uv#lnBY19M}KdPenl zn3Yxcx7i$84h<$cO?5p~3JRp)+9en@L9HS*FPfMQUUXd+x*VF_=^-iy!u+@^)U6~s z;utdh_ie{2BpFx%&qSd?+E>3DYi`ItNx~|Q8W)y0A0)e#o7RPcqpzvjrg<qHQvVESbAV1~FPYStJ;3Wp=Z@Own8UHFZaUpTP=%=Y*)b$*!^rzX zPda7FX_$mV*X489hKYxL;0Kn@agHjOzCUAYcsp`~S_Smp#fZ@iFIPJ>Ow3KQC0+KF z3Dr_aTsqbNho&P*()hq-OvYkPFskB42SS}P1idHM~2 z!fI8U??g6C3jE+xic1KeN^HXN#8C%~5U|p5(CKC84iC2>JIKSFM@%@9?i$SW^9S(! z+|ZL}{ZjX-a&|G%k4?t})G@Dy^0uJ+;;Sbh`GJfTeeNdAPw?6LvXIgcEuD$B-K%jL z5$gtH>7lC+C@6h7ME8!Vem`mZveHPNSe;t5sS664p+Y36l;ZTa87`EBRlj~BxiTJR zxoVugA6zv1Ie#v<8maSF0P6Ga4;jnQ`E7K1RYadb&ycG zg|#`Yp8y?&X^e|tsQxL8`;!MZTNpA|UGRGTM(XiO5)T!U+sV*h(_gQ)V(oRIQoeHEJlsG*m+Cxby=xotCM4kWF_a!HUU$d%_N0C7UVy zHp6=d6+%|v#$m!}xcv~2!jI~8Wpc(nRaAd;DdsHS*4dUaWf<{2)e zEY^z%#tVMx`}zdT59?0K0Sb(Wp+Tj6p0CJMK}>zcaheM~)z#G^<9~1=fnPFR2BSZ& znYPD*3ci-~Q7Z$`XH68)^BO&fL>AEbEli`<$~uxXb}w8ZwytqMa`P*aBm&L#^xaUi z7dqzPjD-$RZJO(iI)0wBx7u!Hto-r4$p$})=*F$MFBzE%eo&+ilO37a;9aBPe&^}r zpJOC@4%%Q(Fy~xkWaNmi#U@5Lz%;O;qA}^r9aj+FuS4;7K1KHVI;f_D z+q|fH0_o~)jms=91QVFqEA~WoXVJrE2A8&)D+*>%*!xF+2z<2VPeRGQzAn{& zd))MH**-M(m{QqN_LE^%t2bYM)57KI zRFeV?&%}W8S(h4mw8$yG@H;QBJ)9f`8mj9bP@wu#la9oT`tw!?Rg@wPc%j`mxrcBi zLo`Ys0*MlCCUI*ByvjxNnh^8BF&<{9*6sp@4bU4BU?L_yX`1#4Q-Fa^bBFd<=*r*x zQ5ookU}=XK5WF)hy~cRhr`|Igh3JJo4!-0u~##C*Fd))B{o0$?)YB- zB|i%#dV|QAAYu9(RjSdZ6D)rxH)1vQ<%1U*B0q&nlKJPJ+bBkB3jdjs=zQuhuwrHy z4n+7`Qdpe|{ucADULb&8ce`=r3nQq0&`up~7@rBh;h>{gT9AZ5|6wB4K;lt&P7UoJ zXt$ZGEXP0HCBT3mz4)vvq%h78hyd2hQ*HK{SrofYl=aVfy>!OXGW8}K13$H%lEL}} zf=eQ`pc_N?FGlKZkpm6*VeS)Ls25#dIC?_QI=?${zjg?GS=34OjtO>JGA;9EHSuAoq@%u0m44j$@NoLy&S(SPtP8KA%X1xgZ zr4nzLjDe&lFvNsmu>Y$80_lLOWA7oaQbSga&(}NDWP)@s^4^7O%x}nsVcN^ z7G!(UCUS@x!vx!WyzkVZP|&gZH28t^Z^-2cS6woD{2DRQyYB+7+%9}Bb`t{Ay}Kzjsw%uPCVFn5X~z61u~F76h!opu9St_gt{Cx6Dw*5YvSUV>|ClXB)M-Xs7|(; z+;rJDbWB|?%UwCC(ByFe>pA^F@90*u%c!<4-Q~hLPD5EL^?^_kj2Bl$4bB1WQeLNp zF&(!qa5#4DPUlY6p@e_gF+1gwW(dDe_o=Np1-RYS8~{Aefk<9=S=lGVmt3E*=PTT)8ws>;z9F~&Sc*N69V0HYUGYkU1*_=ih}?O z2I6G*?W+$%6Mq8=>P2m)dqoZfYZb-j$lwvpcel6A;P&Pd2lYSXd47F~7%eA%h;TKU zTd<%YfzNuJTg5D89~@nu!5r{cwYDwA7&C{`EV+sFaF;XAcq{(5yZ6@_EQd4rG}pIt2|X?KP5lP_f9Hf?c`l%c91N;%{uow# zFW)E7_Vy{_ru!5vgW&Q?a|sJtf=tyt95d>Y(R1BT0r`<%Bn^W8g*WB6;w@6%-AV$; zE9%RDHir4Um{<%S-{1UKIv-PkZq2(Y2K4p_Jh^#x7((q&!%Pj@?Bv#sAf1B?Y0ffI zGpxRJYli##7WLY@mEh!40ATc$!kJzP&x{?z z(H0#AE@93CzLCUY4tN6f@%5rwBCsBw2D-myNzqFT^x}CABLAwJ?YB!U?_1$`U}?(Y zhdJYTtaDf_wFGcAVTZ9p?mpH!HM>aS^Pfpee~kJ7y{i6K^`P~oujWtVymrbKN6V>? z;xs;*MiNufp9kC8o&e@rB40zK9{)K0Yk^m$Jm$Bj2PMIJ7!AJBBUq40x>}CHkgF8% z`au#lf7I0npyu(o@+5{w0d)4ed)>)~|JucJll8XanNXIbpe`1|PblV{_4t~4Pr*Vs z!vrQO?^}l&@iGDr{-2VIhI4DIFtXUlsSg{(PJ3r(O|5+dC}gnHPuBuHXt1HhMZ9j| zfjd?B`sVYA3DI%cLsZHy>v5`4r4;IpcN6aisMq7~wc9A8hY%FV<{^;}ZUMK{8S8;# zW}kabXHACN#MYC-O?jrPBCtqIl51N;!4X`2mKQA5;f3z>mk-Mw2Tdce(5PRjH{n&p zO#-SVzTJ+D&Z>G#<=IK%5{-U8xLA_2w2qSHzW1Dcrh&PgbqhSP9>_Wl&U-It8lhTPiq!BW*{i4$Nn|4J~@(4 zko8F{=mMosK7sCsn4?73(Ut%iey{0#RuFbO4%7`bIOxiZ4IaT4_9FvFO2o~k0yn(92_DW z)+baZ--V0DZwus$tY3&@Bi2y>Z48oyXahLPJBmJSZ&MT-Stpg&Siw@Z9CA3WO)S6q zpFeZK@H|)*tJJsI*lg*9S&eM2K3kcrAuFm$nDd@HDr)u@C+K#c-HtApf^7;$+48~j zgzDnTeK+Cq3neC=kxvB;d8mqjrB;a`v%yzUc%aW!`xmi|H@>M;Fer!wy-&R090ZaG zxe`FfT%UUHK>@Xj=Gg#bvYQQ*H617;jzjC03^!&9YfS4IZf)nPJZ-1UYt6rq*RnK<3>AiWqHU;onB)Ve_1(c z!fN!I?rpeB>PSn~6DZ!F0U0LewV=J@ZyZZo$JR-fdB009%D&<3#cWA&;u+y1gZZ6B z)8EO0&qEdgsE`-J;f$i6@->LT$WiO?X8XU$+ zj8*mzVRRupdtI+z)_S!QM1aP>ms7705SVkTeb%5QpZ7ZnYc!BQ?;i_-{uk0KkD(?i z-<3)9@niSpk>Vy+R7c^3Q5`6tMva@rUPzDVANDzx^r zxR^v!9^xIxlF%rQulx00ZO!p*mZ+=UUk#M*{oP?l=Hci+FQ0dpJb~h3%OqmO@%&jz zw9mxoV?VK`FJxnbI~y4OXg;NuH1_;OJ0q3L))E^2x)!Z;9ww%s&SiN({q2FB6CknV zx5~^|?H=zv6}UmyR(wJDE9RPS_5E^ObkyLjo8hmS&0x15kf1ul@EZ+Jj}APOsrva+F> z?Dmt2Vd-Yp4?7bnVy^?(;j9OIP5am`fAzMrM5^1REc_2$rG7&XiA&Ba$}2T_y!3j; zLac2aN%ssQWvdP2?fEFyDSI;S!>j5R%h|kF&vk(pbG9C{q`TdE+c<9v>@2}1%llo2T>r;L1x;G_ zVeAFa4`Dio1;MMRYN<*p-i>QuM2Gl-$>0wgrU$_jyeZifB+&T?QYhTC%)y2{=3St^?X<`K=~aA!F_5e=;9}f) zYT`PCi-_0Yi=?VmMYhE|IUry9ivSivi__MIaqNjo^t6sdpB)5yt=OX7$ zM_h--BSfvPBkmo}TfF|Y0xG1E@TzmIpK;>KhM}-z$VQR#4n4tee3IX4@3~0wxjWZb z^N4nG1eWWQr}2e>dcet!op1Lj|Mf|g-_(x?$7OHygdYxk+X3)&WZg~)lxWg0xH~?7 zOsnd9-sCdxH=AIT$*UwPef5ev2Z<7mDHw{PQ0^>O-X-&0M`&ATn@Srm7$nQvo-@ zgQOdH?}rBq^Rrtv5@EIw40C!$ycfaD>6v+o)SV)V6uMqH?6a-xmZX)aqOEpkTKxIl}tH7{M^eE<-%3Njyy z3yGklqfHMM2HU6rOm*DX&nPBSsJ%_wuO~-ytDBZ2k(1%tK8k@U&xOVuCfENuJYI1^${V`7EfrW;*Ex3!01#*Yf^ErS7N4K0R^q z2ETo5gs zqqZs3n{P5mDqOY6+bhbT>PE5FO+2P8Mv2AMYw_>}x%c*8C820vSu@*#GTKlw4vE4q zH7j8i3!Kp5J-A;~aOEY*TX^G9HC^ii6q+gJ9ope78)p^xI}lg-zEjsX2hGL@gXoZm zrDT>ynd(9D!Uwk6QGzTZjyMKawLcWlp~_E{a34Pq?=A+<=+V(lb@iYc%?PQ_+n&MW zk2-g`H<_UmW>#9~K{SWtS7ws!ID3;cYKsIjU0ZjcCfcm7(af3b0-bH}>DhZawUA=E z-QaNzc^KRllp)@5l6=9#_Ia*i$%G%L?>q>q11oOnhPJ3(#kpKhScP16%=#=;@f@NR z;V;o>f5z)``ST(~|11KH0SdRFhenPSXpti-g#~{ZFrc7BZ-T87$forI@K;>2RWU&H zP(wDSat_ZzIdd_EsN>DM6NO(Bq%m-yAd+!69$#aM{{H0roD2NVu=2G$6%Cqu!WTJ1 zGg^KK1SO0Vr(t`;mF1DP`_Si8vACB5zOp4Q2()N|ShLnqnU^~jAN2Qk!3Ibaw~0WxxyKd-<@e`PXFtrlCx)uhLJsaQkB@Kj zH5wb$U~tabQ`_I!Js{C~~dK`+sCxwtFs5-5Q4+Dx*vnc7}lfFsY*-Cxpa2&h7dB}+4? z`_Cmi_Y6Th0HXMFl@ECbny6RRI7G=0DBB2fa{nuYGVAVcbiDqbn>wt@=Z`ZVjI7ZC zJ!d9QxBrwJ-c1DoWO)pAV1Q}#)}nfP3vXHY&1)#|?^u7F!~F99e{`DDtcu`*UjPfr z=*-ntHVB2W#XS2(s&hCO>&LKa=C4O9>w8H*aR2kH|9$!{+<4)Gx=JuIzunj2WIkx9 zLJt3SP@cy1+BtN5UP|aR;E&TwyTR-eK)=4>pLuQr;WyW_|ITxGN?4R&=>B>fA1m63 zBvvpEipuv*uH-E~HusJP{-?^k&RVabT;VYm7IHeeKncbYJpW)i6pW{GL&t%hzW(?? zt_Ceg1_l7U;D2ZBgg#s*%&z4QG^R2)C=>wXsA4Gk(3ON}H^w>tfX0|I^fa5m1%fCj z!1A&!dVy%cfu8|Px22qx5lZuEcLZM5_e^zH6s17$+52fmB1kzQ1bD(BTv13(fLUUS zuP%yC<8GEIXp;DpLiSmdF9y@((5BwFAlR}!AYK`k{vYcbd02B8LqQfLg8R%Hmfj)- zW>97~fT3gxSbx552aV0C!rGmY++;l$za~P0aTU+H8%`_r3gVjdP*IT!p`U?wGQ*-B zlyNYZa53N9yDq(WSLB4{q^e>kI*W6&2(r9{AgsRj{)JP!SP0dt^84&dd$vEWlxe3| za$BRL07mc9L!-H!3W62K!N{G-rxXbM+IJ)BUW`ie7rpP%*FOgu#i8(Byg9@R$~3QK zd~sglTjz1Q8yG?k0>L?(nih+md)sr7fw#o>tr#pljit>4w z1P-5+FUi4%p5Ahssa4JhmM><2I z=i|&G&6)@%GH$rEqYf7|7UZpAi=Hh)G2%VoecHVG)Qg1*g&B73rg+EJe9JOyUVW75Xx~bc{BjJ#x{o{FW|_-f%Et86!&Tl8ERdtN!a3>SfziLpDSp{SIE8$`#&3tEw2Co From 0c56897cad197d27e247da0d1c8bb435a4421fe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Knuchel?= Date: Thu, 29 Aug 2024 18:36:23 +0200 Subject: [PATCH 16/16] Add resources --- backend/config/config.exs | 4 +-- .../lib/azimutt/organizations/organization.ex | 1 + .../controllers/website_controller.ex | 2 ++ backend/lib/azimutt_web/router.ex | 1 + .../templates/organization/edit.html.heex | 2 +- .../templates/website/resources.html.heex | 23 ++++++++++++++++++ .../resources/arrows-black-fat/down.png | Bin 0 -> 9234 bytes .../resources/arrows-black-fat/left-3.png | Bin 0 -> 11543 bytes .../resources/arrows-black-fat/left-4.png | Bin 0 -> 9639 bytes .../resources/arrows-black-fat/left.png | Bin 0 -> 15026 bytes .../resources/arrows-black-fat/right-2.png | Bin 0 -> 9300 bytes .../resources/arrows-black-fat/right-3.png | Bin 0 -> 11809 bytes .../resources/arrows-black-fat/right-4.png | Bin 0 -> 9575 bytes .../resources/arrows-black-fat/right-5.png | Bin 0 -> 11624 bytes .../resources/arrows-black-fat/right-6.png | Bin 0 -> 9993 bytes .../resources/arrows-black-fat/right.png | Bin 0 -> 9506 bytes .../resources/arrows-black-fat/up-2.png | Bin 0 -> 7972 bytes .../images/resources/arrows-black-fat/up.png | Bin 0 -> 8996 bytes .../images/resources/arrows-gold/down-2.png | Bin 0 -> 9661 bytes .../images/resources/arrows-gold/down-3.png | Bin 0 -> 6924 bytes .../images/resources/arrows-gold/down.png | Bin 0 -> 6180 bytes .../images/resources/arrows-gold/left.png | Bin 0 -> 7207 bytes .../images/resources/arrows-gold/right-2.png | Bin 0 -> 7230 bytes .../images/resources/arrows-gold/right-3.png | Bin 0 -> 6508 bytes .../images/resources/arrows-gold/right-4.png | Bin 0 -> 5193 bytes .../images/resources/arrows-gold/right-5.png | Bin 0 -> 6266 bytes .../images/resources/arrows-gold/right.png | Bin 0 -> 6847 bytes .../images/resources/arrows-gold/up-2.png | Bin 0 -> 7186 bytes .../images/resources/arrows-gold/up-3.png | Bin 0 -> 5920 bytes .../images/resources/arrows-gold/up-4.png | Bin 0 -> 7886 bytes .../images/resources/arrows-gold/up-5.png | Bin 0 -> 7789 bytes .../images/resources/arrows-gold/up.png | Bin 0 -> 8842 bytes .../arrows-highlighter/blue-down.png | Bin 0 -> 4609 bytes .../arrows-highlighter/blue-left.png | Bin 0 -> 1947 bytes .../arrows-highlighter/blue-up-2.png | Bin 0 -> 4109 bytes .../resources/arrows-highlighter/blue-up.png | Bin 0 -> 2561 bytes .../arrows-highlighter/green-down.png | Bin 0 -> 3528 bytes .../arrows-highlighter/green-right-2.png | Bin 0 -> 3533 bytes .../arrows-highlighter/green-right.png | Bin 0 -> 3154 bytes .../arrows-highlighter/orange-down.png | Bin 0 -> 4291 bytes .../arrows-highlighter/orange-top-right.png | Bin 0 -> 2838 bytes .../arrows-highlighter/orange-top.png | Bin 0 -> 4214 bytes .../arrows-highlighter/purple-down-2.png | Bin 0 -> 4410 bytes .../arrows-highlighter/purple-down.png | Bin 0 -> 3895 bytes .../arrows-highlighter/purple-left.png | Bin 0 -> 2275 bytes .../arrows-highlighter/purple-right-2.png | Bin 0 -> 4142 bytes .../arrows-highlighter/purple-right.png | Bin 0 -> 2153 bytes .../arrows-highlighter/yellow-left.png | Bin 0 -> 3967 bytes .../arrows-highlighter/yellow-right.png | Bin 0 -> 1961 bytes .../arrows-highlighter/yellow-up.png | Bin 0 -> 5180 bytes 50 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 backend/lib/azimutt_web/templates/website/resources.html.heex create mode 100644 backend/priv/static/images/resources/arrows-black-fat/down.png create mode 100644 backend/priv/static/images/resources/arrows-black-fat/left-3.png create mode 100644 backend/priv/static/images/resources/arrows-black-fat/left-4.png create mode 100644 backend/priv/static/images/resources/arrows-black-fat/left.png create mode 100644 backend/priv/static/images/resources/arrows-black-fat/right-2.png create mode 100644 backend/priv/static/images/resources/arrows-black-fat/right-3.png create mode 100644 backend/priv/static/images/resources/arrows-black-fat/right-4.png create mode 100644 backend/priv/static/images/resources/arrows-black-fat/right-5.png create mode 100644 backend/priv/static/images/resources/arrows-black-fat/right-6.png create mode 100644 backend/priv/static/images/resources/arrows-black-fat/right.png create mode 100644 backend/priv/static/images/resources/arrows-black-fat/up-2.png create mode 100644 backend/priv/static/images/resources/arrows-black-fat/up.png create mode 100644 backend/priv/static/images/resources/arrows-gold/down-2.png create mode 100644 backend/priv/static/images/resources/arrows-gold/down-3.png create mode 100644 backend/priv/static/images/resources/arrows-gold/down.png create mode 100644 backend/priv/static/images/resources/arrows-gold/left.png create mode 100644 backend/priv/static/images/resources/arrows-gold/right-2.png create mode 100644 backend/priv/static/images/resources/arrows-gold/right-3.png create mode 100644 backend/priv/static/images/resources/arrows-gold/right-4.png create mode 100644 backend/priv/static/images/resources/arrows-gold/right-5.png create mode 100644 backend/priv/static/images/resources/arrows-gold/right.png create mode 100644 backend/priv/static/images/resources/arrows-gold/up-2.png create mode 100644 backend/priv/static/images/resources/arrows-gold/up-3.png create mode 100644 backend/priv/static/images/resources/arrows-gold/up-4.png create mode 100644 backend/priv/static/images/resources/arrows-gold/up-5.png create mode 100644 backend/priv/static/images/resources/arrows-gold/up.png create mode 100644 backend/priv/static/images/resources/arrows-highlighter/blue-down.png create mode 100644 backend/priv/static/images/resources/arrows-highlighter/blue-left.png create mode 100644 backend/priv/static/images/resources/arrows-highlighter/blue-up-2.png create mode 100644 backend/priv/static/images/resources/arrows-highlighter/blue-up.png create mode 100644 backend/priv/static/images/resources/arrows-highlighter/green-down.png create mode 100644 backend/priv/static/images/resources/arrows-highlighter/green-right-2.png create mode 100644 backend/priv/static/images/resources/arrows-highlighter/green-right.png create mode 100644 backend/priv/static/images/resources/arrows-highlighter/orange-down.png create mode 100644 backend/priv/static/images/resources/arrows-highlighter/orange-top-right.png create mode 100644 backend/priv/static/images/resources/arrows-highlighter/orange-top.png create mode 100644 backend/priv/static/images/resources/arrows-highlighter/purple-down-2.png create mode 100644 backend/priv/static/images/resources/arrows-highlighter/purple-down.png create mode 100644 backend/priv/static/images/resources/arrows-highlighter/purple-left.png create mode 100644 backend/priv/static/images/resources/arrows-highlighter/purple-right-2.png create mode 100644 backend/priv/static/images/resources/arrows-highlighter/purple-right.png create mode 100644 backend/priv/static/images/resources/arrows-highlighter/yellow-left.png create mode 100644 backend/priv/static/images/resources/arrows-highlighter/yellow-right.png create mode 100644 backend/priv/static/images/resources/arrows-highlighter/yellow-up.png diff --git a/backend/config/config.exs b/backend/config/config.exs index c1d372739..b5072186f 100644 --- a/backend/config/config.exs +++ b/backend/config/config.exs @@ -28,8 +28,8 @@ config :azimutt, azimutt_github_issues_new: "https://github.com/azimuttapp/azimutt/issues/new", environment: config_env(), # TODO: find an automated process to build it - version: "2.1.3", - version_date: "2024-08-04T00:00:00.000Z", + version: "2.1.4", + version_date: "2024-08-30T00:00:00.000Z", commit_hash: System.cmd("git", ["log", "-1", "--pretty=format:%h"]) |> elem(0) |> String.trim(), commit_message: System.cmd("git", ["log", "-1", "--pretty=format:%s"]) |> elem(0) |> String.trim(), commit_date: System.cmd("git", ["log", "-1", "--pretty=format:%aI"]) |> elem(0) |> String.trim(), diff --git a/backend/lib/azimutt/organizations/organization.ex b/backend/lib/azimutt/organizations/organization.ex index 858996b0d..706d81a6c 100644 --- a/backend/lib/azimutt/organizations/organization.ex +++ b/backend/lib/azimutt/organizations/organization.ex @@ -125,6 +125,7 @@ defmodule Azimutt.Organizations.Organization do :gateway ]) |> put_change(:updated_by_id, current_user.id) + |> validate_required([:name]) end def free_trial_changeset(%Organization{} = organization, now) do diff --git a/backend/lib/azimutt_web/controllers/website_controller.ex b/backend/lib/azimutt_web/controllers/website_controller.ex index cd434a44d..dc1e2d5ae 100644 --- a/backend/lib/azimutt_web/controllers/website_controller.ex +++ b/backend/lib/azimutt_web/controllers/website_controller.ex @@ -73,4 +73,6 @@ defmodule AzimuttWeb.WebsiteController do def terms(conn, _params), do: conn |> render("terms.html") def privacy(conn, _params), do: conn |> render("privacy.html") + + def resources(conn, _params), do: conn |> render("resources.html") end diff --git a/backend/lib/azimutt_web/router.ex b/backend/lib/azimutt_web/router.ex index 5a0df13cf..a39ea103f 100644 --- a/backend/lib/azimutt_web/router.ex +++ b/backend/lib/azimutt_web/router.ex @@ -58,6 +58,7 @@ defmodule AzimuttWeb.Router do get("/sitemap.xml", SitemapController, :index) get("/terms", WebsiteController, :terms) get("/privacy", WebsiteController, :privacy) + get("/resources", WebsiteController, :resources) end # auth routes diff --git a/backend/lib/azimutt_web/templates/organization/edit.html.heex b/backend/lib/azimutt_web/templates/organization/edit.html.heex index 4782b78c7..56a9ba332 100644 --- a/backend/lib/azimutt_web/templates/organization/edit.html.heex +++ b/backend/lib/azimutt_web/templates/organization/edit.html.heex @@ -8,7 +8,7 @@

<%= label f, :name, "Organization name", class: "block text-sm font-medium text-gray-700" %>
- <%= text_input f, :name, class: "block w-full rounded-md border-gray-300 shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" %> + <%= text_input f, :name, required: true, class: "block w-full rounded-md border-gray-300 shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" %> <%= error_tag f, :name %>
diff --git a/backend/lib/azimutt_web/templates/website/resources.html.heex b/backend/lib/azimutt_web/templates/website/resources.html.heex new file mode 100644 index 000000000..119685d2e --- /dev/null +++ b/backend/lib/azimutt_web/templates/website/resources.html.heex @@ -0,0 +1,23 @@ +
diff --git a/backend/priv/static/images/resources/arrows-black-fat/down.png b/backend/priv/static/images/resources/arrows-black-fat/down.png new file mode 100644 index 0000000000000000000000000000000000000000..4db7da7533391f7f6a2707a7c05ac8132953fb94 GIT binary patch literal 9234 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 P27r>By6hKe)1dzcOIL9u literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-black-fat/left-3.png b/backend/priv/static/images/resources/arrows-black-fat/left-3.png new file mode 100644 index 0000000000000000000000000000000000000000..18939554db1583369d72ec64a506c13d1c472ea9 GIT binary patch literal 11543 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 F{vQjn^g93m literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-black-fat/left-4.png b/backend/priv/static/images/resources/arrows-black-fat/left-4.png new file mode 100644 index 0000000000000000000000000000000000000000..7bfb82954afc532fbb6063a86ae52f1c3c4a53f7 GIT binary patch literal 9639 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 N$x13o)QK5|{0|obs8s*} literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-black-fat/left.png b/backend/priv/static/images/resources/arrows-black-fat/left.png new file mode 100644 index 0000000000000000000000000000000000000000..1d5c7aa9e3c3ed78b65e3f9c8a42f670e6cb93d9 GIT binary patch literal 15026 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 literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-black-fat/right-2.png b/backend/priv/static/images/resources/arrows-black-fat/right-2.png new file mode 100644 index 0000000000000000000000000000000000000000..67fc4e4bc9e740c53336cc545a66b8bcbd67b922 GIT binary patch literal 9300 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 U&y^njb_9Zwyt-Vq%=^&)0mohH_5c6? literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-black-fat/right-3.png b/backend/priv/static/images/resources/arrows-black-fat/right-3.png new file mode 100644 index 0000000000000000000000000000000000000000..60f397d788e54d44556d4bd7a6553fd737d48914 GIT binary patch literal 11809 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 literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-black-fat/right-4.png b/backend/priv/static/images/resources/arrows-black-fat/right-4.png new file mode 100644 index 0000000000000000000000000000000000000000..da3bff7dacbe4cf14ea9242f595d740b03e2cf90 GIT binary patch literal 9575 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 literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-black-fat/right-5.png b/backend/priv/static/images/resources/arrows-black-fat/right-5.png new file mode 100644 index 0000000000000000000000000000000000000000..d3e77039ea43d7cefc47bdc621a1275105a18ca0 GIT binary patch literal 11624 zcmYMa1yq|$7d0G0fZ*;H+@0bU+`V{lYjJlAPNBFJ3tX&Ftk7b`Deh9-p-8df-Y@sP z-}nEsW=+oQIp^&CoLTe8T8Y=zRKmufzyJUM*ec5Mx&Qz$8~{Kf2O}d8-ZWb@1n{h_ zuCIWYQd3j@{reX&{;yLZ?Ej`zRR1FXvngn3{x6O&5I6!v82_zOQd0cC>A%Q-APo&A zqW=&7clE#a-zpUq1vT~m@A>~0|NVtPs1f7K%gcWw!tG!5Uv2-__>cNO3It9=L-C(8 zEiKjmr|^IN|FZuV^*@6W5eR|MAZ$iPI)np4Gc7Ik&CSi--5nwj(b?Hqg@s>nad9v( z&^Ha7kvMHB*&aC375k(`>ELP$su5%phVW@eI< z6pxFGMPx%b|Ni~^KRh}41A-JWJvcaMYHB(?Jvl!=M~HWDunP+d`}XZyOG~q;s1P?d zhrGO;o}R9hltfusDGv|V?d{F<^fWs=8!Ic*^2%~)Y3azw@Z7&`mXVR(%*@2o(_?pc zx38}cL1b!bY++%ZpPyG#^EoRk6Cpc1JgmLFO-oBtNl7s&Dbe2E&ehdfLP8uNKt)Am zb8~Zec*xk;5Fut|Wd$)ZF)`%i(dF{FfWct- z`T1E{S%`#x|DycG{~I44kJ#Bir08!D2jIn9S5pu0jQ?_Tf`-0)^az^x!-Vp%MSVAg z{hjxIbi16m{U>2Rm>;v{xM}xlhD4l-jy8#hk`bCI%2vQ4TcOe;$8liD-I>EBkNZ#F z8rdLxAttp#>qmmD(OFeuR=U55)JFXmQxnCC1X~@+&y{kWb?<~;3Fc*a+FBW_E5tcD zSR2cUeNBk-v&+xVO^Ek%vy=bF)7jb1*0|8y+0jTpEk3}{-PuS!Jt5H7!&<=0!}*<~ zk#a_yuZxqDy}gaG8h>1zkF&jnv7uq*#~go8D+?1nH9ub+X~FCue-}Gz4Y?v;PY>PH z_&6)`oY(--+Oz-<^~^v`DStsIb0v(OibCw-g$Mv(qf(KF>iaJr7X+y1*-;G^mrco< zDzeqM975R~M8)7lDV`&IA3R!myXhcCwm7XsXvnxSI2H8B9$v^iIm|euYm12javF(w z2@bOP2NJ&;4(B+JEEIPxzuVdHl3AMiue?YN*9vYW{~5mZlb9TJLIZT0Y#r?tsPaL| zI902fv#Y5AISLYQQDdnq(s-~fhzEaxRH5?SrN8jE|Lk3u*r}S!>dlVnQ%0EA(UOr( zF`Rdmm)n2*_>tg3ckVhk)Y_Je1v&lzi3X_H;t(eh+F_DckvH=jjYUz6Tchac@W_>n zf5^$i2s+oU+_zSR0GdFD7+toa2D5kfw$p zRyBQwEc6^h242fMjt3^f>>swT@+CvyHnzd_E|eJZWmMUA^>{`N!5K2gg}cm z;0HUK2am3s&+CS>ssZO#r1~UQ8eHPpueuuienNv(4?1!I3IIO4SsaBz$(l}Kzm(+D{tSznEUT{4}W8t*X zp<%W&Crg>UP9p>IIojaaDA~IFaG6YeMMVD?^(&!skJ{P!kf$!3tclI6BYx&_NluHT zf=&Ad|Aw5d$ODJ{Ay7Q8O4W5+J0F7Lf@H|T#?r9c7(v?1Y&huI5TZzA&Oq(0h~v6F z@H1aBz|qv39!+=ZsOPJ&2p?7Ey0?B{W3-@6CQ<8&lFxKJ9g&;%RDy>` ziF0C=Q|R`Onzz=gcU$L=e$=@fKbk!QR)WNRrh`8aVKjV&edDI9N}Hs4;Lz{4Sr=Qm zOGP?{CsPWuxj4&`;zTd1dU&LvR_mUI{Ib&UaSo?U61*XoS%aJyFl!0kG;x~{12Igf zEAKq@x0=_Us6To59^yMpZT!vjgH$SMVF|=U zp6Tp^Vxy_B`iuq&vxd+umI-I#KP|3OjMW_rS1?DaVd_vXQ~y;(TqW`D3+N%K=WG_C zR>?5(*HC-vAPvYjIut+sLh%f^ZICS3M8f|U_7v^PenD=eJ4;K4{@-}^xxKUA2H ze43~b;HX&ELLsU9$uqxDzCCdY(o;^o^%#$8aHgA2O-m&oviE^NaOu^eS#B5PJ{qoF6n4)TcCn zsU%@{b>D?dL%1xumNa?u7CIQOe2q71?uZ(ifgFHl?wL_u8AId30x-G#`M-<_Y+ zh1s3`BFkl(>{N3tQ@SmahcYNzPn~aXT>sjt*Ex2jP?RRqeRg+1Pyafqxh|@$Xreuhed+yQ}4gdKH zo8R!EfYLR7?s!Fk#YpXcThV#ug{{?F-(<>D?F?c{m=5J4Q|3RPMq7UVvFlc1Y`lNTn}G2q9U1)N8!#h`lrwnw^+h?!l2*9mM8G7yT?VM>}>4NvTv9gB^hQm zp)yD+@bS)0FyyXbwZ^<_w9oxCm6=RoD1w1W{dq3vW2tkD-MZLwSOxvqd#-lflJ4&7 z!PH*vfVGE;dvZXeX?>@M#k5JBjk?b@UJM%VQy~gg{_~ug+|XZrBZr2MAAsvqJ`XDdR|TxR-}J-1=Z(A z;Pj5gNYZEo;m9!~#E!y}6x2YNhFBK_X~jZN=J_@-$O|^ZjEoz0Up9L5tppyOvC|OX3mKpZc{w`5Ugi9I1g#PEL^^gZ* zW=Df8%Cg0e4`eJC1?T&UZapv1yQa(8xKhcI~U3f$W6TRE;>09eHC)Jz`zhh(~AW;FS0l$ ze=8dH_Ca53VJW7VQ|FUWj5VJOOtPOMZ9#Sp6~peZ+!470`R~)^DCNA>w>xv@3OHKm z7~c{wMfFvGAufI(>&ZLz$2LtZzeFlpvN^3+Rs&uXe2>@uh&zU0*+aXIC(m{!J5H->BeKJM7*8Yb54dXe}-_`?t;bZ^6Q>RCdTXD66 z#*>H>|E~XjbyP>W7VSDtsQv=p-~uPzuXdB?FXy}sB7#A`5y2b*P|WV&;x3&R@?E)} z!SUV9*S=bQRFZ;vh1n&aJJNg?TZwrc{voQM?=r~MEprn0J(u+`VdK#Y$Ka1tsP$BL zMy4D{az^f0qIDseC6_IC+gU*WHiu3@!YhH;V(tecEV?u;vvh+wK2Jx~!9uEP7KOL_ zP2JyL`yW_MY1e9g`uL9ekaZ^Roj*`8Z)%7rs$UDo*;(LJdy(O^6`WfXi5$s2S|DLo z{3TP^dmHJFYa5khzU3etoHp`6q2+tpJ6_n+VJGWG>=DPMUp!GCY(F{KEUf=tpw*i$ zQh@^Pk5GNnT8o^O>UQ#QE|x=(9|=a!_L>;e%Iq)+&7(Z>Ia;w7=E3Wg{b11tZeNX4 zSFXC5D#AXI2%_ZZQ*t*tCOoC$F9Cly1v-Ab6#=J4?)tx__h2=1G^12b4TIzJ9{*Xe zp0crtxfb8+A^Kg{_o2`qkOles;&3+|wFESOYoRqdt#m6~{aS}E;?i?+jzCpFmi~9| zrR&P&?#bc21oRs%_TXmQhFmEDE*rJ*FBfy7do5!i#f#7;-Y$Dv(K-n=sqKl+o%BuZ ztIxw?3C$X0!+44|gs743cspX`@NRiacnSq7I&2ognL5Q^g4Gt`hlGDp5|NtCKWeIz zV;5s@KEm>~soJhg%ePBXi}vVH?(bz78l_FMU+4Fg_1ovLW4RiS8}a>H@h&eM=5BIL ze9MwkLbay%1~qR_KAXT>g}G9K&r_3St+XAVa`NY%&N^lIT9i51z2EBxpRCKgq`e`8 z0O){9gK$;%m#hiy@^pOlaLjI`9kVMoSSIyajh~Ms5lbE!8HK#wxNPZ8Q_$>f*dM=W z2`tO0YdWyq=BuQ*sL^#Uye)uWI9&F@$1UjV$6-hudOf#aA?+}>^Y>}_E0r+OrFK(` z5L~V)2bw5oaRg!Z?pfF0dswuI%9gT0BrtZqdzm!9i=j8!IR}!kO zmxuy|bfc+=Te@%g%_eTHet8&JJHdQ+K_D0Dh%IHqUr3M#uf6yGF|p*yWX;GO1O1F@ zE=N8T_Nf>EoVt6(z^@xz(!i!Sps%1PB6S_~g#kkLgrTq;U0nXbpXKoy3k7=Sjz|Lf{aRhm z_w(E5FC5ejIG|AOXZvn>(mY6ByXB9KI{Ud#W|Xl0&teDD6R2>;1cw_ZG~>XfPIYo* z4ybKUm-0IhNKm>CFVlB=#4hA@%QNP94@hI&}Q9eEWi}2s?Uk$d>bdW^Q~~Pxtq$=iAAwebxS2Oeln2lUfiYFjkS7Ko$}G^$866=XbW@55AGISBpsa zB5|QQ)+%oX_g;(-zkq~QI{M^z`INi{(Hi%3Gsy@VILI0-Ia~B_yJt8r>~jdp{E31c zIUqx<)m071+x{1l4bIKx>4XQqn+{|BV3bC|M+?s36xDv6T2Y>eTP4G*y>uxS(u{94 zmHwXLnPZya@Xi>vOh{pmJc=dOB;OI8!94V?Y@acz-Q^A&4tJhO7f;{yslt;sG|TCJ z{HM=ATHOR^cR!>KlUcd`HQtklfZPG^H_Jn9Bu84txLwK{A2+>k%p6nCYvi51=kh)e z=~^sYiRZ0SF`;%JMI2cr=jCro?OOuRKwz0sEkGt*xwXoNgh3EmZ%MpGE}~Q!tBSFe zUAT|5C7crH#Vq-dTWidCXCRa)Nc4}bO2TOB z*yTv|6%=}{q1*0p;=qUB<#{#nNq1q_O2o19sge5Eu5zvw2CN1Jo{EDEe)mP9T{xEL zpz#JB>>4X~_h#u$X5l_`O9^gykkj%ko<5SGLsR}H2Ng?yHPkDC%BejLE~ zxeDKI?YWRkZ3kEnUn~S-kEvyfH}09e4*U?yXwhi8V%%ITLB&<_xLolkp>NO@Yv!qW z<5iB;aX4IcWqR>+*cN1rx6YadL~5w{-kt0+&eWk;a1gNNz=~p5_gyC~VhH@42{F$; zr;6jtK!t?ENn4umz#rnTD@z5PG53rj3XUnM-mL$#u*(!^aPcbOB_)=Ryts>i2;|R} zp<+=gt|@;%}nnsRm8y5%s`2L?Gf zI3A)wIh9FW+$Df=Jc0mBU*&xygUBS1*sj9xmWZ0 zqr@chBQk_6S>`Y~%RguKkrTm#S~H z5y97QsgD)Hl}JF6_K`qc%ZUt2l!3NXxdao*Pc#NbBD#T$rBV+s-ZjbDn3ZuCvCNMz zGM&zD5yU*O6Hn^BYIfWucsMcHZ!VGJ=D79g){J<)aL7=8h^PX3G^7Ip*5CC^eh zBOW(6Gd$t2gN@NH8JP${`4#sX1=UPG+7aVA;wqlzylb0?G*{#>sZ`aF2qtB<_IRuS zvG_JRmbAx9ZJ;6^xFWC?RzS(h%QUVWfp4VN<-_raZ)bBfPHfvd|6P=l7-lX!^&w(} zx?uio!%nbEON04xbOmf!>evY5!@9@B2{uNj-T+>ZKZ?Pu+pVi&`9^W{CTJNGdOi@9 zdDd{h)~jDn2o`A>uDp|XYtNe;N8g#`(QMd`h`17W`L*R6^KSs0dn`5-OMbVu0`trJ zafA8>R7MTO)zBm?>+V5SIEpos%3RHnmHWdhHqhC+nl$m&nzo6NL}SAnn+`mzu5kRR zfG^liw##b^@No6YFeAR=?F+4dDz{HcZ;vKOVa+b8C2Nde82sQSE4F%8cJST=v-^-e zFpRYd$u47}d@$*HL{3dn&LU z8WacMUf1WrHe2onam$VPi)A08kHeQ0u(Z0$^>;f&QFK3ILM1pWP%<}4Vn@W!t3{hl zFX&TF##{F($j{ubb4}SD0FRAu-TAda*u~`C_lo{e92bpL_5+qasUMf7LN-4pwo~!c z%t139t@mdw8|U?IQ#p-ZoVnUtYPrRn8-0$~Kj?{<))jxeHMziJddJ;0XNOb*`|^QQ z!D#)xOs8=3>e|yo?_En|8(7K`uGtW$D5o|ODg#svqSwA07w-0Kg z(DX%toL|_~_BA-1f@S(9?jphJF_cMHig5gr5#R4wHGJIpn~3!9m8i$8vq>m8yjoi@ znY*uZkZ{jBCFe(&?|)omYCkmcPLt~FO`IvNNd0M3u;vVDE1*beQmd}*qt=uF@8|%z zg|xbJLiN9Q&aHtMOlWPbvMnLukk4zMTtq91K$s5E>sxNZ+GODX*kTz9D#`*5?&D?S zgeBpo`+eCqK&{Qq)esFQ3a%{HSVl|xk)kL#)Cn~c2~0_3Z5b(hCba;A^Lo6=lel|m zfLSrGT_AIo(b`vBfU!!$lJ_=$-WKw-UpQTC$Wo3xgXUgH>!DkvYC&G>#i@e{rQ2ld z^>@{aeX93AWI;luyJ;;XS{~pSg4v%i`P2`WvnVRE9XH;ig>xTjMUcIlm8yN(N2}4A!_L^L|1*)KW@geYLt=yOPWE!`aqm~p z;Rn7RW@PGwoQu;3J1Txi0sL(Uh+2^n9*Rf|hDBgwTp>OU(DA5uWYHIcW!xFE z!^Y!>Y=Tm$j1v0E?4^)=-)gwDa_DI=P?Inhy5+G0(WmazHm^vXG+G(NP9(af6O+23 zkw6!N*Oriq^r->S^(h5WVzibgr+AFIJ^@oKjowJqXcG`DwP{rXK)P8hD#s|ZUdbAL zF;7hOVr;$|fRD??D*}vHtuM)B&dzd|P!6Xn2OR82`jU8E7bUGA36QDDtDmhNpHc+y z1F?4f(d{9M0Ib~d747ju9--QbD86irJSy6c%ZpMMsL>wiE6qUUE$r5{OHMK7$sa{u zr=MGcrVj+Y;^Y2IU@ybrb>uqL?6w)zDl-9m60`TCzxrOQxpw{$J2furbqwLk`JsC_jti;NHovk=h z$Acx&6?z0mhjt?)wRNTwT2hJGR?qV1$K}8_JMov`0IX70zj`#-PO<<%OkJLtw=j;( z?(ku6E)rsn`g|xmhfFR)WpYG#bA(ijv|TUxHEWtWwHT5!J(Eiwe|WCUhbL0-dENsX zZ!msHXm`sllz^tRZ?9&tY)^{~neQ;-e88NCEyxOqMJ7G>pP&3oS(c|WBa7B8>MC5w zR%YiB-r95$7`6_0k^d_MsO#rX#_CbhK4t5Ij=?j~rdLBo zq-*7$lLj3-+3cl%M-~a_!^cZgx${oVAhz3-VXB<+y%N&#I>z*Ez%Kj;Uj{kKOGey7 z$I=5TuZ%^RcHZ5BqnAn84q3(nU7j9OJJB$xXdn zsV%*lz~;KYxcop4&<21?Z<s>&=DyG-FP-gzFXFzv z#r-7{vIzLg`&kwb_1;i-6QXTrO`=i7<-8vDpYd9tP?w-0@+{Y%-fl5IWvmy8GJ*RE@<& zIPw?AlgQKtvnL(;0e$vGg=me5_?p9GRiBi^yV&Yxrgm(jA_X&kE~UPWx$&=z5M+cOX+N+ z95G$~xiWsANCx4;YVO;Rlwz}J2>u9zOj$We%{Ba^1Dv=^a_ULyz9fz*uMtlx0kQY$ z;$cO+;>Wbz88k+fX-dKl0xXPe$E3WtosET=e&`dSsd05`s@7bntNrO(?fU!pfXK;7 zNvw=xjY4d0x|rTo4ovUy1cAzfIlwX7 zx9n!A!B@^ya&PdP1JqUh&|#%4ik!|V`1flU6j${FU!FO|o{<^R7oY3|Ya_NODpk%x zd7WLF!LZIv!|DS!FP=XXobsV*A8K{oA^^$+=L2>|5nF|&SGx8OdtzP&s=e7DXsGU+ z`=^gdj{_e$Uk(=j(8B%mJC*}bIe1gyhMv$P00C%Ai#MXEFPL3g=j)fV2b6!8g&sWD+8 zW?Zdo}LiM{a`7xG@b zNJ=OwU)mh;pNTVmbb;=})RW28vUFzU2<8+oG9*}`J8ZQFkm(eQo-D*mvKh&K9sb?* zX!UDb*pvECcougbQ$UDX))+UONAKF|zxS)>BX(N?~`1w!a-a8J4 zwIj9K+w`9ufnBgby;+@XmqKnS!iLGKl;NH$|D9=4=mj=VrRR@L-fO`w zB|4;hj2N1NqjuP`9{JHwi#3#yP!@xNcT~C*rB86w%Zp*>XmzOriNNk@McERF-d4xn zw`;>n{-%2mBGkX~U4+#~*Or0GuxERk%ZXezN;@e&BFW7IzF z@|s0{*^Ns_Y4GyN*BxJlDg;i-S&)4m$4jueetoRfd6^;bR36KCRqbB;X|J`$2$;yH zOvXt)BeK?hHnqLv89hRaW}_ArmPccr9_>pNrL4QPs$q8#Fv5dy6?G(Q@~3f?4z5gm zSFf5vt4ANTnO#AjPUG_Uy?jK_KQK!DAtlJCajz5S(FirKE=h|E^d7};wlNtM>8!L1?9FWHJ>2E0Jyn0PrdAcJ;yrsm zwI7*XTs`F(UmfEAvU|y{8!68bPW-{$y{I6o>#>{?T|Vun*|o9wE)SSGRrEnlhpy<& zeNWr4m(-D>63Obt$marNOf*KS7(LoV`>mkqU8a zE5*9jUFwO5yGxaF920N_#i=7*x2VjH8HRtJW6YqMP;e*;7f5~appTC-#&}aBs8vav zh)IRLRM##zRC#Ds52|bj`H`F+5$?nDM#+LB`ccvt@vN#s&l7Uj1!9FiZxrWi>9eMN z(&Zltvy!@<{Q;21&R<>76krzHiT{7|$%KhL#kE?R2e-;AP& z&6StasnH+(BdXc;B=6mo5|2LRO5B9~^iON;>5Mlg(g1mO2%o?H&Af03$7&sjV{bS%_%aUw_ z(t+M4KWyuwJp!+?pB<|^cy8&HV=HMbJ{A8BrxMJAJ#B8izmNlh-9I6NhF2oDKlS@ibu_+QS5!A&cxC!WJ5(9(oYM`Btx0l`{DQbA zly2soMf`;vEGpY;1qo>D)HAyFpfDgC90=*bJkLkY7a>7S>b^2cDn}zAILf!dK>^pl z7nbBd)WDU@dQQ;}!vBy7#W=MdjQFw(&Y>~#gUWt`)rkbQ$MyU=^OH_-IJ$xODBVcdY8 z_pQ4~xmPl?$cGdRpBM6tUw6o5(Nev(oVt=}!$=M=MfN$+KH|PgYl`Sm!HvR3T8}9n zgYTh@J|D1Id~SzuUen_tT|}<&l>Q?ui6!C~RS!D5<8zEbU-t^yuF?gsK`iUQ%?zGi?y2{dkwjGW z^PS7951aSu$uuj^cv-25!K=;&@%Isd1&3@Khe>i6e>QNf@{YH&(=9ol|2q9R)QJuZ z)JOVd02cZI;c7X@0FT;N7#R(b#nD z5mrU8M;BhN=+TZhPp@=P!MLXLS0#F6qn>*Dzh`PQ+z2Vv6X4r$K(;JK`NgGSfgw5B zXE6qR*^pp1LHXHTHPe$}4cy}!IeHMdKDP<^=Gi82Zl{ix0LqAx{4ujcg6{b?$hVlL zd6^*zE*=#h&*O^R)w^qBP^S;M1& literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-black-fat/right-6.png b/backend/priv/static/images/resources/arrows-black-fat/right-6.png new file mode 100644 index 0000000000000000000000000000000000000000..67510d0c5b48ff7b83f0f7a237cccc1c18020912 GIT binary patch literal 9993 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 IVg`Z#19`tUf&c&j literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-black-fat/up-2.png b/backend/priv/static/images/resources/arrows-black-fat/up-2.png new file mode 100644 index 0000000000000000000000000000000000000000..429eb433184bb1f3a3bee7e9861f6cedcdbc4c70 GIT binary patch literal 7972 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 M$wR@FvSz{m54X5)&j0`b literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-gold/down-2.png b/backend/priv/static/images/resources/arrows-gold/down-2.png new file mode 100644 index 0000000000000000000000000000000000000000..27e40e840f8d2df6bdc126c5e7894f85447677da GIT binary patch literal 9661 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 HIO6{R;Md-x literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-gold/down-3.png b/backend/priv/static/images/resources/arrows-gold/down-3.png new file mode 100644 index 0000000000000000000000000000000000000000..a7e14924f020074f1d0978eacde9a6544c67b243 GIT binary patch literal 6924 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 Yb==RR-fErCE`Nin54Ds&qbx)I2jo4m#Q*>R literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-gold/down.png b/backend/priv/static/images/resources/arrows-gold/down.png new file mode 100644 index 0000000000000000000000000000000000000000..51fd66a17ad7c75f37eed8d090974a80cdb11f61 GIT binary patch literal 6180 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 literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-gold/left.png b/backend/priv/static/images/resources/arrows-gold/left.png new file mode 100644 index 0000000000000000000000000000000000000000..c5c271a6a602af99996cd968a8f50c31cdd68af2 GIT binary patch literal 7207 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 RNW|@)`s1f66-w}s{{y~>XAS@W literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-gold/right-2.png b/backend/priv/static/images/resources/arrows-gold/right-2.png new file mode 100644 index 0000000000000000000000000000000000000000..f4ddabffc77f4b2a17e02b96569e6949f9cf9989 GIT binary patch literal 7230 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 literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-gold/right-3.png b/backend/priv/static/images/resources/arrows-gold/right-3.png new file mode 100644 index 0000000000000000000000000000000000000000..5bb553bf1204cb926fc9a6292c6e05b942380dc8 GIT binary patch literal 6508 zcmbVwbx@RF^!_eg(z)bBog1sCqkfMFL<9f;?rCbMzyJU&%oGbifQ@-{ zmEG^f1O<9phN_s5nVIo_jG2Rjm4$_Azn7Bv@A#X?gsiN8J!a0$&5iL)OpL6oEbQ!T z{{XuKG%PGEd%aZuN*Ip`K_I$+3-^1eb_eM82WSraXqlOrSXeMUF&+Z|iHnQ>%Nz~S z^6;=@<`~=Sqxz4Ig^`hQzYnzANBtkmUv@BVpsSKeMf)qWo} zrZJ|&Kf~zU?ZspmG2wncM&4ic-F}P==JQ_0e}eb=sM*>7Zt(At|F*E-he0y4urMF= zQStHd-Sq-6nSWdu@NO>+8yhnhC-|uUFMhv|64Uc9doT6g05vNs)6po^!2pJo>A0H? z1Ne*ii=@V^-Rq~pXgK&!Hm2dfDu#EbpXRck@-K3L{;rS5REHh|-ocReQ%C#LVK%CbQBO}JfMi7XSw6r8ACx?WD*!K4J zuV1SJ1N|Br>Q`4+qM{-b6BA`+rJ*?t}dZekSD8IbC+}_^S+}xa=p62T6Vrgk1EBm0h zxF{#*b!KKpYHCV!bdrrB20uqUM{yfOX$Ga(q zX7(f1*w`2!56H=kKERnSBb+ws8Esz`H3AVKEe_IFWhhCcRaFE%d;l`aEKkCGqw#() z9Rt9h>)Sw=sfdb#;M5dZ+qp{5GNFlc7C zBOId<057mqFA$u7#XhMSO)bm5h9-)1dBWlghB;! zQc0)Fazhk0(|jP8MBKa-v4XX~*|El-{j#XdN49KHyYjAmOx5C|IJ9ykDeWrNpvh9!kxg z`FxtIWK1W>{Cu z4bByJl$dr2j2gBk0^@BUDAB@qbyz2=5TmPTMEXr5B{GP&U?c32V$q$A*-AuXv|vj< z3Ro6zi59VekEoJOe~jaDVRx*OznU2q$*k}BPCd?Bol=~zRp^YnJr4bQ((5BqrTiae z-fZ#?s!0*Z>OR-ef@&us^7l-wl94A{UuFZq{vd|)$~uC#qX9t{d?h19=X^&)B8g8A zo6I!wWuJYiZCa`lDAA)4Z6hVGWH?N-C3vgP+@^-4e%)tvSS#4cy20huDu24aPT1_g z2PGQn5!O98)!IGDIhF@P>%fS7owl9q#iWHEiK|Fzb9jEe^dNQek+dQW`g_3jN&od4 zR~a9HYa?x4)zqN1Cu<%Ik;JYhj`L!{5*Xv8{_5eI99!(s#D*_?r+O1xMOiZHBni0StLzP^+>{e-rJkdK zxgIagei7H;A*_(VpHyD;#@C!9EixdTR9N-JA}of2hNAv_YYwpmE4Aa^Z4%`eQhuz2kz5w4Wc z!n72%J~uZahrPUTJ$x$HzG#b_D~54}sI`;3z6cCiG_cw&r6==#`LFzvP(hahYgY~g`qVtO+;Jc9#htM7Pno)sgDFB zTD><2|1p90E_kc3wU^h9U;df|`ytepSqcA=yc%ADeP#=^aC`s_(oaA+^6gRBh3KAm zCjTH73~J66%c1zLsL^F8t8Ta%B5t$cLo8t@%pLMJVIm- z$MFI_xi#m-*1GZyEymNcd|ty}pD-nVl>uHlc1QXdFo<(?*FI|;Dc!gEj61XRVeu(( zXBh)NP)3palWjHpeb8XZ9GKl9yZ`WvEyG0E>&uq?sMghLU8x&HMf`}8|1pJ>vZEFr z#X!dZw}IaYwFFhO9Jx+WHiNjWCE;>cCKrqjSCVTkC%Lo zq$(wFEB3urW3muho+Tu1JYHhAJaeF+z*_F!7AW|T+Akv)Ei&w^Un|-{jph_ZXdU1eJ>e z;0>~~*#tSo^<`Kw8_Pn(mthPSqmv<3C&Pr+Mge3q6sKwZubCk7uky+0$6UhS2VYBc z7yy>sv*crImzJUy0ERx|Lz=@=tjYK;MGQ#qfc#2o+ktAL;x7c04pS49o~DAMrf0Z( z%Xok+8UET#+gL5vU-wSgUS($D^d{iB44(Cvt+}NqA~_NXcI4F8E;3(f2>eu)@t(m; zv`oD+xd|6pc#39$n(A_=PaQE)3UKm1B%S!ArDxk2b@HJvDPzF&57)A0={?(#ij>(< z)RM-LU@~^(XvRTnet-667ZKU=$n$`dcDJlEe@kPY8~+ z4LEP{QHJUD@8HBBF$bi9Ea>t94&`pz=@@0>(pj26jnn^lqifqIVOT_`Rl-Rhx^ z8!4B!plQW6rx3u9^k7`#SRWtY=JCPCww|x_4H0BM3xu>PPmFq&r-WIkWN%)5i zBy&H|fx8TH*=g3R{uVVWD+i)Q@=}0yKcsBFhE`VoQTsqB7B|FO`_L4Q)75bHZctI@ z`)c`=I-m_30A8~~H>)#{ECiDv*RzkZZ^ZE)kWRVb_essJ zsV3wJft;yH)>-mO6Yywjzjd!sde6TE@;i;d0;I7}>A9I(3yX58dE9f-@ zA;enRVhGw`;rBlZnu>0e?+X1y*8F-*+K=Xk`(Geme3U|) z20^EDk0Ftp3RWi^n(q~iVx+#SmTF}cY`)}o4497gPog#jdQDT18J`5|2b_I@%BD5w<)y@Gmjl$jY_$KuaawmsA@!~Pz}rdRGpTH(9XN)SYB)?!J?CtNz4#j(_vHeM z?U5tcSnx?vLR2m9`_RSaNA*d@Db=$S(sx(U{pL|vlgS~T^s=G1NTzGNst9x!oYjKe zIEbvtaLPirCD2JCHL>>r>dM^M{xiR|3Q6h1R@UEGIp>!<%L^fIKq>JwAV+x?(Znpr`VPhS5{L z`NTzdVYx|0)K#tJOv~F=DV{C;3G#Sk>7Qaq=(_qiTM2=^y%VtB$8xlD|7NIYdfVuMJ1Lx=$-b} za^HO$ZC!pN|07+hl+D6j?A^%9Q!t;s?|Wt+94kI$uNgw%PDGflzNP^L{ZZX4f&IA_ zw(rr4CwtuC-g{)c)A|bu4Gy7%fDat6ZtiPxm<4n*=F5d$EpKk#c(U5v zgGnJYG63l!buo!9`B%s5ClAGSSuKwt5vb>=l5~U7wpF_Gd=d zT#e!9lhOoQlt7?M1plZ`g`!xP)ZiX&d>di^Iw+-dgFW$CF|)bPc5Nta)xl@IuPj)> zD2dEfZush`24Z;lMw)K`=ChkjYx}d< zgyvT2dr$Y=pI=;mM3?x;Y3otFX&3+T$kC6~p7G=l1UpHKLiGh# zJznyj@0E27hm-SD;d@Af8Uc=7?x{@9Qr-tl1V%Mn_W8~^hItF2Jdsd{s+KVq32h#Y@PGw%{`{$} z+2Y$UDCAs+tLdmaU6v7LG$d#3RvDOXJl#gCwbTFRBC>}`3TWY< zuye{Bbtfq;ZPLb2#}OFzif&iM9$^xu6JZGy-P9q>a%5x(mG$c-0JwU*0~i#xGu;;ZFPsbxcOHMftC20&pw&$!>BUW8;* z{Gs*fNyEP3)hlh;bym5y`5EPbuA3_`u2;H(G|@gA&ebO+(1iyR(nTs)A^_2TxOkA% zZUb|yO850j!PXv7FD{7l$qBpOGJ%O#2XInGe^db0JklGsyADFP_JTOka8j@|O~O}g zd=o+UpNcksldVKi*c7OyFT)-U{-*S<1){dy+}Y&%pc~Xdd|BEog= zQOW36`9m6Ep6jN>6GTj+zo}(9PFgcv&p-H-SyhBfOocPzqDg3JX3x4uz!+EzbCjhT z-jSKIKQMNxa24_Fq;hgd`lJ0MIZ|4{63bZ$*>A7*R0Sye#JWS^*+;rtwK}*`PP1nf zZM75a77paMWy0WOXOqioOYo=KSTlAeT>WpM3Daa{QKQ z_T(G(C9Sdz6SC?Ad_d^#^|j9nHM@?2sh#*9>~Oc+O7HnAyY8L6 z?$D{x?cBMTvP_#ey-GfujI6@~Po`NX7u*m4!~OXzb)pZs8<(H)9^9V~q&JV(eKx-k zE&xRYZ4eB<_x@}Jmxp>bKErw8>78p8p#=-d>HXksX%+5J4T~Ld%fJTerprW<3u`1F{)U>YtHS>=)zlKP zM%5t7JP>3{E}tI|H8HlHPJmeYNZtCm%fdnguj82t1zoIHO(#9hUDcPvnFbfaZ)`#D z2_|KhT7C@OSz{$Dd5V)XZBr^?0Hs;o^MbuU-*XHEDda2pO2~Z=c6`vrcAm_umQ?LB z#*9M;;n@i*>(uzM2l9#-VN>YNEox{K@^I~>!MQ_9-+QyVRI?`Y8t6i2I)1r69u#5o zi>7eKZAm_Z?Yu=t?Y61udAXK>?Fr84^7o|BfnQ`1?Hx0$m7Qhl&O{nydueb!W~)G1 zAdFZ9X01M@CyP~2RM-wtOCP|#LHO202yi@&T-~b)A^0UW7$fDeKw)B@=cvS*Kf%4U z$1k7dcl#LJ6GP$A_Hx9AR~o3JDvF|Cj&2)!1vcSb+(Ab}rB9PYsQen|f9Gy_u?jV_ zI2@;^eJ;Mwhm$oDCP<$Aq9vlZ&a|bxa`(1+>2GXBz&4{%!+Om z5UMGX1GT2DtFB=hjJ5*EBqSnm%NXiPqZMo-c`LDg!h(2!v^;is#7zz1nzc~rP`%!~ z2ym^E9r^K(h9 zw-2vkX@gpbTyPr_O8juzwhbQ3=q0`GiHSeRV8Rs&w(!8zTs}?7}xUFXq m%Ku&8Lhh^?6@dTy7FWQP=-ts7m&wK7lBTMTN)6N|;{O5IILd$k literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-gold/right-4.png b/backend/priv/static/images/resources/arrows-gold/right-4.png new file mode 100644 index 0000000000000000000000000000000000000000..5900627bb4431eef2e5acd2d0fc493fab9c3199c GIT binary patch literal 5193 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 Qe{lj(x`sL>S{UsA0ng>K`~Uy| literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-gold/right.png b/backend/priv/static/images/resources/arrows-gold/right.png new file mode 100644 index 0000000000000000000000000000000000000000..eef066dec7af34c81e7d6cee1273daa3d72296a0 GIT binary patch literal 6847 zcmZ`-Wl$X5(guQTaF+m!OK|r9ySTds5ALqP1HmB)!DZ1PA-H>h;O-FIZE?46dEf6= z-9LA#tIwS7=REy%&6%m0iBwgV!9ab33I_*=Atx)T4hM$-J4Jv4yn+o~g|vOJNwcb= zrW9;SPEHC0lEOU9$jDy&Q9s^4Q!*fsjEw9Jv>%Uxf*gi{Wwo@l{zU?Tum~9g1H*sT zl2cLwfxtJg;6Db0ExGI^gk>ox$PNbxkNRMouoSEokdl&=fr09dr0)YKIJ!k~S){~>?jfw93bx5H%g^z{EQyn&T~AzwVq24D8DJUplrT@Xa)PZFn>IN3xy#E2+y0?VQLRw8X<-D;vM%BQBzaH zrqF)e7ao}P;k_V7VBi-$hcM;;EQe`+?!$#;DJWn)k{^#!9=vpc2OYwJtvwmQB_JSx z;mf`eBn1=2`4Br9zchH*hxh#a%*4dFzP>gwF|Mnt107~~e!72pym-2Ya&of6`aK#T zIXF1T&(8}D4KX+WARxeZG)Q^aPw)UcF2}2?D!sfsPo|_#CPa@%Ij*j*+S*$0jvH=| zex1&!$jZt*J>H(4o=#6s4-E~KloV%YXJ2oBi;azmi1>WD9^&usce(0&{?|fTSrN8j z?#~CV_aGO`F3!$QXA4GWb2<_d;O*_LrKP32)8CDa4LAD*qM{lijjy)r^ge0nw=hG~CFs6GQnFw!VWjXL|jg+8mT55`z*XM&x zzjP_P3an_Tf#fGksmY&$TujB#Uypo!=xhEG>1V{aI>CywR+`IzgH&CfnCNRSB0z$2 zx4Zdwz5#F_1mGOR~3|pBbyhelR`e=A@4~afXi_ABHt*hW6v~ zeC?Mdh)4_$j)+W75~S(9aM&3P(+d{_c`PO>ez_n2_hC6}+WO|wIcKBSams0?MZZUxO3H2>ebT}#C00p7yAcl_tLZp zvOPATPiI4or+Ggrt2YPl9H@%eAJVCV8x}o^TD*{lS(-onJ!|8r0VCPq2-{j?pj{7= z-D87QyuuGW!#bvm^X~GRhpI{wE__UQ$LI}u6P3x{jhczSnKGx?THVkTP9oXT9g_X> z_I?+SU9li*33rZ;e2(PPb{P>AV9@c$c%C~6@QxpHgSM_FxoI> zzW1$~+Ylii?_~Crg4u2|(JFY|L9fZboL5%gfo0?3uNa484Z`>QF>7Em^JD4wU#Wpy zaST!Jn-%-)TrTW|H=#ceX(T3A9sBO9j@^d|t_OoFzkPLBi9Dm9l@rH6F2^=7+WEbN zSobAnVTeKCmUY)TbNU+ zgkxo3Hp0b)5U7LLm+{>D*cB@*5UN*={=*r*MT5tsA(+!4l#JSRCs_?Cd*rjtEW@z? zN{w31*BlWxXf9**Wmu7X{CA1ZBs()+KZsL_AM*kZGH_Uh@>XC+aO7+2n}qUZM|V~R5{?Nc$5{V)P2iaUinJvR z_D2)?U^XUJ7G-&#Q)%dg80(vF237aARPT&)o(Wdgt!>iOX2cm2ObW5?pdq-tMzm=8 zX)JvefS|tNNtPai=r??KV)@~-1UZAI0d*)>sl870u42N>Re08=S6dt~(}OHGK-DD@ zFVTU^I2PMeP*ApSoww9}o~Wvdhz~qQP`2TOyVdg3NPznw%pEgB!*H5uyxj&P*!V1E z#w8vV&mJ0zz$e>1#jDXiQ6r9bv8TcWC1uj%d+q0|L-l$x=vTDe#)=9MqRpcq)iY7l zT}cFJkVptRMKVa|;1-Ot-8(=eaEr1%i1DXfX_r`xF?@GD7<+3A)Y*S}AA=f|8=hIL zI<|Cmx8YP&Tr*1!2CtJ>{a-B{&(yJJl7JMVb+4#ZE{V8W%JvaV3r&2 zlwu-u?=j4cSx2T|r$2K|IMca0wUIe)Cs9M#^cNI47>k2U!{_qr=gR`4T+WKj8K5B3 zG!B!#xFnJ?#Ro*Gy)Lqn%#{hN-nW3t3TLiWiBd2PyU&?e`kGB@pa|RWGyW&NL??2W z9I3iw7Yb>KJ4~gbtCU!cG=V|!M9`jq$)5;q=dOJg4`|9P8lk3wOkNT5I(<}{ox{y{ zXM{_r%B7h2qb0o7)LBi z5Rmy2&-ejeX+EI%?aDSw9C7DPoOWXaXq-*0TOiFu*YXgMZrJKMCEsHc%Z%^rn;WFY z!?vsH<5Au+M5yTp5n)p^*`+&6m+U&UpW&=xUX}X3k~r#we|Uj6Kb!}`AsXiyv;c=G z3>=^$8Al$9SOa!6&UyI zE}50pH-O?|r{5WmNXFPy2!p*iO3H;;XP}j+D)Mv@2r^Rc+;`#F2`N?X%&G(MK+W%J@Rde4WGz zeT1lg=ih}1B`>eKr!_%uIeMx>ak^)nVkRKt9?J~Z#*(Xv6eH~8p z;Fn2oD^szB12(nnS48zUa-OL93hvM?RcxS;J8B4~VThx4m##K#6Y4%#-XTqaN|w?* z)g%mi;UN2q=xB9&X#6O91SaqOqrpzo!?us*c4{jD`K#rAp>T&2TZUleA9;Ff4Dn_q zpp+i)}!drx4{kb&E83Y$BP1a%UdT;tU0V#+stFV6nXG*LR zVw6_3o3Y3ey{ZgEmrmGi-RA>BEMgkn+`#8;glk;uB(sC>-pGopjKP)#_7>gWq_`mf zdw@#4sFAk+yacG4nx8SodSYbQh|$R2QyOgCQjL3{{3`*V8e)9}i; zjGmt|pT-P0JQ0iPvNOM^zP%w1HY4X8hV-_q(+8UkAJWQLl&RraQ>wBIkC<4qwZw>5 z4j*1bSPda6WAA!U^{g4G0zD`%Z5vG#MMzixs^u}6%ctVx);ojsN{}S+GE_F=#0~*jgyRr==Ey;~uM*^{jr)kbBAD4qXHkZ* zOXkwqa&wk~tOhj+LF3AC7~cU**{=7=S}U2L1#54~#Wf?wty)yL3JYAJa0F?Mx6d_y z%dGpwfw{UuZa?2v6}vP4`zs2q2orgjx0v;}^^+$Lc^X|S{(~w+W#}j>xB`X#tS0Xf9L}hYul}}KNR_puorfUWNBC>+o(WZJn_cY2*mA(hup~F*F zcUyiwg8oMYF_%*7=FoO%Odu=#!kz)*^*YK;vADOp4}NVl!NE z%sThPAF??!E4KJ-Mep4}ApD%I|M&CzO8gUz*LExS{k`jfC5lsP>SPLVLK_P!ftAwe zYCyIvi`NjVH0NU40|XEHjhUNKQ9A^8%im0bD^(SvflHUG>I7!W7OrDjBP(*sv!vYP zAK9^)wNP_3!sOr1V7V9EGOjSPm))7ZHgHcOmIq;(akY>TPp!MXr|p$4ZBS*sJm=oZ zN5T4h{*Jo7RGgG;B0>I?rI??SsJzFwt&RvQDBZ<}`bJVxqj4M3Al0NdG&M1}mJiTy zX(??6B|_qUd|~?v(hn2o+4^krDLnc;!Y@$ck}pIyJRPlIv}r5_3~1)1CJs?=JTVC! z`evAtp@Pb>+$L-#aRX6o?r^M5%>ee9V_AWT$zQpFl(dlbQmTV#z#?;Ggrz*|5RYX;x zt#^r{VJQ3jy>RGKZ@BHv@9>4-oZbkV_Di4AE>laL3!^RBFnbo9TrfYUdN99&OOr})mji;izfE7~^yL8D z8~`(E(T`&}fE5(UlpQMCu!Xo}GZOm#HC0th!UGw^J%cAjza07FTP*zXfYNjfcS!s+ z!jc8DmoClVAQ-;#uZBqL4n#M7=zJ1r4PhqSq17P zyi)r_QD@{I9eG5KwoIB_6QqYOTgJLPrEEBc?H--QU)dh{&`fS|JWI8Tw9cH~BBpr|CSGXkQI|${zHSMA`?WwdT-!jWKdfZy7!fz11587qsmG+0 zU=KPH+%6{c=ZyEO?cYx_bs}pQAHes)T(~JcTeQ;?6*N)qCRYv+3^<*vbUnk@{Nw>- zahDtMDp@VJ+Y^gA&rhBR-<&VE32iPKn8B|=xhm8R6jqO-k|K^bHbo;V?Y|L?z(&!`$}?bbWbY5>H z3Gd`k^8{7YlGAFOm`R$0gSC>49OO}~9AOn6N$C>$*q9){Lsk0>!jm3$3DzvIF|~0z zW#0F?9JEDxfJRJL!M7a=jDVmx5$cpr^BnaQj>uZ7+*tZq^9oSzq9_yYFc5mQTFRa8Ww z$poTn35D|+lr)QDS;l?F5trUlEGgN#+GBW^u*oRQf5+T&@oPGI2qa5@9glkX)o8EXX`JYAt# z>G^9YA7H5T?Q!U;D`0o{{c;Qv>-9)`k3A~te2eU+=fO8_qg^v$-bp*cBWLa_JxUbv zg1)+KTX@mbP$5C5sAPIHlJ^D?F}lW~arR@}+eX!4a`U0UYwhHLhco%&3dfvsVFJRu zF_qK|({+e0aW?|9y6FB!m+2GOT~Gg(hnerDZ#g=^&<*QszEwG<(JYT+{yXj4VF`W@ zGka>%6hesDEJi_9ad8X4!`_%_fLN$d)wvTr_5vxCXhV5)PJ5{1dXH_(dx+lxCZ+41vLdpcZ5B1T|#E4CGwYApx$Xh&0)@z$F z+k_@_Mc(&B&gV0MdY&y~w1fvF(1(fhfSOVAiq~|xu0^gt1-)%lwu&BHPR83@*T$7S zhYAZ_r@$%E6}##3xPKgN{MZtsWd~f4r+EpOw**2Rd6CQENaHkf0TCVN6IWz zXE7R69TW2J={KVK);B1{r-kQu=L-@=%DX^Ue>}y~a}&hZY!`pG#r<$9>!zF(aNs|) z{^e?_T%Evfw$o`5rC7RxG@hp@KugP%jr<|mBQE)pVgm*R&Xo8@!ai~U@ME7kclR~V zZZ=K2it0N~b3(~ODU@0{MM{N<&&L*J@#Kyczfbz1e5-=$1o-{Wzsvuf2wV((1^*HN jJ6cSN~7U!rnS%96jpCL#X^Zji{s literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-gold/up-2.png b/backend/priv/static/images/resources/arrows-gold/up-2.png new file mode 100644 index 0000000000000000000000000000000000000000..05460304dc6922aab836977ca2e36315538cca52 GIT binary patch literal 7186 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 literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-gold/up-3.png b/backend/priv/static/images/resources/arrows-gold/up-3.png new file mode 100644 index 0000000000000000000000000000000000000000..55a1c48d9ea5405eb8dda8b9577fdb8a3e8dffc0 GIT binary patch literal 5920 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 literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-gold/up-4.png b/backend/priv/static/images/resources/arrows-gold/up-4.png new file mode 100644 index 0000000000000000000000000000000000000000..0ecce56022179cff5e6d88d85b7a354e5b977938 GIT binary patch literal 7886 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 literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-gold/up-5.png b/backend/priv/static/images/resources/arrows-gold/up-5.png new file mode 100644 index 0000000000000000000000000000000000000000..741ab7e903930d35297b33bd19e8c987f5124e78 GIT binary patch literal 7789 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 bRbn8#Il2b8yMrP8KLcoK=&RSL+JyfaQk2xx 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 literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-highlighter/blue-left.png b/backend/priv/static/images/resources/arrows-highlighter/blue-left.png new file mode 100644 index 0000000000000000000000000000000000000000..dbe528e8def449caae0d391f8ea3fedded4c4684 GIT binary patch literal 1947 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 LNkvXXu0mjf9eCWo literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-highlighter/blue-up.png b/backend/priv/static/images/resources/arrows-highlighter/blue-up.png new file mode 100644 index 0000000000000000000000000000000000000000..49683fc562471a51ed1d2ae4cef96589487c5f44 GIT binary patch literal 2561 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 PcA*G(4_w)P|Ac=5?-II5 literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-highlighter/green-down.png b/backend/priv/static/images/resources/arrows-highlighter/green-down.png new file mode 100644 index 0000000000000000000000000000000000000000..606f02662196096b5a3b069822e3e7aa880d9c43 GIT binary patch literal 3528 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 literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-highlighter/green-right-2.png b/backend/priv/static/images/resources/arrows-highlighter/green-right-2.png new file mode 100644 index 0000000000000000000000000000000000000000..e23d8634df1564307f3e109d17b62e46041a20c2 GIT binary patch literal 3533 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 Hu0mjfkW<9V literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-highlighter/green-right.png b/backend/priv/static/images/resources/arrows-highlighter/green-right.png new file mode 100644 index 0000000000000000000000000000000000000000..18a7af2863cdab465a0339f4fa265dc8e8c11fde GIT binary patch literal 3154 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 literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-highlighter/orange-down.png b/backend/priv/static/images/resources/arrows-highlighter/orange-down.png new file mode 100644 index 0000000000000000000000000000000000000000..88df2186c81a01fc9ddc6d3d56bb176bc638f2f9 GIT binary patch literal 4291 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 literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-highlighter/orange-top-right.png b/backend/priv/static/images/resources/arrows-highlighter/orange-top-right.png new file mode 100644 index 0000000000000000000000000000000000000000..0da228a8a611619ed2fa4bcec8b2b76f405d551e GIT binary patch literal 2838 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 literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-highlighter/orange-top.png b/backend/priv/static/images/resources/arrows-highlighter/orange-top.png new file mode 100644 index 0000000000000000000000000000000000000000..3f948cd00271657a9333d09a52c8a9f8528413df GIT binary patch literal 4214 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 M07*qoM6N<$f@3~LLjV8( literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-highlighter/purple-down-2.png b/backend/priv/static/images/resources/arrows-highlighter/purple-down-2.png new file mode 100644 index 0000000000000000000000000000000000000000..bb10d3804c0206f07e48f5c781088d472ff6057b GIT binary patch literal 4410 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 literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-highlighter/purple-right-2.png b/backend/priv/static/images/resources/arrows-highlighter/purple-right-2.png new file mode 100644 index 0000000000000000000000000000000000000000..68feda56d0893535e992639ba29caceff27e676c GIT binary patch literal 4142 zcmV+}5Yg|6P)1AflxvrJo?ApCO{4AEKZk zqn{t5pC6*0AEKWhqMsk4pC6&1AE9Nk;)MVJ02*{sPE!D~=vnv+s4a$^Ll$t6A~!@e%(Okb>8QvclRLiy;zex7%Vdh>>=?DNVqU zc1w)LZ^$%xLmU7x{w_F-Avtp+3`RMpO4tC@i1Bv;HDdfdumHsPyI?VuvqYUOrI(CP zNQ5?$@d?qGgNc+tD}6&QTE@Xm5>7q%j2a){Bb;Nv`>sg{H2#9NW`Zm=xQ$mHA*6b z2NLmjAkeeLmmhtuMLbY-tjr(hCk zxVG^x@)VHH@f+i3sF8*4BvO5=$_Mx2i+lN?s+ni};Q#v%LnRDjGp(Hq@u2uKOi>ii zuVLa;M+0K}A<|6e4qeJd>bJgxBsO1vP(qu)>UlADAk|kRPFDtl2z6x*(Jn8isiolHvN-_@0~g}L6oD% zCPk-g|NG+T#eSCVO}AY}@n!nP_QyT5kmXp!eWCWZ_Cr%1H`%8bgQZl8(Q_s%~5U3_R*ML?Ie> zC_0Cgen5D-ZhP%~I!>^+J>jW~&h^y!c$8p2P~%Cv?dgcp$2l7IDmteh(%%5~C-4J} z9`xPz`cwLf|C%Z?=tEz0PBqs_9ne`o8o`kAp-8yHFLcO@AEeFW8OyE7KoF z`rwQmDF;m7m!97YCpDmCyxU$I>3L5ssmuJh@lP+MFW4P;)$o8$x4pKc=e$9fzz^;{ z<$Kce`b|&Zi}J0t?Wx6|7Iz?5YzWTqhp%pX9g@D}lr6nd{=3_r2Bl{daC}q#Y5eQ3 z^nALkf6CXCr$Ol}Hl^N6l}9huH?a9VPYxd`f0-k2dCh=7dA`l9 zSylB)eZl0w3XS19cTN`PeJ2$jDUbY^Ff`RFS5Nl(c&QkRj*4j(;yrQnBd`

    =Js0lO=A}~)4Nsdo@A>_VY!=r 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
    63-+y1;)7^sx|wi}^eIgApj zB{%!MOs756tcKgL0-NGcw{$l`2N7GH4ItT#&OyYI_|NZTH!1^_1{*+^J!*qj@Wv3~z0ccdWiRIRNpp{y3Bk_Q<)vqm`H7&UjIKg#f zE@pm8;<>@4iHF-;9?wm-vP&N&yWzh@rTq`f0?7@=7G~*FBa)lT7z#8loqv(SapShB z<#tP=xWT2Z<#vmwxZzJ!L3_D{1cDogW`=3(g5Wkaa(4TaTX4fa!i^-~D$MIjyMbou zQTgYagj8v_;ak&mJAVtzyBBVa{LZ*suI%fTEIkdI%1bDiWyz8G4vRvj#m5^)mL(<* zx93cgV*w%C=2$46Io$HH?YyZ+%^b&&yu{&_l|0^^+6!=l{Q@!>w@ybiL(-n+9H~oc zX!pP5K=kh#ocHd_7I0m5>Xt-y>YB7Kn^2k21Jn*XbxHb1_GISz%lVN+`qXA(V8^K+ zaliLnCO>e@!w(!2jzkzMIHou&XX?+s*-GSCScx#s;F!sc$~@et%<9mWneFY7?DZO^ zc-?`iW(H=p*J1{TB8<~ZX0jAv7E6(YLOH0@sqxsum;6=0u4J8+<0L z;+QZuFk$)2gu`EEFsU+DBakoNAj>!dcgVoqg@H40hYZ|Z7&xdII3^4n6OQ9v4_uOg z>#jNgW~u{VW;Ae2@%LGn>;M?D{(ZR~@j3ZZHXjW#i>IoP_oks=Ut2Q8oeHfkI3|bx f*Z@t|zEAoC$={6O^H8i300000NkvXXu0mjf=XENH literal 0 HcmV?d00001 diff --git a/backend/priv/static/images/resources/arrows-highlighter/yellow-left.png b/backend/priv/static/images/resources/arrows-highlighter/yellow-left.png new file mode 100644 index 0000000000000000000000000000000000000000..cbe5c7227e5b1ac48826d71ce8450c63967e1f7a GIT binary patch literal 3967 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