100 Exercises / System Development / 100 Exercise on System Development

Introduction to System Development in Manufacturing | Learning Web, API, and DB Design with Equipment Maintenance Apps

Introduction to Designing a Maintenance Request Management System to Reduce Equipment Downtime

100 Exercise “System Development” No.001–No.010

This article focuses on business challenges in manufacturing and offers a practical approach that helps you understand the overall picture of system development step by step with 10 exercises. The subjects are Management of equipment shutdown and maintenance requests spread across paper, telephone, and spreadsheet files. It connects the system’s purpose, web application structure, HTTP/API, requirements definition, consistency between designs, business flow, and overall structure all within a single hypothetical case.

Across the entire 100-click phase, we will move on to development environments, databases, APIs, frontends, authentication, testing, CI/CD, business functions, and AI and data utilization. For the first 10 articles, we create a “map” to avoid confusion in subsequent implementations. What matters is not simply introducing the technology itself, but how to improve on-site decision-making speed, record quality, and downtime losses.

[!NOTE] This material is a notebook previously used by Surikoubo (or personally by the representative, Kazuyama), and has been reconstructed, edited, and published with the company’s permission.
All data listed is fictional and has no relation whatsoever to real companies, factories, or figures.

1. Introduction: Practical Challenges in Manufacturing Covered in This Article

In the fictional ‘Suri Seiki Factory,’ workers who discover equipment abnormalities contact the team leader, who then calls the maintenance staff. The details of the procedures are later transcribed into paper daily reports and spreadsheet files. While the response capability for emergency cases is high, records of reception, assignment, and recovery times are not aligned, so even at the end of the month, it is impossible to compare which equipment should be prioritized for preventive maintenance.

The business objectives of the business app being developed here are set as follows.

  • Shorten the waiting time from anomaly detection to conservation initiation
  • Monitor unsupported, in progress, and completed on a single screen
  • Accumulate downtime and causes by equipment to use as a basis for decision-making in maintenance investment.
  • Minimize the operation that allows the site to continue entering data

System development is not just about creating screens. This activity involves verbalizing business rules, aligning the meaning of data, and transforming it into a system that allows stakeholders to view the same state and make judgments.

2. Common Situations on Site

Information about equipment abnormalities tends to be scattered across verbal, extension, chat, paper daily reports, and personal spreadsheet files. As a result, duplicate registrations of the same case, misunderstandings among responsible persons, and missed records after restoration occur. Administrators recollect data with each monthly report, and the preliminary and final values do not match.

What’s especially difficult is that the faster the first aid on site, the more likely it is to ‘record later.’ If you add too many input items, they won’t be used; if you reduce them too much, they can’t be used for improvement analysis. Therefore, it is necessary to simultaneously consider business workflows, screens, APIs, and databases.

3. Why is this issue difficult to judge?

Systematizing equipment maintenance involves competing decisions.

  1. Immediacy and accuracy: While registering with fewer items immediately after discovery, you also want to leave detailed information about the cause and treatment.
  2. Standardization and exception handling: Standard flows are necessary, but there are exceptions for emergency safety stops or outsourced repairs.
  3. On-site Optimization and Overall Optimization: A code structure that respects the unique naming of each line while enabling cross-factory comparisons is necessary.
  4. Short-term development and future expansion: While we want to start small, we also want to integrate sensors, inventory, and predictive maintenance in the future.

Therefore, rather than creating a large list of features from the start, clarify the minimum data required for decision-making and the division of business responsibilities before moving them into technology.

4. The overall picture of exercise covered this time

No.ThemeQuestions Answered in This Case
001What is system development?What to decide, and in what order?
002Business Systems and Web AppsHow to distinguish between business purpose and delivery method
003Front Back: DBWhat is each layer responsible for?
004Client/ServerHow do devices and servers coordinate
005HTTPWhat are the units of data exchange?
006APIHow to define the function window
007Requirements definitionWhat to agree on before development
008Screen, API, and database designHow to prevent omissions in design
009Business FlowHow to extract functions from on-site movements
010Small-scale app designHow to consolidate all elements into a single structure

In each exercise, we use the fictional data generated by fixed seeds, replacing concepts with tables, aggregates, graphs, and simple simulations.

5. Preparing the Python environment

It does not connect to external data or services. numpy, pandas, and matplotlib are used, and japanize_matplotlib is used to display Japanese labels. Fix the random seed to 42 so that rerunning it yields the same result.

from dataclasses import dataclass, asdict
from datetime import datetime, timedelta
import json
import platform
from urllib.parse import urlencode

import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import japanize_matplotlib
from IPython.display import display

SEED = 42
rng = np.random.default_rng(SEED)
pd.set_option("display.max_columns", 20)
pd.set_option("display.width", 120)
plt.rcParams["figure.figsize"] = (8, 4.5)

print("Python     :", platform.python_version())
print("numpy      :", np.__version__)
print("pandas     :", pd.__version__)
print("matplotlib :", matplotlib.__version__)
print("random seed:", SEED)
Python     : 3.11.9
numpy      : 1.26.4
pandas     : 2.2.2
matplotlib : 3.9.2
random seed: 42

6. Creation of Fictional Data

Generate 120 maintenance requests for 3 lines and 8 facilities. reported_at indicates the time of abnormality detection and reception, started_at is the time maintenance began, and closed_at is the time restoration or completion. The key KPIs are as follows.

Initial Response Time (minutes)=started_atreported_at\text{Initial Response Time (minutes)} = \text{started\_at} - \text{reported\_at} stop time (minutes)=closed_atreported_at\text{stop time (minutes)} = \text{closed\_at} - \text{reported\_at}

Downtime loss is calculated as a simple indicator for comparison, based on downtime time and marginal profit per minute for each piece of equipment. During actual implementation, production planning, work-in-progress, alternative equipment, and quality loss must also be considered.

equipment = pd.DataFrame({
    "equipment_id": [f"EQ-{i:03d}" for i in range(1, 9)],
    "equipment_name": ["Press1", "Press2", "lathe1", "lathe2", "grinding1", "Cleaning1", "Examination1", "transport1"],
    "line": ["A", "A", "B", "B", "B", "C", "C", "C"],
    "loss_yen_per_min": [12000, 10000, 8000, 7500, 9000, 5000, 6500, 4000],
})

n = 120
reported = pd.Timestamp("2026-04-01 08:00") + pd.to_timedelta(
    np.sort(rng.integers(0, 60 * 24 * 60, n)), unit="m"
)
priority = rng.choice(["high", "middle", "low"], n, p=[0.22, 0.50, 0.28])
wait_base = np.select([priority == "high", priority == "middle"], [12, 28], default=55)
initial_response = np.maximum(2, rng.gamma(shape=2.0, scale=wait_base / 2))
repair_time = rng.gamma(shape=2.2, scale=28, size=n) + np.where(priority == "high", 25, 0)

requests = pd.DataFrame({
    "request_id": [f"MR-{i:04d}" for i in range(1, n + 1)],
    "equipment_id": rng.choice(equipment["equipment_id"], n, p=[.16, .13, .14, .12, .13, .10, .12, .10]),
    "reported_at": reported,
    "priority": priority,
    "cause_category": rng.choice(["wear", "Adjustment Misalignment", "Electrical Systems", "foreign object", "Unknown"], n, p=[.28, .24, .18, .16, .14]),
    "report_channel": rng.choice(["telephone", "paper", "Chat"], n, p=[.45, .30, .25]),
})
requests["started_at"] = requests["reported_at"] + pd.to_timedelta(initial_response, unit="m")
requests["closed_at"] = requests["started_at"] + pd.to_timedelta(repair_time, unit="m")
requests["status"] = "Finished"
requests = requests.merge(equipment, on="equipment_id", how="left")
requests["response_min"] = (requests["started_at"] - requests["reported_at"]).dt.total_seconds() / 60
requests["downtime_min"] = (requests["closed_at"] - requests["reported_at"]).dt.total_seconds() / 60
requests["estimated_loss_yen"] = requests["downtime_min"] * requests["loss_yen_per_min"]

print(f"Conservation Request: {len(requests)}records / Eligible Facilities: {requests['equipment_id'].nunique()}platform")
display(requests.head().round({"response_min": 1, "downtime_min": 1, "estimated_loss_yen": 0}))
Conservation requests: 120 / Target equipment: 8
request_id equipment_id reported_at priority cause_category report_channel started_at closed_at status equipment_name line loss_yen_per_min response_min downtime_min estimated_loss_yen
0 MR-0001 EQ-006 2026-04-01 18:36:00 middle wear Chat 2026-04-01 19:02:20.766500160 2026-04-01 20:28:50.649064020 Finished Cleaning1 C 5000 26.3 112.8 564221.0
1 MR-0002 EQ-005 2026-04-03 13:39:00 middle wear Chat 2026-04-03 14:07:53.397734982 2026-04-03 15:08:05.648771814 Finished grinding1 B 9000 28.9 89.1 801847.0
2 MR-0003 EQ-003 2026-04-03 23:04:00 middle Adjustment Misalignment Chat 2026-04-03 23:31:31.636614581 2026-04-04 01:32:48.822951995 Finished lathe1 B 8000 27.5 148.8 1190510.0
3 MR-0004 EQ-008 2026-04-05 03:53:00 low wear telephone 2026-04-05 05:30:23.773472670 2026-04-05 05:58:24.436947378 Finished transport1 C 4000 97.4 125.4 501629.0
4 MR-0005 EQ-004 2026-04-05 09:48:00 middle wear telephone 2026-04-05 10:51:33.109732547 2026-04-05 11:40:09.319322723 Finished lathe2 B 7500 63.6 112.2 841165.0

7. No.001: Organizing What System Development Is

Meaning in Practice

System development is not just about replacing on-site challenges with software. It is an activity that defines “who decides what, when, and what,” and integrates the necessary tasks, data, operations, and operations. In this case, the goal is not to “increase the number of registrations,” but to reduce initial response time and downtime losses.

Approach to Analysis and Modeling

The probability of rework and impact vary at each stage—planning, requirements definition, design, implementation, testing, and operation. Simply put, the expected reversal loss at stage ii

Ei=pi×CiE_i = p_i \times C_i

Let’s say so. pip_i is the probability of misunderstandings in requirements, and CiC_i is the cost of corrections if they are discovered later in the process. The numbers themselves are fictional, but they can visualize why time is being used for early agreements.

Check with Python

development_phases = pd.DataFrame({
    "Project": ["Planning", "Requirements definition", "Design", "Implementation", "Test", "Utilization"],
    "Main Deliverables": ["Purpose/KPI", "Business and Functional Requirements", "Screen/API/DBDesign", "Functional Functions", "Quality Inspection", "Monitoring and Improvement"],
    "Misunderstanding Residual Probability": [0.30, 0.22, 0.16, 0.10, 0.06, 0.04],
    "cost_of_correction_upon_discovery_ten_thousand_yen": [20, 45, 90, 180, 320, 500],
})
development_phases["expected_rework_loss_ten_thousand_yen"] = (
    development_phases["Misunderstanding Residual Probability"] * development_phases["cost_of_correction_upon_discovery_ten_thousand_yen"]
)
display(development_phases.round(1))

fig, ax = plt.subplots()
ax.bar(development_phases["Project"], development_phases["expected_rework_loss_ten_thousand_yen"], color="#4472C4")
ax.set_title("Expected rework loss by development process (hypothetical scenario)")
ax.set_xlabel("Project")
ax.set_ylabel("Expected resettable loss (ten thousand yen)")
ax.grid(axis="y", alpha=0.3)
plt.tight_layout()
plt.show()
Project Main Deliverables Misunderstanding Residual Probability cost_of_correction_upon_discovery_ten_thousand_yen expected_rework_loss_ten_thousand_yen
0 Planning Purpose/KPI 0.3 20 6.0
1 Requirements definition Business and Functional Requirements 0.2 45 9.9
2 Design Screen/API/DBDesign 0.2 90 14.4
3 Implementation Functional Functions 0.1 180 18.0
4 Test Quality Inspection 0.1 320 19.2
5 Utilization Monitoring and Improvement 0.0 500 20.0

png

Reading the results

Even if the probability of misunderstanding remains, the range of changes for subsequent processes expands, resulting in greater expected losses. Therefore, it is worth checking the equipment name, priority, completion conditions, and KPI definitions with the site, maintenance, and managers before implementation. Rather than prolonging requirements definition, it is practical to eliminate them in short cycles due to ambiguity that causes significant losses.

8. No.002: Understanding the Differences Between Business Systems and Web Applications

Meaning in Practice

“Business Systems” are classified by Business Objectives such as receiving maintenance requests, assigning responsibilities, and managing historical records. “Web applications” are classified based on Delivery Methods that use browsers and web technologies. The two are not opposing concepts; they can provide a business system called maintenance request management as a web application.

Approach to Analysis and Modeling

The delivery method compares multiple criteria such as site suitability, ease of updates, offline resistance, device function integration, and implementation costs. Here, a provisional evaluation out of 5 points and a weighting wjw_j are used, and the weighted evaluation of Method aa

Sa=jwjxajS_a = \sum_j w_j x_{aj}

Calculate it as follows. The evaluation value is a hypothetical value used to indicate the selection process, but in reality, it reflects the factory’s communication environment and security standards.

Check with Python

delivery_options = pd.DataFrame({
    "Evaluation Axis": ["Multi-device support", "ease of updating", "Offline Tolerance", "Camera Integration", "Lightness of initial implementation"],
    "weight": [0.25, 0.25, 0.20, 0.10, 0.20],
    "WebApp": [5, 5, 2, 3, 5],
    "Device-only app": [3, 2, 5, 5, 2],
    "spreadsheet file": [2, 2, 4, 1, 4],
})
scores = {
    col: float((delivery_options["weight"] * delivery_options[col]).sum())
    for col in ["WebApp", "Device-only app", "spreadsheet file"]
}
display(delivery_options)
display(pd.Series(scores, name="Weighted evaluation (5Perfect score)").sort_values(ascending=False).round(2).to_frame())

fig, ax = plt.subplots()
ax.bar(scores.keys(), scores.values(), color=["#4472C4", "#70AD47", "#A5A5A5"])
ax.set_title("Comparison of Provision Methods for Conservation Request Management (Hypothetical Evaluation)")
ax.set_xlabel("Delivery Methods")
ax.set_ylabel("Weighted evaluation (5Perfect score)")
ax.set_ylim(0, 5)
ax.grid(axis="y", alpha=0.3)
plt.tight_layout()
plt.show()
Evaluation Axis weight WebApp Device-only app spreadsheet file
0 Multi-device support 0.25 5 3 2
1 ease of updating 0.25 5 2 2
2 Offline Tolerance 0.20 2 5 4
3 Camera Integration 0.10 3 5 1
4 Lightness of initial implementation 0.20 5 2 4
Weighted evaluation (5Perfect score)
WebApp 4.20
Device-only app 3.15
spreadsheet file 2.70

png

Reading the results

In this scenario, web apps are the most prominent. This is because it can be used on multiple shared devices and is easy to distribute updates all at once. However, if immediate registration is required in places without signal, offline support for web apps or dedicated apps is also a comparative option. Avoid judgments like “It’s not a business system because it’s web” or “It’s a business system and needs dedicated software.”

9. No.003: Organizing the Roles of Frontend, Backend, and DB

Meaning in Practice

The frontend supports screens viewed by workers and input, the backend handles business rules such as priority determination and permission verification, and the database (DB) is responsible for consistent storage of equipment, requests, and history. By sharing responsibility, changing the screen makes it less likely to disrupt the meaning of the history.

Approach to Analysis and Modeling

Response time: the sum of screen processing TfT_f, communication TnT_n, backend processing TbT_b, and database processing TdT_d

T=Tf+Tn+Tb+TdT = T_f + T_n + T_b + T_d

It will be broken down as such. Not only does it give the impression of being slow, but you can also determine which segment of the company should invest in improvements.

Check with Python

layer_roles = pd.DataFrame({
    "layer": ["Front End", "Backend", "DB"],
    "Responsibilities in the security app": ["Input, List, and Warning Display", "Certification, Priority, and State Transitions", "Storing Equipment, Requests, and Change History"],
    "Examples when it breaks": ["Difficult to input", "Allowing unauthorized state changes", "Missing or duplicate history"],
})
display(layer_roles)

routes = pd.DataFrame({
    "operation": ["List of Requests", "Request Registration", "Assignment of Responsibilities", "monthly tallying"],
    "Screen": [35, 45, 30, 40],
    "communication": [25, 30, 25, 30],
    "Backend": [20, 40, 35, 75],
    "DB": [30, 45, 40, 210],
}).set_index("operation")
display(routes.assign(total_milliseconds=routes.sum(axis=1)))

ax = routes.plot(kind="bar", stacked=True, color=["#5B9BD5", "#ED7D31", "#70AD47", "#FFC000"])
ax.set_title("Breakdown of response times by operation (fictitious measurements)")
ax.set_xlabel("operation")
ax.set_ylabel("Time (milliseconds)")
ax.grid(axis="y", alpha=0.3)
plt.xticks(rotation=0)
plt.tight_layout()
plt.show()
layer Responsibilities in the security app Examples when it breaks
0 Front End Input, List, and Warning Display Difficult to input
1 Backend Certification, Priority, and State Transitions Allowing unauthorized state changes
2 DB Storing Equipment, Requests, and Change History Missing or duplicate history
Screen communication Backend DB total_milliseconds
operation
List of Requests 35 25 20 30 110
Request Registration 45 30 40 45 160
Assignment of Responsibilities 30 25 35 40 130
monthly tallying 40 30 75 210 355

png

Reading the results

Monthly aggregation is dominated by database processing. Simply reducing the screen weight limits the range of improvements, so we should consider aggregation methods, indexes, and preliminary aggregation. On the other hand, time is distributed across each tier of request registration. Layered responsibility division not only covers the development team’s responsibilities but also serves as a unit for fault investigation and performance improvement.

10. No.004: Understanding Client-Server Configuration

Meaning in Practice

The browsers on on-site PCs or tablets serve as clients. The client requests a list of requests, the server checks permissions and conditions, retrieves data from the database, and returns the results. By aggregating data and critical business rules on the server side, inconsistencies between devices can be suppressed.

Approach to Analysis and Modeling

Between client and server, consider concurrent usage, network latency, processing time, and failure rate. This time, we simulate the round-trip time of the request and check the 95th percentile (p95). Average alone overlooks the slowness felt by some workers during busy times.

Check with Python

request_log = pd.DataFrame({
    "network_ms": rng.lognormal(mean=np.log(35), sigma=0.35, size=500),
    "server_ms": rng.lognormal(mean=np.log(90), sigma=0.45, size=500),
})
request_log["round_trip_ms"] = request_log.sum(axis=1)
latency_summary = request_log["round_trip_ms"].agg(["mean", "median", lambda s: s.quantile(.95), "max"])
latency_summary.index = ["average", "median", "p95", "largest"]
display(latency_summary.round(1).to_frame("Round-trip time (milliseconds)"))

fig, ax = plt.subplots()
ax.hist(request_log["round_trip_ms"], bins=25, color="#4472C4", edgecolor="white")
ax.axvline(request_log["round_trip_ms"].quantile(.95), color="#C00000", linestyle="--", label="p95")
ax.set_title("Round-trip times for requests from the client's perspective")
ax.set_xlabel("Round-trip time (milliseconds)")
ax.set_ylabel("Requirement number")
ax.grid(axis="y", alpha=0.3)
ax.legend()
plt.tight_layout()
plt.show()
Round-trip time (milliseconds)
average 129.7
median 123.2
p95 209.7
largest 386.1

png

Reading the results

The distribution has a right hem, and the p95 is larger than average. Performance targets for business screens can be verified not only by setting targets like “average less than 1 second,” but also by setting them as “within a certain number of seconds under normal load.” Additionally, by measuring Wi-Fi latency and server processing separately within the factory, you can determine whether to prioritize network enhancement or app improvement.

11. No.005: Understanding HTTP Requests and Responses

Meaning in Practice

In web apps, the client sends an HTTP request, and the server returns an HTTP response. Requests should include methods, URLs, headers, and, if necessary, the body. Responses include state codes, headers, and body messages. By correctly handling status codes, users can distinguish between “input errors,” “insufficient permissions,” and “server failures.”

Approach to Analysis and Modeling

Monitors the proportion of normal and abnormal cases by operation. The success rate is

success rate=2xxnumber of casesTotal number of requests\text{success rate}=\frac{\text{2xxnumber of cases}}{\text{Total number of requests}}

That’s right. However, the 400 series has input and permission issues, while the 500 series has internal server issues, so the person responsible for improvement is different.

Check with Python

http_samples = pd.DataFrame([
    ["GET", "/api/requests?status=open", 200, "List Success"],
    ["POST", "/api/requests", 201, "Request registration successful"],
    ["POST", "/api/requests", 400, "Insufficient mandatory items"],
    ["PATCH", "/api/requests/MR-0001", 403, "No update permission"],
    ["GET", "/api/requests/MR-9999", 404, "No target"],
    ["GET", "/api/summary", 500, "Failures in aggregation processing"],
], columns=["method", "path", "status", "Operational Significance"])
display(http_samples)

status_log = rng.choice([200, 201, 400, 403, 404, 500], 1000, p=[.70, .20, .035, .015, .035, .015])
status_class = pd.Series(status_log).map(lambda x: f"{x // 100}xx").value_counts().sort_index()
display(status_class.rename("number_of_cases").to_frame().assign(ratio=lambda x: (x["number_of_cases"] / x["number_of_cases"].sum()).round(3)))

fig, ax = plt.subplots()
ax.bar(status_class.index, status_class.values, color=["#70AD47", "#ED7D31", "#C00000"])
ax.set_title("HTTPNumber of entries by status code category (fictional logs)")
ax.set_xlabel("State Code Classification")
ax.set_ylabel("number_of_cases")
ax.grid(axis="y", alpha=0.3)
plt.tight_layout()
plt.show()
method path status Operational Significance
0 GET /api/requests?status=open 200 List Success
1 POST /api/requests 201 Request registration successful
2 POST /api/requests 400 Insufficient mandatory items
3 PATCH /api/requests/MR-0001 403 No update permission
4 GET /api/requests/MR-9999 404 No target
5 GET /api/summary 500 Failures in aggregation processing
number_of_cases ratio
2xx 902 0.902
4xx 74 0.074
5xx 24 0.024

png

Reading the results

Even if 2xx is the majority, treating 4xx and 5xx together as “errors” will be a mistake in countermeasures. For the 400, check the input guide; for the 403, check permission design; for the 404, check screen transitions and data synchronization; and for the 500, check the server logs and exception handling. Messages are converted not into status codes but into messages indicating the next action to be taken.

12. No.006: Understanding What an API Is

Meaning in Practice

An API is a contract for frontend and other systems to utilize backend functionality. For example, define a window for “obtaining an incomplete maintenance request” or “registering a new request.” Clarifying APIs makes it easier to reuse the same functions from sensors and production management systems in the future.

Approach to Analysis and Modeling

API contracts define input, output, state code, authentication, and business constraints. Here, we simulate local APIs with functions, filtering by query conditions, and checking JSON responses. Actual communication is not conducted, but the focus is on data contracts.

Check with Python

def get_maintenance_requests(data: pd.DataFrame, line: str | None = None, priority: str | None = None) -> dict:
    # A pure local function that mimics GET /api/maintenance-requests
    filtered = data.copy()
    if line is not None:
        filtered = filtered.loc[filtered["line"] == line]
    if priority is not None:
        filtered = filtered.loc[filtered["priority"] == priority]
    records = filtered[["request_id", "equipment_id", "line", "priority", "status"]].head(5).to_dict("records")
    return {"status": 200, "count": len(filtered), "items": records}

query = {"line": "A", "priority": "high"}
print("request : GET /api/maintenance-requests?" + urlencode(query))
api_response = get_maintenance_requests(requests, **query)
print("response:")
print(json.dumps(api_response, ensure_ascii=False, indent=2))

api_catalog = pd.DataFrame([
    ["GET", "/maintenance-requests", "List & Search", "worker/preserve/administrator"],
    ["POST", "/maintenance-requests", "New Registration", "worker/preserve"],
    ["PATCH", "/maintenance-requests/{id}", "Responsible and Status Update", "preserve"],
    ["GET", "/equipment/{id}", "See facility information", "all"],
    ["GET", "/reports/downtime", "Stop time aggregation", "administrator"],
], columns=["Method", "Pass", "Purpose", "user"])
display(api_catalog)
request : GET /api/maintenance-requests?line=A&priority=%E9%AB%98
response:
{
  "status": 200,
  "count": 10,
  "items": [
    {
      "request_id": "MR-0009",
      "equipment_id": "EQ-002",
      "line": "A",
      "priority": "High",
      "status": "It's over"
    },
    {
      "request_id": "MR-0052",
      "equipment_id": "EQ-001",
      "line": "A",
      "priority": "High",
      "status": "It's over"
    },
    {
      "request_id": "MR-0055",
      "equipment_id": "EQ-001",
      "line": "A",
      "priority": "High",
      "status": "It's over"
    },
    {
      "request_id": "MR-0068",
      "equipment_id": "EQ-001",
      "line": "A",
      "priority": "High",
      "status": "It's over"
    },
    {
      "request_id": "MR-0069",
      "equipment_id": "EQ-001",
      "line": "A",
      "priority": "High",
      "status": "It's over"
    }
  ]
}
Method Pass Purpose user
0 GET /maintenance-requests List & Search worker/preserve/administrator
1 POST /maintenance-requests New Registration worker/preserve
2 PATCH /maintenance-requests/{id} Responsible and Status Update preserve
3 GET /equipment/{id} See facility information all
4 GET /reports/downtime Stop time aggregation administrator

Reading the results

Even with the same list API, if you specify the line and priority as conditions, the screen side does not need to independently retrieve and filter all items. On the other hand, if APIs are tightly coupled only for screen convenience, they become difficult to reuse. It is important to define naming, search criteria, and updatable states centered around the operational resource called “Equipment Shutdown Cases.”

13. No.007: Organizing Items to Check in Requirements Definition

Meaning in Practice

In requirements definition, we examine the target business, users, functions, data, performance, availability, security, migration, operations, and acceptance conditions. Just saying “I want a list screen” doesn’t make you know who judges what. For example, “Team leaders can check unaddressed high-priority cases within 30 seconds at the start of the shift,” and establish conditions that can be evaluated with the work scene.

Approach to Analysis and Modeling

Candidate requirements are evaluated based on value, urgency, risk reduction, and scale of work. As a simple priority

priority score=value+urgency+risk reductionwork scale\text{priority score} = \frac{\text{value} + \text{urgency} + \text{risk reduction}}{\text{work scale}}

We use it. Numbers are not a substitute for discussion, but tools to visualize the implicit weight of each department.

Check with Python

requirements = pd.DataFrame({
    "requirement": ["Immediate Request Registration", "List of Unsupported Items", "Notification to the person in charge", "Photo Attachment", "Monthly Stop Analysis", "Parts Inventory Coordination"],
    "Value": [10, 10, 9, 6, 8, 7],
    "Urgency": [10, 9, 9, 5, 6, 4],
    "Risk reduction": [8, 9, 8, 7, 8, 6],
    "scale of work": [3, 3, 5, 5, 4, 9],
})
requirements["Priority score"] = (
    requirements[["Value", "Urgency", "Risk reduction"]].sum(axis=1) / requirements["scale of work"]
)
requirements = requirements.sort_values("Priority score", ascending=False)
display(requirements.round(2))

fig, ax = plt.subplots()
ax.barh(requirements["requirement"][::-1], requirements["Priority score"][::-1], color="#4472C4")
ax.set_title("Priority score for candidate requirements (hypothetical evaluation)")
ax.set_xlabel("Priority score")
ax.set_ylabel("requirement")
ax.grid(axis="x", alpha=0.3)
plt.tight_layout()
plt.show()
requirement Value Urgency Risk reduction scale of work Priority score
0 Immediate Request Registration 10 10 8 3 9.33
1 List of Unsupported Items 10 9 9 3 9.33
4 Monthly Stop Analysis 8 6 8 4 5.50
2 Notification to the person in charge 9 9 8 5 5.20
3 Photo Attachment 6 5 7 5 3.60
5 Parts Inventory Coordination 7 4 6 9 1.89

png

Reading the results

In the initial version, immediate registration and a list of unsupported items are priority candidates. While parts inventory coordination is valuable, its scale is large and it can be divided into subsequent stages. However, safety regulations are mandatory regardless of the score. Agree not only on functional requirements but also on users, performance, audit logs, backups, inquiry handling, and migration of existing data.

14. No.008: Understanding the Relationship Between Screen Design, API Design, and DB Design

Meaning in Practice

Input fields on the screen require the receiving API, and the information to be saved requires DB columns and related information. On the other hand, just having an item in the database does not determine who registers or refers to it when. If you proceed with the three designs separately, inconsistencies arise, such as being able to input on the screen but not being saved, and APIs being returned but not used on the screen.

Approach to Analysis and Modeling

Check traceability from requirements to screens, APIs, and databases in a matrix. Place the business item in the row and the design element in the column, and set the corresponding correspondence to 1. Items with insufficient total lines are candidates for design omissions.

Check with Python

traceability = pd.DataFrame({
    "Registration Screen": [1, 1, 1, 0, 0, 0],
    "List Screen": [1, 1, 1, 1, 1, 0],
    "RegistrationAPI": [1, 1, 1, 0, 0, 0],
    "UpdateAPI": [0, 0, 0, 1, 1, 1],
    "Request table": [1, 1, 1, 1, 1, 1],
    "History table": [0, 0, 0, 1, 1, 1],
}, index=["EquipmentID", "abnormal content", "priority", "person in charge", "Condition", "Reason for Update"])
display(traceability)

fig, ax = plt.subplots(figsize=(9, 4.5))
im = ax.imshow(traceability.values, cmap="Blues", vmin=0, vmax=1, aspect="auto")
ax.set_xticks(range(len(traceability.columns)), traceability.columns, rotation=25, ha="right")
ax.set_yticks(range(len(traceability.index)), traceability.index)
for i in range(len(traceability.index)):
    for j in range(len(traceability.columns)):
        ax.text(j, i, "●" if traceability.iloc[i, j] else "-", ha="center", va="center")
ax.set_title("Tasks and Screen/API/DBTraceability")
ax.set_xlabel("Design Elements")
ax.set_ylabel("Business Items")
ax.grid(False)
plt.tight_layout()
plt.show()
Registration Screen List Screen RegistrationAPI UpdateAPI Request table History table
EquipmentID 1 1 1 0 1 0
abnormal content 1 1 1 0 1 0
priority 1 1 1 0 1 0
person in charge 0 1 0 1 1 1
Condition 0 1 0 1 1 1
Reason for Update 0 0 0 1 1 1

png

Reading the results

The reason for updating is in the history table and the update API, but there is no input screen. As it is, recording is impossible unless you use the API directly, so adding a status update dialog or similar is necessary. While this matrix does not guarantee design integrity, it helps align “where to input, where to verify, where to save, and where to view” during review.

15. No.009: Identifying System Functions from Business Workflows

Meaning in Practice

If you consider the list of functions only in the meeting room, you can skip the on-site handover, waiting, and exceptions. First, break down the current operations (As-Is) into start conditions, responsibilities, tasks, decisions, handovers, records, and exceptions. On top of that, after systemization (To-Be), we separate the decisions left by the person and the processes to be automated.

Approach to Analysis and Modeling

Separate processing time and waiting time for each process in the flow. The overall lead time is

Tlead=k(Tprocess,k+Twait,k)T_{lead}=\sum_k (T_{process,k}+T_{wait,k})

That’s right. The system can reduce not only work time but also the waiting time for information to pass from person to person.

Check with Python

workflow = pd.DataFrame({
    "Project": ["Abnormal Detection", "Contact the team leader", "Preservation Reception", "Assignment of Responsibilities", "On-site Inspection", "repair", "Completion record"],
    "Person in charge": ["worker", "worker", "squad leader", "Person responsible for preservation", "Security officer", "Security officer", "Security officer"],
    "processing_time_minutes": [2, 3, 4, 3, 10, 55, 8],
    "waiting_time_minutes": [0, 8, 12, 18, 10, 5, 25],
    "Candidate Features": ["Request Registration", "automatic notification", "List of Receptions", "Assignment of Responsibilities", "See facility history", "Treatment Records", "Completion & History Saving"],
})
workflow["lead_time_minutes"] = workflow["processing_time_minutes"] + workflow["waiting_time_minutes"]
display(workflow)

fig, ax = plt.subplots()
ax.bar(workflow["Project"], workflow["processing_time_minutes"], label="processing_time", color="#5B9BD5")
ax.bar(workflow["Project"], workflow["waiting_time_minutes"], bottom=workflow["processing_time_minutes"], label="waiting_time", color="#ED7D31")
ax.set_title("Current Business Flow Lead Time by Process (Hypothetical Observation)")
ax.set_xlabel("Project")
ax.set_ylabel("Time (minutes)")
ax.grid(axis="y", alpha=0.3)
ax.legend()
plt.xticks(rotation=25, ha="right")
plt.tight_layout()
plt.show()
Project Person in charge processing_time_minutes waiting_time_minutes Candidate Features lead_time_minutes
0 Abnormal Detection worker 2 0 Request Registration 2
1 Contact the team leader worker 3 8 automatic notification 11
2 Preservation Reception squad leader 4 12 List of Receptions 16
3 Assignment of Responsibilities Person responsible for preservation 3 18 Assignment of Responsibilities 21
4 On-site Inspection Security officer 10 10 See facility history 20
5 repair Security officer 55 5 Treatment Records 60
6 Completion record Security officer 8 25 Completion & History Saving 33

png

Reading the results

The repair itself takes the longest, but there is also a long wait for assignments and completion records. Improving repair skills requires education and standard work, but reception lists, automatic notifications, assigning tasks, and completion reminders are examples of systems that can reduce waiting times. Do not force input during emergency stops to delay safe action. Include exception flow and post-registration as requirements.

16. No.010: Designing the overall structure of a small business app

Meaning in Practice

Integrate the first 9 exercises and design the minimum utility product (MVP). Users are workers, maintenance staff, and managers. Key features include request registration, list of unhandled items, updates on responsible and status, equipment history, and downtime aggregation. The basic configuration consists of a browser, web/API server, and database, and monitoring, backup, and authentication are not considered “unnecessary because they are small.”

Approach to Analysis and Modeling

When selecting configurations, performance, availability, maintainability, security, and cost are aligned with your requirements. Here, we conduct a simple simulation of the P95 response time against the number of concurrent users to check whether the single configuration has enough capacity for test implementation. This is not a strict queue model, but rather hypothesis formation before the load test.

The expected structure is as follows.

[Factory PC/Tablet]
        │ HTTPS

[Web/APIServer] ── [Monitoring and operation logs]


[BusinessDB] ── [Daily Backup]

Check with Python

architecture = pd.DataFrame([
    ["browser", "Registration, Listing, and Updates", "Reduce input load", "Usage confirmation on shared devices"],
    ["Web/APIServer", "Certification, Business Rules, and Aggregation", "Centralizing rules", "p95_response_time"],
    ["BusinessDB", "Facilities, Requests, and History Saving", "Integrity and Traceability", "Restoration Test"],
    ["Monitoring & Logs", "Recording of Failures and Operations", "Early Detection and Auditing", "Notification Training"],
    ["backup", "Recovery in Case of Failure", "Limiting data loss", "Regular restoration"],
], columns=["Components", "Responsibility", "Objectives of the business", "Main Verification"])
display(architecture)

users = np.array([5, 10, 20, 30, 40, 50])
simulation = []
for concurrent_users in users:
    samples = 110 + 2.2 * concurrent_users + rng.gamma(2.0, 18 + concurrent_users * 0.8, 1000)
    simulation.append([concurrent_users, samples.mean(), np.quantile(samples, .95)])
capacity = pd.DataFrame(simulation, columns=["Number of concurrent users", "average_response_time_ms", "p95_response_time_ms"])
display(capacity.round(1))

fig, ax = plt.subplots()
ax.plot(capacity["Number of concurrent users"], capacity["average_response_time_ms"], marker="o", label="average")
ax.plot(capacity["Number of concurrent users"], capacity["p95_response_time_ms"], marker="o", label="p95")
ax.axhline(500, color="#C00000", linestyle="--", label="provisional goal 500ms")
ax.set_title("Simplified simulation of concurrent users and response time")
ax.set_xlabel("Number of concurrent users")
ax.set_ylabel("Response time (milliseconds)")
ax.grid(True, alpha=0.3)
ax.legend()
plt.tight_layout()
plt.show()
Components Responsibility Objectives of the business Main Verification
0 browser Registration, Listing, and Updates Reduce input load Usage confirmation on shared devices
1 Web/APIServer Certification, Business Rules, and Aggregation Centralizing rules p95response time
2 BusinessDB Facilities, Requests, and History Saving Integrity and Traceability Restoration Test
3 Monitoring & Logs Recording of Failures and Operations Early Detection and Auditing Notification Training
4 backup Recovery in Case of Failure Limiting data loss Regular restoration
Number of concurrent users average_response_time_ms p95response time_ms
0 5 165.1 224.6
1 10 185.8 261.8
2 20 219.9 307.0
3 30 259.1 374.6
4 40 298.0 441.8
5 50 336.5 500.8

png

Reading the results

Under this assumption, even with 50 people using simultaneously, the P95 will only reach less than 500 milliseconds. Therefore, a policy is to first implement a simple configuration for trial implementation, then decide on enhancement after actual measurement. However, simulations are not actual data. Before actual implementation, tests are conducted for peak operations, aggregation processing, communication outages, database failures, recovery from backups, and permission violations.

The boundaries of MVP are also important. Sensor automatic linkage, parts inventory, and predictive maintenance are future candidates, while the initial version focuses on reliably keeping the status and time of maintenance requests.

17. Practical Insights Seen Through Target Exercise

The most important thing throughout these ten is to establish the “decision we want to improve” before the technical configuration. In this case, the goal was for managers to identify equipment with long downtime, team leaders to ensure they did not overlook unhandled cases, and for maintenance staff to share history with their staff.

From the hypothetical data, the following insights can be drawn:

  • Looking at not only the average but also the P95 allows you to grasp some of the slower experiences.
  • Distinguishing between HTTP’s 4xx and 5xx allows you to separate on-site training from system modifications.
  • Items that cannot be recorded or are not used can be discovered through the screen, API, and database compatibility tables.
  • By dividing the business flow into processing and waiting, you can see where notifications and assignments can shorten the process.
  • By narrowing down the MVP range, you can quickly obtain actual measurement data and move on to your next investment decisions.

KPIs for system implementation are tracked not only by login and registration counts but also by initial response time, downtime, unresolved congestion, record completion rate, and usage retention rate. Since changes in downtime are affected by production volume and busyness, evaluations are made by aligning lines, equipment, and priorities without simply comparing before and after implementation.

kpi = requests.groupby("line").agg(
    number_of_requests=("request_id", "count"),
    median_initial_response_time_minutes=("response_min", "median"),
    total_stopping_time_hours=("downtime_min", lambda s: s.sum() / 60),
    estimated_suspension_loss_million_yen=("estimated_loss_yen", lambda s: s.sum() / 1_000_000),
).round(1)
display(kpi)

fig, ax = plt.subplots()
ax.bar(kpi.index, kpi["estimated_suspension_loss_million_yen"], color="#ED7D31")
ax.set_title("Estimated Stop Loss by Line (Fictitious Data)")
ax.set_xlabel("Line")
ax.set_ylabel("Estimated Stop Loss (million yen)")
ax.grid(axis="y", alpha=0.3)
plt.tight_layout()
plt.show()
number_of_requests Median initial response time_minutes Total stopping time_hours estimated_suspension_loss_million_yen
line
A 39 27.8 62.3 41.6
B 49 26.3 78.2 37.8
C 32 26.1 58.5 18.0

png

18. What is necessary for practical implementation

In practical implementation, to move from notebook estimation to business systems, at least the following are implemented.

  1. On-site observation and consensus building: Observe the actual operations, emergencies, outsourced repairs, and handovers of each shift, and align terminology and completion conditions.
  2. Data definition: Define equipment ID, priority, cause, status, and time, and determine the person responsible for entering it. Existing equipment ledgers will also be maintained.
  3. acceptance criteria: For example, define “High-priority unresolved cases can be checked within 3 operations” and “All status changes can be tracked.”
  4. Non-functional requirements: Decide on concurrent usage, response time, uptime, authentication, permissions, audit, retention period, backup, and recovery goals.
  5. small-scale trial: Tested with a single line or limited user to measure input time, record completion rate, initial response time, and number of inquiries.
  6. Operations Design: Manage equipment masters, conduct account inventory, notify faults, approve changes, provide training, and establish contact points.
  7. Effectiveness Verification: Preserve the baseline values before implementation and continuously evaluate them considering equipment configuration and production load.

Even in systems that rarely handle personal information, worker names and operation histories are managed as subject to management. Minimum privileges, communication encryption, password management, audit logs, and vulnerability response are included in the initial design. Furthermore, when it becomes an official record of safety and quality, we verify the requirements for electronic records in accordance with internal regulations and relevant laws.

19. Summary

From No.001 to No.010, through a single operation called equipment maintenance requests, we connected the purpose of system development to the overall structure of a small-scale app.

  • System development is an activity that integrates business, data, human decision-making, and operations
  • Business systems represent the purpose, while web apps represent the delivery method.
  • Frontend, backend, and database each have different responsibilities
  • Clients and servers exchange requests and responses over HTTP, and the API becomes the contract.
  • Reduce design omissions by making requirements, business flows, screens, APIs, and databases traceable.
  • Implement small, measure KPIs and actual usage before scaling up.

In the next exercise group, we move on to development environments and Git where these designs can be implemented and operated.

20. Consultations for Corporations

At Surikoubo, we support system development in manufacturing, including business streamlining, requirements definition, data infrastructure, visualization, and AI and mathematical optimization. From stages such as “spreadsheet files continue to grow,” “wanting to connect on-site data to improvement decisions,” and “wanting to test small and verify investment returns,” we organize the issues and implementation scope together.

📩 Contact Us: surikobo.co.jp/contact
Please feel free to consult us first.