◀بازگشت به پروپوزال اصلی نگاهبان
نگاهبان • محرمانه — ویژهٔ تیم فنی

سند فنی و راهنمای پیاده‌سازی

سامانهٔ هوشمند امنیت و نگهبانی — مرجع مهندسی و نقشهٔ راه ساخت
نسخهٔ ۱٫۰خرداد ۱۴۰۵

1مقدمه و دامنهٔ سند

این سند، مرجع فنیِ واحدِ تیم مهندسی برای طراحی، پیاده‌سازی و استقرار سامانهٔ «نگاهبان» است. هدف، تبدیل نیازمندی‌های محصول به یک معماری اجراییِ دقیق و یک نقشهٔ راهِ ساختِ بخش‌به‌بخش است.

مخاطب این سند، توسعه‌دهندگان Backend و موبایل، مهندسان هوش مصنوعی، DevOps و مسئول امنیت است. فرض بر آشنایی خواننده با معماری میکروسرویس، کانتینر، پایگاه‌دادهٔ رابطه‌ای و مفاهیم بینایی ماشین است.

اصول طراحی حاکم بر پروژه

  • امنیت پیش‌فرض (Secure by Default): رمزنگاری در حالت سکون و انتقال، کمینهٔ دسترسی، و ایزولاسیون شبکهٔ دوربین‌ها از همان ابتدا.
  • حاکمیت داده (Data Sovereignty): امکان استقرار کاملاً On-Prem بدون خروج هیچ بایتی از دادهٔ زیست‌سنجشی از محیط مشتری — الزام مراکز حساس.
  • چندمستأجری و مقیاس‌پذیری (Multi-tenant & Scalable): یک هسته که از یک لابی تا یک کلاستر چندطبقه را با همان کد پوشش دهد.
  • رخدادمحور (Event-Driven): هر ورود/خروج، هر fix مکانی و هر تطبیق چهره یک رخداد است که از طریق گذرگاه پیام جریان می‌یابد.
  • مشاهده‌پذیری کامل (Observability): هیچ سرویسی بدون log ساخت‌یافته، metric و trace به Production نمی‌رود.

واژه‌نامهٔ کوتاه

اصطلاحتوضیح
RTLSReal-Time Location System — سامانهٔ مکان‌یابی بلادرنگ داخلی
Embeddingبردار عددی (۵۱۲ بُعدی) نمایندهٔ یک چهره برای تطبیق
Geofenceمحدودهٔ جغرافیایی/چندضلعی برای زون یا شعاع عملیاتی
FAR / FRRنرخ پذیرش غلط / نرخ رد غلط در احراز هویت زیست‌سنجشی
Livenessتشخیص زنده‌بودن چهره برای مقابله با جعل (عکس/ویدئو/ماسک)
Tenantیک مشتری/سازمان مجزا با دادهٔ ایزوله در سامانه

2معماری کلان سیستم

نگاهبان از پنج لایهٔ منطقی تشکیل شده است: لایهٔ لبه (دوربین، اسکنر، تگ و گیت‌وی)، لایهٔ دریافت و دروازه، لایهٔ سرویس‌ها (میکروسرویس‌ها)، لایهٔ داده، و لایهٔ کلاینت (اپ موبایل و داشبورد). ارتباط درون‌سرویسی با gRPC و ارتباط بیرونی با REST/WebSocket است؛ رخدادها از طریق یک گذرگاه پیام (NATS/Kafka) منتشر می‌شوند.

معماری لایه‌ای نگاهبان لایهٔ لبه (Edge)دوربین IP (RTSP/ONVIF)اسکنر چهره/اثرانگشتتگ امنیتی + گیت‌وی دریافت و دروازهVideo IngestionAPI Gateway + AuthTag/RTLS Gateway سرویس‌ها (Microservices)FaceZone/AccessAttendanceBehaviorAlertRealtime دادهPostgreSQL + pgvectorTimescaleDBRedisMinIO (S3) کلاینتاپ موبایل (نگهبان/مدیر)داشبورد وب

جریان‌های کلیدی داده

  1. ثبت حضور: اسکنر چهره/اثرانگشت ← Attendance Service ← اعتبارسنجی (زمان+مکان+liveness+تطبیق) ← رخداد attendance.checked_in.
  2. تشخیص چهرهٔ ورودی: دوربین (RTSP) ← Video Service (نمونه‌گیری فریم) ← Face Service (تشخیص←embedding←تطبیق با گالری) ← رخداد face.detected / face.unauthorized ← Alert Service.
  3. مکان‌یابی نیرو: تگ ← گیت‌وی‌ها (RSSI/TWR) ← RTLS Service (فیلتر+مثلث‌بندی) ← fix مکانی ← Zone Service (تعیین زون/شعاع) ← Realtime Service (WebSocket به نقشه).
  4. تحلیل رفتار: fixهای مکانی + رخدادها ← Behavior Service (استخراج ویژگی per shift) ← مقایسه با baseline ← امتیاز ناهنجاری ← Alert در صورت تخطی.
نکته — مرز بلادرنگ
مسیرهای حساس به تأخیر (تطبیق چهره، هشدار ورود غیرمجاز، خروج از محدوده) باید بودجهٔ تأخیر کمتر از ۱ ثانیه از سنسور تا اعلان داشته باشند؛ این قید، انتخاب gRPC، پردازش جریانی و کش Redis را دیکته می‌کند.

3پشتهٔ فناوری و قراردادها

لایهفناورینسخهٔ پیشنهادیعلت انتخاب
Backend سرویس‌هاGo1.22+هم‌روندی بالا، باینری سبک، مناسب سرویس‌های بلادرنگ
AI / بینایی ماشینPython + ONNX Runtime3.11 / 1.17اکوسیستم مدل‌ها؛ اجرا با TensorRT/CUDA
اپ موبایلFlutter3.22+یک کد، دو پلتفرم؛ دسترسی به دوربین/BLE/بیومتریک
داشبورد وبReact + TypeScript18 / 5اکوسیستم بالغ، نقشهٔ تعاملی، RBAC در UI
پایگاه‌دادهPostgreSQL16 + pgvector + TimescaleDBرابطه‌ای + بردار چهره + سری‌زمانی مکان
کش/حضورRedis7+presence، geofence state، rate-limit، pub/sub
گذرگاه پیامNATS JetStream2.10+سبک، تأخیر پایین (جایگزین Kafka در مقیاس کوچک)
پردازش ویدئوGStreamer / FFmpeg1.24 / 6رمزگشایی سخت‌افزاری (NVDEC)، نمونه‌گیری فریم
استقرارDocker + KubernetesK8s 1.29+مقیاس‌پذیری، GPU scheduling، rollout
شیء‌ذخیرهMinIO (S3 API)—آرشیو ویدئو/کلیپ رویداد، On-Prem

قراردادهای مهندسی

  • API بیرونی: REST/JSON با نسخه‌بندی مسیر (/api/v1/...)، احراز هویت Bearer JWT؛ خطاها با مدل یکنواخت ({code, message, traceId}).
  • API درونی: gRPC با Protobuf؛ احراز سرویس‌به‌سرویس با mTLS.
  • رخدادها: نام‌گذاری domain.action (مثل access.denied)، payload نسخه‌دار، تحویل at-least-once و idempotency-key.
  • زمان: همهٔ مهرهای زمانی UTC و ISO-8601؛ ساعتِ مرجع، سرور است نه دستگاه.
  • شناسه‌ها: UUIDv7 (مرتب‌شدنی زمانی) برای کلیدهای اصلی.
  • پیکربندی: ۱۲-Factor؛ از طریق متغیر محیطی و Vault؛ هیچ رازی در ایمیج یا کد.

4مدل داده

مدل داده چندمستأجری است؛ هر ردیف دارای tenant_id برای ایزولاسیون است (با Row-Level Security در PostgreSQL). موجودیت‌های اصلی و رابطهٔ آن‌ها در زیر آمده، سپس DDL جداول کلیدی.

موجودیت‌های اصلی

موجودیتشرحروابط کلیدی
tenantسازمان/مشتری۱ به n با sites, persons
site / building / floorسلسله‌مراتب مکان فیزیکیfloor دارای zones و cameras
zoneناحیهٔ چندضلعی روی یک طبقه با سطح دسترسیn به n با roles (قواعد دسترسی)
personنگهبان/کارمند/بازدیدکننده۱ به n با face_templates، shifts
deviceاسکنر، تگ، گیت‌وی، دوربینمتعلق به floor/site
face_templateبردار embedding چهره (رمزنگاری‌شده)متعلق به person
shiftشیفت کاری با پنجرهٔ زمانی و سایت۱ به n با attendance
attendance_recordثبت ورود/خروج زیست‌سنجشیمتعلق به person+shift
location_fixمختصات لحظه‌ای نیرو (سری‌زمانی)متعلق به person/tag
access_eventورود/خروج به زون (مجاز/غیرمجاز)person × zone
alertهشدار تولیدشدهمنبع: هر سرویس
behavior_profileامضای رفتاری پایهٔ هر نیرومتعلق به person
audit_logگزارش ممیزی تغییرناپذیر—

DDL جداول کلیدی (PostgreSQL)

sql
-- افزونه‌ها
CREATE EXTENSION IF NOT EXISTS vector;       -- pgvector
CREATE EXTENSION IF NOT EXISTS timescaledb;

-- اشخاص
CREATE TABLE person (
  id            UUID PRIMARY KEY DEFAULT uuidv7(),
  tenant_id     UUID NOT NULL,
  full_name     TEXT NOT NULL,
  national_id   TEXT,
  role          TEXT NOT NULL CHECK (role IN ('guard','employee','visitor','admin')),
  status        TEXT NOT NULL DEFAULT 'active',
  created_at    TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX ON person (tenant_id, role);

-- قالب چهره: فقط embedding رمزنگاری‌شده نگهداری می‌شود، نه تصویر خام
CREATE TABLE face_template (
  id            UUID PRIMARY KEY DEFAULT uuidv7(),
  tenant_id     UUID NOT NULL,
  person_id     UUID NOT NULL REFERENCES person(id) ON DELETE CASCADE,
  embedding     vector(512) NOT NULL,        -- L2-normalized
  quality       REAL NOT NULL,               -- 0..1
  enc_blob      BYTEA,                        -- نسخهٔ رمزنگاری‌شدهٔ متادیتا (AES-256-GCM)
  created_at    TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- ایندکس برداری برای جست‌وجوی نزدیک‌ترین همسایه
CREATE INDEX ON face_template USING hnsw (embedding vector_cosine_ops);

-- زون: چندضلعی روی یک طبقه
CREATE TABLE zone (
  id            UUID PRIMARY KEY DEFAULT uuidv7(),
  tenant_id     UUID NOT NULL,
  floor_id      UUID NOT NULL,
  name          TEXT NOT NULL,
  polygon       JSONB NOT NULL,              -- [[x,y],...] مختصات محلی طبقه
  sensitivity   SMALLINT NOT NULL DEFAULT 1  -- 1..5
);

-- قاعدهٔ دسترسی: نقش × زون × بازهٔ زمانی
CREATE TABLE access_rule (
  id            UUID PRIMARY KEY DEFAULT uuidv7(),
  zone_id       UUID NOT NULL REFERENCES zone(id),
  role          TEXT NOT NULL,
  time_window   JSONB,                       -- {days:[...], from:'08:00', to:'20:00'}
  effect        TEXT NOT NULL CHECK (effect IN ('allow','deny'))
);

-- fixهای مکانی به‌صورت hypertable سری‌زمانی
CREATE TABLE location_fix (
  ts            TIMESTAMPTZ NOT NULL,
  tenant_id     UUID NOT NULL,
  person_id     UUID NOT NULL,
  floor_id      UUID NOT NULL,
  x             REAL NOT NULL,
  y             REAL NOT NULL,
  accuracy_m    REAL,
  source        TEXT NOT NULL                -- 'uwb' | 'ble' | 'fused'
);
SELECT create_hypertable('location_fix','ts');
CREATE INDEX ON location_fix (person_id, ts DESC);

-- رخداد دسترسی
CREATE TABLE access_event (
  id            UUID PRIMARY KEY DEFAULT uuidv7(),
  tenant_id     UUID NOT NULL,
  person_id     UUID,
  zone_id       UUID NOT NULL,
  decision      TEXT NOT NULL,               -- 'authorized' | 'unauthorized'
  ts            TIMESTAMPTZ NOT NULL DEFAULT now()
);

-- گزارش ممیزی تغییرناپذیر (append-only، زنجیرهٔ هش)
CREATE TABLE audit_log (
  id            BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  tenant_id     UUID NOT NULL,
  actor         TEXT NOT NULL,
  action        TEXT NOT NULL,
  target        TEXT,
  ts            TIMESTAMPTZ NOT NULL DEFAULT now(),
  prev_hash     BYTEA,
  row_hash      BYTEA NOT NULL
);
امنیت — حفاظت از داده زیست‌سنجشی
تصویر خام چهره پس از استخراج embedding نگهداری نمی‌شود (مگر با رضایت صریح و برای بازآموزی، آن هم رمزنگاری‌شده و با عمر محدود). جدول face_template در سطح ستون با کلید per-tenant از Vault رمزنگاری می‌شود.

در Redis، ساختارهای زیر نگهداری می‌شوند: presence:{person_id} (آخرین وضعیت/زون با TTL)، geo:{person_id} (آخرین fix برای ارزیابی geofence)، و کانال‌های pubsub: alerts, positions برای انتشار بلادرنگ.

5سرویس‌ها (میکروسرویس‌ها) — بخش به بخش

هر سرویس مستقل، صاحب دادهٔ خود و مستقل قابل‌استقرار است. در ادامه برای هر سرویس: مسئولیت، API، الگوریتم/نکات پیاده‌سازی و گام‌های ساخت آمده است.

۴٫۱ — Auth & API Gateway

نقطهٔ ورود واحد؛ مسئول احراز هویت، صدور/نوسازی JWT، نرخ‌گذاری، مسیریابی و ترجمهٔ REST↔gRPC.

POST/api/v1/auth/loginورود با نام‌کاربری/گذرواژه یا توکن دستگاه؛ خروجی: access (۱۵ دقیقه) + refresh
POST/api/v1/auth/refreshنوسازی access با refresh token چرخشی

کنترل دسترسی ترکیبی RBAC + ABAC است: نقش پایه + ویژگی‌ها (tenant، site، سطح حساسیت). ادعاهای JWT شامل sub, tenant, roles[], scopes[] است.

گام‌های ساخت
  1. تعریف مدل نقش/مجوز و seed نقش‌های پایه (admin, operator, guard, viewer).
  2. پیاده‌سازی صدور JWT با امضای EdDSA و چرخش کلید (kid).
  3. Middleware اعتبارسنجی توکن + بررسی scope در Gateway.
  4. نرخ‌گذاری per-IP و per-token با Redis (الگوریتم token-bucket).
  5. mTLS برای ارتباط Gateway با سرویس‌های داخلی.

۴٫۲ — Personnel & Identity Service

مدیریت اشخاص، نقش‌ها، شیفت‌ها و فرایند ثبت‌نام چهره (enrollment).

POST/api/v1/personsایجاد شخص
POST/api/v1/persons/{id}/face:enrollثبت چهره از چند فریم؛ خروجی: کیفیت و وضعیت
اجرا — فرایند enrollment
۵ تا ۱۰ فریم گرفته می‌شود؛ هر فریم از فیلتر کیفیت (blur، pose ≤ ±۲۰°، روشنایی) عبور می‌کند؛ embedding هر فریم محاسبه و میانگینِ نرمال‌شده به‌عنوان قالب نهایی ذخیره می‌شود. اگر انحراف بین فریم‌ها زیاد باشد، enrollment رد می‌شود.

۴٫۳ — Face Recognition Service

هستهٔ هوش مصنوعیِ تصویر. خط لولهٔ استنتاج: تشخیص چهره ← هم‌ترازی ← embedding ← liveness ← تطبیق با گالری ← تصمیم.

خط لولهٔ تشخیص چهرهفریم دوربینتشخیص چهرههم‌ترازیEmbedding ۵۱۲Livenessتطبیق گالریتصمیم
مرحلهمدل/روشخروجینکته
DetectionSCRFD / RetinaFace (ONNX)bbox + ۵ لندمارکاجرا روی GPU، batch فریم‌ها
Alignmentتبدیل تشابهی به 112×112چهرهٔ هم‌ترازاز ۵ لندمارک استاندارد
EmbeddingArcFace (glintr100)بردار ۵۱۲ بُعدی L2-normFP16 با TensorRT
LivenessMiniFASNet (anti-spoof)امتیاز زنده‌بودنرد عکس/ویدئو/ماسک
MatchingCosine + pgvector HNSWنزدیک‌ترین + امتیازآستانهٔ کالیبره‌شده

تطبیق بر اساس شباهت کسینوسی است. آستانهٔ عملیاتی بر مبنای منحنی ROC و نقطهٔ کاری مطلوب (مثلاً FAR ≤ 1e-4) تعیین و per-deployment کالیبره می‌شود.

python
# شبه‌کد تطبیق
emb = embed(align(detect(frame)))          # بردار 512، نرمال‌شده
if liveness_score(frame) < LIVENESS_TH:
    return reject("spoof")
cand = pgvector_search(emb, gallery, k=1)   # 1 <-> cosine distance
score = 1.0 - cand.distance                 # شباهت کسینوسی
if score >= MATCH_TH:                        # مثلاً 0.42 (کالیبره‌شونده)
    emit("face.detected", person=cand.id, score=score)
else:
    emit("face.unauthorized", score=score)
کارایی — throughput
با یک GPU میان‌رده و TensorRT-FP16، نرخ پردازش در حد چند صد چهره در ثانیه است. برای کاهش بار، تشخیص فقط روی فریم‌های نمونه (مثلاً ۵ فریم بر ثانیه) و فقط هنگام وجود حرکت (motion gate) انجام می‌شود.
گام‌های ساخت
  1. آماده‌سازی مدل‌ها به ONNX و سپس TensorRT engine (FP16) برای GPU هدف.
  2. سرویس استنتاج با gRPC streaming؛ ورودی فریم، خروجی نتیجهٔ تطبیق.
  3. بارگذاری گالری embedding به pgvector + ساخت ایندکس HNSW.
  4. پیاده‌سازی liveness و motion gate برای کاهش بار.
  5. ابزار کالیبراسیون آستانه روی دادهٔ هر استقرار + گزارش FAR/FRR.

۴٫۴ — Video Ingestion & Stream Service

اتصال به دوربین‌ها با ONVIF (کشف) و RTSP (جریان)، رمزگشایی سخت‌افزاری، نمونه‌گیری فریم و تحویل به Face Service؛ و ضبط کلیپ کوتاه پیرامون هر رخداد مهم.

bash
# نمونهٔ خط لولهٔ GStreamer با رمزگشایی NVDEC و نمونه‌گیری فریم
gst-launch-1.0 rtspsrc location=rtsp://CAM/Streaming/Channels/101 latency=100 ! \
  rtph264depay ! h264parse ! nvv4l2decoder ! \
  videorate ! 'video/x-raw,framerate=5/1' ! appsink
  • هر دوربین یک worker مستقل؛ پایش سلامت و reconnect خودکار.
  • Motion gate برای فعال‌سازی استنتاج فقط هنگام حرکت → صرفه‌جویی GPU.
  • ضبط حلقه‌ای (ring buffer) برای داشتن ۱۰ ثانیه پیش از رخداد در کلیپ.
  • آرشیو کلیپ‌ها در MinIO با سیاست ماندگاری قابل‌پیکربندی.

۴٫۵ — RTLS / Tag Location Service

محاسبهٔ موقعیت دقیق نیرو از سیگنال تگ‌ها. دو فناوری پشتیبانی می‌شود: UWB (دقت ۱۰ تا ۳۰ سانتی‌متر، مبتنی بر TWR/TDoA) برای مراکز حساس، و BLE (دقت متری، مبتنی بر RSSI + فینگرپرینت) برای استقرار اقتصادی.

جریان مکان‌یابی و کنترل ترددتگ نیروگیت‌وی/AnchorRTLS (فیلتر کالمن)Zone Service (PIP)رخداد دسترسینقشهٔ زنده / هشدار
  • هر طبقه دارای چند anchor/گیت‌وی با مختصات کالیبره‌شده است.
  • BLE: مدل افت مسیر (path-loss) برای فاصله + فیلتر کالمن برای صاف‌سازی مسیر و حذف نوسان.
  • UWB: Two-Way Ranging بین تگ و anchorها و سپس چندجانبه‌سازی (multilateration).
  • تشخیص طبقه با تجمیع anchorهای پاسخ‌دهنده (+ بارومتر تگ در صورت وجود).
  • خروجی: location_fix با نرخ ۱ تا ۴ هرتز ← Timescale + Redis.
اجرا — ضد لرزش (hysteresis)
برای جلوگیری از flapping در مرز زون‌ها، تغییر زون فقط پس از تثبیت موقعیت برای N نمونهٔ متوالی (یا ماندن بیش از آستانهٔ زمانی) اعمال می‌شود.

۴٫۶ — Zone & Access Control Service

ارزیابی هر fix مکانی نسبت به زون‌ها و قواعد دسترسی، و تولید رخداد ورود مجاز/غیرمجاز و خروج از محدودهٔ عملیاتی.

go
// تعیین زون با الگوریتم point-in-polygon (ray casting)
func PointInPolygon(p Point, poly []Point) bool {
    inside := false
    j := len(poly) - 1
    for i := 0; i < len(poly); i++ {
        if (poly[i].Y > p.Y) != (poly[j].Y > p.Y) &&
            p.X < (poly[j].X-poly[i].X)*(p.Y-poly[i].Y)/(poly[j].Y-poly[i].Y)+poly[i].X {
            inside = !inside
        }
        j = i
    }
    return inside
}

// خط لولهٔ ارزیابی هر fix
func Evaluate(fix Fix) {
    zone := resolveZone(fix)                  // کدام زون؟
    if !withinOperationalRadius(fix) {        // خارج از محدودهٔ مجاز؟
        emit("guard.out_of_bounds", fix)
    }
    if zone != nil {
        if !accessAllowed(fix.PersonRole, zone, fix.TS) {
            emit("access.unauthorized", fix, zone)   // ← Alert
        } else {
            emit("access.authorized", fix, zone)
        }
    }
}

موتور قواعد به‌صورت اعلانی (declarative) است: قواعد allow/deny بر حسب نقش × زون × بازهٔ زمانی ذخیره و به‌ترتیب اولویت ارزیابی می‌شوند (deny مقدم بر allow).

۴٫۷ — Attendance Service

ثبت ورود/خروج زیست‌سنجشی مقیّد به زمان و مکان. اعتبارسنجی سمت سرور است و به ساعت/موقعیت دستگاه اعتماد نمی‌شود.

توالی ثبت حضور زیست‌سنجشیاپ/اسکنر:چهره+اثرانگشتسرور:liveness+تطبیقبررسی geofenceبررسی پنجرهٔ زمانیثبت + رخداد
  1. دستگاه/اپ، چهره و اثرانگشت + شناسهٔ دستگاه و موقعیت را ارسال می‌کند.
  2. سرور بررسی می‌کند: liveness پاس شده باشد، چهره با person تطبیق یابد، اثرانگشت تأیید شود.
  3. بررسی geofence: موقعیت در محدودهٔ سایتِ شیفت باشد.
  4. بررسی پنجرهٔ زمانی: زمان سرور در بازهٔ شیفت ± مهلت مجاز باشد.
  5. ثبت idempotent رکورد؛ تولید رخداد attendance.checked_in/out.
امنیت — ضد جعل
ترکیب liveness + اثرانگشت + قید مکان، عملاً مانع ثبت با عکس یا از راه دور می‌شود. شناسهٔ دستگاه با گواهی دستگاه (device cert) احراز می‌شود.

۴٫۸ — Behavior Analytics Service

یادگیری «امضای رفتاری» هر نیرو و تشخیص ناهنجاری و جایگزینی پنهان.

ویژگی‌های استخراجی per shift

  • طول مسیر پیموده‌شده و توزیع سرعت حرکت
  • زمان ماندگاری در هر زون و توالی بازدید زون‌ها
  • میزان پوشش/کامل‌بودن گشت (نسبت زون‌های بازدیدشده به الزامی)
  • دوره‌های بی‌حرکتی/توقف غیرعادی و زمان حضور در پست
  • الگوی زمانی رویدادها (ساعت‌های فعالیت)

baseline هر نیرو به‌صورت پروفایل غلتان (میانگین/انحراف هر ویژگی) نگهداری می‌شود. تشخیص ناهنجاری چندمتغیره با Isolation Forest (یا Autoencoder در مقیاس داده‌ٔ بزرگ‌تر) انجام می‌شود.

اجرا — منطق کشف جایگزینی
اگر طبق حضوروغیاب «نیروی A» در شیفت باشد، اما (الف) تطبیق چهره در ایست‌های بازرسی با A نخواند، یا (ب) امضای رفتاریِ امروز به‌طور معنادار از baseline ‌A فاصله بگیرد در حالی که تگ A حاضر است، سامانه احتمال «جایگزینی بدون اطلاع» را علامت می‌زند و هشدار می‌دهد. تصمیم نهایی بر پایهٔ ترکیب سه سیگنال (چهره + رفتار + تگ) و امتیاز اطمینان است.

۴٫۹ — Alert & Notification Service

دریافت رخدادهای خطر، اعمال قواعد، حذف تکرار (dedup)، تشدید (escalation) و ارسال چندکاناله.

  • کانال‌ها: اعلان درون‌برنامه‌ای (WebSocket/Push)، پیامک، و وب‌هوک برای یکپارچگی.
  • Dedup با پنجرهٔ زمانی و کلید رخداد برای جلوگیری از سیل هشدار.
  • Escalation پلکانی: اگر هشدار در زمان مقرر تأیید/رسیدگی نشد، به سطح بالاتر ارجاع می‌شود.
  • هر هشدار دارای شدت (info/warning/critical) و چرخهٔ حیات (new→ack→resolved) است.

۴٫۱۰ — Realtime, Map & Reporting

Realtime Service موقعیت‌ها و رخدادها را از طریق WebSocket به نقشهٔ داشبورد می‌رساند. Reporting Service گزارش‌های کارکرد، تردد و رویداد را تولید و به Excel/PDF خروجی می‌دهد.

json
// پیام WebSocket موقعیت زنده
{ "type": "position", "personId": "...", "floorId": "...",
  "x": 12.4, "y": 33.1, "zone": "lobby", "ts": "2026-..." }

6اپلیکیشن موبایل (Flutter)

دو نقش در یک اپ: نگهبان (ثبت حضور، وضعیت شیفت/محدوده، اعلان‌ها) و مدیر (پایش و هشدارها). معماری پیشنهادی: لایه‌ای + الگوی BLoC/Riverpod.

  • ماژول بیومتریک: دوربین برای چهره (+liveness سمت اپ به‌عنوان لایهٔ اول)، و local_auth برای اثرانگشت.
  • ماژول BLE: اسکن/ارتباط با تگ امنیتی و گزارش مجاورت.
  • ذخیرهٔ امن توکن/کلید با flutter_secure_storage (Keystore/Keychain).
  • حالت آفلاین: صف رویدادها و همگام‌سازی هنگام اتصال (با مهر زمانی سرور هنگام دریافت).
  • Push با FCM/APNs برای هشدارها؛ نقشهٔ داخلی طبقه برای نمایش موقعیت.
امنیت — اعتماد صفر به کلاینت
هیچ تصمیم امنیتی سمت اپ گرفته نمی‌شود؛ liveness و تطبیق نهایی همیشه سمت سرور تکرار و اعتبارسنجی می‌شود.

7داشبورد مدیریتی (Web)

  • نقشهٔ تعاملی طبقات با موقعیت زندهٔ نیروها و زون‌ها (Leaflet با لایهٔ تصویر طبقه یا Mapbox GL).
  • صفحهٔ رویدادها/هشدارها با فیلتر و چرخهٔ رسیدگی.
  • ویرایشگر زون: ترسیم چندضلعی روی نقشهٔ طبقه و تخصیص قواعد دسترسی.
  • گزارش کارکرد، بازپخش مسیر (timeline scrubber) و خروجی گزارش.
  • مدیریت کاربران/نقش‌ها؛ UI مبتنی بر RBAC (مخفی‌سازی اقدامات غیرمجاز).
  • به‌روزرسانی بلادرنگ از طریق WebSocket.

8امنیت و حریم خصوصی

محورتصمیم فنی
انتقالTLS 1.3 بیرونی؛ mTLS داخلی بین سرویس‌ها
سکونAES-256-GCM؛ کلید per-tenant از Vault/KMS؛ رمزنگاری ستونی برای داده زیست‌سنجشی
زیست‌سنجشنگهداری فقط embedding (نه تصویر خام)؛ امکان template protection/cancelable
دسترسیRBAC + ABAC؛ JWT کوتاه‌عمر + refresh چرخشی؛ device cert برای دوربین/اسکنر
ممیزیaudit_log تغییرناپذیر با زنجیرهٔ هش؛ ثبت هر دسترسی به داده حساس
شبکهجداسازی VLAN دوربین‌ها؛ بدون اینترنت در حالت On-Prem؛ egress کنترل‌شده
اسرارVault؛ هیچ رازی در ایمیج/کد/لاگ؛ چرخش دوره‌ای کلیدها
ماندگاریسیاست retention قابل‌پیکربندی per داده؛ حذف خودکار پس از انقضا
هشدار — مدل تهدید
سامانهٔ امنیتی، خود یک هدف ارزشمند است. سطح حمله شامل دوربین‌های در معرض شبکه، endpointهای API، و دادهٔ زیست‌سنجشی است. اقدامات: سخت‌سازی کانتینرها، اسکن آسیب‌پذیری ایمیج، WAF روی Gateway، نرخ‌گذاری، و تست نفوذ پیش از تحویل مراکز حساس.

9مشاهده‌پذیری، پایایی و پشتیبان‌گیری

  • Log: ساخت‌یافته (JSON) با correlation/trace id ← Loki.
  • Metric: Prometheus (نرخ، تأخیر، خطا per سرویس) + داشبورد Grafana.
  • Trace: OpenTelemetry ← Tempo/Jaeger برای ردیابی مسیر رخداد.
  • Alert زیرساخت: Alertmanager (سلامت سرویس، صف، GPU، دیسک).
  • SLO نمونه: تأخیر تشخیص چهره p95 < ۱s؛ در دسترس‌بودن سرویس هشدار ۹۹٫۹٪.
  • HA/DR: چند replica برای سرویس‌های بی‌حالت؛ replication پایگاه‌داده؛ پشتیبان‌گیری زمان‌بندی‌شده و تستِ بازگردانی دوره‌ای.

10زیرساخت و استقرار

استقرار با Kubernetes (یا k3s برای On-Prem کوچک). نودهای GPU با nvidia device plugin برای سرویس‌های هوش مصنوعی برچسب‌گذاری می‌شوند.

yaml
# نمونهٔ Deployment سرویس تشخیص چهره روی نود GPU
apiVersion: apps/v1
kind: Deployment
metadata: { name: face-service, namespace: negahban }
spec:
  replicas: 2
  selector: { matchLabels: { app: face-service } }
  template:
    metadata: { labels: { app: face-service } }
    spec:
      nodeSelector: { gpu: "true" }
      containers:
        - name: face
          image: registry.local/negahban/face:1.0
          resources:
            limits: { nvidia.com/gpu: 1, memory: "8Gi" }
          envFrom:
            - secretRef: { name: face-secrets }
مقیاسنمونهٔ توپولوژی
لابی/کوچک (≤۱۶ دوربین)تک‌نود k3s + ۱ GPU ورودی؛ Postgres+Redis محلی؛ MinIO تک‌نود
سازمانی (≤۶۴ دوربین)کلاستر ۳ نود + نود GPU میان‌رده؛ Postgres با replica؛ NATS
مرکز حساس (۱۲۸+)کلاستر چندنود، چند GPU، شبکهٔ ایزوله، افزونگی کامل، Vault اختصاصی

CI/CD

  • Pipeline: lint → unit → build image → scan آسیب‌پذیری → push → deploy (GitOps/ArgoCD).
  • محیط‌ها: dev → staging → prod؛ مهاجرت پایگاه‌داده نسخه‌دار (migrations).
  • ایمیج‌های امضاشده و SBOM برای استقرار در محیط حساس.

11راهبرد تست

نوعهدفابزار/روش
واحد (Unit)منطق سرویس‌هاgo test / pytest / flutter test
یکپارچگیتعامل سرویس‌ها + DB + گذرگاهمحیط docker-compose تست
بار (Load)تأخیر و throughput زیر بارk6 / Locust؛ شبیه‌سازی N دوربین و تگ
دقت AIFAR/FRR، دقت livenessدیتاست برچسب‌خورده + گزارش ROC
امنیتآسیب‌پذیری و نفوذاسکن SAST/DAST + تست نفوذ
پذیرش میدانیکارکرد واقعی در محلچک‌لیست استقرار + سناریوهای واقعی

12نقشهٔ راه پیاده‌سازی (بخش به بخش)

ترتیب ساخت بر پایهٔ وابستگی‌ها چیده شده تا در هر فاز یک قابلیتِ قابل‌نمایش به دست آید. هر فاز خروجی مشخص و معیار پذیرش دارد.

فازماژول‌هاخروجی قابل‌نمایشوابستگی
۰ — پی‌ریزیRepo، CI/CD، Auth، مدل داده، گذرگاهاسکلت پروژه + لاگین + محیط‌ها—
۱ — هستهٔ افراد/حضورPersonnel، Attendance، اپ نگهبان (حضور)ثبت حضور زیست‌سنجشی واقعیفاز ۰
۲ — ویدئو/چهرهVideo، Face Service، گالریتشخیص ورود مجاز/غیرمجاز + هشدارفاز ۰
۳ — مکان‌یابی/زونRTLS، Zone، Realtime، نقشهٔ داشبوردموقعیت زنده + کنترل تردد + خروج از محدودهفاز ۱
۴ — هوش رفتاریBehavior، کشف جایگزینیهشدار ناهنجاری/جایگزینیفاز ۱،۲،۳
۵ — گزارش/سخت‌سازیReporting، امنیت، Observability، HAگزارش‌ها + آماده‌سازی Productionهمه
نکته — تعریف MVP
خروجی پایان فاز ۲ یک MVP قابل‌ارائه است: حضور زیست‌سنجشی + تشخیص چهرهٔ ورودی + هشدار. فازهای ۳ تا ۵ آن را به محصول کامل و آمادهٔ مراکز حساس می‌رسانند.

13پیوست: نمونهٔ قراردادهای API و رخداد

نمونهٔ Protobuf سرویس چهره (gRPC داخلی)

proto
syntax = "proto3";
package negahban.face.v1;

service FaceService {
  rpc Match(stream Frame) returns (stream MatchResult);
  rpc Enroll(EnrollRequest) returns (EnrollResponse);
}

message Frame {
  string tenant_id = 1;
  string camera_id = 2;
  bytes  image     = 3;   // JPEG/RAW
  int64  ts_unix_ms = 4;
}

message MatchResult {
  string person_id = 1;   // خالی اگر ناشناس
  float  score     = 2;   // شباهت کسینوسی
  bool   live      = 3;
  string decision  = 4;   // authorized | unauthorized
}

نمونهٔ رخداد روی گذرگاه

json
{
  "event": "access.unauthorized",
  "version": 1,
  "tenantId": "0190...",
  "personId": null,
  "zoneId": "0190-zone-serverroom",
  "floorId": "0190-floor-2",
  "ts": "2026-06-15T11:20:33Z",
  "evidence": { "cameraId": "cam-12", "clipUrl": "s3://events/..." },
  "idempotencyKey": "evt-0190..."
}

نمونهٔ REST گزارش کارکرد

GET/api/v1/reports/attendance?personId=..&from=..&to=..گزارش کارکرد یک نیرو در بازه؛ خروجی JSON/Excel/PDF