Problem
Fragmented operations and feedback
Orders, items, payments, products, customers, sellers, delivery timestamps, and Portuguese reviews describe different parts of the same purchase.
RAW TO RELIABLE / ENGINEERING CASE STUDY / OLIST
An e-commerce analytics project connecting Snowflake and dbt models, Cortex-enriched Portuguese reviews, Power BI reporting, and a separate Neo4j graph investigation.
Historical public-data project · warehouse models, recorded BI output, and graph investigation. The source shows separate local and cloud workflows.
Focus areas
Technology stack
01 / Project Overview
One purchase, several grains, two analytical perspectives.
Problem
Orders, items, payments, products, customers, sellers, delivery timestamps, and Portuguese reviews describe different parts of the same purchase.
Engineering challenge
Align order-level and item-level records, preserve customer ratings, and attach AI-inferred sentiment to the review text that produced it.
Approach
Snowflake SQL loads CSVs from an S3 stage. dbt standardizes sources, invokes Cortex for eligible reviews, and builds fact and dimension models.
Output
A recorded Power BI dashboard explores categories, sentiment, sellers, and geography. A separate Snowflake-to-Neo4j bridge supports relationship exploration.
Code inventory from the audited repository. The dataset is attributed to Kaggle’s historical Brazilian Olist e-commerce data; these counts describe model definitions, not loaded rows or production scale.
02 / System Architecture
Warehouse processing and local orchestration are separate paths in the supplied implementation.
Warehouse path
01 / Source
Nine source datasets
02 / Storage
CSV objects / manual boundary
03 / Warehouse
External stage / COPY INTO
04 / Transformation
Ten staging models
05 / Modeling
One fact / four dimensions
Graph investigation / direct warehouse bridge
01 / Source
Staging + raw review records
02 / Transfer
Join on review_id
03 / Graph
Order → HAS_REVIEW → Review
Local orchestration / separate control path
01 / Control
Local task orchestration
02 / Simulation
Simulated success / no load
03 / Invocation
Configured cwd: dbt_olist
Local CSV loader / independent of the Prefect simulation
01 / Source
data/raw
02 / Ingestion
ingest_raw_data.py
03 / Local database
Docker Compose service
Recorded analytics output / documented relationship
01 / Analytical models
Published SQL models
02 / Recorded output
Dashboard screenshot
Snowflake SQL defines S3 file loading through an external stage and COPY INTO. No uploader is committed. Cortex runs inside stg_reviews_enriched before dim_reviews_enriched; it is a dbt dependency, not a separately orchestrated service.
The bridge reads staging and raw reviews directly, filters non-null sentiment, and MERGEs Order–HAS_REVIEW–Review with ai_sentiment_score. The broader Customer–Review–Product–Seller investigation model is documented separately below.
Prefect retries its ingestion task once and checks subprocess exit codes. That task calls a simulation, not the PostgreSQL loader. Its dbt_olist working directory also differs from the public dbt/ configuration and root models/ layout; these paths do not establish a successful replay.
The Power BI screenshot records an analytical output. Its precise connection and semantic-model definitions are absent, so the dashed link marks a documented relationship rather than a verified runtime integration.
03 / Data Modeling
The central grain is one order line item, identified by order_id and item_sequence.
The fact left joins staged orders onto staged items. It retains customer, product, and seller identifiers alongside item price, freight, their sum, order status, and purchase and delivery timestamps. Customer identity is preserved separately in customer_unique_id.
Fact / Order line item
order_id + item_sequencecustomer_id · product_id · seller_iditem_price · item_freighttotal_item_valueorder_status · purchase/delivery timestampscustomer_id
Order-linked customer attributes
customer_unique_idzip_code_prefix · city · stateproduct_id
Item-linked product attributes
category_name_pt / enweight_g · dimensionsseller_id
Item-linked seller attributes
zip_code_prefixcity · statePotential analytical join / order_id
Cardinality must be validated before joining reviews to item measures.
Review grain / cardinality unproven
Review-record output joined to enrichment on review_id; not aggregated to one row per order.
review_id · order_idoriginal_star_rating · ai_sentiment_scoreOrders can contain multiple items. dim_reviews_enriched keeps review records and left joins enrichment on review_id; it does not aggregate reviews to one row per order. Multiple matching review rows joined on order_id would duplicate item facts and inflate summed measures. Even a single review repeats across an order’s items when counting joined reviews. No uniqueness or relationship tests prove these cardinalities.
The fact calculates total_item_value, but not delivery latency or an SLA breach flag. Customer and seller dimensions retain ZIP, city, and state; they do not join the geolocation model.
(i.price + i.freight_value) AS total_item_value
FROM order_items AS i
LEFT JOIN orders AS o
ON i.order_id = o.order_id04 / AI Review Enrichment
Portuguese review text becomes a queryable attribute inside Snowflake.
A customer’s star rating and the sentiment inferred from their written feedback answer different questions. The materialized stg_reviews_enriched model calls SNOWFLAKE.CORTEX.COMPLETE with llama3-8b for eligible comments and asks for a score from 1 to 10. dim_reviews_enriched left joins this result onto the original review records.
Non-null, trimmed length greater than three, and no listed placeholder strings.
The raw response is retained in ai_sentiment_raw for inspection.
REGEXP_SUBSTR extracts digits; TRY_TO_NUMBER safely converts the result.
Original star rating and AI sentiment remain separate fields.
ai_sentiment_raw, -- Debugging column: Keep the raw output so we can see exactly what the LLM said
TRY_TO_NUMBER(REGEXP_SUBSTR(ai_sentiment_raw, '\\d+')) AS sentiment_scoreA non-numeric extraction converts to NULL. There is no enforced 1–10 range, sentiment calibration, or accuracy evaluation in the source. This is numeric extraction for analytics, not a validated normalized sentiment model. The separate Snowflake Cortex SQL file is an incomplete excerpt; the full dbt staging model is the evidence used here.
05 / Data Quality & Reliability
Safeguards are described at the point where they act, with their limits visible.
Failure mode
Engineering decision
Prefect task retries once; non-zero return codes raise an exception
Reliability benefit / boundary
The flow surfaces execution failures. A successful stub exit is not proof of a completed ingestion.
Failure mode
Engineering decision
Keep the raw response, extract digits with REGEXP_SUBSTR, then use TRY_TO_NUMBER
Reliability benefit / boundary
Non-numeric extraction becomes NULL instead of a hard cast failure. The model does not enforce the requested 1–10 range.
Failure mode
Engineering decision
Require non-null comments, trimmed length > 3, and exclude N/A, NA, NONE, NULL
Reliability benefit / boundary
Filters ineligible text before inference; filtered records remain available through the review dimension’s left join.
Failure mode
Engineering decision
MERGE Order and Review identifiers and the HAS_REVIEW relationship
Reliability benefit / boundary
Reuses matching graph entities instead of creating a new pair for every matching record.
Failure mode
Engineering decision
Left join category translations and COALESCE to Unknown
Reliability benefit / boundary
Retains the product when an English category translation is absent.
Snowflake COPY uses ON_ERROR = CONTINUE. A load can finish while skipping invalid records, so success alone does not establish complete ingestion. No recorded COPY results substantiate a success percentage.
The README describes unique and not_null tests, but the public source includes no such test definitions or dbt run results. stg_order_reviews casts order_id to INTEGER although the raw identifier is VARCHAR. That mismatch needs correction and validation before relying on a fresh build.
06 / Business Analytics & Power BI
The recorded Power BI output connects product categories, seller review volumes, sentiment, and geography.

Original Power BI project screenshot. Filters, totals, and charts describe this recorded view; the underlying BI measures were not independently reproduced in this audit.
Source: public Olist repository / dashboard_images. Full image preserved without cropping.The image shows category sentiment comparisons, a time trend, a seller watchlist with average sentiment and review counts, and a Brazil heatmap. These views support exploratory questions about customer feedback and seller concentration.
The displayed totals belong to this screenshot. The public repository has no PBIX, DAX definitions, or reproducible result export to independently validate those aggregates. Delivery-delay causality, offboarding impact, and business savings are not established by this image.
07 / Neo4j Graph Investigation
Graph queries make an entity path visible, while the loader and investigation schema have different scopes.
The Python bridge reads enriched staging reviews joined to raw reviews on review_id. It MERGEs Order and Review nodes, attaches HAS_REVIEW, and stores ai_sentiment_score. The investigation query separately follows Customer → Review → Product → Seller, using WROTE, REVIEWS, and SOLD_BY relationships.
The broader relationship loader is not committed. The Cypher reads sentiment_score, while the Python bridge writes ai_sentiment_score; connecting those properties also requires work. This path is a query-defined investigation model, not a claim that the bridge constructs the full graph.

Recorded investigation topology: one customer, six reviews, one product, and one seller. Demonstration-style labels do not verify real fraud or establish provenance from the historical dataset.
Source: public Olist repository / dashboard_images. The broader investigation schema is distinct from the committed Order–Review bridge.MATCH (c:Customer)-[:WROTE]->(r:Review)-[:REVIEWS]->(p:Product)-[:SOLD_BY]->(s:Seller)
WHERE r.sentiment_score >= 9.0
WITH c, count(DISTINCT s) AS distinct_sellers, count(r) AS total_perfect_reviews
// Core Logic: The customer left more than 5 perfect reviews, but ALL of them are exclusively for ONE single seller.
WHERE total_perfect_reviews > 5 AND distinct_sellers = 1
RETURN c.customer_id, total_perfect_reviews
ORDER BY total_perfect_reviews DESCThe query filters sentiment_score ≥ 9, counts matched paths per customer, and requires more than five matches to one distinct seller. count(r) counts matched rows, not distinct review IDs; duplicated paths can affect the threshold.
The screenshot returns FRAUD_BOT_MASTER and shows six reviews, one product, one seller, and one customer. These demonstration-style identifiers do not establish that the cluster occurred in the original Olist data. The topology illustrates a potential coordinated-review pattern, not confirmed fraud.
08 / Engineering Decisions & Troubleshooting
Specific troubleshooting patterns, with implementation evidence separated from project notes.
Source + documentation
Source evidence
Source + documentation
Source evidence
Documented decision
Source evidence
Documented decision
Source evidence
09 / Evidence & Project Boundaries
The page is grounded in public code and recorded project visuals.
Raw-table DDL and loading SQL; dbt source definitions and model dependencies; Cortex filtering and parsing; a local Prefect flow; a PostgreSQL Compose service; graph-bridge logic; the investigation query; and two recorded screenshots.
Fresh execution of the complete pipeline, passed schema tests, actual inference volume, ingestion success rate, seller-risk percentages, logistics sentiment differences, and measured business impact. No production usage by Olist is claimed.
Evidence limits for the engineering decisions: original compilation failures and rerun logs are not published. Cortex output range, accuracy, and failure-rate improvements were not evaluated here. No Power BI semantic model verifies the geographic hierarchy or seller-ranking calculation; no statistical weighting or Bayesian smoothing implementation is claimed.
Source reviewed at revision 35333e0. Runtime services were not replayed during the website audit. README folder names differ from the checked-in layout; evidence links point to actual files at the reviewed revision.