CRYSTAL OF CONSTRUCTION
Below is a breakdown of construction as a system of Nodes, Rhoeber and Crystal. This is a convenient model if we want to turn the industry not just into a set of processes, but into a managed semantic, digital and organizational architecture.
Basic logic of the model
Nodes are the points of concentration of functions, resources, decisions, data and responsibility.
Ribs are connections between nodes: flows of materials, money, documents, teams, technology, people, and control.
A crystal is a complete structure in which all nodes and edges are assembled not chaotically, but according to the laws of symmetry, hierarchy, transparency and development.
In other words:
- Node = who or what does;
- rib = as related;
- crystal = as the whole system keeps shape and does not fall apart.
Building as a Count
The construction industry is not one chain, but a multilayer graph.
It has:
- organizational nodes,
- resource nodes,
- technological nodes,
- legal nodes,
- financial nodes,
- logistic nodes,
- operational units,
- digital nodes.
And the ribs between them form:
- Flow of materials,
- The flow of people,
- flows of information,
- capital flows,
- flow of permits,
- flows of responsibility,
- flows of risks,
- flows of feedback.
Nodes of construction
Nodes of design. This is the beginning of any object.
Key nodes:
- State priority;
- the customer;
- investor;
- developer;
- urban idea;
- land plot;
- social request;
- master plan;
- architectural concept.
Their function:
to form an answer to the question: what we build, why we build, for whom we build, on what means and in what logic of the territory.
Nodes of regulation. Without them, the system is not legitimate.
This includes:
- Federal authorities;
- Regional bodies;
- Municipal authorities;
- norms and standards;
- examination;
- permit system;
- cadastre;
- Supervisory authorities;
- Environmental harmonization;
- Fire and industrial safety.
Their function:
Ensure acceptability, security, compliance and legal framework.
Design nodes
These are birthform nodes.
This includes:
- architectural bureau;
- the general designer;
- constructor;
- engineering sections;
- BIM/TIM model;
- estimate model;
- Digital twin of the object;
- Author's supervision.
Their function:
translate the idea into an accurate system of solutions, drawings, parameters, volumes and restrictions.
Resource and supply hubs
Without them, the object will not materialize.
This includes:
- manufacturers of building materials;
- career;
- metallurgy;
- concrete units;
- woodworking;
- engineering equipment;
- machinery and mechanisms;
- energy supply;
- warehouses;
- logistic centers.
Their function:
to provide the construction with everything necessary in terms of volume, time, quality and price.
Nodes of work
It is the center of physical embodiment.
This includes
- General contractor;
- Subcontractors;
- construction teams;
- installation organizations;
- machinery;
- construction site;
- calendar plan;
- labor protection;
- dispatching of works;
- construction control.
Their function is to collect an object in reality.
Nodes of Finance
Construction without a financial framework is rapidly turning into chaos.
Nodes:
- bank;
- Treasury of the project;
- escrow/project financing;
- budgetary funds;
- private investment;
- contractual system;
- calculated contours;
- tax contour;
- insurance;
- Risk and reserves assessment.
Their function:
ensure the stability of cash flow and predictability of execution.
Nodes of operation
In fact, the object is built not for the sake of construction, but for the sake of life after construction.
Nodes:
- operating organization;
- management company;
- resource-supplying organizations;
- monitoring system of the object;
- maintenance;
- major repairs;
- user;
- resident/tenant/enterprise;
- feedback system.
Their function:
Turn it into a working environment.
Nodes of the digital environment. This is the core of the future industry.
Nodes:
- a single digital platform;
- register of objects;
- register of participants;
- digital passport of the object;
- Digital footprint of solutions;
- BIM/TIM storage;
- marketplace of materials and services;
- geoanalytics;
- AI-prediction module;
- industry control panel.
Their function is to make the system transparent, manageable and predictive.
Ryobra Construction
Now the main thing: nodes without edges are just dead points.
Smysnye ribs
Link:
- Company need ↔ construction program;
- State strategy ↔ specific project;
- area ↔ object function.
This answers the question: why this construction has the right to be.
Legal ribs
Link:
- project ↔ standard;
- Section ↔ authorized use;
- Contractor ↔ contract;
- object ↔ construction permit;
- result ↔ commissioning.
It's the edges of legitimacy.
Information ribs
Link:
- customer ↔ designer;
- the designer ↔ contractor;
- Contractor ↔ supervision;
- ↔ digital platform;
- operation of ↔ digital twin.
It's the edges of the data.
Financial ribs
Link:
- investor ↔ project;
- Bank ↔ in a row;
- Treasury ↔ payment;
- ↔ estimated actual work;
- risk ↔ reserve.
These are the edges of value and trust.
Material ribs
Link:
- manufacturer ↔ warehouse;
- warehouse ↔ site;
- machinery ↔ work area;
- Supply ↔ installation.
These are the ribs of physical embodiment.
Management ribs
Link:
- KPI ↔ the Artist;
- period ↔ stage;
- Control ↔ deviation;
- Decision ↔ liability;
- Incident ↔ system response.
It's the ribs of coordination.
Ribs of quality. Link:
- Material ↔ certificate;
- Work ↔ act;
- Project ↔ compliance;
- facility ↔ standard of operation;
- defect ↔ corrective action.
These are the ribs of reliability.
Ribs feedback
Link:
- user ↔ operator;
- operator ↔ designer;
- Accident ↔ revision of the norm;
- operation of ↔ new generation projects.
These are the ribs of evolution.
Crystal Construction
Now the main thing: what is a crystal?
A crystal is not just a network. It is a harmoniously organized multi-layered system, where each node has a place, function, degree of connection and measure of responsibility.
In construction, the crystal is:
Single spatial-digital model of the industry, where:
- each object has a digital passport;
- Each participant has a digital profile;
- Each process has a route and control;
- Each resource has its origin and state;
- each decision has an author, date and consequences;
- every ruble has a trace;
- Each risk is visible in advance;
- Each result is included in the overall architecture of the country.
Construction Crystal Geometry
We will decompose the crystal into at least 7 faces.
Edge 1. Meaning
What and why is being built.
Edge 2. Space
Where, in what context.
Edge 3. Law
On what basis and by what rules.
Edge 4. Resources
From what, by whom and on what is built.
Edge 5. Production
How exactly the object is assembled in stages.
Edge 6. Finance. What money and with what sustainability.
Edge 7. Life Cycle
How the object lives after input. If you add a digital core, you get the 8 level crystal, where the digital environment connects all the other faces.
Crystal Core
Any crystal system must have a nucleus.
To build such a core should be:
Unified digital operator of construction services
It does not replace all participants, but becomes:
- The data coordinator,
- process integrator,
- The digital arbiter,
- Navigator of the object life cycle,
- operator of transparency,
- environment of interaction between the state, business and citizens.
It turns the industry from a disparate set of participants into a single crystal of construction.
Construction Crystal Formula
Construction Crystal = Nodes × Ribs × Rules × Data × Time
Where:
- the nodes give structure,
- ribs give interaction,
- The rules are sustainable,
- Data is transparent,
- Time is the dynamic of the life cycle.
Practical node architecture
Contour A. State
Nodes:
- The strategy,
- National projects,
- standards,
- control,
- the registers,
- infrastructure programs.
Contour B. Development and order
Nodes:
- the customer,
- The investor,
- developer,
- land bank,
- financial model.
Contour C. Design
Nodes:
- architecture,
- engineering,
- BIM,
- examination,
- estimate.
Contour D. Production
Nodes:
- Contractors,
- suppliers,
- technique,
- construction control,
- calendar plan.
Contour E. Operation
Nodes:
- The owner,
- the management company,
- service,
- monitoring,
- Repairs.
Contour F. Digital platform
Nodes:
- digital passport,
- object identifier,
- digital marketplace,
- analytics,
- AI,
- monitoring,
- Ratings of participants.
What ribs are the most critical
Strictly speaking, the industry most often collapses not because of the lack of nodes, but because of bad edges.
The most problematic ribs are usually:
- project ↔ construction;
- estimate ↔ real value;
- ↔ liability;
- ↔ actual execution;
- Resolution ↔ digital transparency;
- operation ↔ feedback in new design;
- public data ↔ private data;
- supplier ↔ quality ↔ material origin.
That is, the main task of the reform is not just to create new nodes, but to reassemble the edges.
Crystal on the life cycle of the object
You can imagine one object as a small crystal:
Initiation. Idea, need, site, model.
Design Concept, calculations, BIM, estimate.
Harmonization. Expertise, permissions, connections.
Construction. Deliveries, works, controls, acts.
Input. Checks, documentation, launch.
Operation Monitoring, maintenance, feedback.
Transformation
Reconstruction, modernization, re-use of data. This is the crystal of the life cycle.
Speaking of Meta-Architecture
Then we can formulate it as follows:
Nodes are organs of the building organism. The ribs are its vessels, nerves, and channels. The crystal is its skeleton, shape, genome, and the law of inner harmony. Without nodes, there is no function. Without ribs, there is no coordination. Without a crystal, there is no integrity.
Management Conclusion
For the concept of a Unified Digital Operator of Construction Services, this means the following: the operator should be built not as a site, not as a set of services and not as a marketplace in a narrow sense, but as:
Crystal platform of the industry, where:
- industry nodes are digitized,
- the edges of the industry are standardized
- crystal industry is visualized and managed.
The portal should be able to show:
- who is associated with whom;
- where the connection is broken;
- where is a narrow place;
- where there is a corrupt risk;
- where there is a shortage of materials;
- Where is the delay;
- where the contractor is overburdened;
- where the object falls out of the normative contour;
- where the life cycle loses control.
Final wording to be included in the concept
You can insert this:
The construction industry is considered as a crystalline network system consisting of nodes, edges and an integral digital core. The nodes represent the participants, resources, functions and stages of the object's life cycle. The ribs reflect the material, financial, informational, legal and managerial connections between them. The crystal industry is formed as a complete architecture in which all elements are interconnected, standardized, transparent and manageable in real time. On this basis, the Unified Digital Operator of Construction Services is created as a system integrator that ensures coordination, traceability and evolutionary development of the construction complex.
The strongest version of this model
If you bring the idea to the end, you can make 3 product:
- A semantic map of construction by Nodes and Ribs
- Crystal construction industry in Russia as a visual model
- Technical architecture of the digital platform - based on this crystal
This is not just a description, but a foundation for:
- The road map,
- technical tasks,
- atlas of construction,
- architecture of the marketplace,
- The state digital platform.
Table: Nodes — Ribs — Functions — Digital services
1. Outline: Design and initiation
Customer ↔ investor, ↔ designer Task formation Customer LC, TZ-designer Investor ↔ bank, ↔ developer Financing Fin model, ROI-calculator Land plot ↔ cadastre, ↔ Spatial base Geoanalytics, GIS Concept ↔ design Object Idea Concept Designer, AI Demand Analysis State ↔ strategy, ↔ region Development priorities Register of programs, national projects Regulatory framework ↔ project Rules Base of norms (GIS), auto-verification Expertise ↔ Designer Verification Digital Expertise Permissions ↔ object Legalization EPC (single permitting system) Supervisory authorities ↔ building Oversight Online control, check-lists Cadastre ↔ plot Accounting Integration with Rosreestr Architect ↔ customer Image BIM/TIM General Designer ↔ Contractor Coordination CDE (single data environment) Engineering ↔ networks Technical solutions Calculation modules Estimates ↔ Finance Cost Auto-estimate BIM-model ↔ building Digital twin Storage BIM Suppliers ↔ building Materials Marketplace Manufacturers ↔ Logistics Production Product catalogue Warehouses ↔ Playground Storage WMS Logistics ↔ object Delivery Trekking Techniques ↔ Contractor Mechanization Accounting for technology General Contractor ↔ customer Management ERP constructions Subcontractors ↔ General contract Works Register of Contractors Playground ↔ resources Implementation Construction Manager Monitoring ↔ Quality Verification Mobile technical supervision Plan-schedule ↔ fact Deadlines Plan-fact analytics Bank ↔ project Financing Project financing Treasury ↔ contracting Payments Treasury Module Escrow ↔ object Security Escrow accounts Contracts ↔ members Obligations Smart contracts Insurance ↔ risks Protection Risk management UC ↔ object Management Operating system User ↔ UK Feedback Mobile App Resource supply ↔ object Utilities IoT Accounting Monitoring ↔ system Monitoring Sensors, IoT Repairs ↔ wear Support Repair plan Single platform ↔ all nodes Integration Portal Register of objects ↔ life cycle Accounting Object ID Register of participants ↔ Market Transparency Rating Digital passport ↔ object Data Object passport AI-analytics ↔ data Forecast Predictive analytics Marketplace ↔ resources Transactions Trading platform
Node
Ryobra (links)
Function
Digital services
2. Outline: Regulation
Node
Ryobra
Function
Digital services
3. Outline: Design
Node
Ryobra
Function
Digital services
4. Outline: Resources and supplies
Node
Ryobra
Function
Digital services
5. Outline: Construction
Node
Ryobra
Function
Digital services
6. Outline: Finance
Node
Ryobra
Function
Digital services
7. Outline: Operation
Node
Ryobra
Function
Digital services
8. Outline: Digital Core (Crystal)
Node
Ryobra
Function
Digital services
How it turns into a crystal
Now the most important thing is not just a table, but logic:
Each node — digitized → has a profile, data, history
Each rib transparently → can be seen:
- Who is related to whom
- under what conditions
- with what result
The whole system is observed in real time
→ is already an operating system of construction
Key management conclusion
Now the industry:
- There are knots
- The ribs are chaotic.
- Crystal is missing.
Our model does:
- Nodes →
- Ribs →
- Crystal →
What it gives in practice
“Black box” → is missing, where the money, where the materials, where the delay
Corruption drops sharply → because the ribs are transparent
Accelerated construction → no breaks between nodes
→ forecasting appears system sees problems BEFORE they occurred
Next step (recommended)
Scheme (visual crystal) - how the system really looks
Platform architecture — modules, API, roles
MVP portal - at least:
- the Register of Participants
- Marketplace
- Digital object passport
CRYSTAL CONSTRUCTION
(metaarchitecture of the industry)
The essence of crystal. Crystal is not a scheme. It is a living, self-consistent system where:
- Every element is there,
- Every connection makes sense.
- each operation leaves a digital trace,
- The whole system develops through feedback.
In construction, this means that the industry becomes managed as a single organism, rather than a fragmented market.
Crystal Geometry
Imagine the crystal as a polyhedron with a nucleus and layers.
NUCLEAR. Digital construction operator. Functions:
- integration of all nodes,
- storage of data,
- coordination of processes,
- analytics and forecast,
- Transparency control.
INTERNAL LAYER (7 faces). These are the crystal structural fields:
Meaning
- Why we build
- Who needs it
Space
- Where we build
- Context of Territory
Right
- rules and norms
Resources
- materials, equipment, people
Production
- Construction processes
Finance
- money and calculations
Life Cycle
- exploitation and development
EXTERNAL SLAY (Wednesday)
- State
- Market
- Society
- Ecology
- Technology
This is what the crystal is constantly interacting with.
Crystal lattice (key idea)
The crystal is not held by knots, but by a grid of connections.
The main types of ribs:
- > Information
- > financial
- > material
- > legal
- > management
- . feedback
If at least one type of connection is weak, the crystal begins to break down.
Crystal axis (control)
The crystal has 3 main axes:
The Time Axis
Idea → project → construction → operation → transformation
Here's the data
Each action is recorded and available
RESPONSIBILITY
Every decision has an author. . . . These are the three pillars of transparency.
Fractal structure
The most powerful: each object is a small crystal
And it completely repeats the structure of the entire industry. That is:
- house = crystal
- Area = crystal
- City = Crystal
- Country = Crystal
This gives scalability without loss of controllability.
Digital double crystal. In the platform, it looks like this: Each object has:
- ID
- digital passport
- BIM-model
- history of decisions
- financial footprint
- status in real time
This transforms the construction from a process into an observable system.
The behavior of the crystal. Crystal should be able to:
1. Self-diagnosis
- Where are the delays
- Where are the risks
- Where are the gaps
2. Self-adaptation
- redeployment of resources
- change of schedules
3. Self-learning
- Analysis of past projects
- Improving the future
The main defects of the current industry
There is no crystal, there is chaos.
- Nodes are not related
- Data is scattered
- Solutions are non-transparent
- Responsibility is blurred
- money is lost
- The “Floating” Period
This is not a problem of people - it is a problem of lack of structure.
What does the crystal
Connects everything into a system
- Project ↔
- money ↔ works
- standards ↔ facts
- operation ↔ design
Makes the industry manageable
You see:
- Where is the problem
- Who is responsible
- What to do
. . . makes a prediction. The system begins to say, “This object will collapse in 3 months.”
Platform architecture (crystal skeleton)
Module 1. Roster
- objects
- Participants
- resources
Module 2. Marketplace
- materials
- Contractors
- Technics
Module 3. Project Management
- Timeline
- Tasks
- control
Module 4. Finance
- payments
- estimates
- control
Module 5. BIM/Digital twin
- Object Model
Module 6. Analytics and AI
- forecast
- Risks
- optimization
Crystal Formula
Can be fixed as a basic principle: Construction Crystal (Nodes × Ribs) + Data + Time + Responsibility
The most important thing (without illusions)
If you really want to change the industry,
Don't make another portal
Don’t just do the marketplace.
? do the construction operating system. Here is the wording of the strategy level:
Crystal Construction is an integrated digital and organizational architecture of the industry, based on the structuring of nodes, standardization of connections and the formation of a single digital core. Such a model ensures transparency, manageability and evolutionary development of the construction complex at all stages of the life cycle of objects.
> VISUAL SCHEME
CRYSTAL OF CONSTRUCTION
Central structure (core)
In the center of the crystal:
A SINGLE DIGITAL OPERATOR
He is not a market participant, but a coordination environment. Inside the core:
- the Register of Objects
- the Register of Participants
- digital passports
- BIM/doubles
- AI-analytics
This is the “brain” of the system.
First circle - 7 faces of the crystal
Around the core are 7 key modules (like petals/edges):
1. MEANING
- requirements
- strategy
- Development scenarios
2. SPACE
- Land
- Geoanalyst
- master plan
3. LAW
- Standards
- permissions
- Expertise
4. RESOURCES
- materials
- Technics
- Personnel
5. PRODUCTION
- construction
- Contractors
- processes
6. FINANCE
- investments
- payments
- control
7. LIFE CYCLE
- Operation
- Service
- feedback
Second round - knots
Each facet is broken into nodes: Example:
The term “production”
- General Contractor
- Subcontractors
- Playground
- control
- schedule
The term “Finance”
- Bank
- Treasury Department
- contracts
- Insurance
Visually, it is a cluster within each facet
Ryobra (most important)
Now the key part of the scheme:
> ALL Knots ARE BETWEEN YOU
Types of lines (can be visually distinguished):
- solid → material flows
- dotted → data
- double → finance
- red → risks
- green → feedback
This turns the schema into a living network, not a hierarchy.
Crystal Axes
3 axes pass through the center:
Here is the time Idea → Project → Construction → Operation
Here's the data. All nodes are connected to the digital core
Responsibility Axis Each node has an owner
Outer shell
Outside the crystal - context:
- State
- Market
- Society
- Ecology
- Technology
This can be depicted as a sphere around a crystal.
What it looks like (in words)
Imagine:
- in the center - the luminous core
- around symmetric segments
- Inside the segments - nodes
- There is a close network of connections between them.
- All this pulsates data
This is no longer a scheme - it is an operating model of the industry
Simplified scheme (for document)
You can insert this:
[EXPLATMENT]
▲
|
[RESOURCES] > [NUCLEAR / DIGITAL OPERATOR] > [FINANCE]
▲ ▲ ▲
| | |
[PRODUCTION] [DATA / AI] [PRODUCTION]
▲ ▲
| |
? [RIGHT] ?
How to use this scheme
For the state - the model of industry management
For investors - transparency of the system
For IT - platform architecture
For presentations - a strong visual image
INTERACTIVE CRYSTAL MAP
(platform interface)
Main screen (Core View). This is not a list or a table. It's a living crystal map.
On screen:
- center → core (operator)
- around → 7 faces
- inside → knots
- between → edges (links)
The user sees the entire system at once.
Display modes (key chip)
The same crystal switches:
Mode 1 — Object
Shows:
- One construction project
- All the connections around him.
Mode 2 — Territory
- City / Region
- all constructions
Mode 3 — Industry
- The entire system of the country
Interaction (UX)
Node click:
- Who is this?
- rating
- projects
- Communications
Rib click:
- Contract
- amount
- Timeline
- status
Click on the object:
- BIM
- Finance
- schedule
- Risks
Color Logic
To the interface “speak”:
- . . . standard
- > risk
- The problem
- > data
- * Finances
Panel on the right (Control Panel)
- filters (region, object type)
- Mode Switching
- Analytics
- Warnings
Bottom panel (Timeline)
Slider time: ? can "scroll construction"
- How it was
- as is
- forecast
The main value of the interface
It's not UI.
This is: - real-time industry operational map
TECHNICAL ARCHITECTURE (TC)
General architecture
Type: Microservices + Data Platform + Digital Twin
Main modules
Core Platform
- Authorization
- Roles
- API-gateway
Registries
Register of objects
- ID
- status
- Geo
- Stage
Register of participants
- Company
- Ratings
- History
Digital Twin (BIM)
- Storage of models
- Version
- Link to Stages
Graph Engine (KEY MODULE)
This is the heart of the system. Stores:
- Nodes
- Ribs
- Communications
> Technologies:
- Neo4j / TigerGraph
Project Management
- Tasks
- Timeline
- Dependency
Financial module
- contracts
- payments
- control
Marketplace
- materials
- Contractors
- Technics
AI / Analytics
- forecast of terms
- Risk identification
- optimization
Monitoring (IoT)
- Sensors
- construction
- Operation
Data types
Nodes:
- object
- Participant
- resource
- Document
Ryobra:
- Contract
- delivery
- Task
- payment
API (example)
Get object graph
GET /api/object/{id}/graph
Get member connections: GET /api/company/{id}/relations
Get risks: /api/object/GET {id}/risks
Roles of Users
- State
- Investor
- Customer
- Contractor
- control
- citizen
Data Flows
1. BIM → Graph
2. Finance → Graph
3. IoT → Monitoring
4. User → UI > Everything fits in Graph Engine
? 2.7. Without what the system will not work
If there is no Graph Engine, there is no crystal
If there is no object ID - chaos
If there is no digital passport, there is no transparency.
KEY IDEA
We are not currently building:
- Site
- Marketplace
- CRM
You are building:
Graph-based Operating System for Construction
MVP CONSTRUCTION CRYSTAL
(first working version of the system)
Goal MVP . Do not try to build the entire crystal at once. Goal MVP: ? to show that the system “sees construction as a graph”. That is, MVP should be able to:
- create an object
- Link to participants
- show links
- display status
- Identifying the problem
If not, everything else is meaningless.
What is included in MVP (minimum)
Register of objects
- Object ID
- Address / Geo
- stage (project / construction / operation)
- basic parameters
Register of participants
- Company
- roles (customer, contractor, etc.)
- Rating (so far simple)
Graph Engine (core) > The most important. Stores:
- Who is related to whom
- What contracts
- What Roles
Visual map (UI)
- Nodes = Mugs
- the = Line
- Click → Information
The simplest object status
- . . . okay
- > risk
- The problem
Basic analytics
- Delays
- Contractor Overload
- Lack of communication
Architecture MVP
Simplified:
[Frontend]
↓
[API Gateway]
↓
-------------------------
| Core Backend |
|-----------------------|
| Objects Service |
| Companies Service |
| Graph Service |
| Auth Service |
-------------------------
↓
[Databases]
- PostgreSQL
- Graph DB (Neo4j)
Technology stack (optimal)
Backend - Node.js (NestJS) or Python (FastAPI). Why:
- Quickly
- flexible
- easy to scale
Frontend React + Next.js. Add:
- fast development
- SSR
- Convenient UI
Graph visualization (Key)
? Cytoscape.js Or ? D3.js. If you want an easier start: > React Flow
Graph Database > Neo4j. It's the heart of the crystal.
Main DB > PostgreSQL
API
- REST (MVP is enough)
- later → GraphQL
Hosting > Quick Start:
- Vercel (frontend)
- Railway / Render (backend)
- Neo4j Aura (graph)
Authorization: Auth0 / Firebase Auth or simple JWT at launch
Data Model (Simplified)
Nodes:
Object
- id
- name
- status
- location
Company
- id
- name
- role
Ribs: RELATION
- type (contract / supplier / control)
- start_date
- status
Example of Graph Logic
[Object]
|
|----(Contract)---> [Contractor]
|
|----(financing)--> [Bank]
|
|----(control)---> [Supervisor]
This is the minimum crystal.
MVP interface (what should be)
Main screen:
- Count (center)
- Right panel:
- node list
- Filter
When Clicking:
Object:
- status
- Participants
- Risks
Company:
- projects
- Communications
Development plan (real)
Week 1–2
Week 3–4
Week 5–6
Week 7–8
After 2 months you already have the system
Minimum team
- 1 backend
- 1 frontend
- 1 fullstack (or CTO)
- 1 designer (optional)
Where they usually break
Error 1
CRM instead of graph
Error 2
There is no normal data model
Error 3
Overload MVP
Error 4
Trying to “goose”
First the count, then everything else. If you have:
- there are nodes
- There are connections
- there is a visual
You already have a crystal.
What do you get out MVP
- live construction map
- Transparent Connections
- The first level of control
- Investor / State Demonstration
After MVP: add: finance, BIM, marketplace
If we: I will start now MVP the National Park 6–8 Weeks - we will outshine everyone who writes strategies.
Database structure
The logic is simple: PostgreSQL stores directories, object cards, users, documents, events. Neo4j keeps the graph of connections: who is connected to whom, by what type of connection, in what status.
PostgreSQL: main tables
The users table. Users of the system.
Field |
Type |
Purpose |
|
id |
UUID PK |
ID |
|
|
varchar unique |
Username |
|
password_hash |
varchar |
Password hash |
|
full_name |
varchar |
Full name |
|
phone |
varchar |
Phone |
|
status |
varchar |
active / blocked / invited |
|
created_at |
timestamp |
Creation date |
|
updated_at |
timestamp |
Update Date |
Table of RolesYU Roles of access.
|
Field |
Type |
|
id |
UUID PK |
|
code |
varchar unique |
|
name |
varchar |
Examples:
- super_admin
- government_operator
- investor
- customer
- contractor
- supervisor
- viewer
The user_roles table. Linking users and roles.
Field |
Type |
|
id |
UUID PK |
|
user_id |
UUID FK -> users.id |
|
role_id |
UUID FK -> roles.id |
|
created_at |
timestamp |
Table companies. market participants.
|
Field |
Type |
Purpose |
|
id |
UUID PK |
Company ID |
|
name |
varchar |
Name |
|
short_name |
varchar |
Short name |
|
inn |
varchar |
Taxpayer Identification Number (INN) |
|
ogrn |
varchar |
Primary State Registration Number (OGRN) |
|
company_type |
varchar |
customer / contractor / supplier / bank / regulator |
|
rating |
numeric(3,2) |
Rating |
|
status |
varchar |
active / inactive |
|
website |
varchar |
Site |
|
created_at |
timestamp |
Creation date |
|
updated_at |
timestamp |
Update Date |
Company_users table. The user’s attachment to the company.
Field |
Type |
|
id |
UUID PK |
|
company_id |
UUID FK -> companies.id |
|
user_id |
UUID FK -> users.id |
|
position |
varchar |
|
is_primary |
boolean |
|
created_at |
timestamp |
Table of regions. Directory of regions.
Field |
Type |
|
id |
UUID PK |
|
code |
varchar unique |
|
name |
varchar |
Table of locations. Addresses and coordinates.
Field |
Type |
|
id |
UUID PK |
|
region_id |
UUID FK -> regions.id |
|
address |
text |
|
lat |
numeric(10,7) |
|
lon |
numeric(10,7) |
|
cadastral_number |
varchar |
|
created_at |
timestamp |
Table of projects. Construction object card.
Field |
Type |
Purpose |
|
id |
UUID PK |
Object ID |
|
code |
varchar unique |
Internal number |
|
name |
varchar |
Name |
|
description |
text |
Description |
|
project_type |
varchar |
residential / industrial / infrastructure |
|
lifecycle_stage |
varchar |
concept / design / construction / operation |
|
status |
varchar |
normal / risk / problem / archived |
|
location_id |
UUID FK -> locations.id |
Location |
|
customer_company_id |
UUID FK -> companies.id |
Customer |
|
start_date |
date |
Planned start |
|
end_date |
date |
Planned completion |
|
planned_budget |
numeric(18,2) |
Planned budget |
|
actual_budget |
numeric(18,2) |
Actual data |
|
created_at |
timestamp |
Creation date |
|
updated_at |
timestamp |
Update Date |
Project_stages table. Project phases.
|
Field |
Type |
|
id |
UUID PK |
|
project_id |
UUID FK -> projects.id |
|
stage_code |
varchar |
|
stage_name |
varchar |
|
planned_start |
date |
|
planned_end |
date |
|
actual_start |
date |
|
actual_end |
date |
|
status |
varchar |
|
created_at |
timestamp |
Table of contracts. contracts within the system.
Field |
Type |
|
id |
UUID PK |
|
project_id |
UUID FK -> projects.id |
|
contract_number |
varchar |
|
contract_type |
varchar |
|
customer_company_id |
UUID FK -> companies.id |
|
contractor_company_id |
UUID FK -> companies.id |
|
amount |
numeric(18,2) |
|
currency |
varchar |
|
date_start |
date |
|
date_end |
date |
|
status |
varchar |
|
created_at |
timestamp |
|
updated_at |
timestamp |
Table of documents. Project documents.
Field |
Type |
|
id |
UUID PK |
|
project_id |
UUID FK -> projects.id |
|
company_id |
UUID FK -> companies.id null |
|
contract_id |
UUID FK -> contracts.id null |
|
doc_type |
varchar |
|
title |
varchar |
|
file_url |
text |
|
version |
integer |
|
issued_at |
date |
|
status |
varchar |
|
created_by |
UUID FK -> users.id |
|
created_at |
timestamp |
Risk table for the object.
Field |
Type |
|
id |
UUID PK |
|
project_id |
UUID FK -> projects.id |
|
related_company_id |
UUID FK -> companies.id null |
|
related_stage_id |
UUID FK -> project_stages.id null |
|
risk_type |
varchar |
|
severity |
varchar |
|
probability |
varchar |
|
description |
text |
|
status |
varchar |
|
detected_at |
timestamp |
|
resolved_at |
timestamp null |
Table of events. Tape of events.
|
Field |
Type |
|
id |
UUID PK |
|
project_id |
UUID FK -> projects.id null |
|
company_id |
UUID FK -> companies.id null |
|
user_id |
UUID FK -> users.id null |
|
event_type |
varchar |
|
event_payload |
jsonb |
|
created_at |
timestamp |
Table project_metrics. Project metrics.
|
Field |
Type |
|
id |
UUID PK |
|
project_id |
UUID FK -> projects.id |
|
metric_date |
date |
|
progress_percent |
numeric(5,2) |
|
cost_variance |
numeric(18,2) |
|
schedule_variance_days |
integer |
|
open_risks_count |
integer |
|
created_at |
timestamp |
PostgreSQL
Minimum required:
- projects(code)
- projects(status, lifecycle_stage)
- projects(customer_company_id)
- contracts(project_id)
- contracts(customer_company_id, contractor_company_id)
- documents(project_id, doc_type)
- risks(project_id, status, severity)
- events(project_id, created_at desc)
- locations(region_id)
- GIN index on events.event_payload
Neo4j: graph model
In the graph, we store entities as nodes and relationships as edges.
Nodes. Primary labels:
- Project
- Company
- User
- Contract
- Document
- Stage
- Location
- Risk
Mandatory properties of the node. For uniformity:
- id — UUID from PostgreSQL
- type — type of entity
- name
- status
- createdAt
- updatedAt
Types of edges Neo4j. Main relationships
- [:LOCATED_AT]
Project -> Location - [:OWNED_BY]
Project -> Company - [:PARTICIPATES_IN]
Company -> Project - [:HAS_STAGE]
Project -> Stage - [:HAS_CONTRACT]
Project -> Contract - [:CUSTOMER_IN]
Company -> Contract - [:CONTRACTOR_IN]
Company -> Contract - [:HAS_DOCUMENT]
Project -> Document - [:ISSUED_BY]
Document -> Company - [:HAS_RISK]
Project -> Risk - [:RELATED_TO]
Risk -> Company or Risk -> Stage - [:EMPLOYED_BY]
User -> Company
Rib Properties
For example, in PARTICIPATES_IN:
- role
- startDate
- endDate
- status
In HAS_CONTRACT:
- contractNumber
- amount
- currency
- status
In HAS_RISK:
- severity
- detectedAt
Example of graph
(Company: Customer) -[:PARTICIPATES_IN {role:"customer"}]-> (Project)
(Company: GeneralContractor) -[:PARTICIPATES_IN {role:"general_contractor"}]-> (Project)
(Project) -[:HAS_CONTRACT]-> (Contract)
(Company: Customer) -[:CUSTOMER_IN]-> (Contract)
(Company: GeneralContractor) -[:CONTRACTOR_IN]-> (Contract)
(Project) -[:HAS_STAGE]-> (Stage: Construction)
(Project) -[:HAS_RISK {severity:"high"}]-> (Risk)
(Project) -[:LOCATED_AT]-> (Location)
Architecture API
For MVP REST API 1 is enough. Later you can add GraphQL for complex graph screens.
General rules API
Basic prefix
/api/v1
Format
{
"data": {},
"meta": {},
"error": null
}
Error
{
"data": null,
"meta": {},
"error": {
"code": "PROJECT_NOT_FOUND",
"message": "Project not found"
}
Authorization Authorization: Bearer <token>
Auth API. POST /auth/login. Login.
Request
{
"email": "user@example.com",
"password": "secret"
}
Response
{
"data": {
"accessToken": "jwt",
"refreshToken": "jwt",
"user": {
"id": "uuid",
"fullName": "Ivan Petrov",
"email": "user@example.com",
"roles": ["customer"]
}
},
"meta": {},
"error": null
}
POST /auth/refresh. Token Update.
GET /auth/me. Current User Profile.
API companies
GET /company. List of companies. Options:
- search
- companyType
- status
- page
- limit
POST /company. Create a company.
Request
{
"name": "StrojGrad" LLC,
"shortName": "StroyGrad",
"inn": "1234567890",
"ogrn": "1234567890123",
"companyType": "contractor",
"website": "https://example.com"
}
GET /companies/{id}. Company card.
PATCH /companies/{id}. Refresh the company.
GET /companies/{id}/projects. Company projects.
GET /companies/{id}/relations. Company relations in the graph.
Response
{
"data": {
"nodes": [
"id": "c1", "type": "company", "name": "StroyGrad" LLC ,
. "id": "p1", "type": "project", "name": "LK North" .
],
"edges": [
{
"from": "c1",
"to": "p1",
"type": "PARTICIPATES_IN",
"role": "contractor",
"status": "active"
}
]
},
"meta": {},
"error": null
}
API projects
GET /projects. List of projects. Filters:
- status
- lifecycleStage
- regionId
- customerCompanyId
- search
- page
- limit
POST /projects. Create a project.
Request
{
"name": "LK North",
"description": "Multifunctional residential complex",
"projectType": "residential",
"lifecycleStage": "design",
"status": "normal",
"location": {
"regionId": "uuid",
"address": "St. Petersburg, ...",
"lat": 59.93,
"lon": 30.31,
"cadastralNumber": "78:00:0000000:1234"
},
"customerCompanyId": "uuid",
"startDate": "2026-04-01",
"endDate": "2028-10-31",
"plannedBudget": 2500000000
}
GET /projects/{id}Project card.
PATCH /projects/{id}. Update the project.
GET /projects/{id}/graph. Main endpoint MVP. Returns the nodes and edges of the object.
Response
{
"data": {
"project": {
"id": "uuid",
"name": "LK North",
"status": "risk",
"lifecycleStage": "construction"
},
"nodes": [
"id": "p1", "type": "project", "name": "LK North", "status": "risk"
"id": "c1", "type": "company", "name": "Customer Development", "status": "active" ,
"id": "c2", "type": "company", "name": "GenContract 1", "status": "active" ,
"id": "r1", "type": "risk", "name": "Breaking deadlines", "status": "open"
],
"edges": [
{ "from": "c1", "to": "p1", "type": "PARTICIPATES_IN", "role": "customer", "status": "active" },
{ "from": "c2", "to": "p1", "type": "PARTICIPATES_IN", "role": "general_contractor", "status": "active" },
{ "from": "p1", "to": "r1", "type": "HAS_RISK", "severity": "high" }
]
},
"meta": {},
"error": null
}
GET /projects/{id}/timeline. Timeline of changes and events.
GET /projects/{id}/metrics. Project metrics.
GET /projects/{id}/risks. List of risks.
POST /projects/{id}/risks. Create risk.
GET /projects/{id}/documents. Project documents.
POST /projects/{id}/documents. Upload the document.
GET /projects/{id}/companies. Project participants.
POST /projects/{id}/companies. Add a participant to the project.
Request
{
"companyId": "uuid",
"role": "supplier",
"startDate": "2026-05-01",
"status": "active"
}
API stages of the project
GET /projects/{id}/stages. List of stages.
POST /projects/{id}/stages. Create a stage.
PATCH /projects/{id}/stages/{stageId}. Refresh the stage.
API contracts
GET /contracts. List of contracts. Filters:
- projectId
- customerCompanyId
- contractorCompanyId
- status
POST /contracts. Create a contract.
Request
{
"projectId": "uuid",
"contractNumber": "C-2026-001",
"contractType": "general_contract",
"customerCompanyId": "uuid",
"contractorCompanyId": "uuid",
"amount": 1500000000,
"currency": "RUB",
"dateStart": "2026-04-10",
"dateEnd": "2027-12-20",
"status": "active"
}
GET /contracts/{id}. Contract card.
PATCH /contracts/{id}. Update the contract.
API Risk
GET /risks. Overall list of risks. Filters:
- projectId
- severity
- status
- relatedCompanyId
POST /risks. Create risk.
PATCH /risks/{id}. Change the risk.
POST /risks/{id}/resolve. Close the risk.
API documents
GET /documents/{id}. Document metadata.
GET /documents/{id}/download Download file.
API Count. This is a separate service, because it is the heart of the system.
GET /graph/projects/{id}
Graph of the project.
GET /graph/companies/{id}
Company Count.
POST /graph/query
Search or analytical query to the graph. For MVP, it is better to limit template queries rather than give an arbitrary Cypher.
Request
{
"queryType": "project_neighbors",
"entityId": "uuid",
"depth": 2
}
GET /graph/search. Search for entities in the graph:
- q
- type
API analysts
GET /analytics/dashboard
Summary indicators:
- Number of projects
- Number of problem projects
- Number of open risks
- Number of active companies
GET /analytics/projects/status-summary
Summary of project status.
GET /analytics/companies/top-contractors
Top contractors by number of projects.
GET /analytics/risks/hotspots
Where the most risk.
API events
GET /events
Event log. Filters:
- projectId
- companyId
- eventType
- from
- to
Division into services. MVP requires 5 services.
auth-service
- login
- refresh
- me
- users
- roles
directory-service
- companies
- regions
- locations
project-service
- projects
- stages
- contracts
- documents
- risks
- metrics
- events
graph-service
- graph endpoints
- sync from PostgreSQL to Neo4j
- graph queries
analytics-service
- dashboards
- summaries
- alerts
PostgreSQL and Neo4j Sync
It's a big moment. The source of truth for cards is PostgreSQL. The source of truth for connections and detours is Neo4j.
Approach. After creating/updating the entity in PostgreSQL:
- Write an entry in events
- Publish an Event
- graph-service updates the graph
Examples of events:
- project.created
- project.updated
- company.added_to_project
- contract.created
- risk.created
Minimum DTO
CreateProjectDto
{
"name": "string",
"description": "string",
"projectType": "residential",
"lifecycleStage": "design",
"status": "normal",
"customerCompanyId": "uuid",
"startDate": "2026-04-01",
"endDate": "2027-12-31",
"plannedBudget": 1000000
}
AddCompanyToProjectDto
{
"companyId": "uuid",
"role": "contractor",
"startDate": "2026-04-01",
"endDate": null,
"status": "active"
}
CreateRiskDto
{
"projectId": "uuid",
"relatedCompanyId": "uuid",
"riskType": "deadline_delay",
"severity": "high",
"probability": "medium",
"description": "Lagging at 21 day"
}
What to do in the first version
Without this, MVP will be empty:
I will.
- projects
- companies
- contracts
- risks
- events
- GET /projects/{id}/graph
- GET /companies/{id}/relations
Can be postponed
- complex documents
- Advanced Analytics
- IoT
- BIM-storage
- Marketplace
Direct recommended stack under this scheme
Backend
- NestJS
- PostgreSQL
- Prisma or TypeORM
- Neo4j
- Redis for cache and queues
- Swagger/OpenAPI for documentation
Frontend
- Next.js
- React Query
- Cytoscape.js for graph
- Tailwind CSS or MUI
Infra
- Docker
- Docker Compose for MVP
- Nginx
- S3-compatible document storage
Repository Structure
/crystal-construction
/apps
/api-gateway
/auth-service
/directory-service
/project-service
/graph-service
/analytics-service
/web-client
/packages
/shared-types
/shared-utils
/ui
/infra
/docker
/nginx
/db
/docs
openapi.yaml
database-schema.md
graph-model.md
The most correct order of assembly
- Raise auth-service
- Raise directory-service
- Make a project-service
- Make graph-service
- Connect UI to GET /projects/{id}/graph
- Add risks and events
- Add Dashboard
MVP should answer 4 questions:
- What kind of object is that?
- Who's connected to him?
- Where's the risk?
- What's going on now?
If API and DB give it, you already have the working core of the Building Crystal.
1. OpenAPI
Below is a shortened, but working framework specification OpenAPI 3.1 for MVP.
openapi: 3.1.0
info:
title: Crystal Construction API
version: 1.0.0
description: API MVP Platform "Crystal Construction"
servers:
- url: https://api.crystal-construction.local/api/v1
tags:
- name: Auth
- name: Companies
- name: Projects
- name: Contracts
- name: Risks
- name: Graph
- name: Analytics
paths:
/auth/login:
post:
tags: [Auth]
summary: User login
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/LoginRequest'
responses:
'200':
Description: Successful entry
content:
application/json:
schema:
$ref: '#/components/schemas/AuthResponse'
/auth/me:
get:
tags: [Auth]
summary: Profile of current user
security:
- bearerAuth: []
responses:
'200':
description: User profile
content:
application/json:
schema:
$ref: '#/components/schemas/UserProfileResponse'
/companies:
get:
tags: [Companies]
summary: List of companies
security:
- bearerAuth: []
parameters:
- in: query
name: search
schema: { type: string }
- in: query
name: companyType
schema: { type: string }
- in: query
name: status
schema: { type: string }
- in: query
name: page
schema: { type: integer, minimum: 1, default: 1 }
- in: query
name: limit
schema: { type: integer, minimum: 1, maximum: 100, default: 20 }
responses:
'200':
description: List of companies
content:
application/json:
schema:
$ref: '#/components/schemas/CompanyListResponse'
post:
tags: [Companies]
Summary: Creating a company
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateCompanyRequest'
responses:
'201':
description: Company created
content:
application/json:
schema:
$ref: '#/components/schemas/CompanyResponse'
/companies/{id}:
get:
tags: [Companies]
summary: Company card
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdPath'
responses:
'200':
description: Company data
content:
application/json:
schema:
$ref: '#/components/schemas/CompanyResponse'
patch:
tags: [Companies]
Summary: Renovating the company
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdPath'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateCompanyRequest'
responses:
'200':
description: Company updated
content:
application/json:
schema:
$ref: '#/components/schemas/CompanyResponse'
/companies/{id}/relations:
get:
tags: [Graph]
summary: Company relations graph
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdPath'
- in: query
name: depth
schema: { type: integer, minimum: 1, maximum: 3, default: 1 }
responses:
'200':
description: Company Count
content:
application/json:
schema:
$ref: '#/components/schemas/GraphResponse'
/projects:
get:
tags: [Projects]
summary: List of projects
security:
- bearerAuth: []
parameters:
- in: query
name: status
schema: { type: string }
- in: query
name: lifecycleStage
schema: { type: string }
- in: query
name: regionId
schema: { type: string, format: uuid }
- in: query
name: customerCompanyId
schema: { type: string, format: uuid }
- in: query
name: search
schema: { type: string }
- in: query
name: page
schema: { type: integer, default: 1 }
- in: query
name: limit
schema: { type: integer, default: 20 }
responses:
'200':
description: List of projects
content:
application/json:
schema:
$ref: '#/components/schemas/ProjectListResponse'
post:
tags: [Projects]
summary: Create a project
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateProjectRequest'
responses:
'201':
description: Project created
content:
application/json:
schema:
$ref: '#/components/schemas/ProjectResponse'
/projects/{id}:
get:
tags: [Projects]
summary: Project card
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdPath'
responses:
'200':
description: Project data
content:
application/json:
schema:
$ref: '#/components/schemas/ProjectResponse'
patch:
tags: [Projects]
summary: Update the project
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdPath'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateProjectRequest'
responses:
'200':
description: Project updated
content:
application/json:
schema:
$ref: '#/components/schemas/ProjectResponse'
/projects/{id}/graph:
get:
tags: [Graph]
summary: Project graph
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdPath'
- in: query
name: depth
schema: { type: integer, minimum: 1, maximum: 3, default: 2 }
responses:
'200':
description: Project graph
content:
application/json:
schema:
$ref: '#/components/schemas/ProjectGraphResponse'
/projects/{id}/companies:
post:
tags: [Projects]
summary: Add a participant to the project
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdPath'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/AddCompanyToProjectRequest'
responses:
'201':
description: Member added
content:
application/json:
schema:
$ref: '#/components/schemas/OperationResponse'
/contracts:
get:
tags: [Contracts]
summary: List of contracts
security:
- bearerAuth: []
parameters:
- in: query
name: projectId
schema: { type: string, format: uuid }
- in: query
name: customerCompanyId
schema: { type: string, format: uuid }
- in: query
name: contractorCompanyId
schema: { type: string, format: uuid }
- in: query
name: status
schema: { type: string }
responses:
'200':
description: List of contracts
content:
application/json:
schema:
$ref: '#/components/schemas/ContractListResponse'
post:
tags: [Contracts]
Summary: Create a contract
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateContractRequest'
responses:
'201':
description: Contract created
content:
application/json:
schema:
$ref: '#/components/schemas/ContractResponse'
/risks:
get:
tags: [Risks]
Summary: List of risks
security:
- bearerAuth: []
parameters:
- in: query
name: projectId
schema: { type: string, format: uuid }
- in: query
name: severity
schema: { type: string }
- in: query
name: status
schema: { type: string }
responses:
'200':
Description: List of risks
content:
application/json:
schema:
$ref: '#/components/schemas/RiskListResponse'
post:
tags: [Risks]
Summary: Creating Risk
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateRiskRequest'
responses:
'201':
Description: Risk created
content:
application/json:
schema:
$ref: '#/components/schemas/RiskResponse'
/risks/{id}/resolve:
post:
tags: [Risks]
Summary: Closing the Risk
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdPath'
responses:
'200':
Description: Risk is closed
content:
application/json:
schema:
$ref: '#/components/schemas/RiskResponse'
/analytics/dashboard:
get:
tags: [Analytics]
summary: Dashboard MVP
security:
- bearerAuth: []
responses:
'200':
description: Summary analytics
content:
application/json:
schema:
$ref: '#/components/schemas/DashboardResponse'
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
parameters:
IdPath:
in: path
name: id
required: true
schema:
type: string
format: uuid
schemas:
ApiError:
type: object
properties:
code: { type: string }
message: { type: string }
required: [code, message]
LoginRequest:
type: object
properties:
email: { type: string, format: email }
password: { type: string }
required: [email, password]
AuthUser:
type: object
properties:
id: { type: string, format: uuid }
fullName: { type: string }
email: { type: string, format: email }
roles:
type: array
items: { type: string }
required: [id, fullName, email, roles]
AuthResponse:
type: object
properties:
data:
type: object
properties:
accessToken: { type: string }
refreshToken: { type: string }
user:
$ref: '#/components/schemas/AuthUser'
meta: { type: object }
error:
oneOf:
- $ref: '#/components/schemas/ApiError'
- { type: 'null' }
UserProfileResponse:
type: object
properties:
data:
$ref: '#/components/schemas/AuthUser'
meta: { type: object }
error:
oneOf:
- $ref: '#/components/schemas/ApiError'
- { type: 'null' }
Company:
type: object
properties:
id: { type: string, format: uuid }
name: { type: string }
shortName: { type: string }
inn: { type: string }
ogrn: { type: string }
companyType: { type: string }
rating: { type: number }
status: { type: string }
website: { type: string, nullable: true }
required: [id, name, companyType, status]
CreateCompanyRequest:
type: object
properties:
name: { type: string }
shortName: { type: string }
inn: { type: string }
ogrn: { type: string }
companyType: { type: string }
website: { type: string }
required: [name, inn, ogrn, companyType]
UpdateCompanyRequest:
type: object
properties:
name: { type: string }
shortName: { type: string }
companyType: { type: string }
rating: { type: number }
status: { type: string }
website: { type: string }
CompanyResponse:
type: object
properties:
data:
$ref: '#/components/schemas/Company'
meta: { type: object }
error:
oneOf:
- $ref: '#/components/schemas/ApiError'
- { type: 'null' }
CompanyListResponse:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/Company'
meta:
type: object
properties:
page: { type: integer }
limit: { type: integer }
total: { type: integer }
error:
oneOf:
- $ref: '#/components/schemas/ApiError'
- { type: 'null' }
LocationInput:
type: object
properties:
regionId: { type: string, format: uuid }
address: { type: string }
lat: { type: number }
lon: { type: number }
cadastralNumber: { type: string }
required: [regionId, address]
Project:
type: object
properties:
id: { type: string, format: uuid }
code: { type: string }
name: { type: string }
description: { type: string, nullable: true }
projectType: { type: string }
lifecycleStage: { type: string }
status: { type: string }
customerCompanyId: { type: string, format: uuid }
startDate: { type: string, format: date, nullable: true }
endDate: { type: string, format: date, nullable: true }
plannedBudget: { type: number, nullable: true }
actualBudget: { type: number, nullable: true }
required: [id, name, projectType, lifecycleStage, status]
CreateProjectRequest:
type: object
properties:
name: { type: string }
description: { type: string }
projectType: { type: string }
lifecycleStage: { type: string }
status: { type: string }
location:
$ref: '#/components/schemas/LocationInput'
customerCompanyId: { type: string, format: uuid }
startDate: { type: string, format: date }
endDate: { type: string, format: date }
plannedBudget: { type: number }
required:
- name
- projectType
- lifecycleStage
- status
- location
- customerCompanyId
UpdateProjectRequest:
type: object
properties:
name: { type: string }
description: { type: string }
lifecycleStage: { type: string }
status: { type: string }
actualBudget: { type: number }
endDate: { type: string, format: date }
ProjectResponse:
type: object
properties:
data:
$ref: '#/components/schemas/Project'
meta: { type: object }
error:
oneOf:
- $ref: '#/components/schemas/ApiError'
- { type: 'null' }
ProjectListResponse:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/Project'
meta:
type: object
properties:
page: { type: integer }
limit: { type: integer }
total: { type: integer }
error:
oneOf:
- $ref: '#/components/schemas/ApiError'
- { type: 'null' }
GraphNode:
type: object
properties:
id: { type: string }
type: { type: string }
name: { type: string }
status: { type: string, nullable: true }
metadata:
type: object
additionalProperties: true
required: [id, type, name]
GraphEdge:
type: object
properties:
from: { type: string }
to: { type: string }
type: { type: string }
role: { type: string, nullable: true }
status: { type: string, nullable: true }
metadata:
type: object
additionalProperties: true
required: [from, to, type]
GraphResponse:
type: object
properties:
data:
type: object
properties:
nodes:
type: array
items: { $ref: '#/components/schemas/GraphNode' }
edges:
type: array
items: { $ref: '#/components/schemas/GraphEdge' }
meta: { type: object }
error:
oneOf:
- $ref: '#/components/schemas/ApiError'
- { type: 'null' }
ProjectGraphResponse:
type: object
properties:
data:
type: object
properties:
project:
$ref: '#/components/schemas/Project'
nodes:
type: array
items: { $ref: '#/components/schemas/GraphNode' }
edges:
type: array
items: { $ref: '#/components/schemas/GraphEdge' }
meta: { type: object }
error:
oneOf:
- $ref: '#/components/schemas/ApiError'
- { type: 'null' }
CreateContractRequest:
type: object
properties:
projectId: { type: string, format: uuid }
contractNumber: { type: string }
contractType: { type: string }
customerCompanyId: { type: string, format: uuid }
contractorCompanyId: { type: string, format: uuid }
amount: { type: number }
currency: { type: string }
dateStart: { type: string, format: date }
dateEnd: { type: string, format: date }
status: { type: string }
required:
- projectId
- contractNumber
- contractType
- customerCompanyId
- contractorCompanyId
- amount
- currency
- status
Contract:
type: object
properties:
id: { type: string, format: uuid }
projectId: { type: string, format: uuid }
contractNumber: { type: string }
contractType: { type: string }
customerCompanyId: { type: string, format: uuid }
contractorCompanyId: { type: string, format: uuid }
amount: { type: number }
currency: { type: string }
status: { type: string }
required: [id, projectId, contractNumber, contractType, amount, currency, status]
ContractResponse:
type: object
properties:
data:
$ref: '#/components/schemas/Contract'
meta: { type: object }
error:
oneOf:
- $ref: '#/components/schemas/ApiError'
- { type: 'null' }
ContractListResponse:
type: object
properties:
data:
type: array
items: { $ref: '#/components/schemas/Contract' }
meta: { type: object }
error:
oneOf:
- $ref: '#/components/schemas/ApiError'
- { type: 'null' }
CreateRiskRequest:
type: object
properties:
projectId: { type: string, format: uuid }
relatedCompanyId: { type: string, format: uuid, nullable: true }
riskType: { type: string }
severity: { type: string }
probability: { type: string }
description: { type: string }
required: [projectId, riskType, severity, probability, description]
Risk:
type: object
properties:
id: { type: string, format: uuid }
projectId: { type: string, format: uuid }
relatedCompanyId: { type: string, format