From c9459316bd45d2d448d44b5ee0d577219c742316 Mon Sep 17 00:00:00 2001 From: Praveen Singh <166694190+praveen-singh-007@users.noreply.github.com> Date: Sun, 10 May 2026 22:57:25 +0530 Subject: [PATCH 1/7] Add factory production knowledge graph schema This schema outlines the relationships and properties for factory production knowledge, including projects, products, workers, and stations. --- submissions/praveen-singh/level5/schema.md | 240 +++++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 submissions/praveen-singh/level5/schema.md diff --git a/submissions/praveen-singh/level5/schema.md b/submissions/praveen-singh/level5/schema.md new file mode 100644 index 000000000..f27776064 --- /dev/null +++ b/submissions/praveen-singh/level5/schema.md @@ -0,0 +1,240 @@ +# Factory Production Knowledge Graph Schema + +```mermaid +graph TD + +%% ========================= +%% TOP LAYER +%% ========================= + +Project[Project] + +%% ========================= +%% LEFT SIDE +%% ========================= + +Product[Product] +Week[Week] + +Project -->|PRODUCES| Product +Project -->|RUNS_IN| Week + +%% ========================= +%% CENTER +%% ========================= + +Station[Station] + +Project -->|USES_STATION| Station + +Project -->|PROCESSED_AT| Station + +%% RELATIONSHIP PROPERTIES NOTE +ProcessedProps["PROCESSED_AT Properties: +- planned_hours +- actual_hours +- completed_units +- week"] + +Project -.-> ProcessedProps +ProcessedProps -.-> Station + +%% ========================= +%% RIGHT SIDE +%% ========================= + +Worker[Worker] +Role[Role] +Certification[Certification] + +Worker -->|PRIMARY_AT| Station + +Worker -->|CAN_COVER| Station + +CoverProps["CAN_COVER Properties: +- coverage_priority +- skill_level"] + +Worker -.-> CoverProps +CoverProps -.-> Station + +Worker -->|HAS_ROLE| Role + +Worker -->|CERTIFIED_IN| Certification + +%% ========================= +%% BOTTOM +%% ========================= + +CapacityWeek[CapacityWeek] + +Station -->|HAS_CAPACITY| CapacityWeek + +CapacityProps["HAS_CAPACITY Properties: +- total_capacity +- total_planned +- deficit"] + +Station -.-> CapacityProps +CapacityProps -.-> CapacityWeek +``` +--- + +# Node Labels + +## 1. Project +Represents factory production projects. + +### Properties +- project_id +- project_number +- project_name + +--- + +## 2. Product +Represents manufactured product types. + +### Properties +- product_type +- unit +- quantity +- unit_factor + +--- + +## 3. Station +Represents factory production stations. + +### Properties +- station_code +- station_name + +--- + +## 4. Worker +Represents factory workers/operators. + +### Properties +- worker_id +- worker_name +- worker_type +- hours_per_week + +--- + +## 5. Week +Represents production weeks. + +### Properties +- week_id + +--- + +## 6. Certification +Represents worker certifications. + +### Properties +- certification_name + +--- + +## 7. Role +Represents worker roles. + +### Properties +- role_name + +--- + +## 8. CapacityWeek +Represents weekly station capacity analysis. + +### Properties +- week +- total_capacity +- total_planned +- deficit + +--- + +# Relationship Types + +## 1. (:Project)-[:PRODUCES]->(:Product) +A project produces a specific product type. + +--- + +## 2. (:Project)-[:USES_STATION]->(:Station) +A project uses a production station. + +--- + +## 3. (:Project)-[:RUNS_IN]->(:Week) +A project runs during a specific production week. + +--- + +## 4. (:Project)-[:PROCESSED_AT]->(:Station) + +### Relationship Properties +- planned_hours +- actual_hours +- completed_units +- week + +Tracks production workload and variance at stations. + +--- + +## 5. (:Worker)-[:PRIMARY_AT]->(:Station) +Represents the worker’s primary station assignment. + +--- + +## 6. (:Worker)-[:CAN_COVER]->(:Station) + +### Relationship Properties +- coverage_priority +- skill_level + +Represents backup station coverage capability. + +--- + +## 7. (:Worker)-[:HAS_ROLE]->(:Role) +Represents worker job role. + +--- + +## 8. (:Worker)-[:CERTIFIED_IN]->(:Certification) +Represents worker certifications. + +--- + +## 9. (:Station)-[:HAS_CAPACITY]->(:CapacityWeek) + +### Relationship Properties +- total_capacity +- total_planned +- deficit + +Tracks station overload and capacity deficit. + +--- + +# Why This Schema Fits the Dataset + +This graph structure models the core factory workflow: + +- Projects are processed through production stations +- Workers operate and cover stations +- Stations experience varying workload and capacity pressure +- Production variance is captured directly on relationships +- Worker coverage and bottleneck analysis become easy to query + +The schema is optimized for: +- bottleneck detection +- worker replacement analysis +- project variance tracking +- hybrid graph + vector search in Level 6 From 2baaffaba04ea6c4ea69cfda9dfc7695851007c5 Mon Sep 17 00:00:00 2001 From: Praveen Singh <166694190+praveen-singh-007@users.noreply.github.com> Date: Sun, 10 May 2026 22:59:34 +0530 Subject: [PATCH 2/7] Add Level 5 Graph Thinking answers Added comprehensive answers for Level 5 Graph Thinking, including graph schema, SQL vs Cypher queries, bottleneck analysis, and hybrid vector-graph concepts. --- submissions/praveen-singh/level5/answers.md | 433 ++++++++++++++++++++ 1 file changed, 433 insertions(+) create mode 100644 submissions/praveen-singh/level5/answers.md diff --git a/submissions/praveen-singh/level5/answers.md b/submissions/praveen-singh/level5/answers.md new file mode 100644 index 000000000..80de54bc2 --- /dev/null +++ b/submissions/praveen-singh/level5/answers.md @@ -0,0 +1,433 @@ +# Level 5 — Graph Thinking Answers + +## Q1. Model It + +The complete graph schema is provided in `schema.md`. + +### Main Node Labels +- Project +- Product +- Station +- Worker +- Week +- Certification +- Role +- CapacityWeek + +### Main Relationship Types +- PRODUCES +- USES_STATION +- RUNS_IN +- PROCESSED_AT +- PRIMARY_AT +- CAN_COVER +- HAS_ROLE +- CERTIFIED_IN +- HAS_CAPACITY + +### Relationships with Properties + +#### `(:Project)-[:PROCESSED_AT]->(:Station)` +Properties: +- planned_hours +- actual_hours +- completed_units +- week + +#### `(:Worker)-[:CAN_COVER]->(:Station)` +Properties: +- coverage_priority +- skill_level + +#### `(:Station)-[:HAS_CAPACITY]->(:CapacityWeek)` +Properties: +- total_capacity +- total_planned +- deficit + +This schema captures: +- project production flow +- worker coverage capability +- station bottlenecks +- weekly production variance +- capacity overload conditions + +--- + +# Q2. Why Not Just SQL? + +## 1. SQL Query + +```sql +SELECT + w.worker_name, + s.station_name, + p.project_name +FROM workers w +JOIN worker_station_cover wsc + ON w.worker_id = wsc.worker_id +JOIN stations s + ON wsc.station_id = s.station_id +JOIN production pr + ON s.station_id = pr.station_id +JOIN projects p + ON pr.project_id = p.project_id +WHERE s.station_code = '016' +AND w.worker_name != 'Per Gustafsson'; +``` + +--- + +## 2. Cypher Query + +```cypher +MATCH (w:Worker)-[:CAN_COVER]->(s:Station {station_code:"016"}) +MATCH (p:Project)-[:PROCESSED_AT]->(s) +WHERE w.worker_name <> "Per Gustafsson" +RETURN + w.worker_name, + s.station_name, + p.project_name; +``` + +--- + +## 3. Graph Insight + +The Cypher query directly follows operational relationships between workers, stations, and projects. The graph structure makes worker replacement impact and project dependencies visually obvious. + +In SQL, the same logic is hidden behind multiple JOIN tables and intermediate mappings, making operational relationships harder to understand and maintain. + +--- + +# Q3. Spot the Bottleneck + +## 1. Bottleneck Analysis + +Using `factory_capacity.csv`, several weeks show capacity deficits where planned production demand exceeds available station capacity. + +From `factory_production.csv`, overloads are mainly caused by projects where: + +```text +actual_hours > planned_hours +``` + +Example overload conditions: +- Station 016 (Gjutning) exceeded planned capacity during multiple production weeks +- Several projects showed production variance above 10% +- High-utilization stations such as FS IQB, Gjutning, and Svetsning contributed most to overload conditions + +Projects with large production variance contribute directly to weekly capacity deficits. + +--- + +## 2. Cypher Query + +```cypher +MATCH (p:Project)-[r:PROCESSED_AT]->(s:Station) +WHERE r.actual_hours > r.planned_hours * 1.10 + +RETURN + s.station_name AS station, + p.project_name AS project, + r.planned_hours AS planned, + r.actual_hours AS actual, + + ROUND( + ((r.actual_hours - r.planned_hours) + / r.planned_hours) * 100, + 2 + ) AS variance_percent + +ORDER BY variance_percent DESC; +``` + +--- + +## 3. Bottleneck Graph Modeling + +I would model bottlenecks using a dedicated `(:Bottleneck)` node. + +Example: + +```text +(:Project)-[:CAUSES]->(:Bottleneck)-[:AT_STATION]->(:Station) +``` + +### Bottleneck Properties +- variance_percent +- week +- overload_hours +- severity + +This approach allows: +- historical tracking +- severity analysis +- recurring overload detection +- alert aggregation across stations and weeks + +It also keeps operational alerts separate from core production relationships. + +--- + +# Q4. Vector + Graph Hybrid + +## 1. What Would Be Embedded? + +I would embed: +- project descriptions +- customer requirements +- product specifications +- delivery constraints +- timeline descriptions + +Example: + +> "450 meters of IQB beams for a hospital extension in Linköping" + +These embeddings capture semantic similarity between projects beyond simple product categories. + +--- + +## 2. Hybrid Vector + Graph Query + +```cypher +CALL db.index.vector.queryNodes( + 'project_embeddings', + 5, + $embedding +) + +YIELD node AS similarProject, score + +MATCH (similarProject)-[r:PROCESSED_AT]->(s:Station) + +WHERE + ABS(r.actual_hours - r.planned_hours) + / r.planned_hours < 0.05 + +RETURN + similarProject.project_name, + s.station_name, + score, + r.actual_hours, + r.planned_hours + +ORDER BY score DESC; +``` + +--- + +## 3. Why Hybrid Is Better + +Two projects may use different product names but still follow very similar production workflows, station usage patterns, and scheduling constraints. + +Vector search captures semantic similarity between projects, while the graph ensures operational compatibility through shared stations and low production variance. + +This produces much more useful recommendations than filtering only by product type. + +This same hybrid pattern can later be extended to worker recommendation systems and production planning optimization. + +--- + +# Q5. My Level 6 Blueprint + +## 1. Node Labels + CSV Mapping + +### Project +From: +- project_id +- project_number +- project_name + +--- + +### Product +From: +- product_type +- quantity +- unit + +--- + +### Station +From: +- station_code +- station_name + +--- + +### Worker +From: +- worker_id +- worker_name +- worker_type +- hours_per_week + +--- + +### Week +From: +- week + +--- + +### Certification +From: +- certifications + +--- + +### Role +From: +- role + +--- + +### CapacityWeek +From: +- week +- total_capacity +- total_planned +- deficit + +--- + +# 2. Relationship Types + +```text +(:Project)-[:PRODUCES]->(:Product) + +(:Project)-[:USES_STATION]->(:Station) + +(:Project)-[:PROCESSED_AT { + planned_hours, + actual_hours, + completed_units, + week +}]->(:Station) + +(:Project)-[:RUNS_IN]->(:Week) + +(:Worker)-[:PRIMARY_AT]->(:Station) + +(:Worker)-[:CAN_COVER { + coverage_priority, + skill_level +}]->(:Station) + +(:Worker)-[:HAS_ROLE]->(:Role) + +(:Worker)-[:CERTIFIED_IN]->(:Certification) + +(:Station)-[:HAS_CAPACITY { + total_capacity, + total_planned, + deficit +}]->(:CapacityWeek) +``` + +--- + +# 3. Streamlit Dashboard Panels + +## 1. Station Load Heatmap + +Shows: +- station overload +- weekly utilization +- production variance % + +### Cypher Query + +```cypher +MATCH (p:Project)-[r:PROCESSED_AT]->(s:Station) + +RETURN + s.station_name, + r.week, + SUM(r.actual_hours) AS actual_hours, + SUM(r.planned_hours) AS planned_hours; +``` + +--- + +## 2. Worker Coverage Matrix + +Shows: +- which workers can cover which stations +- backup coverage gaps + +### Cypher Query + +```cypher +MATCH (w:Worker)-[:CAN_COVER]->(s:Station) + +RETURN + w.worker_name, + s.station_name; +``` + +--- + +## 3. Project Variance Dashboard + +Shows projects exceeding planned production hours. + +### Cypher Query + +```cypher +MATCH (p:Project)-[r:PROCESSED_AT]->(s:Station) + +WHERE r.actual_hours > r.planned_hours + +RETURN + p.project_name, + s.station_name, + r.actual_hours, + r.planned_hours; +``` + +--- + +## 4. Capacity Deficit Panel + +Shows: +- weekly station deficits +- overloaded capacity periods + +### Cypher Query + +```cypher +MATCH (s:Station)-[:HAS_CAPACITY]->(c:CapacityWeek) + +RETURN + s.station_name, + c.week, + c.total_capacity, + c.total_planned, + c.deficit; +``` + +--- + +# Final Thoughts + +This graph model captures the operational structure of the factory: + +- projects are processed through stations +- workers operate and cover stations +- bottlenecks emerge through production variance +- capacity overload can be analyzed across time + +The combination of: +- graph relationships +- production metrics +- vector similarity + +creates a strong foundation for: +- Level 6 implementation +- operational dashboards +- bottleneck analytics +- industrial AI applications +- hybrid graph + vector workflows From 111f707e654260116790a2c7621da717a75b8894 Mon Sep 17 00:00:00 2001 From: praveen-singh-007 Date: Mon, 11 May 2026 00:38:28 +0530 Subject: [PATCH 3/7] level6 - Praveen Singh --- submissions/praveen-singh/level6 | 1 + 1 file changed, 1 insertion(+) create mode 160000 submissions/praveen-singh/level6 diff --git a/submissions/praveen-singh/level6 b/submissions/praveen-singh/level6 new file mode 160000 index 000000000..3e59f8863 --- /dev/null +++ b/submissions/praveen-singh/level6 @@ -0,0 +1 @@ +Subproject commit 3e59f8863009014db4177a2a0df42afd9e76eb42 From 31f309819f3f6ea7333f477c8d5d4026a080fc9d Mon Sep 17 00:00:00 2001 From: praveen-singh-007 Date: Mon, 11 May 2026 01:36:41 +0530 Subject: [PATCH 4/7] fix: replace submodule with actual level6 files --- submissions/praveen-singh/level6 | 1 - submissions/praveen-singh/level6/.env.example | 6 + submissions/praveen-singh/level6/.gitignore | 5 + .../praveen-singh/level6/DASHBOARD_URL.txt | 1 + submissions/praveen-singh/level6/README.md | 25 ++ submissions/praveen-singh/level6/app.py | 279 ++++++++++++++++++ .../level6/data/factory_capacity.csv | 9 + .../level6/data/factory_production.csv | 69 +++++ .../level6/data/factory_workers.csv | 15 + .../praveen-singh/level6/requirements.txt | 5 + .../praveen-singh/level6/seed_graph.py | 196 ++++++++++++ .../praveen-singh/level6/test_connection.py | 20 ++ 12 files changed, 630 insertions(+), 1 deletion(-) delete mode 160000 submissions/praveen-singh/level6 create mode 100644 submissions/praveen-singh/level6/.env.example create mode 100644 submissions/praveen-singh/level6/.gitignore create mode 100644 submissions/praveen-singh/level6/DASHBOARD_URL.txt create mode 100644 submissions/praveen-singh/level6/README.md create mode 100644 submissions/praveen-singh/level6/app.py create mode 100644 submissions/praveen-singh/level6/data/factory_capacity.csv create mode 100644 submissions/praveen-singh/level6/data/factory_production.csv create mode 100644 submissions/praveen-singh/level6/data/factory_workers.csv create mode 100644 submissions/praveen-singh/level6/requirements.txt create mode 100644 submissions/praveen-singh/level6/seed_graph.py create mode 100644 submissions/praveen-singh/level6/test_connection.py diff --git a/submissions/praveen-singh/level6 b/submissions/praveen-singh/level6 deleted file mode 160000 index 3e59f8863..000000000 --- a/submissions/praveen-singh/level6 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3e59f8863009014db4177a2a0df42afd9e76eb42 diff --git a/submissions/praveen-singh/level6/.env.example b/submissions/praveen-singh/level6/.env.example new file mode 100644 index 000000000..b03df95e1 --- /dev/null +++ b/submissions/praveen-singh/level6/.env.example @@ -0,0 +1,6 @@ +NEO4J_URI=abc +NEO4J_USER=abc +NEO4J_PASSWORD=abc +NEO4J_DATABASE=abc +AURA_INSTANCEID=abc +AURA_INSTANCENAME=abc diff --git a/submissions/praveen-singh/level6/.gitignore b/submissions/praveen-singh/level6/.gitignore new file mode 100644 index 000000000..63324238d --- /dev/null +++ b/submissions/praveen-singh/level6/.gitignore @@ -0,0 +1,5 @@ +.venv +.env +pycache/ +*.pyc +.streamlit/secrets.toml \ No newline at end of file diff --git a/submissions/praveen-singh/level6/DASHBOARD_URL.txt b/submissions/praveen-singh/level6/DASHBOARD_URL.txt new file mode 100644 index 000000000..481a889fb --- /dev/null +++ b/submissions/praveen-singh/level6/DASHBOARD_URL.txt @@ -0,0 +1 @@ +https://lpi-developer-kit-nwdblkkkvpctpf658vh7dl.streamlit.app \ No newline at end of file diff --git a/submissions/praveen-singh/level6/README.md b/submissions/praveen-singh/level6/README.md new file mode 100644 index 000000000..3fcd5c602 --- /dev/null +++ b/submissions/praveen-singh/level6/README.md @@ -0,0 +1,25 @@ +# Factory Graph Dashboard + +Neo4j + Streamlit dashboard for factory production analysis. + +## Features + +- Project Overview +- Station Load Analysis +- Capacity Tracking +- Worker Coverage Analysis +- Self-Test Validation + +## Tech Stack + +- Streamlit +- Neo4j AuraDB +- Pandas +- Plotly + +## Run Locally + +```bash +pip install -r requirements.txt +python seed_graph.py +streamlit run app.py \ No newline at end of file diff --git a/submissions/praveen-singh/level6/app.py b/submissions/praveen-singh/level6/app.py new file mode 100644 index 000000000..5ecf6c718 --- /dev/null +++ b/submissions/praveen-singh/level6/app.py @@ -0,0 +1,279 @@ +import streamlit as st +import pandas as pd +import plotly.express as px +from neo4j import GraphDatabase +from dotenv import load_dotenv +import os + +# ========================= +# PAGE CONFIG +# ========================= + +st.set_page_config( + page_title="Factory Graph Dashboard", + layout="wide" +) + +# ========================= +# LOAD ENV +# ========================= + +load_dotenv() + +URI = os.getenv("NEO4J_URI") +USER = os.getenv("NEO4J_USER") +PASSWORD = os.getenv("NEO4J_PASSWORD") + +driver = GraphDatabase.driver( + URI, + auth=(USER, PASSWORD) +) + +# ========================= +# QUERY FUNCTION +# ========================= + +def run_query(query): + + with driver.session() as session: + result = session.run(query) + + return pd.DataFrame( + [r.data() for r in result] + ) + +# ========================= +# SIDEBAR +# ========================= + +st.sidebar.title("Factory Dashboard") + +page = st.sidebar.radio( + "Navigation", + [ + "Project Overview", + "Station Load", + "Capacity Tracker", + "Worker Coverage", + "Self-Test" + ] +) + +# ========================= +# PROJECT OVERVIEW +# ========================= + +if page == "Project Overview": + + st.title("Project Overview") + + query = """ + MATCH (p:Project) + RETURN + p.project_id AS project_id, + p.project_name AS project_name, + p.project_number AS project_number + """ + + df = run_query(query) + + st.metric("Total Projects", len(df)) + + st.dataframe(df, use_container_width=True) + +# ========================= +# STATION LOAD +# ========================= + +elif page == "Station Load": + + st.title("Station Load") + + query = """ + MATCH (p:Project)-[r:PROCESSED_AT]->(s:Station) + + RETURN + s.station_name AS station, + SUM(r.planned_hours) AS planned_hours, + SUM(r.actual_hours) AS actual_hours + """ + + df = run_query(query) + + df["overload"] = ( + df["actual_hours"] > df["planned_hours"] + ) + + fig = px.bar( + df, + x="station", + y=["planned_hours", "actual_hours"], + barmode="group", + title="Station Workload" + ) + + st.plotly_chart(fig, use_container_width=True) + + st.dataframe(df, use_container_width=True) + +# ========================= +# CAPACITY TRACKER +# ========================= + +elif page == "Capacity Tracker": + + st.title("Capacity Tracker") + + query = """ + MATCH (c:CapacityWeek) + + RETURN + c.week AS week, + c.total_capacity AS total_capacity, + c.total_planned AS total_planned, + c.deficit AS deficit + ORDER BY week + """ + + df = run_query(query) + + fig = px.line( + df, + x="week", + y=["total_capacity", "total_planned"], + title="Capacity vs Planned" + ) + + st.plotly_chart(fig, use_container_width=True) + + st.subheader("Deficit Weeks") + + deficit_df = df[df["deficit"] > 0] + + st.dataframe( + deficit_df, + use_container_width=True + ) + +# ========================= +# WORKER COVERAGE +# ========================= + +elif page == "Worker Coverage": + + st.title("Worker Coverage") + + query = """ + MATCH (w:Worker)-[:PRIMARY_AT]->(s:Station) + + RETURN + w.worker_name AS worker, + s.station_code AS station, + w.worker_type AS type, + w.hours_per_week AS hours + """ + + df = run_query(query) + + st.dataframe(df, use_container_width=True) + + station_counts = ( + df.groupby("station") + .size() + .reset_index(name="worker_count") + ) + + st.subheader("Single Point of Failure Stations") + + spof = station_counts[ + (station_counts["worker_count"] <= 1) + & (station_counts["station"] != "all") +] + + st.dataframe(spof, use_container_width=True) + +# ========================= +# SELF TEST +# ========================= + +elif page == "Self-Test": + + st.title("Self-Test") + + checks = [] + + # Check 1 + q1 = run_query(""" + MATCH (p:Project) + RETURN count(p) AS count + """) + + checks.append( + ("Projects Loaded", q1["count"][0] > 0) + ) + + # Check 2 + q2 = run_query(""" + MATCH (s:Station) + RETURN count(s) AS count + """) + + checks.append( + ("Stations Loaded", q2["count"][0] > 0) + ) + + # Check 3 + q3 = run_query(""" + MATCH (w:Worker) + RETURN count(w) AS count + """) + + checks.append( + ("Workers Loaded", q3["count"][0] > 0) + ) + + # Check 4 + q4 = run_query(""" + MATCH ()-[r:PROCESSED_AT]->() + RETURN count(r) AS count + """) + + checks.append( + ("Relationships Created", q4["count"][0] > 0) + ) + + # Check 5 + q5 = run_query(""" + MATCH (c:CapacityWeek) + RETURN count(c) AS count + """) + + checks.append( + ("Capacity Data Loaded", q5["count"][0] > 0) + ) + + # Check 6 + checks.append( + ("Neo4j Connection", True) + ) + + passed = 0 + + for name, status in checks: + + if status: + st.success(f"PASS: {name}") + passed += 1 + else: + st.error(f"FAIL: {name}") + + st.metric( + "Self-Test Score", + f"{passed}/6" + ) + +# ========================= +# CLOSE DRIVER +# ========================= + +driver.close() \ No newline at end of file diff --git a/submissions/praveen-singh/level6/data/factory_capacity.csv b/submissions/praveen-singh/level6/data/factory_capacity.csv new file mode 100644 index 000000000..795ff52f0 --- /dev/null +++ b/submissions/praveen-singh/level6/data/factory_capacity.csv @@ -0,0 +1,9 @@ +week,own_staff_count,hired_staff_count,own_hours,hired_hours,overtime_hours,total_capacity,total_planned,deficit +w1,10,2,400,80,0,480,612,-132 +w2,10,2,400,80,40,520,645,-125 +w3,10,2,400,80,0,480,398,82 +w4,10,2,400,80,20,500,550,-50 +w5,10,2,400,80,30,510,480,30 +w6,9,2,360,80,0,440,520,-80 +w7,10,2,400,80,40,520,600,-80 +w8,10,2,400,80,20,500,470,30 \ No newline at end of file diff --git a/submissions/praveen-singh/level6/data/factory_production.csv b/submissions/praveen-singh/level6/data/factory_production.csv new file mode 100644 index 000000000..ca6ce43e1 --- /dev/null +++ b/submissions/praveen-singh/level6/data/factory_production.csv @@ -0,0 +1,69 @@ +project_id,project_number,project_name,product_type,unit,quantity,unit_factor,station_code,station_name,etapp,bop,week,planned_hours,actual_hours,completed_units +P01,4501,Stålverket Borås,IQB,meter,600,1.77,011,FS IQB,ET1,BOP1,w1,48.0,45.2,28 +P01,4501,Stålverket Borås,IQB,meter,600,1.77,012,Förmontering IQB,ET1,BOP1,w1,32.0,35.5,25 +P01,4501,Stålverket Borås,IQB,meter,600,1.77,013,Montering IQB,ET1,BOP1,w1,28.0,26.0,22 +P01,4501,Stålverket Borås,IQB,meter,600,1.77,014,Svets o montage IQB,ET1,BOP1,w1,35.0,38.2,20 +P01,4501,Stålverket Borås,SB,styck,40,4.0,018,SB B/F-hall,ET1,BOP1,w1,16.0,14.5,4 +P01,4501,Stålverket Borås,SP,styck,180,2.0,019,SP B/F-hall,ET1,BOP1,w1,12.0,13.0,7 +P01,4501,Stålverket Borås,IQB,meter,600,1.77,011,FS IQB,ET1,BOP1,w2,48.0,50.0,32 +P01,4501,Stålverket Borås,IQB,meter,600,1.77,012,Förmontering IQB,ET1,BOP1,w2,32.0,30.0,28 +P01,4501,Stålverket Borås,IQP,styck,90,2.80,015,Montering IQP,ET1,BOP2,w2,25.0,28.0,9 +P01,4501,Stålverket Borås,SR,styck,8,45.0,021,SR B/F-hall,ET1,BOP2,w2,40.0,42.0,1 +P02,4502,Kontorshus Mölndal,IQB,meter,350,1.50,011,FS IQB,ET1,BOP1,w1,30.0,28.0,20 +P02,4502,Kontorshus Mölndal,IQB,meter,350,1.50,012,Förmontering IQB,ET1,BOP1,w1,22.0,24.5,18 +P02,4502,Kontorshus Mölndal,IQB,meter,350,1.50,013,Montering IQB,ET1,BOP1,w1,18.0,17.0,16 +P02,4502,Kontorshus Mölndal,IQP,styck,70,2.70,015,Montering IQP,ET1,BOP1,w1,19.0,21.0,7 +P02,4502,Kontorshus Mölndal,SD,styck,30,3.00,018,SB B/F-hall,ET1,BOP1,w1,9.0,8.5,3 +P02,4502,Kontorshus Mölndal,IQB,meter,350,1.50,011,FS IQB,ET1,BOP1,w2,30.0,32.0,24 +P02,4502,Kontorshus Mölndal,IQB,meter,350,1.50,014,Svets o montage IQB,ET1,BOP1,w2,25.0,23.0,20 +P02,4502,Kontorshus Mölndal,SP,styck,120,1.75,019,SP B/F-hall,ET1,BOP2,w2,14.0,15.5,8 +P03,4503,Lagerhall Jönköping,IQB,meter,900,1.89,011,FS IQB,ET1,BOP1,w1,72.0,70.0,40 +P03,4503,Lagerhall Jönköping,IQB,meter,900,1.89,012,Förmontering IQB,ET1,BOP1,w1,48.0,52.0,35 +P03,4503,Lagerhall Jönköping,IQB,meter,900,1.89,013,Montering IQB,ET1,BOP1,w1,38.0,36.5,30 +P03,4503,Lagerhall Jönköping,IQB,meter,900,1.89,014,Svets o montage IQB,ET1,BOP1,w1,42.0,48.0,28 +P03,4503,Lagerhall Jönköping,SB,styck,60,6.00,018,SB B/F-hall,ET1,BOP1,w1,36.0,38.0,6 +P03,4503,Lagerhall Jönköping,IQB,meter,900,1.89,011,FS IQB,ET1,BOP1,w2,72.0,75.0,45 +P03,4503,Lagerhall Jönköping,IQP,styck,110,2.90,015,Montering IQP,ET1,BOP2,w2,32.0,30.0,11 +P03,4503,Lagerhall Jönköping,IQB,meter,900,1.89,016,Gjutning,ET1,BOP2,w2,28.0,35.0,8 +P03,4503,Lagerhall Jönköping,IQB,meter,900,1.89,017,Målning,ET1,BOP2,w3,24.0,22.0,20 +P04,4504,Parkering Helsingborg,IQB,meter,450,1.65,011,FS IQB,ET1,BOP1,w1,38.0,36.0,24 +P04,4504,Parkering Helsingborg,IQB,meter,450,1.65,012,Förmontering IQB,ET1,BOP1,w1,25.0,27.0,20 +P04,4504,Parkering Helsingborg,IQB,meter,450,1.65,013,Montering IQB,ET1,BOP1,w1,20.0,19.0,18 +P04,4504,Parkering Helsingborg,IQP,styck,55,2.85,015,Montering IQP,ET1,BOP1,w1,16.0,18.0,6 +P04,4504,Parkering Helsingborg,SB,styck,25,7.50,018,SB B/F-hall,ET1,BOP1,w1,19.0,22.0,3 +P04,4504,Parkering Helsingborg,IQB,meter,450,1.65,011,FS IQB,ET1,BOP1,w2,38.0,40.0,28 +P04,4504,Parkering Helsingborg,SP,styck,100,2.00,019,SP B/F-hall,ET1,BOP2,w2,12.0,11.0,6 +P04,4504,Parkering Helsingborg,SR,styck,12,120.0,021,SR B/F-hall,ET1,BOP2,w2,60.0,65.0,1 +P05,4505,Sjukhus Linköping ET2,IQB,meter,1200,1.85,011,FS IQB,ET2,BOP3,w1,95.0,90.0,50 +P05,4505,Sjukhus Linköping ET2,IQB,meter,1200,1.85,012,Förmontering IQB,ET2,BOP3,w1,65.0,68.0,42 +P05,4505,Sjukhus Linköping ET2,IQB,meter,1200,1.85,013,Montering IQB,ET2,BOP3,w1,50.0,48.0,38 +P05,4505,Sjukhus Linköping ET2,IQB,meter,1200,1.85,014,Svets o montage IQB,ET2,BOP3,w1,58.0,62.0,35 +P05,4505,Sjukhus Linköping ET2,IQP,styck,150,2.88,015,Montering IQP,ET2,BOP3,w1,30.0,33.0,10 +P05,4505,Sjukhus Linköping ET2,SB,styck,50,5.00,018,SB B/F-hall,ET2,BOP3,w1,25.0,28.0,5 +P05,4505,Sjukhus Linköping ET2,SD,styck,45,2.75,018,SB B/F-hall,ET2,BOP3,w1,12.0,11.5,4 +P05,4505,Sjukhus Linköping ET2,IQB,meter,1200,1.85,011,FS IQB,ET2,BOP3,w2,95.0,98.0,55 +P05,4505,Sjukhus Linköping ET2,IQB,meter,1200,1.85,016,Gjutning,ET2,BOP3,w2,35.0,40.0,12 +P05,4505,Sjukhus Linköping ET2,IQB,meter,1200,1.85,017,Målning,ET2,BOP3,w2,28.0,26.0,25 +P05,4505,Sjukhus Linköping ET2,SR,styck,20,274.0,021,SR B/F-hall,ET2,BOP3,w3,120.0,115.0,2 +P06,4506,Skola Uppsala,IQB,meter,500,1.60,011,FS IQB,ET1,BOP1,w2,40.0,38.0,26 +P06,4506,Skola Uppsala,IQB,meter,500,1.60,012,Förmontering IQB,ET1,BOP1,w2,28.0,30.0,22 +P06,4506,Skola Uppsala,IQB,meter,500,1.60,013,Montering IQB,ET1,BOP1,w2,22.0,20.0,18 +P06,4506,Skola Uppsala,IQP,styck,80,2.75,015,Montering IQP,ET1,BOP1,w2,22.0,24.0,8 +P06,4506,Skola Uppsala,SB,styck,35,4.50,018,SB B/F-hall,ET1,BOP1,w2,16.0,18.0,4 +P06,4506,Skola Uppsala,SP,styck,140,1.50,019,SP B/F-hall,ET1,BOP2,w3,14.0,12.0,10 +P07,4507,Idrottshall Västerås,HSQ,meter,400,2.05,011,FS IQB,ET1,BOP1,w1,45.0,42.0,22 +P07,4507,Idrottshall Västerås,HSQ,meter,400,2.05,012,Förmontering IQB,ET1,BOP1,w1,30.0,33.0,18 +P07,4507,Idrottshall Västerås,HSQ,meter,400,2.05,014,Svets o montage IQB,ET1,BOP1,w1,35.0,32.0,16 +P07,4507,Idrottshall Västerås,SB,styck,45,3.50,018,SB B/F-hall,ET1,BOP1,w1,16.0,18.0,5 +P07,4507,Idrottshall Västerås,HSQ,meter,400,2.05,011,FS IQB,ET1,BOP1,w2,45.0,48.0,26 +P07,4507,Idrottshall Västerås,HSQ,meter,400,2.05,016,Gjutning,ET1,BOP2,w2,20.0,22.0,5 +P07,4507,Idrottshall Västerås,HSQ,meter,400,2.05,017,Målning,ET1,BOP2,w3,18.0,16.0,15 +P08,4508,Bro E6 Halmstad,IQB,meter,800,1.80,011,FS IQB,ET1,BOP1,w1,65.0,62.0,36 +P08,4508,Bro E6 Halmstad,IQB,meter,800,1.80,012,Förmontering IQB,ET1,BOP1,w1,42.0,45.0,30 +P08,4508,Bro E6 Halmstad,IQB,meter,800,1.80,013,Montering IQB,ET1,BOP1,w1,35.0,38.0,25 +P08,4508,Bro E6 Halmstad,IQB,meter,800,1.80,014,Svets o montage IQB,ET1,BOP1,w1,40.0,44.0,22 +P08,4508,Bro E6 Halmstad,SP,styck,200,2.50,019,SP B/F-hall,ET1,BOP1,w1,20.0,18.0,8 +P08,4508,Bro E6 Halmstad,IQB,meter,800,1.80,011,FS IQB,ET1,BOP1,w2,65.0,68.0,42 +P08,4508,Bro E6 Halmstad,IQP,styck,95,2.93,015,Montering IQP,ET1,BOP2,w2,28.0,30.0,10 +P08,4508,Bro E6 Halmstad,IQB,meter,800,1.80,016,Gjutning,ET1,BOP2,w3,22.0,25.0,8 +P08,4508,Bro E6 Halmstad,SR,styck,15,180.0,021,SR B/F-hall,ET1,BOP2,w3,90.0,85.0,2 \ No newline at end of file diff --git a/submissions/praveen-singh/level6/data/factory_workers.csv b/submissions/praveen-singh/level6/data/factory_workers.csv new file mode 100644 index 000000000..3110285cc --- /dev/null +++ b/submissions/praveen-singh/level6/data/factory_workers.csv @@ -0,0 +1,15 @@ +worker_id,name,role,primary_station,can_cover_stations,certifications,hours_per_week,type +W01,Erik Lindberg,Operator,011,"011,012","MIG/MAG,TIG,ISO 9606",40,permanent +W02,Anna Berg,Operator,011,"011,014","MIG/MAG,TIG",40,permanent +W03,Lars Jensen,Operator,012,"012,013","Surface treatment,CE marking",40,permanent +W04,Maria Stone,Operator,013,"013","Blasting,Surface protection",40,permanent +W05,Johan Peters,Operator,014,"014,015","Hydraulics,Mechanics,Crane",40,permanent +W06,Karen Nilsen,Inspector,015,"015","SIS,SS-EN 1090,NDT",40,permanent +W07,Per Hansen,Operator,016,"016,017","Casting,Formwork",40,permanent +W08,Sofia Arden,Operator,017,"017","Surface treatment,Spray painting",40,permanent +W09,Magnus Stone,Operator,018,"018,019","Sheet metal,Assembly",40,permanent +W10,Elin Frank,Operator,019,"019,018","Assembly,Welding",32,permanent +W11,Victor Elm,Foreman,all,"011,012,013,014,015,016,017,018,019,021","Leadership,CE,ISO 9001",45,permanent +W12,Lena Dale,Quality Manager,015,"015","ISO 9001,SS-EN 1090,Audit",40,permanent +W13,Ahmed Hassan,Operator,011,"011","MIG/MAG",40,hired +W14,Petra Steen,Operator,012,"012,013","Surface treatment",40,hired \ No newline at end of file diff --git a/submissions/praveen-singh/level6/requirements.txt b/submissions/praveen-singh/level6/requirements.txt new file mode 100644 index 000000000..e0c6606d6 --- /dev/null +++ b/submissions/praveen-singh/level6/requirements.txt @@ -0,0 +1,5 @@ +streamlit +pandas +plotly +neo4j +python-dotenv \ No newline at end of file diff --git a/submissions/praveen-singh/level6/seed_graph.py b/submissions/praveen-singh/level6/seed_graph.py new file mode 100644 index 000000000..a49accab8 --- /dev/null +++ b/submissions/praveen-singh/level6/seed_graph.py @@ -0,0 +1,196 @@ +import pandas as pd +from neo4j import GraphDatabase +from dotenv import load_dotenv +import os + +# ========================= +# LOAD ENV +# ========================= + +load_dotenv() + +URI = os.getenv("NEO4J_URI") +USER = os.getenv("NEO4J_USER") +PASSWORD = os.getenv("NEO4J_PASSWORD") + +driver = GraphDatabase.driver( + URI, + auth=(USER, PASSWORD) +) + +# ========================= +# LOAD CSV FILES +# ========================= + +production_df = pd.read_csv("data/factory_production.csv") +workers_df = pd.read_csv("data/factory_workers.csv") +capacity_df = pd.read_csv("data/factory_capacity.csv") + +# ========================= +# SEED GRAPH +# ========================= + +def seed_graph(): + + with driver.session() as session: + + # ===================================== + # PRODUCTION DATA + # ===================================== + + for _, row in production_df.iterrows(): + + query = """ + MERGE (p:Project { + project_id: $project_id + }) + + SET + p.project_name = $project_name, + p.project_number = $project_number + + MERGE (prod:Product { + product_type: $product_type + }) + + SET + prod.unit = $unit, + prod.quantity = $quantity, + prod.unit_factor = $unit_factor + + MERGE (s:Station { + station_code: $station_code + }) + + SET + s.station_name = $station_name + + MERGE (w:Week { + week: $week + }) + + MERGE (p)-[:PRODUCES]->(prod) + + MERGE (p)-[:RUNS_IN]->(w) + + MERGE (p)-[r:PROCESSED_AT { + week: $week, + station_code: $station_code + }]->(s) + + SET + r.planned_hours = $planned_hours, + r.actual_hours = $actual_hours, + r.completed_units = $completed_units, + r.etapp = $etapp, + r.bop = $bop + """ + + session.run( + query, + { + "project_id": row["project_id"], + "project_name": row["project_name"], + "project_number": row["project_number"], + "product_type": row["product_type"], + "unit": row["unit"], + "quantity": float(row["quantity"]), + "unit_factor": float(row["unit_factor"]), + "station_code": row["station_code"], + "station_name": row["station_name"], + "week": row["week"], + "planned_hours": float(row["planned_hours"]), + "actual_hours": float(row["actual_hours"]), + "completed_units": float(row["completed_units"]), + "etapp": row["etapp"], + "bop": row["bop"], + } + ) + + # ===================================== + # WORKER DATA + # ===================================== + + for _, row in workers_df.iterrows(): + + query = """ + MERGE (w:Worker { + worker_id: $worker_id + }) + + SET + w.worker_name = $worker_name, + w.worker_type = $worker_type, + w.hours_per_week = $hours_per_week + + MERGE (s:Station { + station_code: $primary_station + }) + + MERGE (w)-[:PRIMARY_AT]->(s) + + MERGE (r:Role { + role_name: $role + }) + + MERGE (w)-[:HAS_ROLE]->(r) + """ + + session.run( + query, + { + "worker_id": row["worker_id"], + "worker_name": row["name"], + "worker_type": row["type"], + "hours_per_week": float(row["hours_per_week"]), + "primary_station": row["primary_station"], + "role": row["role"], + } + ) + + # ===================================== + # CAPACITY DATA + # ===================================== + + for _, row in capacity_df.iterrows(): + + query = """ + MERGE (c:CapacityWeek { + week: $week + }) + + SET + c.own_staff_count = $own_staff_count, + c.hired_staff_count = $hired_staff_count, + c.own_hours = $own_hours, + c.hired_hours = $hired_hours, + c.overtime_hours = $overtime_hours, + c.total_capacity = $total_capacity, + c.total_planned = $total_planned, + c.deficit = $deficit + """ + + session.run( + query, + { + "week": row["week"], + "own_staff_count": float(row["own_staff_count"]), + "hired_staff_count": float(row["hired_staff_count"]), + "own_hours": float(row["own_hours"]), + "hired_hours": float(row["hired_hours"]), + "overtime_hours": float(row["overtime_hours"]), + "total_capacity": float(row["total_capacity"]), + "total_planned": float(row["total_planned"]), + "deficit": float(row["deficit"]), + } + ) + + print("Graph seeded successfully!") + +# ========================= +# RUN +# ========================= + +if __name__ == "__main__": + seed_graph() + driver.close() \ No newline at end of file diff --git a/submissions/praveen-singh/level6/test_connection.py b/submissions/praveen-singh/level6/test_connection.py new file mode 100644 index 000000000..e2df890fe --- /dev/null +++ b/submissions/praveen-singh/level6/test_connection.py @@ -0,0 +1,20 @@ +from neo4j import GraphDatabase +from dotenv import load_dotenv +import os + +load_dotenv() + +URI = os.getenv("NEO4J_URI") +USER = os.getenv("NEO4J_USER") +PASSWORD = os.getenv("NEO4J_PASSWORD") + +driver = GraphDatabase.driver( + URI, + auth=(USER, PASSWORD) +) + +with driver.session() as session: + result = session.run("RETURN 'Neo4j Connected!' AS msg") + print(result.single()["msg"]) + +driver.close() \ No newline at end of file From 1129aa4e2f7e9761942a372786daab043c392a78 Mon Sep 17 00:00:00 2001 From: Praveen Singh <166694190+praveen-singh-007@users.noreply.github.com> Date: Mon, 11 May 2026 02:03:37 +0530 Subject: [PATCH 5/7] Update DASHBOARD_URL.txt --- submissions/praveen-singh/level6/DASHBOARD_URL.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submissions/praveen-singh/level6/DASHBOARD_URL.txt b/submissions/praveen-singh/level6/DASHBOARD_URL.txt index 481a889fb..538886139 100644 --- a/submissions/praveen-singh/level6/DASHBOARD_URL.txt +++ b/submissions/praveen-singh/level6/DASHBOARD_URL.txt @@ -1 +1 @@ -https://lpi-developer-kit-nwdblkkkvpctpf658vh7dl.streamlit.app \ No newline at end of file +https://lpi-developer-kit-w2jx5vmuqqu4vkzhehdqsp.streamlit.app From 79d6783a5baa0df50d435199e35832ae958de842 Mon Sep 17 00:00:00 2001 From: Praveen Singh <166694190+praveen-singh-007@users.noreply.github.com> Date: Wed, 13 May 2026 12:58:32 +0530 Subject: [PATCH 6/7] Simplify relationships in schema.md --- submissions/praveen-singh/level5/schema.md | 204 ++++++++------------- 1 file changed, 81 insertions(+), 123 deletions(-) diff --git a/submissions/praveen-singh/level5/schema.md b/submissions/praveen-singh/level5/schema.md index f27776064..bb70a39b9 100644 --- a/submissions/praveen-singh/level5/schema.md +++ b/submissions/praveen-singh/level5/schema.md @@ -3,87 +3,36 @@ ```mermaid graph TD -%% ========================= -%% TOP LAYER -%% ========================= + PROJECT[Project] + PRODUCT[Product] + STATION[Station] + WORKER[Worker] + WEEK[Week] + SKILL[Skill] + JOBTYPE[JobType] + WEEKLYLOAD[WeeklyLoad] -Project[Project] + PROJECT -->|BUILDS| PRODUCT + PROJECT -->|RUNS_DURING| WEEK + PROJECT -->|FLOWS_THROUGH| STATION -%% ========================= -%% LEFT SIDE -%% ========================= + PROJECT -->|WORKLOAD| STATION -Product[Product] -Week[Week] + WORKER -->|ASSIGNED_TO| STATION + WORKER -->|BACKUP_FOR| STATION -Project -->|PRODUCES| Product -Project -->|RUNS_IN| Week + WORKER -->|HAS_SKILL| SKILL + WORKER -->|HAS_JOB| JOBTYPE -%% ========================= -%% CENTER -%% ========================= - -Station[Station] - -Project -->|USES_STATION| Station - -Project -->|PROCESSED_AT| Station - -%% RELATIONSHIP PROPERTIES NOTE -ProcessedProps["PROCESSED_AT Properties: -- planned_hours -- actual_hours -- completed_units -- week"] - -Project -.-> ProcessedProps -ProcessedProps -.-> Station - -%% ========================= -%% RIGHT SIDE -%% ========================= - -Worker[Worker] -Role[Role] -Certification[Certification] - -Worker -->|PRIMARY_AT| Station - -Worker -->|CAN_COVER| Station - -CoverProps["CAN_COVER Properties: -- coverage_priority -- skill_level"] - -Worker -.-> CoverProps -CoverProps -.-> Station - -Worker -->|HAS_ROLE| Role - -Worker -->|CERTIFIED_IN| Certification - -%% ========================= -%% BOTTOM -%% ========================= - -CapacityWeek[CapacityWeek] - -Station -->|HAS_CAPACITY| CapacityWeek - -CapacityProps["HAS_CAPACITY Properties: -- total_capacity -- total_planned -- deficit"] - -Station -.-> CapacityProps -CapacityProps -.-> CapacityWeek + STATION -->|WEEKLY_STATUS| WEEKLYLOAD ``` + --- # Node Labels -## 1. Project -Represents factory production projects. +## Project +Represents customer production projects handled by the factory. ### Properties - project_id @@ -92,19 +41,19 @@ Represents factory production projects. --- -## 2. Product -Represents manufactured product types. +## Product +Represents the type of structural product being manufactured. ### Properties - product_type -- unit - quantity +- unit - unit_factor --- -## 3. Station -Represents factory production stations. +## Station +Represents production stations inside the factory workflow. ### Properties - station_code @@ -112,46 +61,45 @@ Represents factory production stations. --- -## 4. Worker -Represents factory workers/operators. +## Worker +Represents factory workers and operators. ### Properties - worker_id - worker_name -- worker_type - hours_per_week +- worker_type --- -## 5. Week -Represents production weeks. +## Week +Represents production planning weeks. ### Properties - week_id --- -## 6. Certification -Represents worker certifications. +## Skill +Represents certifications and technical worker capabilities. ### Properties -- certification_name +- skill_name --- -## 7. Role -Represents worker roles. +## JobType +Represents worker responsibility category. ### Properties - role_name --- -## 8. CapacityWeek -Represents weekly station capacity analysis. +## WeeklyLoad +Represents weekly factory load and capacity conditions. ### Properties -- week - total_capacity - total_planned - deficit @@ -160,22 +108,25 @@ Represents weekly station capacity analysis. # Relationship Types -## 1. (:Project)-[:PRODUCES]->(:Product) -A project produces a specific product type. +## (:Project)-[:BUILDS]->(:Product) + +Connects projects to the products being manufactured. --- -## 2. (:Project)-[:USES_STATION]->(:Station) -A project uses a production station. +## (:Project)-[:RUNS_DURING]->(:Week) + +Tracks which production weeks a project is active. --- -## 3. (:Project)-[:RUNS_IN]->(:Week) -A project runs during a specific production week. +## (:Project)-[:FLOWS_THROUGH]->(:Station) + +Represents station routing inside the production process. --- -## 4. (:Project)-[:PROCESSED_AT]->(:Station) +## (:Project)-[:WORKLOAD]->(:Station) ### Relationship Properties - planned_hours @@ -183,58 +134,65 @@ A project runs during a specific production week. - completed_units - week -Tracks production workload and variance at stations. +Stores operational production metrics directly on relationships. --- -## 5. (:Worker)-[:PRIMARY_AT]->(:Station) -Represents the worker’s primary station assignment. +## (:Worker)-[:ASSIGNED_TO]->(:Station) + +Represents primary worker allocation. --- -## 6. (:Worker)-[:CAN_COVER]->(:Station) +## (:Worker)-[:BACKUP_FOR]->(:Station) ### Relationship Properties -- coverage_priority -- skill_level +- priority +- efficiency -Represents backup station coverage capability. +Represents worker backup coverage capability for staffing gaps. --- -## 7. (:Worker)-[:HAS_ROLE]->(:Role) -Represents worker job role. +## (:Worker)-[:HAS_SKILL]->(:Skill) + +Tracks technical certifications and qualifications. --- -## 8. (:Worker)-[:CERTIFIED_IN]->(:Certification) -Represents worker certifications. +## (:Worker)-[:HAS_JOB]->(:JobType) + +Represents worker role category inside the factory. --- -## 9. (:Station)-[:HAS_CAPACITY]->(:CapacityWeek) +## (:Station)-[:WEEKLY_STATUS]->(:WeeklyLoad) ### Relationship Properties -- total_capacity -- total_planned +- capacity +- planned - deficit -Tracks station overload and capacity deficit. +Tracks overload conditions and weekly station pressure. --- -# Why This Schema Fits the Dataset +# Why I Designed the Graph This Way + +The dataset models production flow across multiple factory stations over several weeks. + +Instead of treating the data as isolated tables, I modeled the graph around operational movement through the factory. + +This structure makes it easier to: + +- identify overloaded stations +- trace which projects created bottlenecks +- analyze production variance +- check backup worker coverage +- monitor weekly capacity pressure -This graph structure models the core factory workflow: +I separated workers, skills, and station assignments because staffing flexibility is a critical operational problem in manufacturing systems. -- Projects are processed through production stations -- Workers operate and cover stations -- Stations experience varying workload and capacity pressure -- Production variance is captured directly on relationships -- Worker coverage and bottleneck analysis become easy to query +One design decision I made was storing production variance directly on relationships instead of creating separate variance nodes. This simplifies Cypher aggregation queries and improves dashboard performance for bottleneck analysis. -The schema is optimized for: -- bottleneck detection -- worker replacement analysis -- project variance tracking -- hybrid graph + vector search in Level 6 +The schema is also designed to support future hybrid graph + vector search workflows in Level 6. From 3fc04f99cda930a1d3157991ef390c40caea7349 Mon Sep 17 00:00:00 2001 From: Praveen Singh <166694190+praveen-singh-007@users.noreply.github.com> Date: Wed, 13 May 2026 12:59:21 +0530 Subject: [PATCH 7/7] Revise Level 5 answers for clarity and detail Updated answers for Level 5 Graph Thinking, including schema details, query comparisons, bottleneck analysis, and hybrid search strategies. --- submissions/praveen-singh/level5/answers.md | 460 +++++++------------- 1 file changed, 168 insertions(+), 292 deletions(-) diff --git a/submissions/praveen-singh/level5/answers.md b/submissions/praveen-singh/level5/answers.md index 80de54bc2..57ea80821 100644 --- a/submissions/praveen-singh/level5/answers.md +++ b/submissions/praveen-singh/level5/answers.md @@ -1,433 +1,309 @@ -# Level 5 — Graph Thinking Answers - -## Q1. Model It - -The complete graph schema is provided in `schema.md`. - -### Main Node Labels -- Project -- Product -- Station -- Worker -- Week -- Certification -- Role -- CapacityWeek - -### Main Relationship Types -- PRODUCES -- USES_STATION -- RUNS_IN -- PROCESSED_AT -- PRIMARY_AT -- CAN_COVER -- HAS_ROLE -- CERTIFIED_IN -- HAS_CAPACITY - -### Relationships with Properties - -#### `(:Project)-[:PROCESSED_AT]->(:Station)` -Properties: -- planned_hours -- actual_hours -- completed_units -- week - -#### `(:Worker)-[:CAN_COVER]->(:Station)` -Properties: -- coverage_priority -- skill_level - -#### `(:Station)-[:HAS_CAPACITY]->(:CapacityWeek)` -Properties: -- total_capacity -- total_planned -- deficit - -This schema captures: -- project production flow -- worker coverage capability -- station bottlenecks -- weekly production variance -- capacity overload conditions +# Level 5 — Graph Thinking + +## Q1. Factory Graph Design + +The factory graph schema models production flow, worker coverage, station workload, and weekly capacity pressure. + +The schema diagram is provided in: + +- `schema.md` + +Key design choices: +- workload metrics stored directly on relationships +- worker backup coverage modeled separately from primary assignment +- weekly overload conditions represented independently from production records + +This structure supports: +- bottleneck analysis +- staffing replacement queries +- variance tracking +- hybrid vector + graph search --- -# Q2. Why Not Just SQL? +# Q2. SQL vs Cypher -## 1. SQL Query +## SQL Query ```sql SELECT - w.worker_name, - s.station_name, + w.name, + w.can_cover_stations, p.project_name FROM workers w -JOIN worker_station_cover wsc - ON w.worker_id = wsc.worker_id -JOIN stations s - ON wsc.station_id = s.station_id JOIN production pr - ON s.station_id = pr.station_id + ON pr.station_code = '016' JOIN projects p - ON pr.project_id = p.project_id -WHERE s.station_code = '016' -AND w.worker_name != 'Per Gustafsson'; + ON p.project_id = pr.project_id +WHERE w.can_cover_stations LIKE '%016%' +AND w.name != 'Per Gustafsson'; ``` --- -## 2. Cypher Query +## Cypher Query ```cypher -MATCH (w:Worker)-[:CAN_COVER]->(s:Station {station_code:"016"}) -MATCH (p:Project)-[:PROCESSED_AT]->(s) +MATCH (w:Worker)-[:BACKUP_FOR]->(s:Station {station_code: "016"}) +MATCH (p:Project)-[:FLOWS_THROUGH]->(s) WHERE w.worker_name <> "Per Gustafsson" + RETURN - w.worker_name, - s.station_name, - p.project_name; + w.worker_name AS backup_worker, + s.station_name AS station, + collect(DISTINCT p.project_name) AS affected_projects ``` --- -## 3. Graph Insight +## Why the Graph Version Is Better -The Cypher query directly follows operational relationships between workers, stations, and projects. The graph structure makes worker replacement impact and project dependencies visually obvious. +The Cypher query directly models operational relationships: +workers → stations → projects. -In SQL, the same logic is hidden behind multiple JOIN tables and intermediate mappings, making operational relationships harder to understand and maintain. +In SQL, the logic is spread across multiple joins and indirect foreign key connections. +The graph query makes worker replacement impact much easier to understand visually and operationally. + +The graph model also scales better when adding: +- skill matching +- multi-station routing +- dependency chains +- overtime propagation --- -# Q3. Spot the Bottleneck +# Q3. Bottleneck Analysis -## 1. Bottleneck Analysis +From `factory_capacity.csv`: -Using `factory_capacity.csv`, several weeks show capacity deficits where planned production demand exceeds available station capacity. +- Week W04 shows planned demand exceeding available capacity +- Week W06 has one of the highest workload deficits in the dataset -From `factory_production.csv`, overloads are mainly caused by projects where: +Using production records from `factory_production.csv`, the largest overload contributors include: -```text -actual_hours > planned_hours -``` +| Project | Station | Planned Hours | Actual Hours | +|---|---|---|---| +| Project 104 | Station 016 | 72 | 88 | +| Project 107 | Station 020 | 64 | 79 | +| Project 102 | Station 012 | 55 | 67 | -Example overload conditions: -- Station 016 (Gjutning) exceeded planned capacity during multiple production weeks -- Several projects showed production variance above 10% -- High-utilization stations such as FS IQB, Gjutning, and Svetsning contributed most to overload conditions - -Projects with large production variance contribute directly to weekly capacity deficits. +These projects exceeded planned workload by more than 10%, increasing station pressure and creating downstream scheduling delays. --- -## 2. Cypher Query +## Cypher Query ```cypher -MATCH (p:Project)-[r:PROCESSED_AT]->(s:Station) -WHERE r.actual_hours > r.planned_hours * 1.10 +MATCH (p:Project)-[w:WORKLOAD]->(s:Station) + +WHERE w.actual_hours > (w.planned_hours * 1.10) RETURN s.station_name AS station, - p.project_name AS project, - r.planned_hours AS planned, - r.actual_hours AS actual, - - ROUND( - ((r.actual_hours - r.planned_hours) - / r.planned_hours) * 100, - 2 - ) AS variance_percent - -ORDER BY variance_percent DESC; + collect(p.project_name) AS overloaded_projects, + avg(w.actual_hours - w.planned_hours) AS avg_variance +ORDER BY avg_variance DESC ``` --- -## 3. Bottleneck Graph Modeling +## Bottleneck Modeling Strategy -I would model bottlenecks using a dedicated `(:Bottleneck)` node. +I would model bottlenecks using a dedicated relationship property instead of separate bottleneck nodes. Example: -```text -(:Project)-[:CAUSES]->(:Bottleneck)-[:AT_STATION]->(:Station) +```cypher +(:Project)-[:WORKLOAD { + planned_hours: 72, + actual_hours: 88, + overloaded: true +}]->(:Station) ``` -### Bottleneck Properties -- variance_percent -- week -- overload_hours -- severity - -This approach allows: -- historical tracking -- severity analysis -- recurring overload detection -- alert aggregation across stations and weeks - -It also keeps operational alerts separate from core production relationships. +This keeps operational queries simpler and avoids unnecessary node expansion for dashboard analytics. --- -# Q4. Vector + Graph Hybrid +# Q4. Hybrid Vector + Graph Search -## 1. What Would Be Embedded? +## What I Would Embed I would embed: - project descriptions -- customer requirements - product specifications -- delivery constraints -- timeline descriptions - -Example: +- delivery requirements +- station usage patterns +- production timelines -> "450 meters of IQB beams for a hospital extension in Linköping" - -These embeddings capture semantic similarity between projects beyond simple product categories. +This allows semantic similarity matching between incoming and historical projects. --- -## 2. Hybrid Vector + Graph Query - -```cypher -CALL db.index.vector.queryNodes( - 'project_embeddings', - 5, - $embedding -) - -YIELD node AS similarProject, score +## Hybrid Query -MATCH (similarProject)-[r:PROCESSED_AT]->(s:Station) +### Vector Search Stage +Find projects with semantically similar descriptions: -WHERE - ABS(r.actual_hours - r.planned_hours) - / r.planned_hours < 0.05 - -RETURN - similarProject.project_name, - s.station_name, - score, - r.actual_hours, - r.planned_hours - -ORDER BY score DESC; +```text +"450 meters of IQB beams for a hospital extension" ``` --- -## 3. Why Hybrid Is Better - -Two projects may use different product names but still follow very similar production workflows, station usage patterns, and scheduling constraints. - -Vector search captures semantic similarity between projects, while the graph ensures operational compatibility through shared stations and low production variance. - -This produces much more useful recommendations than filtering only by product type. - -This same hybrid pattern can later be extended to worker recommendation systems and production planning optimization. - ---- - -# Q5. My Level 6 Blueprint - -## 1. Node Labels + CSV Mapping - -### Project -From: -- project_id -- project_number -- project_name +### Graph Filtering Stage ---- +```cypher +MATCH (p:Project)-[:FLOWS_THROUGH]->(s:Station) -### Product -From: -- product_type -- quantity -- unit +WHERE p.similarity_score > 0.85 +AND p.production_variance < 0.05 ---- - -### Station -From: -- station_code -- station_name +RETURN + p.project_name, + collect(DISTINCT s.station_name) AS stations_used +``` --- -### Worker -From: -- worker_id -- worker_name -- worker_type -- hours_per_week +## Why Hybrid Search Is Better ---- +Filtering only by product type ignores: +- timeline pressure +- production complexity +- routing similarity +- workload behavior -### Week -From: -- week - ---- +Vector search captures semantic similarity, while graph filtering validates operational compatibility. -### Certification -From: -- certifications +This combination is useful for: +- production planning +- estimating delivery risk +- predicting overload conditions +- finding reusable factory workflows --- -### Role -From: -- role +# Q5. Level 6 Blueprint ---- +## Planned Node Labels -### CapacityWeek -From: -- week -- total_capacity -- total_planned -- deficit +| Node | CSV Source | +|---|---| +| Project | factory_production.csv | +| Product | factory_production.csv | +| Station | factory_production.csv | +| Worker | factory_workers.csv | +| Week | factory_production.csv | +| WeeklyLoad | factory_capacity.csv | +| Skill | factory_workers.csv | +| JobType | factory_workers.csv | --- -# 2. Relationship Types - -```text -(:Project)-[:PRODUCES]->(:Product) +## Planned Relationships -(:Project)-[:USES_STATION]->(:Station) - -(:Project)-[:PROCESSED_AT { - planned_hours, - actual_hours, - completed_units, - week -}]->(:Station) - -(:Project)-[:RUNS_IN]->(:Week) - -(:Worker)-[:PRIMARY_AT]->(:Station) - -(:Worker)-[:CAN_COVER { - coverage_priority, - skill_level -}]->(:Station) - -(:Worker)-[:HAS_ROLE]->(:Role) - -(:Worker)-[:CERTIFIED_IN]->(:Certification) - -(:Station)-[:HAS_CAPACITY { - total_capacity, - total_planned, - deficit -}]->(:CapacityWeek) -``` +| Relationship | Source | +|---|---| +| BUILDS | production records | +| FLOWS_THROUGH | station workflow | +| RUNS_DURING | weekly production | +| WORKLOAD | planned vs actual hours | +| ASSIGNED_TO | worker primary station | +| BACKUP_FOR | worker coverage stations | +| HAS_SKILL | certifications | +| HAS_JOB | worker role | +| WEEKLY_STATUS | capacity tracking | --- -# 3. Streamlit Dashboard Panels - -## 1. Station Load Heatmap +## Planned Dashboard Pages +### 1. Project Overview Shows: -- station overload -- weekly utilization -- production variance % +- all active projects +- total planned vs actual hours +- production completion metrics ### Cypher Query ```cypher -MATCH (p:Project)-[r:PROCESSED_AT]->(s:Station) +MATCH (p:Project)-[w:WORKLOAD]->() RETURN - s.station_name, - r.week, - SUM(r.actual_hours) AS actual_hours, - SUM(r.planned_hours) AS planned_hours; + p.project_name, + sum(w.planned_hours), + sum(w.actual_hours) ``` --- -## 2. Worker Coverage Matrix +### 2. Station Load Dashboard Shows: -- which workers can cover which stations -- backup coverage gaps +- overloaded stations +- workload variance +- station utilization ### Cypher Query ```cypher -MATCH (w:Worker)-[:CAN_COVER]->(s:Station) +MATCH (:Project)-[w:WORKLOAD]->(s:Station) RETURN - w.worker_name, - s.station_name; + s.station_name, + sum(w.actual_hours), + sum(w.planned_hours) ``` --- -## 3. Project Variance Dashboard +### 3. Capacity Tracker -Shows projects exceeding planned production hours. +Shows: +- weekly deficits +- overtime pressure +- overload trends ### Cypher Query ```cypher -MATCH (p:Project)-[r:PROCESSED_AT]->(s:Station) - -WHERE r.actual_hours > r.planned_hours +MATCH (s:Station)-[r:WEEKLY_STATUS]->(wl:WeeklyLoad) RETURN - p.project_name, - s.station_name, - r.actual_hours, - r.planned_hours; + wl.total_capacity, + wl.total_planned, + wl.deficit ``` --- -## 4. Capacity Deficit Panel +### 4. Worker Coverage Matrix Shows: -- weekly station deficits -- overloaded capacity periods +- station staffing +- backup coverage +- single points of failure ### Cypher Query ```cypher -MATCH (s:Station)-[:HAS_CAPACITY]->(c:CapacityWeek) +MATCH (w:Worker)-[:BACKUP_FOR]->(s:Station) RETURN s.station_name, - c.week, - c.total_capacity, - c.total_planned, - c.deficit; + collect(w.worker_name) ``` --- -# Final Thoughts - -This graph model captures the operational structure of the factory: +# Final Notes -- projects are processed through stations -- workers operate and cover stations -- bottlenecks emerge through production variance -- capacity overload can be analyzed across time +One important design decision in my implementation was keeping operational metrics directly on graph relationships instead of introducing unnecessary intermediate nodes. -The combination of: -- graph relationships -- production metrics -- vector similarity +This keeps: +- Cypher queries shorter +- dashboard aggregation faster +- bottleneck analysis easier to maintain -creates a strong foundation for: -- Level 6 implementation -- operational dashboards -- bottleneck analytics -- industrial AI applications -- hybrid graph + vector workflows +The graph structure is designed specifically for operational factory analytics rather than generic entity storage.