Môi trường — GIW POC

Trạng thái: CHỈ CHẠY LOCAL · Ngày: 21/09/2026 Quy định đang áp dụng: chạy local trên máy của Founder. Không cloud, không môi trường test, không server dùng chung, không production, không hosting bên ngoài.

Tài liệu này tách cái đang chạy hôm nay khỏi cái mà một môi trường thật sẽ cần, để hai bên không lẫn vào nhau.


1. LOCAL — môi trường duy nhất đang tồn tại

Docker Compose, localhost, service giả lập, dữ liệu tổng hợp.

Các endpoint

Mọi cổng đều bind vào 127.0.0.1. Không thứ gì với tới được từ LAN hay Internet.

Service URL Xác thực Ghi chú
Wi-Fi Portal http://localhost:3000 không Host duy nhất mà trình duyệt liên hệ
› ứng dụng (mọi màn) http://localhost:3000/ không Portal tự render. Không tồn tại trang Keycloak nào.
› login POST http://localhost:3000/api/v1/auth/login không Đặt cookie sid
› register POST http://localhost:3000/api/v1/auth/register không
› xác minh nhân viên POST http://localhost:3000/api/v1/auth/employee không
› trạng thái phiên GET http://localhost:3000/api/v1/auth/session cookie sid Chỉ trả token gốc khi DEBUG_EXPOSE_TOKEN=1
› refresh POST http://localhost:3000/api/v1/auth/refresh cookie sid
› logout POST http://localhost:3000/api/v1/auth/logout cookie sid Thu hồi cả phiên mạng
› meta GET http://localhost:3000/api/v1/meta không
› health http://localhost:3000/health không
Keycloak (Galaxy ID) http://localhost:8080 admin / admin Admin console. Không nằm trong hành trình người dùng nào.
› realm discovery http://localhost:8080/realms/galaxy-id-poc/.well-known/openid-configuration không
› JWKS http://localhost:8080/realms/galaxy-id-poc/protocol/openid-connect/certs không
› health (readiness) http://localhost:9000/health/ready không Cổng riêng — không phải 8080
Mock HR API http://localhost:3001 X-API-Key
› verify POST http://localhost:3001/api/v1/employees/verify X-API-Key
› tiêm lỗi POST http://localhost:3001/admin/fault không Công cụ test. Không được tồn tại trong môi trường thật.
› health http://localhost:3001/health không
Entitlement Service http://localhost:3002 Bearer JWT
› evaluate POST http://localhost:3002/api/v1/entitlements/evaluate Bearer JWT
› read GET http://localhost:3002/api/v1/entitlements/{id} Bearer JWT
› health http://localhost:3002/health không
Session Service http://localhost:3003 X-API-Key
DMN Decision Service http://localhost:3005 không Luật lấy từ file .dmn trên đĩa
› evaluate POST http://localhost:3005/api/v1/decisions/{model}/evaluate không
› liệt kê model GET http://localhost:3005/api/v1/decisions không Cho biết mỗi model đến từ file nguồn nào
› reload POST http://localhost:3005/api/v1/decisions/reload không ⚠️ không xác thực
› create / grant / revoke / read /api/v1/sessions* X-API-Key
› health http://localhost:3003/health không
Module giw-admin http://localhost:8080/realms/galaxy-id-poc/giw-admin/ Bearer (realm, manage-users) Vỏ GUI là công khai; mọi lệnh gọi /api đều xác thực
› webhook POST .../giw-admin/webhook/{company} HMAC trên raw body Không phải endpoint bearer — bên gọi là công ty thành viên
Mail sink http://localhost:3008 không Hộp thư trình diễn. Service này không có socket đi ra
› SMTP localhost:1025 không Từ chối thẳng AUTH và STARTTLS thay vì giả vờ
› messages GET/DELETE http://localhost:3008/api/v1/messages không Nằm trong bộ nhớ, có giới hạn, mất khi restart
Postgres không publish — Chỉ trong mạng container

Các cổng do biến môi trường quyết định (PORT_PORTAL, PORT_HR, PORT_ENTITLEMENT, PORT_SESSION, PORT_KEYCLOAK, PORT_KEYCLOAK_HEALTH, PORT_DMN, PORT_LOYALTY, PORT_CONSENT, PORT_MAIL_SINK, PORT_SMTP), và địa chỉ bind là BIND_ADDR, mặc định 127.0.0.1.

Theme của realm và đích SMTP do bootstrap áp từ GIW_THEME, SMTP_HOST, SMTP_PORT và SMTP_FROM — không ghi vào realm-export.json, nên cùng một file realm chạy được dù mail sink có bật hay không, và môi trường khác có thể trỏ đi nơi khác mà không phải sửa file đã commit.

Đừng đặt BIND_ADDR=0.0.0.0. Trên mạng quán cà phê, khách sạn hay văn phòng, việc đó công khai Keycloak với admin/admin, một endpoint tiêm lỗi không xác thực và một cổng SMTP mở cho mọi máy trong cùng subnet.

Chạy

cd poc/identity
cp .env.example .env
docker compose up -d --build
node tests/e2e.mjs

Local cố ý là như thế nào

Khía cạnh Local Vì sao chấp nhận được ở đây
Đường truyền HTTP thuần chỉ loopback; không gì đi qua dây
Secret giá trị mặc định yếu trong .env khởi động không cần can thiệp; .env đã git-ignore
Dữ liệu tổng hợp không người thật, không hồ sơ nhân viên, không số căn cước thật
Kho entitlement trong bộ nhớ mất khi restart, và với một bản demo thì không sao
Kho session trong bộ nhớ như trên
HR service giả lập hệ nhân sự gốc thật chưa được chốt (T-HR-SOR)
Xác thực giữa service X-API-Key dùng chung (giữa các service) + client secret (Galaxy ID) không có bên nào không tin cậy trên mạng
Grant Direct Grant — CHỈ CHO POC xem docs/AUTH-STRATEGY.md. Đường production là browser OIDC / federation, TBC
Quan sát hệ thống log JSON ra stdout docker logs là toàn bộ công cụ

2. Ranh giới cấu hình — vì sao sau này dịch chuyển được

Điểm của các quy tắc dưới đây là: một môi trường tương lai cần giá trị mới, không cần kiến trúc mới.

Quy tắc Đang được tôn trọng thế nào
Cấu hình qua biến môi trường Mọi service đọc host, port, URL, timeout, TTL và credential từ env. Không file cấu hình nào được đọc lúc chạy, trừ realm-export.json vốn là dữ liệu mồi.
Không hard-code localhost trong business logic localhost chỉ xuất hiện như giá trị mặc định của env. Kiểm chứng: grep -rn localhost */src trả về bốn dòng, tất cả đều là process.env.X || "http://localhost:…".
Mỗi URL một chỗ định nghĩa PORTAL_BASE_URL là định nghĩa duy nhất của địa chỉ portal. bootstrap đối chiếu các client Keycloak theo nó ở mỗi lần khởi động, nên không bao giờ phải sửa realm-export.json.
Địa chỉ cho trình duyệt và địa chỉ trong container tách nhau Portal gọi Galaxy ID qua OIDC_INTERNAL_BASE trên mạng container, còn token mang KC_HOSTNAME làm iss và Entitlement Service kiểm theo giá trị đó. Hai biến, có chủ đích. Gộp chúng lại là lỗi kinh điển của captive portal.
Không secret nào nằm trong repository Client secret của API đến Keycloak qua OIDC_API_CLIENT_SECRET và do bootstrap áp; realm-export.json chỉ chứa một giá trị giữ chỗ.
.env.example Có sẵn, có chú thích, mọi giá trị đều là giữ chỗ. .env đã git-ignore.
Docker Compose là hợp đồng vận hành Một lệnh bật, một lệnh tắt.
OpenAPI không dính chặt vào localhost servers dùng biến {scheme}://{host}:{port}; localhost là mặc định, không phải là đặc tả.
Giả định production nằm tách khỏi code Tài liệu này, cộng api/API-OVERVIEW.md §7 (giả định POC), api/API-SECURITY.md §11 (khoảng trống), RUNBOOK.md §9 (checklist trước khi deploy). Không tuyên bố nào về production nằm bên trong một service.

3. SAU NÀY — một môi trường thật cần thêm gì

Không thứ nào dưới đây đã được xây, và không thứ nào nên được xây trước khi một môi trường thật được phê duyệt.

Hạng mục Cần gì Bị chặn bởi
TLS sslRequired: external, KC_HOSTNAME dạng https, cookie sid có Secure, HSTS một tên miền
DNS / tên miền hostname thật cho portal và Keycloak một tên miền
Hồ sơ triển khai overlay docker-compose.prod.yml hoặc Helm chart một môi trường
Cơ sở dữ liệu Postgres có quản lý cho Keycloak; một kho thật cho entitlement và session T-STORE
Quản lý secret vault hoặc kho secret trên cloud; xoay vòng mọi giá trị trong .env một môi trường
Xác thực giữa service thay cả hai chặng X-API-Key bằng mTLS hoặc service token ngắn hạn —
Audience mỗi resource server một audience riêng; ngừng chấp nhận account T-AUD
Giới hạn tần suất Entitlement và Session chưa có —
Quan sát hệ thống metric, tracing, cảnh báo, chuyển log về trung tâm một môi trường
Sẵn sàng cao (HA) nhiều hơn một replica; kho trong bộ nhớ khiến hôm nay không làm được T-STORE
Tích hợp HR thật hợp đồng, mô hình xác thực, SLA, phiên bản hoá, contract test T-HR-SOR, D7
Thu thập sự đồng ý bắt buộc cho đường CCCD theo Luật 91/2025 T-CCCD
Quyền truy cập / xoá dữ liệu của chủ thể production bắt buộc D7
Gỡ bộ công cụ test xoá POST /admin/fault; đặt DEBUG_EXPOSE_TOKEN=0 —

| Xác thực | Chuyển từ Direct Grant (Mode A) sang browser OIDC / federation (Mode B) | T-GRANT — Direct Grant chỉ dành cho POC |

Checklist đầy đủ trước khi triển khai ở RUNBOOK.md §9. Các chế độ xác thực và lộ trình chuyển đổi: AUTH-STRATEGY.md.

4. Những lằn ranh không được vượt

Đây không phải mục "để sau". Đây là điều kiện phải đạt trước khi bước tương ứng được thực hiện.

Lằn ranh Điều kiện
Không trỏ stack này vào hệ thống HR thật D7 (Bên kiểm soát / Bên xử lý dữ liệu) còn mở
Không nạp dữ liệu cá nhân thật chưa có bằng chứng đồng ý, chưa có chính sách lưu trữ, chưa có đường xoá
Không mở cổng nào ra ngoài 127.0.0.1 Keycloak admin đang là admin/admin; /admin/fault không xác thực
Không coi đây là kiến trúc đã duyệt cả 11 ADR đều đang ở trạng thái PROPOSED
Không đưa luồng CCCD lên production ADR-003 và D3 khuyến nghị bỏ nó; xem AI_CONTEXT.md §11b
Không đưa Direct Grant lên production RFC 9700 nói password grant MUST NOT be used; CHỈ CHO POC, xem AUTH-STRATEGY.md
Không xoá đường browser / PKCE Đó là PRODUCTION CANDIDATE và là lối duy nhất dẫn tới liên kết IdP

GIW POC Identity Platform · bản demo local · không phải production · sinh từ repository