TEKNIK — THE FOUNDATION MODULE
Everything downstream depends on this. No order, no production, no test can exist without data defined here.
Teknik is where a cable is born. Before a single meter of wire is drawn, before a customer order is placed, before a test can be assigned — someone has to define what cables the factory can produce, what machines exist, what parameters those machines accept, what standards the cables must pass, and what gets printed on them. Teknik holds all of this. It is the single source of truth that every other module reads from but never writes to.
TABLE OF CONTENTS
1. WHAT TEKNIK DOES
The Teknik module answers five questions that the entire factory depends on:
- What cables can we produce? — Cable Playground designs them. Cable Database stores the approved results. Every cable is defined as an ordered sequence of machine steps with exact parameters.
- What machines do we have? — Machine Management registers all 7 machine types with their physical capabilities (speed ranges, diameter limits, thickness ranges). The Playground uses these to validate that a design is physically producible.
- What quality standards must be met? — Standards Management defines every test (IEC-EN, UL, SLN) with parameters, pass/fail criteria, and test frequencies. These are linked to cable designs — each design knows exactly which tests it requires at which production step.
- What gets printed on the cable? — Markalama defines the ordered word arrays that the extruder prints during production (company name, standard, voltage, cross-section, etc.).
- Who operates the machines? — Operator Management maintains the registry of production operators who are assigned to sessions.
Zero dependencies. Teknik depends on no other business module. It reads only from the users table (for created_by tracking). Every other module — Sipariş, Üretim, Lab, Stok — depends on Teknik. This makes it the foundation layer of the entire system.
2. THE DATA FLOW
Data flows in one direction: from Teknik outward. Here is how each submodule feeds the rest of the system.
Define capabilities
Design cables
Store approved
Select cables
Define tests
Assign to steps
Store requirements
Execute tests
The Cable Database is the convergence point. It stores the finalized design as structured JSON: the complete production flow, every half-product that will be created, the bill of raw materials, and all test requirements. When Sipariş calculates material needs or Üretim generates work cards, they read from Cable Database — never from the Playground or Machines directly.
3. THE DATABASE LAYER
12 tables serve the Teknik module. They fall into four groups:
Machine Tables (7)
One table per machine type. Each stores the physical capabilities of that machine as min/max/increment ranges. The system generates dropdown options by stepping through these ranges.
| Table | Unique Config | Input Code |
|---|---|---|
kabatel_cekme_machines | speed, tav (anneal current), output diameter | A |
kalaylama_machines | speed, tin thickness (μm) | X |
incetel_cekme_machines | speed, input count, output diameter, tav | — |
buncher_machines | speed, hatve (lay length), input count | Z,T,U |
extruder_machines | speed, insulation thickness, sheath thickness | T,Z |
ebeam_machines | speed, radiation level (kGy) | — |
aktarma_machines | (brand/model only) | — |
Every configurable parameter has a database-level CHECK constraint: max > min, increment > 0, min ≥ 0. This means invalid machine configurations are impossible to save — the database itself enforces physical sanity.
Design Tables (3)
| Table | Purpose | Key Fields |
|---|---|---|
cable_designs | Design sessions from the Playground | design_code (unique), standard (EN/UL/SLN), cross_section, design_data (JSON) |
design_steps | Individual production steps within a design | step_number, machine_type, configuration (JSON), inputs/outputs (JSON), tests (JSON) |
cable_database | Finalized, approved cable definitions | cable_code (unique), production_flow (JSON), half_products (JSON), raw_materials (JSON), test_requirements (JSON) |
The relationship: CableDesign → many DesignStep (cascade delete) → one CableDatabase entry on finalize. The Cable Database stores everything as denormalized JSON blobs — intentionally. When the Material Calculator needs to compute copper requirements for an order, it reads one row from cable_database and has the complete production flow without any joins.
Quality Tables (2)
| Table | Purpose | Key Fields |
|---|---|---|
test_standards | Test definitions | standard_category (IEC-EN/UL/SLN), test_name, standard_number, test_samples |
test_parameters | Parameters within a test | parameter_name, parameter_unit, parameter_order, is_required |
A test standard has N parameters (cascade delete). When a test is assigned to a design step in the Playground, the standard ID and frequency (start/end/every reel) are embedded in the step’s JSON. This means the Cable Database carries the complete test map — Lab knows exactly what to test and when, without querying Teknik at production time.
Supporting Tables
| Table | Purpose |
|---|---|
product_codes | SHA-256 hashed product identifiers for stock deduplication. system_code (human-readable, e.g. BN_73X030) + spec_hash (deterministic hash of specifications). Ensures identical products across different designs share the same stock pool. |
markings | Cable printing templates. name (unique) + words (JSON array of strings). Each order-cable references a marking. |
production_operators | Operator registry. name (unique). Referenced by production sessions. |
4. THE BACKEND ARCHITECTURE
The Teknik backend is split into 6 route files mounted under /api/teknik/ and 6 utility modules that power the Playground’s simulation engine.
Route Files
| File | Prefix | Endpoints | Responsibility |
|---|---|---|---|
machine_routes.py | /teknik/machines | ~45 | CRUD + options for 7 machine types |
design_routes.py | /teknik/design | ~22 | Playground sessions, steps, config, undo/redo, finalize |
cable_database_routes.py | /teknik/cable-database | ~15 | Approved cables, product codes, analytics |
standards_routes.py | /teknik/standards | ~12 | Test standards, parameters, results |
marking_routes.py | /markings | ~6 | Marking template CRUD |
operator_routes.py | /operators | ~4 | Operator CRUD |
Playground Engine (6 utility modules)
The Cable Playground is not a simple CRUD page — it is a real-time simulation engine that runs entirely in-memory on the backend. These are the modules that make it work:
Session Manager
In-memory session storage. Each design session has a unique ID, a step counter, undo/redo stacks (max 50 states), autosave timer (default 30s), and checkpoint/restore for atomic transactions.
Progression Engine
Tracks what exists after each step. Items have codes, quantities, statuses (active/consumed). Each machine type has its own processing function that consumes inputs and produces outputs with correct codes (e.g., BN_73X030).
Form Integration
Populates frontend dropdowns from database + current progression state. Filters available inputs per machine type (e.g., Buncher only sees Z/T/U coded items). Validates quantities before configuration.
DB Integration
Reads real machine tables. Calculates capability intersection when multiple machines are selected — returns only parameter values ALL selected machines can produce.
Validation Engine
Two validators: MachineValidator checks configs against machine ranges. ProductionFlowValidator checks step sequences, parallel groups, and test assignments.
Code Generator
Deterministic product code generation. SHA-256 spec hashing for stock deduplication. Human-readable system codes (e.g., KC_18 for 1.8mm Kabatel wire). Final cable codes encode standard, cross-section, structure, and layer thicknesses.
5. THE FRONTEND
7 pages under /teknik/*, protected by the canTeknik access flag. All pages use Ant Design Pro’s ProTable with Turkish locale, client-side search, and blurred backdrop modals.
| Route | Page | Lines | Complexity |
|---|---|---|---|
| /teknik/dashboard | Dashboard | ~400 | Stats, quick actions, recent designs |
| /teknik/playground | Cable Playground | ~4,300 | SVG canvas, 6 config forms, 3 view modes, undo/redo, autosave |
| /teknik/cable-database | Cable Database | ~690 | Table + detail drawer with 3 tabs |
| /teknik/machines | Machine Management | ~730 | 7 machine tabs, dynamic forms |
| /teknik/standards | Standards | ~550 | Standards CRUD + parameter forms |
| /teknik/markalama | Markalama | ~370 | Marking templates with word arrays |
| /teknik/operator-yonetimi | Operators | ~280 | Simple name CRUD |
The Cable Playground alone accounts for more than half the frontend code. It is built as a modular component system: a usePlayground hook manages state and API calls, FlowCanvas renders the SVG diagram, MachineLibrary is the sidebar palette, ConfigurationDrawer holds 6 machine-specific forms (1,215 lines), and ProgressionPanel shows real-time material tracking.
6. THE SUBMODULES
The sections that follow document each submodule in full detail — every form field, every API endpoint, every database column, every validation rule, and the design decisions behind them. Ordered from foundational data to the tools that consume it.
Machine Management
CRUD for all 7 factory machine types. Each type has a unique configuration schema with min/max/increment ranges. The Playground reads these to validate that designs are physically producible.
Standards Management
Test standard definitions with dynamic parameters, pass/fail criteria, and test frequency rules. Linked to cable designs at the step level — the Lab module reads these to know what to test and when.
Operator Management
Production operator registry. Operators are assigned to production sessions by the person starting the session — they don’t need system logins. Simple name CRUD with uniqueness constraint.
Markalama (Cable Marking)
Marking templates define the text printed on cables during extrusion. Stored as ordered word arrays with variable support ({CABLE_SIZE}, {YEAR}, etc.). Each order-cable references a marking template.
Cable Playground
The visual cable design workshop. Drag machines onto a canvas, configure parameters, watch the production flow build in real-time. Session-based, in-memory simulation with undo/redo, autosave, and three view modes. Where all foundational data — machines, standards, operators, markings — converges into a cable design.
Cable Database
The library of approved cable designs. Each entry stores the complete production flow, half-product tree, bill of materials, and test requirements as structured JSON. The single source of truth for Orders and Production.
What follows: Each submodule above will be expanded into a full section with database schemas, complete API endpoint documentation, frontend form fields, validation rules, code snippets, and the reasoning behind key design decisions.
6.1 MACHINE MANAGEMENT
Before you can design a cable, you need to tell the system what machines the factory has. Machine Management is the registry of every physical machine on the production floor — its brand, model, and most importantly, its capability ranges. These ranges (speed min/max, diameter min/max, etc.) are used throughout the system to generate dropdown options and validate that a cable design is physically producible.
Why one table per machine type? Each machine type has fundamentally different configurable parameters. A Kabatel Çekme has tav (anneal current) and output diameter. A Buncher has hatve (lay length) and input count. An Aktarma has no parameters at all. Rather than a single table with dozens of nullable columns, each type gets its own table with exactly the columns it needs. The database CHECK constraints can then enforce physical sanity per machine type.
6.1.1 The Seven Machine Types
The factory’s production line consists of 7 machine types, each performing a specific step in the cable manufacturing process:
| # | Machine Type | Turkish Name | What It Does | Configurable Parameters |
|---|---|---|---|---|
| 1 | Kabatel Çekme | Kabatel Çekme | Draws thick copper rod (8mm filmaşin) into thinner wire | Speed (m/s), TAV (A), Output Diameter (mm) |
| 2 | Kalaylama | Kalaylama | Coats drawn wire with tin for conductivity and corrosion resistance | Speed (m/s), Tin Thickness (μm) |
| 3 | İncetel Çekme | İncetel Çekme | Draws wire to even finer diameters, optionally from multiple inputs | Speed (m/s), Input Count, Output Diameter (mm), TAV (A) |
| 4 | Buncher | Buncher | Twists multiple wires into a bundle (strand) | Speed (m/s), Hatve/Lay Length, Input Count, Twist Direction (S/Z) |
| 5 | Extruder | Ekstrüder | Applies insulation and/or sheath layers (plastic coating) | Speed (m/s), Insulation Thickness (mm), Sheath Thickness (mm) |
| 6 | E-beam | E-beam | Cross-links insulation via electron beam radiation | Speed (m/s), Radiation Level (kGy) |
| 7 | Aktarma | Aktarma | Transfers/rewinds cable between spools (no transformation) | None (brand/model only) |
6.1.2 Database Schema
7 tables, one per machine type. All share a common structure (id, brand, model, is_active, created_by, timestamps) plus type-specific parameter columns stored as min/max/increment triplets.
Common Columns (all 7 tables)
| Column | Type | Nullable | Default | Notes |
|---|---|---|---|---|
id | Integer | No | Auto | Primary key, indexed |
brand | String(100) | No | — | Machine manufacturer |
model | String(100) | Yes | NULL | Machine model designation |
is_active | Boolean | No | True | Indexed; soft-delete flag |
created_by | Integer | Yes | NULL | FK → users.id |
created_at | DateTime | No | utcnow | Creation timestamp |
updated_at | DateTime | No | utcnow | Auto-updates on change |
Kabatel Çekme — kabatel_cekme_machines
| Column | Type | Unit | CHECK Constraint |
|---|---|---|---|
speed_min | Float | m/s | ≥ 0 |
speed_max | Float | m/s | > speed_min |
speed_increment | Float | m/s | > 0 |
tav_min | Float | Ampere | ≥ 0 |
tav_max | Float | Ampere | > tav_min |
tav_increment | Float | Ampere | > 0 |
output_min | Float | mm | > 0 |
output_max | Float | mm | > output_min |
output_increment | Float | mm | > 0 |
input_type | String(50) | — | Default: '8mm_filmaşin' |
input_code | String(10) | — | Default: 'A' |
Kalaylama — kalaylama_machines
| Column | Type | Unit | CHECK Constraint |
|---|---|---|---|
speed_min | Float | m/s | ≥ 0 |
speed_max | Float | m/s | > speed_min |
speed_increment | Float | m/s | > 0 |
thickness_min | Float | μm | > 0 |
thickness_max | Float | μm | > thickness_min |
thickness_increment | Float | μm | > 0 |
input_code | String(10) | — | Default: 'X' |
İncetel Çekme — incetel_cekme_machines
| Column | Type | Unit | CHECK Constraint |
|---|---|---|---|
speed_min/max/increment | Float | m/s | Same pattern as above |
input_number_min | Integer | — | ≥ 1 |
input_number_max | Integer | — | ≥ input_number_min |
output_min/max/increment | Float | mm | Same pattern as above |
tav_min/max/increment | Float | Ampere | Same pattern as above |
Buncher — buncher_machines
| Column | Type | Unit | CHECK Constraint |
|---|---|---|---|
speed_min/max/increment | Float | m/s | Same pattern |
hatve_min | Float | mm | > 0 |
hatve_max | Float | mm | > hatve_min |
hatve_increment | Float | mm | > 0 |
input_number_min | Integer | — | ≥ 0 |
input_number_max | Integer | — | ≥ input_number_min |
accepted_input_codes | Text | — | Default: 'Z,T,U' |
Extruder — extruder_machines
| Column | Type | Unit | CHECK Constraint |
|---|---|---|---|
speed_min/max/increment | Float | m/s | Same pattern |
insulation_thickness_min | Float | mm | > 0 |
insulation_thickness_max | Float | mm | > insulation_thickness_min |
insulation_thickness_increment | Float | mm | > 0 |
sheath_thickness_min | Float | mm | > 0 |
sheath_thickness_max | Float | mm | > sheath_thickness_min |
sheath_thickness_increment | Float | mm | > 0 |
accepted_input_codes | Text | — | Default: 'T,Z' |
E-beam — ebeam_machines
| Column | Type | Unit | CHECK Constraint |
|---|---|---|---|
speed_min/max/increment | Float | m/s | Same pattern |
radiation_level_min | Float | kGy | > 0 |
radiation_level_max | Float | kGy | > radiation_level_min |
radiation_level_increment | Float | kGy | > 0 |
Aktarma — aktarma_machines
No configurable parameters. Only the common columns (brand, model, is_active, timestamps). No CHECK constraints beyond the common ones.
6.1.3 Options Generation — The Core Mechanism
This is the mechanism that makes the entire Machine Management → Playground pipeline work. When the Playground needs to show dropdown options for a machine parameter, it calls the /options endpoint, which steps through the min/max/increment range and returns every valid value.
def generate_dropdown_options(min_val, max_val, increment): options = [] current = min_val while current <= max_val: options.append(round(current, 4)) # Avoid floating point drift current += increment return options # Example: machine with speed_min=5, speed_max=25, speed_increment=5 # → [5.0, 10.0, 15.0, 20.0, 25.0]
Special cases:
- Integer ranges (İncetel Çekme & Buncher input counts): Uses
list(range(min, max + 1))instead of float stepping — because you can’t have 3.5 input wires. - Hardcoded values (Buncher twist direction): Returns
["S", "Z"]directly — these are the only two possible twist directions in cable manufacturing. - No options (Aktarma): Has no
/optionsendpoint at all — nothing to configure.
Multi-machine intersection: When the Playground selects multiple machines of the same type, the system calculates the intersection of their capability ranges. If Machine A supports speeds [5, 10, 15, 20] and Machine B supports [10, 15, 20, 25], the dropdown shows [10, 15, 20]. This lives in the Playground’s db_integration.py, not here — but it consumes the options generated by this module.
6.1.4 API Endpoints
38 total endpoints. Each machine type gets 5–6 endpoints following a consistent pattern (except Aktarma which has no /options).
Pattern per machine type (replace {type} with e.g. kabatel-cekme)
| Method | Path | Permission | What It Does |
|---|---|---|---|
GET | /teknik/machines/{type} | Authenticated | List all machines. ?active_only=true (default). Ordered by brand, model. |
GET | /teknik/machines/{type}/{id} | Authenticated | Single machine detail. Returns 404 if not found. |
GET | /teknik/machines/{type}/{id}/options | Authenticated | Generate dropdown values from min/max/increment ranges. |
POST | /teknik/machines/{type} | super_admin, production_manager | Create machine. Sets created_by. Broadcasts real-time update. |
PUT | /teknik/machines/{type}/{id} | super_admin, production_manager | Partial update. Only provided fields are changed. |
DELETE | /teknik/machines/{type}/{id} | super_admin only | Hard delete. Returns 204 No Content. |
Common endpoints
| Method | Path | What It Does |
|---|---|---|
GET | /teknik/machines/types | Returns all 7 type names as string array |
GET | /teknik/machines/all | Returns all machines of all types in one response, keyed by type name |
Options response shapes per type
| Machine Type | Options Fields |
|---|---|
| Kabatel Çekme | speeds, tavs, output_diameters |
| Kalaylama | speeds, thicknesses |
| İncetel Çekme | speeds, input_numbers (int), output_diameters, tavs |
| Buncher | speeds, hatves, input_numbers (int), twist_directions (hardcoded S/Z) |
| Extruder | speeds, insulation_thicknesses, sheath_thicknesses |
| E-beam | speeds, radiation_levels |
| Aktarma | — (no options endpoint) |
6.1.5 Permission Model
Uses check_permission_smart() which supports both the legacy user_type system and the granular permission system:
| Action | Legacy Roles | Granular Permission |
|---|---|---|
| View / List / Options | Any authenticated user | Any authenticated user |
| Create / Update | super_admin, production_manager | teknik.machines.create / teknik.machines.edit |
| Delete | super_admin only | teknik.machines.delete |
6.1.6 Frontend — The Machines Page
Single file: pages/Teknik/Machines/index.tsx (726 lines). Route: /teknik/machines, protected by canTeknik access flag.
Page Structure
A PageContainer wrapping a Card with 7 Tabs — one per machine type. Switching tabs fetches the machine list for that type and resets the search text. Default tab: Kabatel Çekme.
Table Columns
Every tab shows a ProTable with these base columns plus type-specific ones:
| Column | Width | Notes |
|---|---|---|
| ID | 60px | Fixed left |
| Marka (Brand) | auto | Ellipsis enabled |
| Model | auto | Shows “-” if empty |
| Type-specific ranges | auto | Formatted as “min–max unit” |
| Durum (Status) | 80px | Green “Aktif” / Red “Pasif” tag |
| İşlemler (Actions) | 100px | Fixed right; edit + delete icons |
Type-specific columns:
- Kabatel Çekme: Hız Aralığı (speed_min–speed_max m/s), Tav Aralığı (tav_min–tav_max A), Çıkış Çapı (output_min–output_max mm)
- Kalaylama: Hız Aralığı, Kalay Kalınlığı (thickness_min–thickness_max μm)
- İncetel Çekme: Girdi Sayısı (input_number_min–max), Çıkış Çapı, Tav Aralığı
- Buncher: Girdi Sayısı, Hatve Aralığı (hatve_min–max)
- Extruder: İzolasyon Kalınlığı (insulation min–max mm), Kılıf Kalınlığı (sheath min–max mm)
- E-beam: Hız Aralığı, Radyasyon Seviyesi (radiation_level_min–max kGy)
- Aktarma: Base columns only
Search & Pagination
Search is client-side: a text input filters the loaded list by ID, brand, model, or status (“aktif”/“pasif”). No server-side search needed because machine counts are small (typically <50 per type).
Pagination defaults to 10 rows, with options [10, 20, 50, 100]. Total shown as “X-Y / Z kayıt”.
CRUD Flow
Create:
- Click “Yeni Makine Ekle” button in the toolbar
- Modal opens with title “Yeni Makine Ekle” (600px, blurred backdrop)
- Form shows fields dynamically based on active tab (machine type)
- On submit:
POST /api/teknik/machines/{type}with form values - System fields (
id,created_at,updated_at,created_by,input_type,input_code,accepted_input_codes) are automatically excluded - On success: toast “Makine başarıyla eklendi!”, close modal, refresh list
Edit:
- Click edit icon in the Actions column
- Modal opens with title “Makine Düzenle”, pre-filled with current values
- On submit:
PUT /api/teknik/machines/{type}/{id}with changed fields only - On success: toast “Makine başarıyla güncellendi!”, close modal, refresh list
Delete:
- Click delete icon in the Actions column
Popconfirmasks: “Bu makineyi devre dışı bırakmak istediğinize emin misiniz?”- Delete button is disabled if machine is already inactive
- On confirm:
DELETE /api/teknik/machines/{type}/{id} - On success: toast “Makine devre dışı bırakıldı!”, refresh list
Form Fields Per Machine Type
The form renders dynamically via renderFormFields() based on the active tab. Common fields (Marka, Model) appear for all types. Type-specific fields use InputNumber with appropriate min, step, and Turkish labels:
| Machine Type | Form Fields (beyond Marka/Model) |
|---|---|
| Kabatel Çekme | Hız: min (0), max (0.1), increment (0.1) • Tav: min (0), max (1), increment (1) • Çıkış Çapı: min/max/increment (all step 0.01) |
| Kalaylama | Hız: min/max/increment • Kalay Kalınlığı: min/max/increment (step 0.1) |
| İncetel Çekme | Girdi Sayısı: min (1), max (1) • Hız: min/max/increment • Çıkış Çapı: min/max/increment (step 0.01) • Tav: min/max/increment |
| Buncher | Girdi Sayısı: min (0), max (1) • Hız: min/max/increment • Hatve: min/max/increment (step 0.1) |
| Extruder | Hız: min/max/increment • İzolasyon Kalınlığı: min/max/increment (step 0.01) • Kılıf Kalınlığı: min/max/increment (step 0.01) |
| E-beam | Hız: min/max/increment • Radyasyon Seviyesi: min/max, increment (step 1) |
| Aktarma | None (Marka/Model only) |
6.1.7 Service Layer (Frontend)
API calls are wrapped in services/teknik/index.ts with a URL transformation: underscores in the machine type name are replaced with hyphens for the URL path.
// kabatel_cekme → kabatel-cekme in URL export async function getMachines(type: MachineType) { return request(`/api/teknik/machines/${type.replace('_', '-')}`); } export async function createMachine(type: MachineType, data: any) { return request(`/api/teknik/machines/${type.replace('_', '-')}`, { method: 'POST', data }); } // Same pattern for updateMachine (PUT), deleteMachine (DELETE) // getMachineDropdown calls /{id}/dropdown for Playground use
6.1.8 How It Connects to Other Submodules
→ Cable Playground (6.5)
The primary consumer. When you add a machine to the canvas and configure it, the Playground calls the /options endpoint to populate dropdowns. When multiple machines are selected, it reads all their ranges and calculates the intersection — only showing parameter values all selected machines can physically produce.
→ Cable Database (6.6)
Indirect. Machine IDs are stored in each DesignStep’s machine_ids field. The Cable Database stores the finalized design including which specific machines were used, so Production knows which physical machine to assign each step to.
→ Üretim (Production Module)
When a work card is generated, the production system reads which machines a cable design requires. Machine IDs stored in the design map directly to the registry maintained here.
Design principle: Machine Management is a pure data provider. It knows nothing about designs, orders, or production. It only answers the question “what can this machine do?” — everything else is the consumer’s responsibility. This keeps the module simple (~726 lines frontend, ~38 endpoints) and makes it the most stable part of the Teknik subsystem.
6.2 STANDARDS MANAGEMENT
Every cable sold must pass a set of quality tests defined by international standards bodies (IEC, CENELEC) or the customer. Standards Management is where those tests are defined — what to measure, how many samples, with which parameters, and what the reference standard number is. These definitions are then embedded into cable designs so that the Lab module knows exactly what to test and when during production.
Three layers of quality: IEC-EN covers European harmonized standards (EN 50618, IEC 60228). UL covers American standards (UL 4703, UL 854). SLN covers Solen’s own internal tests — company-specific checks that go beyond what the standards require. When a cable design is created in the Playground, only tests matching the design’s standard category are shown.
6.2.1 Data Model
Three tables work together: standards define what to test, parameters define what to measure within each test, and results store the actual measurements from production.
test_standards
| Column | Type | Nullable | Constraints / Default | Notes |
|---|---|---|---|---|
id | Integer | No | PK, indexed | — |
standard_category | String(50) | No | CHECK: IN (‘IEC-EN’, ‘UL’, ‘SLN’) | Which standards body |
test_name | String(200) | No | — | Turkish test name |
test_name_en | String(200) | Yes | — | English test name |
standard_number | String(100) | Yes | — | e.g. “EN 50618”, “IEC 60228” |
test_type | String(100) | Yes | — | Free-form: Mekanik, Elektriksel, Görsel, Boyutsal |
unit | String(50) | Yes | — | e.g. “ohm/km”, “kV”, “N/mm²” |
number_of_values | Integer | No | Default: 1, CHECK: ≥ 1 | How many values per measurement |
test_samples | Integer | No | Default: 1, CHECK: ≥ 1 | How many samples to test |
test_method | Text | Yes | — | Free-text test procedure description |
is_active | Boolean | No | Default: True, indexed | Soft-delete flag |
created_by | Integer | Yes | FK → users.id | — |
created_at | DateTime | No | utcnow | — |
updated_at | DateTime | No | utcnow, auto-updates | — |
Unique constraint: (standard_category, test_name, standard_number) — prevents duplicate test definitions within the same standards body.
test_parameters
| Column | Type | Nullable | Constraints / Default | Notes |
|---|---|---|---|---|
id | Integer | No | PK, indexed | — |
test_standard_id | Integer | No | FK → test_standards.id, ON DELETE CASCADE | — |
parameter_name | String(100) | No | — | e.g. “Çekme Dayanımı”, “Uzama”, “Direnç” |
parameter_unit | String(50) | Yes | — | e.g. “N/mm²”, “%”, “ohm/km” |
parameter_order | Integer | No | Default: 1 | Display order in forms |
is_required | Boolean | No | Default: True | Must be filled during testing |
created_at | DateTime | No | utcnow | — |
Unique constraint: (test_standard_id, parameter_name) — no duplicate parameter names within a single test.
test_results
| Column | Type | Nullable | Constraints / Default | Notes |
|---|---|---|---|---|
id | Integer | No | PK, indexed | — |
test_standard_id | Integer | No | FK → test_standards.id | Which test was performed |
design_step_id | Integer | Yes | FK → design_steps.id | Links result to specific production step |
production_session_id | Integer | Yes | — | Links to production session |
cable_batch_code | String(50) | Yes | Indexed | Batch identifier for traceability |
test_date | DateTime | No | — | When the test was performed |
tested_by | Integer | No | FK → users.id | Who performed the test |
measurements | Text | No | — | JSON string of measurement data |
pass_fail | String(10) | Yes | CHECK: IN (‘PASS’, ‘FAIL’, ‘PENDING’) OR NULL | Test outcome |
notes | Text | Yes | — | Appended with timestamps by status updates |
created_at | DateTime | No | utcnow | — |
Measurement storage: The measurements column stores a JSON array. Each entry is a MeasurementData object with parameter (name), values (float array), optional unit, and optional per-parameter result. The model has helper methods: get_measurements() parses the JSON, set_measurements() serializes it, and evaluate_result() returns PASS/FAIL/PENDING based on whether all required parameters have values.
6.2.2 Relationships
cascade delete
no cascade
Delete behavior is smart: if a standard has test results, it is soft deleted (is_active = false) to preserve result traceability. If it has no results, it is hard deleted. Parameters always cascade — deleting a standard removes all its parameters.
6.2.3 API Endpoints
12 endpoints organized into three groups: standards CRUD, parameter management, and test results.
Test Standards
| Method | Path | Permission | What It Does |
|---|---|---|---|
POST | /teknik/tests | super_admin, lab_user, production_manager | Create standard + parameters in one transaction. Checks for duplicate (category + name + number). Flushes DB to get ID before adding parameters. |
GET | /teknik/tests | Authenticated | List all. ?category=IEC-EN, ?active_only=true (default), ?search=tensile. Eager-loads parameters. Orders by category then name. |
GET | /teknik/tests/{id} | Authenticated | Single standard detail. |
GET | /teknik/tests/{id}/full | Authenticated | Full standard with sorted parameters + has_parameters flag. Used by Playground for dynamic form generation. |
PUT | /teknik/tests/{id} | super_admin, lab_user, production_manager | Update standard. If parameters provided: deletes all existing, creates new ones (full replacement). |
DELETE | /teknik/tests/{id} | super_admin, lab_user | Smart delete: soft if has results, hard if no results. |
Test Parameters
| Method | Path | Permission | What It Does |
|---|---|---|---|
POST | /teknik/tests/{id}/parameters | super_admin, lab_user, production_manager | Add single parameter to existing standard. Checks duplicate name. |
DELETE | /teknik/parameters/{id} | super_admin, lab_user | Hard delete single parameter. |
Test Results
| Method | Path | Permission | What It Does |
|---|---|---|---|
POST | /teknik/results | lab_user, super_admin | Create result with measurements JSON. Auto-sets tested_by. Calls evaluate_result() for initial pass/fail. |
GET | /teknik/results | Authenticated | List results. Filter by ?batch_code, ?test_standard_id, ?pass_fail. Limit: 1–200, default 50. Ordered by test_date DESC. |
GET | /teknik/results/{id} | Authenticated | Single result with tester name and standard info. |
PUT | /teknik/results/{id}/status | lab_user, super_admin | Update pass/fail status. Appends notes with timestamp and username for audit trail. |
Reference Data
| Method | Path | Returns |
|---|---|---|
GET | /teknik/categories | ["IEC-EN", "UL", "SLN"] |
GET | /teknik/frequencies | ["üretim_başı", "üretim_sonu", "her_ikisi", "her_makara_sonu"] |
GET | /teknik/result-statuses | ["PASS", "FAIL", "PENDING"] |
6.2.4 Test Frequencies — When Tests Run
When a test is assigned to a cable design step in the Playground, the user selects a frequency that tells the Lab when to execute the test during production:
| Frequency | Turkish | Meaning |
|---|---|---|
üretim_başı | Üretim Başı | Test at the start of the production run |
üretim_sonu | Üretim Sonu | Test at the end of the production run |
her_ikisi | Her İkisi | Test at both start and end |
her_makara_sonu | Her Makara Sonu | Test at the end of every reel (most frequent) |
6.2.5 How Standards Connect to Cable Designs
This is the critical integration point. When the Playground configures a machine step, tests are fetched and filtered by the design’s standard category:
# In db_integration.py — fetches tests matching the design's standard def get_tests_by_standard(db, standard): # Maps frontend code to database category category_map = {'EN': 'IEC-EN', 'UL': 'UL', 'SLN': 'SLN'} category = category_map.get(standard, standard) standards = db.query(TestStandard).filter( TestStandard.standard_category == category, TestStandard.is_active == True ).all() return [{'id': s.id, 'test_name': s.test_name, ...} for s in standards]
When a design is finalized, the assigned tests are stored as a JSON array in cable_database.test_requirements:
# Storage format in cable_database.test_requirements [ { "step": 3, "machine_type": "extruder", "test_id": 12, "test_name": "Çekme Dayanımı", "standard_number": "EN 50618", "frequency": "her_ikisi" } ]
Denormalized by design: Test names and standard numbers are copied into the Cable Database JSON, not just referenced by ID. This means if a test standard is later renamed or deactivated, existing cable designs retain their original test requirements. The Lab reads from Cable Database at production time — it never needs to query the Standards table to know what to test.
6.2.6 Permission Model
| Action | Legacy Roles | Granular Permission |
|---|---|---|
| View / List / Search | Any authenticated user | Any authenticated user |
| Create / Update | super_admin, lab_user, production_manager | teknik.standards.create / teknik.standards.edit |
| Delete | super_admin, lab_user | teknik.standards.delete |
| Create / Update Results | lab_user, super_admin | teknik.standards.create |
Note: lab_user has wider access here than in Machine Management — this is intentional because lab personnel are the primary users of the standards system.
6.2.7 Frontend — Standards Page
Single file: pages/Teknik/Standards/index.tsx (553 lines). Route: /teknik/standards.
Page Structure
PageContainer with a ProTable and a modal for create/edit. No tabs — all standards shown in one table, category distinguished by color-coded tags.
Table Columns (9)
| Column | Width | Notes |
|---|---|---|
| ID | 60px | Fixed left |
| Kategori | 100px | Color-coded tag: IEC-EN blue, UL green, SLN orange |
| Test Adı | auto | Turkish test name, ellipsis |
| Standart No | 150px | e.g. “EN 50618” |
| Test Tipi | 120px | Shows “-” if empty |
| Numune Sayısı | 100px | Centered integer |
| Parametre | 100px | Shows parameter count (e.g. “3”) |
| Durum | 80px | Green “Aktif” / Red “Pasif” |
| İşlemler | 100px | Fixed right; edit + delete icons |
Create/Edit Modal (800px, blurred backdrop)
The modal contains 7 form fields plus a dynamic parameter list:
| Field | Type | Required | Notes |
|---|---|---|---|
| Standart Kategorisi | Select | Yes | Options: IEC-EN, UL, SLN (Özel) |
| Test Adı (TR) | Input | Yes | Placeholder: “Örn: Çekme Dayanımı” |
| Test Adı (EN) | Input | No | Placeholder: “Örn: Tensile Strength” |
| Standart Numarası | Input | Yes | Placeholder: “Örn: EN 50618” |
| Test Tipi | Select | No | Options: Mekanik, Elektriksel, Görsel, Boyutsal |
| Numune Sayısı | InputNumber | No | Min: 1 |
| Test Metodu | TextArea | No | 3 rows, procedure description |
Parameter Management (inside modal)
Below a “Test Parametreleri” divider, each parameter is rendered as a small Card with two fields:
- Parametre Adı — Input, placeholder “Parametre Adı (örn: Çekme Dayanımı, Uzama, Direnç)”
- Birim — Input, placeholder “Birim (örn: N/mm², %, ohm/km)”
“Parametre Ekle” button (dashed, full-width) adds a new empty parameter card. Each card has a delete button in the header. Order is auto-assigned sequentially. On update, all existing parameters are replaced with the new set (delete all + create new).
CRUD Flow
Create: Click “Yeni Test Standardı” → Modal opens → Fill category, name, standard number → Optionally add parameters → Click “Ekle” → POST /api/teknik/standards/tests → Toast “Test standardı başarıyla eklendi!” → Modal closes, list refreshes.
Edit: Click edit icon → Modal opens pre-filled → Modify fields/parameters → Click “Güncelle” → PUT /api/teknik/standards/tests/{id} → Toast “Test standardı başarıyla güncellendi!” → Modal closes, list refreshes.
Delete: Click delete icon → Popconfirm “Bu standardı devre dışı bırakmak istediğinize emin misiniz?” → DELETE /api/teknik/standards/tests/{id} → Toast “Test standardı devre dışı bırakıldı!” → List refreshes. Delete button disabled for already-inactive standards.
Search & Pagination
Search is client-side (200px rounded input). Searches across ID, category, test name, standard number, test type, sample count, and status (aktif/pasif). Pagination defaults to 10 rows with [10, 20, 50, 100] options. Sorted by ID descending (newest first).
6.2.8 How It Connects to Other Submodules
→ Cable Playground (6.5)
Every machine form in the Playground includes an available_tests section populated via get_tests_by_standard(). Users assign tests to steps with a frequency. The Playground’s form integration reads from Standards but never writes to it.
→ Cable Database (6.6)
Finalized designs store test_requirements as denormalized JSON — test IDs, names, standard numbers, and frequencies copied at finalization time. This snapshot ensures immutability.
→ Lab Module
During production, the Lab reads test requirements from Cable Database and creates TestResult records linked to the standard. Lab users fill measurements and set pass/fail status with timestamped notes for audit trail.
Design principle: Standards are defined once, embedded into designs by value (not by reference), and tested during production. The three-table structure (standard → parameters → results) separates definition from execution. Standards Management never touches production data — it only answers “what should be tested?”, leaving “what was the result?” to the Lab module.
6.3 OPERATOR MANAGEMENT
Production operators are the people running the machines on the factory floor. They don’t need system logins — they are simply names in a registry that get assigned to production sessions when someone starts a manufacturing run. This is the simplest submodule in Teknik (284 lines of frontend, 4 endpoints), but its data appears in every production session, every work card, and every half-product record.
Two kinds of “operator” in the system: ProductionOperator (this submodule) is a simple name registry — no login, no password, no permissions. The separate Operator model in the User system extends user accounts for operator-type users who log into the system. When an operator starts a production session, they select their own name from the ProductionOperator registry. The work card they’re producing was planned earlier by a production manager via the planning module.
6.3.1 Database Schema
production_operators
| Column | Type | Nullable | Constraints / Default | Notes |
|---|---|---|---|---|
id | Integer | No | PK, indexed | — |
name | String(100) | No | UNIQUE | Operator’s full name |
is_active | Boolean | No | Default: True | Active status flag |
created_at | DateTime | No | utcnow | — |
updated_at | DateTime | No | utcnow, auto-updates | — |
That’s the entire table. Five columns. No foreign keys, no relationships, no JSON blobs. The UNIQUE constraint on name is the only business rule — you can’t have two operators with the same name.
No relationships defined. The ProductionOperator model has zero SQLAlchemy relationships. Production sessions reference operators by storing the operator_name as a denormalized string — not a foreign key. This means deleting an operator doesn’t cascade to sessions, but it also means old session records always retain the correct operator name even if the operator is later removed.
6.3.2 API Endpoints
4 endpoints under /operators. Notably, there are no role checks beyond authentication — any logged-in user can manage operators. No Pydantic schemas either; the routes accept and return raw dictionaries.
| Method | Path | Permission | What It Does |
|---|---|---|---|
GET | /operators/list | Authenticated | List all operators. ?active_only=true (default). Ordered by name ascending. Returns array + total count. |
POST | /operators/create | Authenticated | Create operator. Trims name, checks empty, checks duplicate. Sets is_active=true. |
PUT | /operators/{id} | Authenticated | Update operator name. Checks exists, checks empty, checks duplicate (excluding self). |
DELETE | /operators/{id} | Authenticated | Hard delete. No cascade check. May fail if referenced by production sessions. |
Validation Details
| Check | When | Error Message (Turkish) |
|---|---|---|
| Name empty | Create / Update | “Operatör adı gerekli” |
| Name duplicate | Create | “‘{name}’ adında operatör zaten mevcut” |
| Name duplicate (excl. self) | Update | “‘{name}’ adında başka operatör zaten mevcut” |
| Not found | Update / Delete | “Operatör bulunamadı” |
6.3.3 How Operators Are Used in Production
This is where the simple name registry becomes critical. When a production session starts, the operator is assigned and their name is stored directly in the session record:
# In production_routes.py — starting a production session if request.operator_id: prod_operator = db.query(ProductionOperator).filter( ProductionOperator.id == request.operator_id ).first() if prod_operator: operator_name = prod_operator.name # Stored in production_sessions table: # operator_id → current_user.id (FK to users, for DB integrity) # operator_name → prod_operator.name (denormalized, for history)
The Dual Storage Pattern
Production sessions store operator information in two ways:
| Column | Points To | Purpose |
|---|---|---|
operator_id | FK → users.id | Database integrity (the user who started the session) |
operator_name | String (denormalized) | The production operator running the machine (from this registry) |
This separation exists because the system tracks both who is logged in (the user account, stored as operator_id FK) and which production operator is physically running the machine (the name from this registry, stored as operator_name). The operator selects their own name from a dropdown when starting a production session for a work card that was pre-planned by the production manager.
Operator in the Production Lifecycle
Names defined here
Select operator
Name stored in session
Preserved forever
- Session Start: Production page fetches operators with
GET /operators/list?active_only=true. The operator selects their own name from the dropdown before starting a pre-planned work card. Required to start. - Mid-Session Change: Operators can be swapped during a session via
POST /production/update-operator— useful for shift changes. - Half-Product Tracking: Stock pages enrich half-product records with
operator_namefrom the production session that created them. - History: Production history pages show operator name for every completed session.
6.3.4 Frontend — Operator Page
Single file: pages/Teknik/OperatorYonetimi/index.tsx (284 lines). Route: /teknik/operator-yonetimi. The smallest page in the entire Teknik module.
Table Columns (3)
| Column | Width | Notes |
|---|---|---|
| ID | 80px | Fixed left |
| Operatör Adı | auto | Ellipsis enabled |
| İşlemler | 100px | Fixed right; edit + delete icons |
No status column, no timestamps. Just the name. The is_active and created_at/updated_at fields exist in the data interface but are not displayed.
Create/Edit Modal (400px, blurred backdrop)
One field:
| Field | Type | Required | Notes |
|---|---|---|---|
| Operatör Adı | Input (large) | Yes | Placeholder: “Operatör adını girin” |
CRUD Flow
Create: Click “Yeni Operatör” → Modal (400px) → Enter name → Click “Oluştur” → POST /api/operators/create → Toast “Operatör oluşturuldu” → Modal closes, list refreshes.
Edit: Click edit icon → Modal pre-filled → Change name → Click “Güncelle” → PUT /api/operators/{id} → Toast “Operatör güncellendi” → Modal closes, list refreshes.
Delete: Click delete icon → Popconfirm “Operatörü silmek istediğinize emin misiniz?” → DELETE /api/operators/{id} → Toast “Operatör silindi” → List refreshes.
Search & Pagination
Search is client-side (200px input). Filters by name and ID (case-insensitive). Pagination defaults to 20 rows (higher than other pages, since the operator list is short), with [10, 20, 50, 100] options.
How Operators Appear in Production Pages
Production pages (KabatelÇekme, Kalaylama, etc.) show operator selection in two states:
- Before session: A
Selectdropdown withUserOutlinedicon, placeholder “Operatör seçin”, populated fromGET /operators/list?active_only=true. Required to enable the “Üretime Başla” button. - During session: A card showing the current operator name with a “Değiştir” button that opens a modal listing all operators as clickable cards for mid-session changes.
6.3.5 How It Connects to Other Submodules
→ Üretim (Production Module)
Primary consumer. Every production session requires an operator. The name is stored denormalized in the session record. Operators can be changed mid-session for shift handoffs. Production history displays operator per session.
→ Stok (Stock Module)
Half-product records trace back to the production session that created them. Stock pages resolve session.operator_name to show which operator produced each item — full production traceability.
Design principle: Radical simplicity. One table, one field that matters (name), four endpoints, no role checks beyond authentication. The complexity lives in how production consumes this data — the dual storage pattern (FK for integrity, name for history) is the clever part. An operator’s name is entered once into the registry, and from then on they simply pick it from a dropdown each time they start a production session — that name then follows every meter of cable they produce.
6.4 Markalama (Cable Marking)
Every meter of cable that leaves the factory has text physically printed on its sheath — company name, standard, voltage rating, cross-section, production year. Markalama is the submodule that manages these marking templates: ordered arrays of words/segments that the extruder machine prints during cable production.
What a marking template is: Not a single string, but an ordered JSON array of words. Each word is printed sequentially on the cable during extrusion, repeating along the cable’s entire length. Words can include dynamic variables ({CABLE_SIZE}, {ORDER_NO}, {YEAR}, {METER}) that are resolved at production time. Example: ["SOLEN BEAM", "TUV RHEINLAND", "H07V-K", "{CABLE_SIZE}", "{YEAR}"] → prints SOLEN BEAM · TUV RHEINLAND · H07V-K · 4mm² · 2025 repeating along the cable.
6.4.1 Database Schema
One table. Minimal design.
| Column | Type | Constraints | Purpose |
|---|---|---|---|
id | Integer | PK, auto-increment, indexed | Unique identifier |
name | String(200) | UNIQUE, NOT NULL, indexed | Template name (e.g. “SOLEN BEAM Standard”) |
words | JSON | NOT NULL | Ordered array of strings — the words printed on the cable |
is_active | Boolean | NOT NULL, default true | Soft delete flag. Inactive markings hidden from order dropdowns. |
created_at | DateTime(tz) | server default now() | Creation timestamp |
updated_at | DateTime(tz) | on update now() | Last modification timestamp |
JSON storage for words: The words column stores a JSON array (e.g. ["SOLEN BEAM", "TUV RHEINLAND", "H07V-K"]). The backend handles both native JSON and string-encoded JSON — the list endpoint explicitly parses: json.loads(m.words) if isinstance(m.words, str) else m.words. This dual handling ensures robustness regardless of how the database driver serializes the column.
Key Constraints
- UNIQUE name: No two marking templates can share the same name. Enforced at both database level (unique index) and application level (duplicate check before create/update).
- No foreign keys: The
markingstable has no FKs. Instead,order_cables.marking_idin the Sipariş module references this table. The relationship is consumer-side, not defined here.
6.4.2 API Endpoints
Six endpoints under /api/teknik/markings:
| Method | Path | Permission | What It Does |
|---|---|---|---|
POST | /markings/create | super_admin + teknik.markalama.create_marking | Create template. Checks duplicate name. Stores name + words array. |
GET | /markings/list | Authenticated | List all. ?active_only=true (default), ?search=solen (name ilike). Ordered by name. Parses JSON words. |
GET | /markings/{id} | Authenticated | Single marking by ID. |
PUT | /markings/{id} | super_admin + teknik.markalama.update_marking | Partial update. If name changes, checks for conflicts. Only provided fields are modified. |
DELETE | /markings/{id}/hard-delete | super_admin + teknik.markalama.delete_marking | Permanent delete. No soft delete on this endpoint. |
PUT | /markings/{id}/toggle-status | Authenticated | Flip is_active between true/false. No permission check beyond auth. |
Validation Details
| Check | Where | Details |
|---|---|---|
| Name required | Schema (min_length=1) | Pydantic rejects empty strings |
| Name max length | Schema + DB | max_length=200 in Pydantic, String(200) in SQLAlchemy |
| Words non-empty | Schema validator | Custom @validator('words') ensures len(v) > 0 |
| Duplicate name | Route handler | Queries DB before create. On update, excludes self (Marking.id != marking_id) |
| Exists check | Route handler | 404 if marking not found on get/update/delete |
Delete Behavior
The delete endpoint is hard delete (db.delete(marking)). Unlike Standards Management, there is no smart delete logic. If a marking is referenced by existing orders, those orders retain the marking_id integer but the marking record is gone. The safer workflow is to toggle status to inactive using the /toggle-status endpoint, which hides the marking from new orders while keeping the record intact for historical lookups.
6.4.3 Pydantic Schemas
| Schema | Fields | Used By |
|---|---|---|
MarkingCreateRequest | name: str, words: List[str] (min 1 item) | POST create |
MarkingUpdateRequest | name?: str, words?: List[str], is_active?: bool | PUT update (all optional for partial) |
MarkingResponse | id, name, words, is_active, created_at, updated_at | All responses |
MarkingListResponse | success: bool, data: List[MarkingResponse], message: str | Defined but not used (list returns raw array) |
Unused wrapper: MarkingListResponse is defined in schemas but the /list endpoint returns a raw array, not the wrapper. The endpoint manually constructs dictionaries with parsed JSON words instead of using the Pydantic response_model. This is a pragmatic choice to handle the JSON string/native dual format.
6.4.4 Dynamic Variables
Marking words support four runtime variables that get resolved during production:
| Variable | Resolves To | Example |
|---|---|---|
{CABLE_SIZE} | Cable cross-section from order | 4mm² |
{ORDER_NO} | Order number | SLN-2025-0042 |
{YEAR} | Production year | 2025 |
{METER} | Running meter mark on cable | 150 |
Variable resolution happens at the production/extrusion layer, not in this submodule. Markalama just stores the templates with placeholder syntax. The frontend displays these as helper text in the form: “Değişkenler: {CABLE_SIZE}, {ORDER_NO}, {YEAR}, {METER}”.
6.4.5 Permission Model
| Action | Role Check | Permission Key |
|---|---|---|
| View / List / Search | Any authenticated user | Any authenticated user |
| Create | super_admin | teknik.markalama.create_marking |
| Update | super_admin | teknik.markalama.update_marking |
| Delete | super_admin | teknik.markalama.delete_marking |
| Toggle Status | Any authenticated user | No additional check |
Unlike Machines (which allow production_manager) or Standards (which allow lab_user), Markalama write operations are restricted to super_admin only. The check_permission_smart function validates both the role and the granular permission key. The toggle-status endpoint is an exception — any authenticated user can activate/deactivate a marking.
Permission Manifest (Frontend)
The frontend permission system defines 5 buttons for the Markalama page:
access_page— Can view the Markalama pageview_markings— Can see the marking listcreate_marking— Can add new markingsedit_marking— Can edit existing markingsdelete_marking— Can permanently delete markings (critical)
6.4.6 Frontend — Page Structure
Single file: src/pages/Teknik/Markalama/index.tsx (374 lines). Route: /teknik/markalama.
PageContainer
Ant Design Pro wrapper with title “Markalama”.
ProTable
Main data table. Fetches from /api/teknik/markings/list with active_only=false (shows all, including inactive). Client-side search and pagination.
Modal (700px)
Create/edit form. Contains name input + dynamic word list (Form.List). Blur-on-backdrop effect.
Table Columns (4)
| # | Column | Width | Features |
|---|---|---|---|
| 1 | İsim (Name) | 250px | Fixed left. Sortable (localeCompare). Primary identifier. |
| 2 | Kelime Sayısı (Word Count) | 120px | Computed: parses words JSON/array, returns .length. Not the words themselves. |
| 3 | Durum (Status) | 100px | Green <Tag> for Aktif, red for Pasif. |
| 4 | İşlemler (Actions) | 100px | Fixed right. Edit button + Delete with Popconfirm (“Are you sure?”). |
Create/Edit Modal
The modal has two form sections:
1. Name Field
<Input>with placeholder “ör: SOLEN BEAM Standard”- Required validation
2. Words (Dynamic List)
- Uses Ant Design
<Form.List>for dynamic add/remove - Each word is a numbered row:
1.,2.,3.… with a 550px-wide input - Minimum 1 word enforced by custom validator
- Red
<MinusCircleOutlined>to remove a word (hidden when only 1 word remains) - Dashed “Kelime Ekle” (Add Word) button at bottom to append new rows
- On create, starts with one empty word slot
- On edit, pre-populates all existing words
- Variable hint text shown in the label: “Değişkenler: {CABLE_SIZE}, {ORDER_NO}, {YEAR}, {METER}”
CRUD Flow
Search & Pagination
Search is client-side (200px rounded input). Filters on name, status text (aktif/pasif), and word count number. Pagination defaults to 10 rows, options [10, 20, 50, 100]. Shows “X-Y / Z kayıt” total.
6.4.7 How Markings Flow Through the System
Markalama templates are reference data. They are created once in the Teknik module and then consumed at two critical points in the order-to-production pipeline:
Step 1: Order Creation (Sipariş Module)
In the order creation form, each cable entry has a “Markalama” dropdown (searchable <Select>). It shows only active markings. The user picks one, and the marking_id is stored in order_cables.marking_id (integer FK). Marking selection is required for a cable to be considered “complete” in the order form.
// Order form cable completion check (SiparisOlustur/index.tsx) const isComplete = hasDesign && hasMeters && hasMakara && hasMarking && hasPrice && hasCurrency && materialsComplete;
Step 2: Work Card Generation & Production Planning
When an order is confirmed and work cards are generated:
The work_card_generator.py service resolves each cable’s marking_id to the actual marking name by querying the Marking table. Both marking_id and marking_name are embedded in the extruder work card’s material_details JSON:
# work_card_generator.py — extruder material_details { 'marking_id': cable_data.get('marking_id'), # Integer FK 'marking_name': cable_data.get('marking_name'), # Resolved text 'tests': ex_tests, 'breakdown': [], ... }
Step 3: Production Planning Display
The Production Planning page reads the extruder work card’s material_details and displays the marking name in the card UI:
// Production/Planning/index.tsx
{materialDetails.marking_name && (
<div>
<div style={{ fontSize: 10, fontWeight: 600 }}>Markalama</div>
<div style={{ fontSize: 11 }}>{materialDetails.marking_name}</div>
</div>
)}
Step 4: Order Detail View
When viewing an existing order, the detail page shows the marking. The order_routes.py endpoint resolves marking_id to the name at query time:
# order_routes.py — marking resolution marking_name = None if cable.marking_id: marking = db.query(Marking).filter(Marking.id == cable.marking_id).first() marking_name = marking.name if marking else None
This pattern appears twice in order_routes.py: once for the single order detail endpoint, and once for the work card generation data extraction.
6.4.8 Data Storage Pattern — ID vs Name
Dual storage in consumption: Like the Operator dual storage pattern (6.3), markings use a hybrid approach — but split across different storage locations. The order_cables table stores only marking_id (integer). The work card material_details JSON stores both marking_id and marking_name (denormalized). This means order detail views must query the Marking table at runtime, but production planning can display the name directly from the JSON without an extra join.
6.4.9 Connections to Other Submodules
→ Sipariş (Order Module)
Primary consumer. Every cable in an order has a marking_id FK pointing to the markings table. The order creation page fetches active markings as a searchable dropdown. Marking is required for cable completion.
→ Üretim Planlama (Production Planning)
The work card generator resolves marking names and embeds them in extruder work card material_details. Production planning displays the marking name on extruder cards so operators know what text to verify on the cable.
→ Sipariş Detay (Order Detail View)
Order detail pages resolve marking_id to marking_name at query time. Displayed as a ValueDisplay component showing the template name.
Design principle: Template-based marking. Rather than storing free-text marking instructions per order, the system maintains a registry of reusable templates. This ensures consistency — every order for the same cable type uses the exact same marking text. The ordered word array structure maps directly to how the extruder printing head works: it cycles through the words sequentially, printing each segment with spacing between them along the cable’s length. Dynamic variables ({CABLE_SIZE}, {YEAR}, etc.) add order-specific context without creating new templates.
6.5 & 6.6 Kablo Tasarım (Cable Playground) & Kablo Veritabanı (Cable Database)
These two submodules are documented together because they are inseparable: Playground is where cables are designed step-by-step using real factory machines, and Cable Database is the permanent repository where finalized designs are stored. Every other module in the system — Orders, Production Planning, Work Cards, Material Calculations, Stock — ultimately depends on the records that Playground creates and saves into Cable Database.
The convergence point: This is where every other Teknik submodule merges. Machine Management provides the machines and their capability ranges. Standards Management provides the tests to assign at each step. Operator Management provides the operators who will execute the design. Markalama provides the text printed during extrusion. Playground consumes all of this data to create a complete production blueprint, which gets saved to Cable Database as the single source of truth for the entire manufacturing pipeline.
6.5.1 Core Concept — How Cable Design Works
Cable manufacturing follows a strict sequential pipeline. Raw copper (8mm filmaşin) enters the first machine and is progressively transformed through 6 machine types until a finished cable emerges. The Playground simulates this entire process digitally.
The Six Machine Types (in order)
| # | Machine | Input | Output | Key Parameters |
|---|---|---|---|---|
| 1 | Kabatel Çekme | 8mm filmaşin (raw copper) | Drawn wire (e.g. 1.8mm) | output_diameter, speed, tav, adet |
| 2 | Kalaylama | Drawn wire from KC | Tinned wire (e.g. 21 pieces) | tin_thickness, speed, adet (critical!) |
| 3 | İncetel Çekme | Tinned wire from KL | Fine wire bundles (e.g. 10×0.30mm) | input_number, output_diameter, output_number, tav |
| 4 | Buncher | Fine wires from IC / other BN / EX | Bunched/twisted wire | dynamic inputs (+ekle), hatve, twist_direction (S/Z) |
| 5 | Extruder | Bunched wire from BN / other EX | Insulated/sheathed cable | insulation_thickness, sheath_thickness, catalyst, dye |
| 6 | E-beam | Extruded cable (no catalyst!) | Cross-linked cable | radiation_level, speed (set at production time) |
Machine Flow Constraints
Not every machine can follow every other machine. The system enforces a directed graph:
Critical loop capabilities:
- Buncher → Buncher: Multi-stage bunching (bunched wire can be re-bunched)
- Extruder → Extruder: Multi-layer extrusion (insulate first, then sheath)
- Extruder → Buncher: Multi-core cables (insulate individual cores, then bunch them together, then sheath)
# Machine flow constraints (playground_session.py) MACHINE_FLOW = { 'kabatel_cekme': ['kalaylama'], 'kalaylama': ['incetel_cekme', 'buncher'], 'incetel_cekme': ['buncher', 'extruder'], 'buncher': ['extruder', 'buncher'], # Self-loop! 'extruder': ['ebeam', 'extruder'], # Self-loop! 'ebeam': [] # Terminal }
6.5.2 Backend Architecture — The Engine
The Playground backend is built from 8 Python files totaling ~4,700 lines:
| File | Lines | Purpose |
|---|---|---|
design_routes.py | 1,155 | API endpoints — session, steps, config, undo/redo, autosave, finalize |
playground_session.py | 986 | Session manager — step lifecycle, undo/redo stacks, checkpoint/restore |
progression_manager_v2.py | 995 | Quantity tracking — consume inputs, produce outputs, per-machine processing |
db_integration.py | 446 | Real machine data — reads machine tables, capability intersection |
form_integration.py | 339 | Form population — builds dropdown data per machine type |
validation_engine.py | 465 | Configuration validation — checks ranges against machine capabilities |
code_generator.py | 291 | Deterministic product codes — SHA256 hash + human-readable codes |
playground_configs.py | 446 | Pydantic schemas — typed config for each machine type |
Session Management (In-Memory)
Sessions are stored in a Python dictionary (_active_sessions: Dict[str, PlaygroundSession]). Each session contains:
- session_id: UUID v4
- standard: EN / UL / SLN (selected at session start)
- cross_section: e.g. “6mm²” (selected at session start)
- steps: List of
DesignStepdataclass instances - progression:
ProgressionManagerinstance tracking all items - history_stack / redo_stack:
StateSnapshotlists (max 50) for undo/redo - autosave: enabled by default, 30-second interval, tracks unsaved changes
The Progression Panel — Heart of the Design
The ProgressionManager maintains a list of ProgressionItem objects. Each item represents a physical product (wire, bunched wire, cable) at some stage of manufacturing:
# ProgressionItem fields { 'id': 'uuid', # Unique identifier 'code': 'KC_18', # Deterministic product code 'quantity': 21, # Current available amount 'original_quantity': 21, # Amount when first produced 'structure': '1.8mm', # Structure formula 'specification': '1.8mm Tel', # Human-readable name 'status': 'active' | 'inactive', # Inactive = fully consumed 'produced_by_step': 1, # Which step created this 'consumed_by_steps': [2], # Steps that consumed from this 'machine_type': 'kabatel_cekme', # Source machine 'properties': { ... } # Machine-specific data }
Key rules:
- Session always starts with one item:
RAW_COPPER_8MM(8mm filmaşin, qty 1) - When a step consumes items, their quantity decreases. At 0, status becomes
inactive. - When a step produces items, new
ProgressionItems are created and added. - Each machine type has its own
process_*method that handles consumption/production logic. - Same-code items are combined (quantity added) unless they’re parallel process outputs.
Quantity Tracking Example — 6mm² Cable
The critical adet parameter: At the Kalaylama step, adet=21 is what makes the entire 6mm² cable work. Kalaylama consumes 1 input but produces 21 pieces, which are then split between two parallel İncetel Çekme processes (10+11=21). This quantity tracking is the core innovation of the progression system.
Atomic Transactions with Checkpoint/Restore
Every configuration attempt is wrapped in an atomic transaction:
The StateSnapshot captures the complete session state (steps + progression items + consumption log + step counter). On failure, the session is restored to exactly its previous state.
6.5.3 API Endpoints — 30+ Endpoints
Session Management
| Method | Path | What It Does |
|---|---|---|
POST | /playground/start | Start session with standard + cross_section. Returns session_id + initial state. |
GET | /playground/{id}/state | Get full session state (steps + progression + summary). |
Step Management
| Method | Path | What It Does |
|---|---|---|
POST | /playground/{id}/steps/add | Add machine step (sequential or parallel). Validates flow constraints. |
DELETE | /playground/{id}/steps/{step_id} | Remove step with full rollback of consumed items. Reports affected dependent steps. |
Form Data (per machine type)
| Method | Path | What It Does |
|---|---|---|
GET | /playground/{id}/form-data/kabatel-cekme | Machines, fixed input (8mm), tests for standard |
GET | /playground/{id}/form-data/kalaylama | Machines, inputs from progression (KC outputs), tests |
GET | /playground/{id}/form-data/incetel-cekme | Machines, tinned inputs with max_quantity, machine input limits |
GET | /playground/{id}/form-data/buncher | Machines, Z/T/U-coded inputs with quantities, twist directions |
GET | /playground/{id}/form-data/extruder | Machines, T/U-coded inputs, layer options (ins/sheath + catalyst/dye) |
GET | /playground/{id}/form-data/ebeam | Machines, extruder outputs without catalyst only |
Machine Configuration (per type)
| Method | Path | What It Does |
|---|---|---|
POST | /playground/{id}/configure/kabatel-cekme/{step} | Configure KC: output_diameter, speed, tav, adet |
POST | /playground/{id}/configure/kalaylama/{step} | Configure KL: input selection, tin_thickness, speed, adet |
POST | /playground/{id}/configure/incetel-cekme/{step} | Configure IC: input, input_number, output_diameter, output_number |
POST | /playground/{id}/configure/buncher/{step} | Configure BN: dynamic inputs, hatve, twist_direction |
POST | /playground/{id}/configure/extruder/{step} | Configure EX: inputs (1+ for twin), ins/sheath layers |
POST | /playground/{id}/configure/ebeam/{step} | Configure EB: input selection (no catalyst) |
PUT | /playground/{id}/configure/{step}/edit | Edit already-configured step (rollback + re-apply) |
Capability Intersection
| Method | Path | What It Does |
|---|---|---|
POST | /playground/{id}/calculate-intersection/{type} | Given selected machine IDs, return only values ALL can produce. Called dynamically when user checks/unchecks machines. |
Undo/Redo & Autosave
| Method | Path | What It Does |
|---|---|---|
POST | /playground/{id}/undo | Pop from history stack, push current to redo stack |
POST | /playground/{id}/redo | Pop from redo stack, push current to history stack |
GET | /playground/{id}/history | Can undo? Can redo? Stack sizes. |
POST | /playground/{id}/autosave | Save session state, mark as saved |
GET | /playground/{id}/autosave-status | Enabled, interval, seconds since save |
PUT | /playground/{id}/autosave-settings | Toggle enabled, change interval |
Validation & Finalization
| Method | Path | What It Does |
|---|---|---|
POST | /playground/{id}/validate/{step} | Dry-run validation: checks inputs exist, quantities sufficient |
POST | /playground/{id}/finalize | Finalize design → saves to cable_designs + design_steps + cable_database in one transaction |
6.5.4 Machine Configuration Schemas
Each machine type has a Pydantic schema defining its exact form fields in order:
| Machine | Schema | Fields (in order) |
|---|---|---|
| Kabatel Çekme | KabatelCekmeConfig | alternative_machines, input_type (fixed), output_diameter, speed, tav, adet, tests |
| Kalaylama | KalaylamaConfig | alternative_machines, input_item_id, tin_thickness, speed, adet, tests |
| İncetel Çekme | IncetelCekmeConfig | alternative_machines, input_item_id, input_number, output_diameter, speed, tav, output_number, tests |
| Buncher | BuncherConfig | alternative_machines, inputs (List[BuncherInputBlock]), adet, speed, hatve, twist_direction, tests |
| Extruder | ExtruderConfig | alternative_machines, inputs (1+ for twin), insulation_*, sheath_*, speed, tests. No adet (always 1). |
| E-beam | EbeamConfig | alternative_machines, input_item_id, tests. Speed/radiation set at production time. |
E-beam is design-only: Unlike other machines, E-beam’s speed and radiation_level are not set during design. They are production-time parameters determined by the cable’s material properties. The Playground only records which cable goes through E-beam and assigns tests.
6.5.5 Capability Intersection — Multi-Machine Flexibility
When a user selects multiple alternative machines for a step, the system computes the intersection of their capability ranges. Only values that all selected machines can produce appear in the dropdowns.
# Machine A speed options: [5, 10, 15, 20, 25] # Machine B speed options: [10, 15, 20, 25, 30] # Intersection: [10, 15, 20, 25] # This means any value from the intersection can be # produced on ANY selected machine → production flexibility
This is called dynamically via POST /calculate-intersection/{machine_type} every time the user checks or unchecks a machine checkbox in the configuration drawer.
6.5.6 Deterministic Code Generation
The CableCodeGenerator ensures that identical products always get the same code, critical for stock management:
| Product Type | Code Format | Example |
|---|---|---|
| Raw material | RAW_XX_spec | RAW_COPPER_8MM |
| Half product | MC_spec | KC_18 (1.8mm wire from Kabatel), BN_73X030 (73-wire bunch) |
| Final cable | {standard}_{item_code}_{id} | StandardEnum.EN_EX_4X10X03_3X11X03+INS_07_CAT_DYE+SHT_08_CAT_DYE_6 |
A SHA256 spec_hash is computed from the full specifications (product_type + machine_type + inputs + outputs + parameters) with sort_keys=True for determinism. If a product with the same hash already exists in product_codes, its existing system_code is returned. Otherwise, a new code is generated with collision-handling (sequence suffix _001, _002, etc.).
6.5.7 Special Cable Types
Twin Cables (Extruder)
Extruder supports multiple inputs for twin/triple cables. Structure uses || separator: (cable1 || cable2)+SHT_0.8mm. Frontend detects twin count from || and generates Turkish names: İkiz, Üçüz, Dördüz, Beşiz.
Multi-Core Cables (Extruder → Buncher → Extruder)
For multi-damar (multi-core) cables, the flow loops: Extruder applies insulation to individual cores, Buncher groups the insulated cores together, then Extruder applies the outer sheath. The system detects this via INS_ patterns in the structure formula.
E-beam Cables (No Catalyst)
E-beam cross-linking replaces chemical catalyst. The form integration completely hides cables with catalyst from the E-beam input dropdown — they are not shown at all, preventing invalid combinations.
6.5.8 Frontend — Playground Page
Main file: src/pages/Teknik/CablePlayground/index.tsx (947 lines) with 7 component files and 1 custom hook.
CablePlayground (index.tsx)
Main orchestrator. Session start modal (standard + cross-section selection), view mode toggle (flow/timeline/code), undo/redo/autosave controls.
FlowCanvas
Visual flow diagram with drag-drop machine placement. Shows production steps as connected nodes.
ConfigurationDrawer
~1,215 lines. The largest component. Opens as a side drawer when configuring a machine. Dynamic forms per machine type. Intersection calculation on machine checkbox change.
ProgressionPanel
Right-side panel showing all items (active/inactive) with quantities, codes, structures. Drives input selection for subsequent steps.
MachineLibrary
Draggable machine palette. 6 machine types with icons and labels.
usePlayground Hook
591 lines. All API integration. Manages session state, loading states, error handling. Bearer token auth via localStorage.
Session Start Flow
Machine Configuration Flow
CRUD Flow
The Playground is not a traditional CRUD page. It is a session-based production simulation engine. The “Create” is a multi-step design process, not a single form submit.
Create (Design a Cable):
- Click “Oturum Başlat” (Start Session) → Modal asks for standard (EN/UL/SLN) and cross-section
POST /playground/start→ In-memory session created with 8mm filmaşin as initial input in the progression panel- Drag machine from library to canvas →
POST /playground/steps/add→ step added to session - Click machine node →
GET /playground/form-data/{type}→ ConfigurationDrawer opens (1,215-line component) - Select real machines (checkboxes) →
POST /playground/calculate-intersection→ dropdowns update with only values all selected machines can produce - Fill configuration form →
POST /playground/configure/{type}/{step}→ progression panel updates with new outputs + quantities - Repeat steps 3–6 for each production machine (KC → KL → IC → BN → EX → optional E-beam)
- System auto-saves via
POST /playground/autosave(every change creates a checkpoint for undo/redo) - Click “Finalize” →
POST /playground/finalize→ atomic database transaction writes tocable_designs,design_steps, andcable_databasetables simultaneously. Deterministic SHA-256 code generated. Session destroyed.
Read (Resume a Session):
- Existing sessions persist in memory. Reload the page →
GET /playground/statuschecks for active session - If session exists: canvas restores from last checkpoint with full progression state
Undo / Redo (In-Session):
- Click Undo →
POST /playground/undo→ session restores to previous checkpoint - Click Redo →
POST /playground/redo→ session advances to next checkpoint - Each configure/add/remove action pushes an atomic checkpoint. Undo stack is unlimited within the session.
Delete (Remove a Step):
- Right-click machine node on canvas → “Kaldır” (Remove)
POST /playground/steps/remove→ step removed from session, progression recalculated, checkpoint created- Removing a step that has downstream dependents triggers cascading removal of those steps
Why this isn’t traditional CRUD: There is no “edit cable” button after finalization. Once a design is finalized to Cable Database, it is immutable. To “edit” a cable, you start a new Playground session, redesign it, and finalize again. The deterministic code system means if the resulting cable has the same physical specifications, it gets the same code automatically. If it’s different, it gets a new code. This eliminates the risk of modifying a cable that’s already being produced.
6.6 Kablo Veritabanı (Cable Database)
6.6.1 What Gets Saved — The Finalization Process
When the user clicks “Finalize” in the Playground, the system saves three things in one database transaction:
| Table | What Gets Saved |
|---|---|
cable_designs | Design metadata: code, name, standard, cross_section, full JSON design_data, approval status, created_by |
design_steps | Each production step: step_number, machine_type, parallel_group, machine_ids, inputs/outputs/configuration/tests as JSON |
cable_database | The finalized cable record: cable_code, cable_type, cross_section, structure_formula, production_flow, half_products, raw_materials, test_requirements (all as JSON) |
6.6.2 Database Schema — 4 Tables
cable_designs (375 lines model)
| Column | Type | Purpose |
|---|---|---|
id | Integer PK | Unique ID |
design_code | String(50) UNIQUE | Generated code |
design_name | String(200) | Optional name |
standard | String(50), CHECK IN (EN, UL, SLN) | Cable standard |
cross_section | String(50) | e.g. “6mm²” |
design_data | Text (JSON) | Complete session state |
is_approved | Boolean | Auto-approved in simplified workflow |
is_active | Boolean | Soft delete |
created_by / approved_by | Integer FK → users | User tracking |
design_steps
| Column | Type | Purpose |
|---|---|---|
id | Integer PK | Unique ID |
design_id | Integer FK → cable_designs (CASCADE) | Parent design |
step_number | Integer | Sequential position |
is_parallel / parallel_group | Boolean / Integer | Parallel processing support |
machine_type | String(50) | kabatel_cekme, kalaylama, etc. |
machine_ids | Text | Comma-separated alternative machine IDs |
configuration | Text (JSON) | Full machine config |
inputs / outputs / tests | Text (JSON each) | Step I/O and test assignments |
Unique constraint: (design_id, step_number, parallel_group)
cable_database — The Core Record
| Column | Type | Purpose |
|---|---|---|
id | Integer PK | Unique ID |
design_id | Integer FK → cable_designs | Source design |
cable_code | String(100) UNIQUE, indexed | Unique cable identifier used everywhere |
standard | String(50) | EN, UL, SLN |
cable_type | String(200) | e.g. “EN 6mm² Klasik Kablo” |
cross_section | String(50) | e.g. “6mm²” |
structure_formula | Text | Full structure notation |
production_flow | Text (JSON) | Step-by-step production sequence with configs |
half_products | Text (JSON) | All intermediate products with properties |
raw_materials | Text (JSON) | Required raw materials (A=Copper, B=Tin, C=Plastic, D=Catalyst, E=Dye) |
test_requirements | Text (JSON) | Tests assigned at each step with frequencies |
is_active | Boolean | Soft delete |
product_codes — Stock Management Bridge
| Column | Type | Purpose |
|---|---|---|
system_code | String(100) UNIQUE | Human-readable code (KC_18, BN_73X030) |
spec_hash | String(256) UNIQUE | SHA256 of specifications (deterministic) |
product_type | String(50) | raw / half / final |
machine_type | String(50) | Which machine produces it |
display_name_tr / en | String(200) | Turkish/English display names |
used_in_designs | Text (JSON) | Array of cable codes using this product |
stock_level | Float | Current stock quantity |
6.6.3 Cable Database API — 15+ Endpoints
| Method | Path | Permission | What It Does |
|---|---|---|---|
GET | /cable-database | Authenticated | List cables. Filters: search, cross_section, active_only. Generates display_name with twin/core/layer detection. |
GET | /cable-database/{code} | Authenticated | Single cable by code. |
GET | /cable-database/{code}/full | Authenticated | Complete raw data for material calculator. Returns half_products with ALL properties. |
GET | /cable-database/{code}/production-flow | Authenticated | Step-by-step production sequence. |
GET | /cable-database/{code}/half-products | Authenticated | All intermediate products. |
GET | /cable-database/{code}/requirements | Authenticated | Raw materials + test requirements. |
GET | /cable-database/{code}/parsed-structure | Authenticated | Structure parsed into extrusion steps for order forms. |
PUT | /cable-database/{code}/deactivate | super_admin, production_manager | Soft delete (is_active=false). |
DELETE | /cable-database/{code}/permanent | super_admin | Hard delete cable + related design. Broadcasts real-time update. |
GET | /products/codes | Authenticated | List all product codes with filters. |
GET | /products/{code}/usage | Authenticated | Which cables use this product + stock level. |
PUT | /products/{code}/stock | super_admin, production_manager, operator | Update stock level. |
GET | /analytics/common-products | Authenticated | Products used in 2+ cables (stock optimization). |
GET | /analytics/production-efficiency | Authenticated | Reuse %, efficiency score, recommendations. |
6.6.4 Frontend — Cable Database Page
Single file: src/pages/Teknik/CableDatabase/index.tsx (691 lines). Route: /teknik/kablo-veritabani.
ProTable
Main data table listing all cables with display_name, cable_code, standard, cross_section, status. Client-side search.
Detail Drawer
Opens when clicking a cable. Tabs: Production Flow (Timeline visualization), Half Products (List), Requirements (raw materials + tests).
ProductionFlowViewer
Ant Design Timeline component showing each production step with machine icons, parameters, and parallel indicators.
CRUD Flow
Cable Database is primarily a read-heavy, write-once store. Cables enter it exclusively via Playground finalization — there is no manual “create cable” form.
Create (via Playground Finalization):
- User finalizes a design in Playground →
POST /playground/finalize - Backend generates deterministic cable code via SHA-256 hash of physical specifications
- If code already exists: finalization is rejected (identical cable already registered)
- If code is new: atomic transaction writes
cable_designs+design_steps+cable_databaserows in one shot - WebSocket broadcast to
teknikroom → Cable Database table refreshes for all connected users
Read:
- Open /teknik/kablo-veritabani →
GET /cable-database→ ProTable lists all cables with display_name, cable_code, standard, cross_section, status - Client-side search filters by cable code, type, or cross-section
- Click a cable row → Detail Drawer opens with three tabs:
- Production Flow:
GET /cable-database/{code}/production-flow→ Ant Design Timeline visualization of each production step - Half Products:
GET /cable-database/{code}/half-products→ all intermediate products with properties - Requirements:
GET /cable-database/{code}/requirements→ raw materials (copper, tin, plastic, catalyst, dye) + test requirements
- Production Flow:
- Other modules read cable data via specialized endpoints:
/full(material calculator),/parsed-structure(order forms)
Soft Delete (Deactivate):
- Click deactivate icon in the table row (requires
super_adminorproduction_managerpermission) - Popconfirm warning
PUT /cable-database/{code}/deactivate→ setsis_active = false- Cable disappears from default list views (still accessible via
active_only=falsefilter). Downstream modules that reference this cable code still function — deactivation prevents new orders from using it.
Hard Delete (Permanent):
- Click permanent delete icon (requires
super_adminpermission only) - Popconfirm with strong warning text
DELETE /cable-database/{code}/permanent- Backend deletes the cable_database record + related cable_designs + design_steps (cascade)
- WebSocket broadcast → table refreshes for all connected users
- Danger: This is a destructive operation. If active orders or work cards reference this cable code, those references become orphaned.
Update (Stock Level — Product Codes):
- Navigate to product codes view →
GET /products/codes - Click stock edit on a product →
PUT /products/{code}/stock(requiressuper_admin,production_manager, oroperator) - Updates the stock_level field for that half/final product
- No WebSocket broadcast for stock updates — polling-based
Key distinction: Cable Database records themselves are immutable after creation. You cannot edit a cable’s structure, production flow, or material requirements. The only mutable fields are is_active (soft delete toggle) and stock_level on product codes. If a cable design needs modification, a new cable must be designed from scratch in the Playground, which will either generate the same code (if physically identical) or a new one (if different).
6.6.5 How Cable Database Feeds the Rest of the System
→ Sipariş (Order Module)
Order creation fetches cable designs from cable_database. Each order cable stores cable_code. The /parsed-structure endpoint provides extrusion step data for dynamic material selection (plastic, catalyst, dye per layer).
→ Üretim Planlama (Production Planning)
Work card generator reads production_flow and half_products to create work cards for each machine step. The /full endpoint provides complete data for material calculations.
→ Material Calculator
Reads cable_database to calculate raw material quantities (copper kg, plastic kg, tin kg, catalyst kg, dye kg) based on half_products properties (wire_count, wire_groups, bundle_diameter).
→ Stok (Stock Module)
Product codes from cable_database link to stock tracking. Same half product used in multiple cables = shared stock. The used_in_designs array enables cross-cable stock optimization.
→ Global Search
Search module indexes cable_database fields (cable_code, cable_type, cross_section, structure_formula) for system-wide search.
Design principle: The Playground is a production simulation engine, not a drawing tool. It doesn’t just record specifications — it executes the entire manufacturing logic step by step, tracking exact quantities, enforcing machine flow constraints, validating against real machine capabilities, and computing capability intersections. The result is a complete production blueprint stored in Cable Database that every downstream module trusts as the single source of truth. The deterministic code generation ensures identical products always get the same code, enabling stock reuse across different cable designs. The in-memory session architecture with atomic checkpoint/restore guarantees that no partial or invalid state ever reaches the database.
7. CONCLUSION
Teknik is not just a module — it is the foundation on which the entire Solen ERP system stands. Every cable ever produced by the factory begins its life as data defined here. Every order, every work card, every quality test, every material calculation, every stock entry traces back to a record that Teknik created. Without it, the rest of the system has nothing to work with.
7.1 What This Document Covered
This deep dive analyzed the Teknik module across six submodules, from high-level architecture down to individual lines of code:
| Section | Submodule | Depth | Key Insight |
|---|---|---|---|
| 6.1 | Machine Management | Full | Capability-range model (min/max/increment) enables dynamic dropdown generation and cross-machine intersection |
| 6.2 | Standards & Tests | Full | Three-layer hierarchy (standard → test group → individual test) with multi-standard assignments |
| 6.3 | Operator Management | Full | Dual-storage pattern: integer FK for integrity + denormalized name for display-without-join |
| 6.4 | Markalama | Full | Cross-module data flow: marking_id travels from order → work card → production planning → operator screen |
| 6.5 | Cable Playground | Exhaustive | Production simulation engine with in-memory sessions, atomic checkpoints, quantity tracking, and machine flow constraints |
| 6.6 | Cable Database | Exhaustive | Single source of truth: denormalized JSON blobs enabling zero-join reads for all downstream modules |
7.2 Architectural Principles
Several design principles recur throughout the Teknik module and define its character:
Read-Only Downstream
Every other module reads from Teknik but never writes to it. Machines, standards, operators, markings, and cable designs are defined here and consumed everywhere else. This enforces a clean dependency direction.
Simulation Before Storage
The Playground doesn’t accept free-form input. It simulates the real production line: enforce flow constraints, validate against actual machine capabilities, compute intersections, track quantities. Only a fully valid design can be finalized to the database.
Deterministic Identity
SHA-256 spec hashing guarantees that the same physical product always gets the same code, regardless of which cable design created it. This is what makes stock pooling across cable designs possible.
Denormalized for Speed
Cable Database stores production_flow, half_products, raw_materials, and test_requirements as JSON blobs. This is intentional: downstream modules need the complete picture in a single read, not a 12-table join.
7.3 The Numbers
7.4 How Teknik Feeds the Factory
Every cable order references a cable_code from Cable Database. Every work card is generated from the production_flow JSON. Every material calculation reads half_products properties. Every quality test is assigned from the standard hierarchy defined in Teknik. The marking printed on the cable comes from the Markalama submodule. The machines that produce it are validated against capabilities stored in Machine Management.
In short: if Teknik is wrong, everything downstream is wrong. This is why the Playground uses atomic transactions, capability validation, and deterministic code generation — to guarantee that what enters the Cable Database is production-ready and correct.
7.5 Final Word
The Teknik module transforms domain expertise — wire diameters, machine capabilities, production sequences, test standards, marking templates — into structured, validated, machine-readable data. It is the bridge between what engineers know and what software can execute. Every record created here carries the weight of the entire production chain that follows. This document has traced that chain from the first 8mm filmaşin entering Kabatel Çekme to the final cable code stored in the database, through every machine step, every quantity split, every validation check, and every downstream consumer. The system works because Teknik is thorough. This document exists to prove it.