Files
microdao-daarion/site/services/CITY_SERVICE_SPEC/index.html
Apple ef3473db21 snapshot: NODE1 production state 2026-02-09
Complete snapshot of /opt/microdao-daarion/ from NODE1 (144.76.224.179).
This represents the actual running production code that has diverged
significantly from the previous main branch.

Key changes from old main:
- Gateway (http_api.py): expanded from ~40KB to 164KB with full agent support
- Router: new /v1/agents/{id}/infer endpoint with vision + DeepSeek routing
- Behavior Policy: SOWA v2.2 (3-level: FULL/ACK/SILENT)
- Agent Registry: config/agent_registry.yml as single source of truth
- 13 agents configured (was 3)
- Memory service integration
- CrewAI teams and roles

Excluded from snapshot: venv/, .env, data/, backups, .tgz archives

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-09 08:46:46 -08:00

953 lines
42 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="canonical" href="https://IvanTytar.github.io/microdao-daarion/services/CITY_SERVICE_SPEC/">
<link rel="icon" href="../../assets/images/favicon.png">
<meta name="generator" content="mkdocs-1.5.3, mkdocs-material-9.5.18">
<title>CITY SERVICE SPEC (PORT 7001) - DAARION Documentation</title>
<link rel="stylesheet" href="../../assets/stylesheets/main.66ac8b77.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
<script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
</head>
<body dir="ltr">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#city-service-spec-port-7001" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header md-header--shadow" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href="../.." title="DAARION Documentation" class="md-header__button md-logo" aria-label="DAARION Documentation" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54Z"/></svg>
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3V6m0 5h18v2H3v-2m0 5h18v2H3v-2Z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
DAARION Documentation
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
CITY SERVICE SPEC (PORT 7001)
</span>
</div>
</div>
</div>
<script>var media,input,key,value,palette=__md_get("__palette");if(palette&&palette.color){"(prefers-color-scheme)"===palette.color.media&&(media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']"),palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent"));for([key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"/></svg>
</label>
<nav class="md-search__options" aria-label="Search">
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41Z"/></svg>
</button>
</nav>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list" role="presentation"></ol>
</div>
</div>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href="../.." title="DAARION Documentation" class="md-nav__button md-logo" aria-label="DAARION Documentation" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54Z"/></svg>
</a>
DAARION Documentation
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../public/" class="md-nav__link">
<span class="md-ellipsis">
Home
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../public/getting-started/" class="md-nav__link">
<span class="md-ellipsis">
Getting Started
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../public/architecture-overview/" class="md-nav__link">
<span class="md-ellipsis">
Architecture
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../public/daiS_daos_overview/" class="md-nav__link">
<span class="md-ellipsis">
DAIS & DAOS
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5" >
<label class="md-nav__link" for="__nav_5" id="__nav_5_label" tabindex="">
<span class="md-ellipsis">
Internal
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_5_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5">
<span class="md-nav__icon md-icon"></span>
Internal
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_1" >
<label class="md-nav__link" for="__nav_5_1" id="__nav_5_1_label" tabindex="0">
<span class="md-ellipsis">
Infra
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_1_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_1">
<span class="md-nav__icon md-icon"></span>
Infra
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../internal/infra/INFRA_AUTOMATION_PACK_V1/" class="md-nav__link">
<span class="md-ellipsis">
Infra Automation Pack v1
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../internal/infra/monitoring_overview/" class="md-nav__link">
<span class="md-ellipsis">
Monitoring Overview
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../internal/infra/nodes_registry_v0/" class="md-nav__link">
<span class="md-ellipsis">
Nodes Registry v0
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_2" >
<label class="md-nav__link" for="__nav_5_2" id="__nav_5_2_label" tabindex="0">
<span class="md-ellipsis">
Specs
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_2">
<span class="md-nav__icon md-icon"></span>
Specs
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../internal/specs/matrix_presence_aggregator/" class="md-nav__link">
<span class="md-ellipsis">
Matrix Presence Aggregator
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../internal/specs/city_map_spec/" class="md-nav__link">
<span class="md-ellipsis">
City Map Spec
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../internal/specs/node_join_protocol_draft/" class="md-nav__link">
<span class="md-ellipsis">
Node Join Protocol (Draft)
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<h1 id="city-service-spec-port-7001">CITY SERVICE SPEC (PORT 7001)<a class="headerlink" href="#city-service-spec-port-7001" title="Permanent link">&para;</a></h1>
<h1 id="version-100">Version: 1.0.0<a class="headerlink" href="#version-100" title="Permanent link">&para;</a></h1>
<hr />
<h2 id="0-purpose">0. PURPOSE<a class="headerlink" href="#0-purpose" title="Permanent link">&para;</a></h2>
<p><code>City Service</code> — геопросторовий та соціальний шар DAARION.city.</p>
<p>Цей сервіс забезпечує:</p>
<ol>
<li><strong>Living Map</strong> — стан міста в реальному часі:</li>
<li>райони,</li>
<li>локації,</li>
<li>структури microDAO,</li>
<li>
<p>активні агенти та користувачі.</p>
</li>
<li>
<p><strong>Presence System</strong> — відстеження присутності:</p>
</li>
<li>хто знаходиться в якому районі/секторі/каналі,</li>
<li>
<p>статуси присутності користувачів і агентів.</p>
</li>
<li>
<p><strong>Geo Intelligence</strong>:</p>
</li>
<li>обробка геолокаційних даних,</li>
<li>інтеграція з Geo-agent (мультимодальність),</li>
<li>
<p>аналіз шляхів, зон та кластерів.</p>
</li>
<li>
<p><strong>Project / MicroDAO Mapping</strong>:</p>
</li>
<li>кожен microDAO має свій "віртуальний район",</li>
<li>
<p>кожен проєкт — "будівлю/кластер".</p>
</li>
<li>
<p><strong>Integration with TeamDefinition &amp; ProjectBus</strong>:</p>
</li>
<li>локації = канали / контексти,</li>
<li>routing для комунікації між агентами у межах "районів".</li>
</ol>
<p>Порт сервісу: <strong>7001</strong>.</p>
<hr />
<h2 id="1-functional-overview">1. FUNCTIONAL OVERVIEW<a class="headerlink" href="#1-functional-overview" title="Permanent link">&para;</a></h2>
<div class="codehilite"><pre><span></span><code>[ Gateway / Web UI / Living Map UI ]
[ DAGI Router ] — (text/multimodal events)
[ City Service (7001) ]
[ PostgreSQL + NATS + Geo-agent ]
</code></pre></div>
<p>City Service синхронізує:</p>
<ul>
<li><em>місто як карту</em> (Region/Area/Point),</li>
<li><em>місто як соціальну мережу</em> (Presence),</li>
<li><em>місто як структуру проектів і microDAO</em>.</li>
</ul>
<hr />
<h2 id="2-core-data-structures">2. CORE DATA STRUCTURES<a class="headerlink" href="#2-core-data-structures" title="Permanent link">&para;</a></h2>
<h3 id="21-region">2.1. Region (Регіон)<a class="headerlink" href="#21-region" title="Permanent link">&para;</a></h3>
<p>Віртуальний район DAARION.city:</p>
<div class="codehilite"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;region_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;district-greenfood&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;name&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;GREENFOOD District&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;type&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;microdao&quot;</span><span class="p">,</span><span class="w"> </span><span class="c1">// microdao | project | custom</span>
<span class="w"> </span><span class="nt">&quot;microdao_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;microdao-greenfood&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;geometry&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nt">&quot;type&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Polygon&quot;</span><span class="p">,</span><span class="w"> </span><span class="nt">&quot;coordinates&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="err">...</span><span class="p">]</span><span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="nt">&quot;meta&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nt">&quot;color&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;#2ecc71&quot;</span><span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<h3 id="22-area-building-sector">2.2. Area / Building / Sector<a class="headerlink" href="#22-area-building-sector" title="Permanent link">&para;</a></h3>
<p>Локальні локації всередині регіонів:</p>
<div class="codehilite"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;area_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;area-greenfood-core&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;region_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;district-greenfood&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;name&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Core Operations&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;geometry&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nt">&quot;type&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Polygon&quot;</span><span class="p">,</span><span class="w"> </span><span class="nt">&quot;coordinates&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="err">...</span><span class="p">]</span><span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="nt">&quot;project_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;proj-greenfood&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;meta&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{}</span>
<span class="p">}</span>
</code></pre></div>
<h3 id="23-presence">2.3. Presence<a class="headerlink" href="#23-presence" title="Permanent link">&para;</a></h3>
<p>Хто перебуває де:</p>
<div class="codehilite"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;subject_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;ag_helix&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;subject_type&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;agent&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;region_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;district-greenfood&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;area_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;area-greenfood-core&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;active&quot;</span><span class="p">,</span><span class="w"> </span><span class="c1">// active|idle|offline</span>
<span class="w"> </span><span class="nt">&quot;updated_at&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;2025-11-24T10:00:00Z&quot;</span>
<span class="p">}</span>
</code></pre></div>
<h3 id="24-location-update-event">2.4. Location Update Event<a class="headerlink" href="#24-location-update-event" title="Permanent link">&para;</a></h3>
<div class="codehilite"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;subject_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;user123&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;subject_type&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;user&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;geo&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nt">&quot;lat&quot;</span><span class="p">:</span><span class="w"> </span><span class="mf">52.52</span><span class="p">,</span><span class="w"> </span><span class="nt">&quot;lon&quot;</span><span class="p">:</span><span class="w"> </span><span class="mf">13.40</span><span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="nt">&quot;region_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;district-greenfood&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;area_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;area-greenfood-core&quot;</span>
<span class="p">}</span>
</code></pre></div>
<hr />
<h2 id="3-database-schema-postgresql-postgis">3. DATABASE SCHEMA (PostgreSQL + PostGIS)<a class="headerlink" href="#3-database-schema-postgresql-postgis" title="Permanent link">&para;</a></h2>
<p>City Service повинен мати PostGIS.</p>
<h3 id="31-regions">3.1. regions<a class="headerlink" href="#31-regions" title="Permanent link">&para;</a></h3>
<div class="codehilite"><pre><span></span><code><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">regions</span><span class="w"> </span><span class="p">(</span>
<span class="w"> </span><span class="n">region_id</span><span class="w"> </span><span class="nb">TEXT</span><span class="w"> </span><span class="k">PRIMARY</span><span class="w"> </span><span class="k">KEY</span><span class="p">,</span>
<span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="nb">TEXT</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="p">,</span>
<span class="w"> </span><span class="k">type</span><span class="w"> </span><span class="nb">TEXT</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="p">,</span>
<span class="w"> </span><span class="n">microdao_id</span><span class="w"> </span><span class="nb">TEXT</span><span class="p">,</span>
<span class="w"> </span><span class="n">geometry</span><span class="w"> </span><span class="n">GEOMETRY</span><span class="p">(</span><span class="n">POLYGON</span><span class="p">,</span><span class="w"> </span><span class="mi">4326</span><span class="p">),</span>
<span class="w"> </span><span class="n">meta</span><span class="w"> </span><span class="n">JSONB</span><span class="w"> </span><span class="k">DEFAULT</span><span class="w"> </span><span class="s1">&#39;{}&#39;</span><span class="p">::</span><span class="n">jsonb</span>
<span class="p">);</span>
</code></pre></div>
<h3 id="32-areas">3.2. areas<a class="headerlink" href="#32-areas" title="Permanent link">&para;</a></h3>
<div class="codehilite"><pre><span></span><code><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">areas</span><span class="w"> </span><span class="p">(</span>
<span class="w"> </span><span class="n">area_id</span><span class="w"> </span><span class="nb">TEXT</span><span class="w"> </span><span class="k">PRIMARY</span><span class="w"> </span><span class="k">KEY</span><span class="p">,</span>
<span class="w"> </span><span class="n">region_id</span><span class="w"> </span><span class="nb">TEXT</span><span class="w"> </span><span class="k">REFERENCES</span><span class="w"> </span><span class="n">regions</span><span class="p">(</span><span class="n">region_id</span><span class="p">),</span>
<span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="nb">TEXT</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="p">,</span>
<span class="w"> </span><span class="n">project_id</span><span class="w"> </span><span class="nb">TEXT</span><span class="p">,</span>
<span class="w"> </span><span class="n">geometry</span><span class="w"> </span><span class="n">GEOMETRY</span><span class="p">(</span><span class="n">POLYGON</span><span class="p">,</span><span class="w"> </span><span class="mi">4326</span><span class="p">),</span>
<span class="w"> </span><span class="n">meta</span><span class="w"> </span><span class="n">JSONB</span><span class="w"> </span><span class="k">DEFAULT</span><span class="w"> </span><span class="s1">&#39;{}&#39;</span><span class="p">::</span><span class="n">jsonb</span>
<span class="p">);</span>
</code></pre></div>
<h3 id="33-presence">3.3. presence<a class="headerlink" href="#33-presence" title="Permanent link">&para;</a></h3>
<div class="codehilite"><pre><span></span><code><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">presence</span><span class="w"> </span><span class="p">(</span>
<span class="w"> </span><span class="n">subject_id</span><span class="w"> </span><span class="nb">TEXT</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="p">,</span>
<span class="w"> </span><span class="n">subject_type</span><span class="w"> </span><span class="nb">TEXT</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="p">,</span>
<span class="w"> </span><span class="n">region_id</span><span class="w"> </span><span class="nb">TEXT</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="p">,</span>
<span class="w"> </span><span class="n">area_id</span><span class="w"> </span><span class="nb">TEXT</span><span class="p">,</span>
<span class="w"> </span><span class="n">status</span><span class="w"> </span><span class="nb">TEXT</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="p">,</span>
<span class="w"> </span><span class="n">updated_at</span><span class="w"> </span><span class="k">TIMESTAMP</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="w"> </span><span class="k">DEFAULT</span><span class="w"> </span><span class="n">now</span><span class="p">(),</span>
<span class="w"> </span><span class="k">PRIMARY</span><span class="w"> </span><span class="k">KEY</span><span class="w"> </span><span class="p">(</span><span class="n">subject_id</span><span class="p">,</span><span class="w"> </span><span class="n">subject_type</span><span class="p">)</span>
<span class="p">);</span>
</code></pre></div>
<hr />
<h2 id="4-public-http-api-city-service">4. PUBLIC HTTP API (CITY SERVICE)<a class="headerlink" href="#4-public-http-api-city-service" title="Permanent link">&para;</a></h2>
<h3 id="41-get-regions">4.1. <code>GET /regions</code><a class="headerlink" href="#41-get-regions" title="Permanent link">&para;</a></h3>
<p>Список усіх регіонів міста.</p>
<h3 id="42-post-regions">4.2. <code>POST /regions</code><a class="headerlink" href="#42-post-regions" title="Permanent link">&para;</a></h3>
<p>Створити новий регіон (переважно для microDAO).</p>
<h3 id="43-get-areasregion_id">4.3. <code>GET /areas?region_id=...</code><a class="headerlink" href="#43-get-areasregion_id" title="Permanent link">&para;</a></h3>
<p>Список локацій у межах регіону.</p>
<h3 id="44-post-presenceupdate">4.4. <code>POST /presence/update</code><a class="headerlink" href="#44-post-presenceupdate" title="Permanent link">&para;</a></h3>
<p>Оновити присутність учасника/агента.</p>
<p><strong>Request:</strong></p>
<div class="codehilite"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;subject_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;ag_helion&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;subject_type&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;agent&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;geo&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nt">&quot;lat&quot;</span><span class="p">:</span><span class="w"> </span><span class="mf">50.45</span><span class="p">,</span><span class="w"> </span><span class="nt">&quot;lon&quot;</span><span class="p">:</span><span class="w"> </span><span class="mf">30.52</span><span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>Відповідь після визначення регіону/зони:</p>
<div class="codehilite"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;ok&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;region_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;district-daariandao&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;area_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;area-governance&quot;</span>
<span class="p">}</span>
</code></pre></div>
<h3 id="45-get-presenceregion_id">4.5. <code>GET /presence?region_id=...</code><a class="headerlink" href="#45-get-presenceregion_id" title="Permanent link">&para;</a></h3>
<p>Повертає, хто зараз у районі.</p>
<hr />
<h2 id="5-geo-agent-integration">5. GEO-AGENT INTEGRATION<a class="headerlink" href="#5-geo-agent-integration" title="Permanent link">&para;</a></h2>
<p>Geo-agent (мультимодальність) використовується для:</p>
<ol>
<li>
<p><strong>Інтерпретація геоданих</strong>:</p>
</li>
<li>
<p>визначити район по координатам,</p>
</li>
<li>визначити найближчу зону,</li>
<li>
<p>кластеризація.</p>
</li>
<li>
<p><strong>Запити від користувача</strong>:</p>
</li>
<li>
<p>"Покажи активність агентів у районі GREENFOOD"</p>
</li>
<li>"Яким шляхом рухається агент X?"</li>
<li>
<p>"Які агенти у проекті Y зараз активні?"</p>
</li>
<li>
<p><strong>Генерація інсайтів</strong>:</p>
</li>
<li>
<p>heat maps,</p>
</li>
<li>аномалії присутності,</li>
<li>навігація робочих потоків.</li>
</ol>
<p>City Service викликає Geo-agent через:</p>
<div class="codehilite"><pre><span></span><code>POST /multimodal/geo/infer
</code></pre></div>
<p>або NATS subject:</p>
<div class="codehilite"><pre><span></span><code>dagi.geo.infer
</code></pre></div>
<p>Payload:</p>
<div class="codehilite"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;lat&quot;</span><span class="p">:</span><span class="w"> </span><span class="mf">50.45</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;lon&quot;</span><span class="p">:</span><span class="w"> </span><span class="mf">30.52</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;regions&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="err">...</span><span class="p">],</span>
<span class="w"> </span><span class="nt">&quot;areas&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="err">...</span><span class="p">]</span>
<span class="p">}</span>
</code></pre></div>
<hr />
<h2 id="6-project-bus-integration">6. PROJECT BUS INTEGRATION<a class="headerlink" href="#6-project-bus-integration" title="Permanent link">&para;</a></h2>
<p>City Service взаємодіє з ProjectBus:</p>
<ul>
<li>коли створюється новий microDAO → створюється новий регіон;</li>
<li>коли створюється новий проект → нова area/cluster;</li>
<li>агенти/користувачі приєднуються до проектів → presence оновлюється.</li>
</ul>
<p>Оновлення:</p>
<ul>
<li><code>project.&lt;id&gt;.events</code> — події щодо присутності,</li>
<li><code>project.&lt;id&gt;.map.events</code> — події для UI living map.</li>
</ul>
<p>Приклад події:</p>
<div class="codehilite"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;type&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;presence_updated&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;project_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;proj-greenfood&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;subject_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;ag_helix&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;region_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;district-greenfood&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;area_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;area-greenfood-core&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;ts&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;2025-11-24T10:10:00Z&quot;</span>
<span class="p">}</span>
</code></pre></div>
<hr />
<h2 id="7-dagi-router-integration">7. DAGI ROUTER INTEGRATION<a class="headerlink" href="#7-dagi-router-integration" title="Permanent link">&para;</a></h2>
<p>City Service інформує DAGI Router про:</p>
<ul>
<li>
<p>зміни регіону/зони:</p>
</li>
<li>
<p>агенти отримують контекст <code>region_id</code> / <code>area_id</code>,</p>
</li>
<li>Router може маршрутизувати події за локацією,</li>
<li>routing за region-каналами (геочати),</li>
<li>особливі правила поведінки в певних регіонах (через TeamDefinition).</li>
</ul>
<p>Router додає в кожен RouterEvent:</p>
<div class="codehilite"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;context&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;region_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;...&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;area_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;...&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;project_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;...&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;microdao_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;...&quot;</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<hr />
<h2 id="8-multinode-support">8. MULTINODE SUPPORT<a class="headerlink" href="#8-multinode-support" title="Permanent link">&para;</a></h2>
<p>City Service може бути:</p>
<ul>
<li>один на всі ноди (centralized),</li>
<li>
<p>або розгорнутий на кожній НОДА:</p>
</li>
<li>
<p>локальна кешована карта,</p>
</li>
<li>синхронізація через NATS.</li>
</ul>
<p>Оптимально:</p>
<div class="codehilite"><pre><span></span><code>NODE1 = primary city-service
NODE2/NODE3 = read replicas cache + local geo-routing
</code></pre></div>
<hr />
<h2 id="9-healthcheck-metrics">9. HEALTHCHECK &amp; METRICS<a class="headerlink" href="#9-healthcheck-metrics" title="Permanent link">&para;</a></h2>
<h3 id="91-get-healthz">9.1. <code>GET /healthz</code><a class="headerlink" href="#91-get-healthz" title="Permanent link">&para;</a></h3>
<div class="codehilite"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;ok&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;db&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;ok&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;geo_agent&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;ok&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;uptime_seconds&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">21344</span>
<span class="p">}</span>
</code></pre></div>
<h3 id="92-prometheus-metrics">9.2. Prometheus metrics<a class="headerlink" href="#92-prometheus-metrics" title="Permanent link">&para;</a></h3>
<ul>
<li><code>presence_updates_total</code></li>
<li><code>active_subjects{region_id}</code></li>
<li><code>geo_queries_total</code></li>
<li><code>geo_inference_latency_ms_bucket</code></li>
<li><code>area_popularity{region_id, area_id}</code></li>
</ul>
<hr />
<h2 id="10-living-map-ui-future">10. LIVING MAP UI (FUTURE)<a class="headerlink" href="#10-living-map-ui-future" title="Permanent link">&para;</a></h2>
<p>City Service підтримує:</p>
<ul>
<li>API для реального часу (WebSocket/NATS),</li>
<li>
<p>2D-UI та 3D-UI клієнти:</p>
</li>
<li>
<p>Three.js / Babylon.js / Unity WebGL.</p>
</li>
</ul>
<p>Плани:</p>
<ul>
<li>місто як <strong>візуальна карта</strong> проектів,</li>
<li>агентські маршрути,</li>
<li>стан об'єктів, сервісів та microDAO,</li>
<li>heatmap активності.</li>
</ul>
<hr />
<h2 id="11-summary">11. SUMMARY<a class="headerlink" href="#11-summary" title="Permanent link">&para;</a></h2>
<p>City Service (7001):</p>
<ul>
<li>геопросторовий та "соціальний" шар DAARION,</li>
<li>формує логіку районів microDAO та проектних зон,</li>
<li>управляє присутністю користувачів і агентів,</li>
<li>інтегрується з DAGI Router, Geo-agent, ProjectBus, MicroDAO Service,</li>
<li>основа для 2D/3D карт та мультимодальних геоаналітик.</li>
</ul>
<p>Це ключовий сервіс, який робить DAARION.city "живим містом", а не просто набором мікросервісів.</p>
</article>
</div>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"base": "../..", "features": ["navigation.sections", "navigation.instant", "content.code.copy"], "search": "../../assets/javascripts/workers/search.b8dbb3d2.min.js", "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}}</script>
<script src="../../assets/javascripts/bundle.3220b9d7.min.js"></script>
</body>
</html>